Configuration Guide#

HASTE environments are configured with the Azure Developer CLI. Every setting is supplied with azd env set <NAME> <value> before azd up; the values are read by infra/main.bicepparam at provision time and by the deploy hooks in deploy/. Defaults live in main.bicepparam, so an unset variable falls back to a sensible value.

This guide documents each configuration mode. For the end-to-end workflow, see setup/README.md and deployment.md.

Contents#

  • Core settings

  • Batch (create vs. bring-your-own)

  • Batch image tags and pool immutability

  • Email sender domain

  • Front Door

  • Development mode

  • First-admin bootstrap

  • Cleaning up an environment

Core settings#

Variable

Default

Purpose

HASTE_RESOURCE_PREFIX

ai4gl

Prefix for all resource names.

HASTE_RANDOM_SUFFIX

dev1

Per-environment suffix; keeps names unique.

AZURE_LOCATION

westus2

Azure region.

HASTE_APIM_PUBLISHER_EMAIL

APIM publisher email (required).

HASTE_APIM_PUBLISHER_NAME

AI For Good Lab

APIM publisher name.

HASTE_SHARED_RESOURCE_GROUP

env RG

Resource group holding bring-your-own shared resources (Batch, ACR).

HASTE_SHARED_ACR_NAME

Shared Azure Container Registry name (without .azurecr.io).

Resource names are HASTE_RESOURCE_PREFIX + HASTE_RANDOM_SUFFIX based (not azd’s resourceToken) so what-if stays clean against existing deployments.

Batch (create vs. bring-your-own)#

HASTE runs GPU workloads on Azure Batch. Both the Batch account and the GPU pool can either be created in the environment resource group or reused from a shared resource group.

Variable

Default

Values

Purpose

HASTE_BATCH_ACCOUNT_MODE

Create

Create | Existing

Create a Batch account in the env RG, or reference a shared one.

HASTE_EXISTING_BATCH_ACCOUNT

account name

Required when the account mode is Existing; looked up in HASTE_SHARED_RESOURCE_GROUP.

HASTE_BATCH_POOL_MODE

Create

Create | Existing

Create the GPU pool, or reference an existing one.

HASTE_EXISTING_BATCH_POOL_ID

pool resource id

Required when the pool mode is Existing.

Additional pool parameters (batchPoolVmSize, batchPoolMaxNodes, batchPoolSubnetName) have defaults in infra/main.bicep and can be overridden by adding them to main.bicepparam.

Common combinations:

  • Self-contained forkHASTE_BATCH_ACCOUNT_MODE=Create and HASTE_BATCH_POOL_MODE=Create create a Batch account and a GPU pool in the environment resource group.

  • Shared account, own poolHASTE_BATCH_ACCOUNT_MODE=Existing with HASTE_BATCH_POOL_MODE=Create creates only a new named pool on the shared account, in the shared resource group, via a cross-RG-scoped sub-module. It never modifies the account or sibling pools.

  • Shared account and pool — both set to Existing reference the account and pool for app-settings wiring only; nothing is written to the shared resource group.

When the pool is created on a shared account, review what-if against both the environment resource group and HASTE_SHARED_RESOURCE_GROUP, and make sure the deploy identity has pool-write on the shared account.

Batch image tags and pool immutability#

The training and imageryprep container images feed two places: the Batch pool (as pre-fetched containerImageNames) and the api/queues app settings (which tell the runner what tag to launch tasks with).

Variable

Default

Purpose

HASTE_TRAINING_IMAGE

hastetraining:1.4.1

Training image repo:tag.

HASTE_IMAGERYPREP_IMAGE

hasteimageryprep:1.4.1

Imageryprep image repo:tag.

A Batch pool’s deploymentConfiguration is immutable — you cannot change a pool’s image tags after creation. Two consequences:

  • Bumping a tag requires recreating the pool (delete and re-provision), not an in-place update.

  • Reusing a shared pool (HASTE_BATCH_POOL_MODE=Existing) means the app settings must use a tag the pool and the shared ACR actually have. This is a mostly harmless constraint, because each task submits its own image tag at runtime and Batch pulls it if the node doesn’t already have it — but the app settings still need a valid tag.

