Settings and environment variables¶
Set by Pulumi on the Web App¶
| Variable | Purpose |
|---|---|
IS_AZURE_ENVIRONMENT |
Enables Azure-specific settings |
SCM_DO_BUILD_DURING_DEPLOYMENT |
Oryx build on deploy |
PRE_BUILD_COMMAND |
Bootstrap curl |
POST_BUILD_COMMAND |
cicd/post_build.sh |
DISABLE_*_BUILD |
Disable unrelated Oryx detectors |
DISABLE_COLLECTSTATIC |
Defer collectstatic to startup |
HEALTH_CHECK_PATH |
/health-check |
WEBSITE_HEALTHCHECK_MAXPINGFAILURES |
Azure health-check threshold (10); set explicitly so it does not drift |
DJANGO_SETTINGS_MODULE |
Your settings module |
DJANGO_SECRET_KEY |
Random 50-char string |
DJANGO_ALLOWED_HOSTS |
Comma-separated hosts from HostDefinitions |
DJANGO_HOSTS_MAP |
JSON host→aliases when aliases exist |
AZURE_KEY_VAULT |
Vault name |
AZURE_STORAGE_ACCOUNT_NAME |
Storage account |
AZURE_STORAGE_CONTAINER_MEDIA / _STATICFILES |
Blob containers |
CDN_HOST / CDN_PROFILE / CDN_ENDPOINT |
CDN wiring |
DB_HOST / DB_NAME / DB_USER |
Postgres connection |
REDIS_SIDECAR |
When Redis enabled |
DJANGO_TASKS |
When tasks enabled |
DJANGO_RQ_CRON |
When RQ cron scheduler enabled |
RQ_CRON_CONFIG |
Path to consumer cron config (default: cron_config.py) |
AZURE_COMMUNICATION_SERVICE_ENDPOINT |
When ACS enabled |
WEBSITE_HTTPLOGGING_RETENTION_DAYS |
When retention > 0 |
{ENV}_SECRET_NAME |
Key Vault secret names from secrets= |
ACCESS_BLOCK_ENABLED |
Per-site: true by default from Pulumi; false when access_block=False |
ACCESS_BLOCK_QUEUE_URL |
Stable add-only queue SAS URL (fixed start/expiry; rotates with the storage key) |
ACCESS_BLOCK_RESOURCE_GROUP |
Resource group for ARM access-rule updates |
ACCESS_BLOCK_SUBSCRIPTION_ID |
Subscription ID for ARM access-rule updates |
| plus | Consumer environment_variables |
Azure also injects WEBSITE_HOSTNAME (and others).
Read by pulumi_django_azure.settings¶
Also consumed when present:
BLOCK_SUSPICIOUS_PATHS(bool, defaulttruewhenIS_AZURE_ENVIRONMENT) — block hardcoded scanner path patternsBLOCK_EMPTY_USER_AGENT(bool, defaulttruewhenIS_AZURE_ENVIRONMENT) — reject requests with missing/emptyUser-AgentDJANGO_DEFAULT_FROM_EMAILAZURE_CACHE_CONTROL(default long-lived immutable)REDIRECT_ALIASES(bool, default true)CICD_SCRIPTS_BRANCH(bootstrap; not settings.py)
Email (MAILERS)¶
When AZURE_COMMUNICATION_SERVICE_ENDPOINT is set (Pulumi does this when ACS is enabled for the site), settings configure Django 6.1 MAILERS:
MAILERS = {
"default": {
"BACKEND": "django_azure_communication_email.EmailBackend",
"OPTIONS": {"endpoint": "<from AZURE_COMMUNICATION_SERVICE_ENDPOINT>"},
},
}
On Azure, AZURE_TENANT_ID is also set so the backend can authenticate with DefaultAzureCredential (managed identity). Set DJANGO_DEFAULT_FROM_EMAIL for the sender address. When ACS is not enabled, no MAILERS entry is added — override with your own mailer locally or in the consumer settings module.
Scanner probe blocking (SuspiciousRequestBlockMiddleware)¶
Registered by patch_django_settings_for_azure on Azure when either BLOCK_SUSPICIOUS_PATHS or BLOCK_EMPTY_USER_AGENT is true (both default on). Inserted before SecurityMiddleware.
Always exempt: HEALTH_CHECK_PATH, paths under /.well-known/.
Path rules (when BLOCK_SUSPICIOUS_PATHS=true, case-insensitive):
| Rule | Examples |
|---|---|
| Dot-prefixed path segment | /.env, /.git/config, /vendor/.env |
| Suffix | .php, .asp, .aspx, .jsp, .cgi, .sql, .bak, .rb |
| Prefix | /wp-, /cgi-bin/, /phpmyadmin, /administrator/, /vendor/phpunit, /drupal, /joomla, /laravel, /symfony, /magento, /prestashop, /typo3, /actuator, /containers/, /server-status, /server-info |
| Contains | /phpunit/ |
User-Agent (when BLOCK_EMPTY_USER_AGENT=true): block if User-Agent is missing, empty, or whitespace-only.
Blocked requests return HTTP 404 and log at DEBUG on pulumi_django_azure.security with reason=suspicious_path or reason=empty_user_agent.
Client IP resolution¶
RequestLogContextMiddleware and access-block enqueue use client_ip_from_request:
- Azure front-end headers (overwritten by App Service, not spoofable):
Client-IP, thenX-Client-IP, thenX-ARR-CLIENTIP - First non-loopback hop in
X-Forwarded-For(skips forged127.0.0.1prefixes scanners often send; Azure appends the real client) REMOTE_ADDR
Ports in Azure-style values (e.g. 203.0.113.10:54321) are stripped before logging or Deny rules.
Automated access block (SuspiciousRequestAccessBlockMiddleware)¶
When ACCESS_BLOCK_ENABLED=true and ACCESS_BLOCK_QUEUE_URL is set (Pulumi default for add_django_website), suspicious requests are enqueued for the shared access-block Function. See Automated access block.
| Setting | Default |
|---|---|
ACCESS_BLOCK_ENABLED |
true on each Web App from Pulumi (unless access_block=False) |
ACCESS_BLOCK_QUEUE_URL |
(from Pulumi when access block is enabled for that site) |
Rate threshold, window, TTL escalation, and the 500-rule cap are configured on the Function app, not in Django.
Helper¶
patch_django_settings_for_azure(INSTALLED_APPS, MIDDLEWARE, TEMPLATES) — see Django app.
Runtime clients¶
When configured:
AZURE_KEY_VAULT_CLIENT— Key VaultSecretClientAZURE_CREDENTIAL/ storage token credential via managed identity helpers inazure_helper.py