To make this transparent, the preprovision hook deploy/resolve-batch-image-tags.ps1 reads the existing pool’s containerImageNames and sets HASTE_TRAINING_IMAGE / HASTE_IMAGERYPREP_IMAGE for you when HASTE_BATCH_POOL_MODE=Existing. It runs only in that mode and never clobbers a tag you set explicitly — set either variable yourself to override the auto-resolved value.

Email sender domain#

The email backend (Azure Communication Services) is provisioned in-IaC, so its connection string is a deploy-time output rather than a manually pasted secret.

Variable

Default

Values

Purpose

HASTE_EMAIL_SENDER_DOMAIN_TYPE

AzureManaged

AzureManaged | Custom

Sender-domain strategy.

HASTE_EMAIL_CUSTOM_DOMAIN

domain

Required when the type is Custom (e.g. notifications.example.com).

  • AzureManaged provisions an azurecomm.net sender domain with no DNS step — the default, best for forks and quick environments.

  • Custom provisions a custom sender domain. DNS verification (TXT/SPF/DKIM records) lives in the customer’s DNS zone and is an out-of-band, one-time step.

No Key Vault is introduced; the connection string is wired from a listKeys() output to the Function App settings.

Front Door#

Azure Front Door and its WAF are a feature-flagged module, deployed only when enabled.

Variable

Default

Purpose

HASTE_ENABLE_FRONT_DOOR

false

Provision Front Door + WAF in front of the app.

Development mode#

Development mode is a dev-only switch. It must never be true in production.

Variable

Default

Purpose

HASTE_DEVELOPMENT_MODE

false

Anonymous Function auth + auto-provisioning of users as administrators.

When true, the API uses anonymous auth and GetUserById auto-creates any unknown caller as an administrator — convenient for local and throwaway environments, unacceptable for production. When false (the default and the production setting), Functions are key-protected (the postdeploy hook injects the host key into the APIM backends) and unknown users are rejected until an admin adds them.

First-admin bootstrap#

Production uses DEVELOPMENT_MODE=false, so users are managed explicitly and are not auto-provisioned as administrators. That creates a bootstrap problem: an admin is needed to add the first users, but a fresh environment has none. The postdeploy hooks solve it by seeding a first admin.

Variable

Default

Purpose

HASTE_FIRST_ADMIN_EMAIL

signed-in user

Email of the first administrator.

  • Interactive deploys — if HASTE_FIRST_ADMIN_EMAIL is unset, the seed uses the signed-in deployer’s email (deploy/seed-storage-defaults.ps1), writes it into users_acl.json as an administrator, and invites it to the Static Web App (deploy/invite-user.ps1).

  • Non-interactive / CI / service-principal deploys — there is no signed-in user, so set HASTE_FIRST_ADMIN_EMAIL. Without it, the first-admin seed is skipped and the environment has no administrator.

Both hooks are idempotent (skip-if-exists / dedup). After the first admin signs in, subsequent users are added through the app’s admin user-management flow — the first-admin seed is a one-time bootstrap, not the ongoing mechanism.

Cleaning up an environment#

Deleting an environment does not immediately free its name. APIM, Front Door, and Batch resources are soft-deleted and retained by Azure for a day or two, so you cannot reuse the same HASTE_RESOURCE_PREFIX + HASTE_RANDOM_SUFFIX combination right away.

To tear down and reuse a name sooner:

# Delete the environment's resources.
azd down --force --purge

# APIM must be purged from its soft-deleted state before the name is free.
az apim deletedservice list -o table
az apim deletedservice purge --service-name <name-from-the-list> --location <region>

azd down --purge purges soft-deletable resources it manages; a shared Batch pool created on a shared account is additive, so remove it explicitly if it is no longer needed. Otherwise, choose a new suffix and let Azure auto-purge the old resources.