Use Azure Key Vault With Django

Load Django secrets from Azure Key Vault: use Key Vault references in App Service and Container Apps, read secrets with azure-identity and managed identities, mount them on AKS with the Secrets Store CSI driver, and rotate values without redeploying code.

Problem statement

Your Django app runs on Azure, and secrets currently live in App Service application settings or Container Apps secrets in plain form, copied between environments by hand. Azure Key Vault centralizes them with access policies or RBAC, versioning, and audit logs. Each Azure hosting option can pull from Key Vault in its own way, and with managed identities no credentials are needed to reach the vault itself.

Key Vault for DjangoKey Vaultsecrets, versionsManaged identityRBAC accessPlatform referenceApp Service, ACADjangoos.environPlatforms resolve Key Vault references into ordinary environment variables.
  1. Create a Key Vault with RBAC authorization and add secrets (django-secret-key, database-url).
  2. Enable a managed identity on the app and grant it the Key Vault Secrets User role on the vault.
  3. App Service: set an app setting to @Microsoft.KeyVault(SecretUri=https://shop-kv.vault.azure.net/secrets/django-secret-key/).
  4. Container Apps: define a secret with a Key Vault reference and map it to an environment variable.
  5. AKS: mount secrets with the Secrets Store CSI driver and workload identity, or read them in code with azure-identity.

Step-by-step solution

1. Create the vault and secrets

az keyvault create -g shop-prod -n shop-kv --location westeurope --enable-rbac-authorization true
az keyvault secret set --vault-name shop-kv -n django-secret-key \
  --value "$(python -c 'import secrets; print(secrets.token_urlsafe(50))')"
az keyvault secret set --vault-name shop-kv -n database-url --value "postgres://..."

Secret names allow letters, digits, and hyphens; map them to Django's underscore names in the platform configuration.

2. Grant the app's identity access

az webapp identity assign -g shop-prod -n shop-web
PRINCIPAL=$(az webapp identity show -g shop-prod -n shop-web --query principalId -o tsv)
az role assignment create --assignee "$PRINCIPAL" --role "Key Vault Secrets User" \
  --scope "$(az keyvault show -n shop-kv --query id -o tsv)"

With RBAC, roles can be scoped to the whole vault or a single secret.

service and methodMethodCode change?App ServiceKey Vault referencenoneContainer Appssecret with keyVaultUrlnoneAKSCSI driver mountread files or envVMazure-identity SDKsmall helperManaged platforms resolve references, so settings stay unchangeddjango-deployment.com
All four use a managed identity to authenticate to the vault.

3. App Service references

In the app's configuration, set:

SECRET_KEY = @Microsoft.KeyVault(SecretUri=https://shop-kv.vault.azure.net/secrets/django-secret-key/)
DATABASE_URL = @Microsoft.KeyVault(VaultName=shop-kv;SecretName=database-url)

App Service resolves these with the managed identity and exposes the values as environment variables. Without a version in the URI, it picks up new versions periodically and on restart. The Configuration blade shows a green check when a reference resolves.

4. Container Apps

az containerapp secret set -g shop-prod -n shop-web \
  --secrets "django-secret-key=keyvaultref:https://shop-kv.vault.azure.net/secrets/django-secret-key,identityref:system"
az containerapp update -g shop-prod -n shop-web \
  --set-env-vars "SECRET_KEY=secretref:django-secret-key"

New revisions read the current secret value; restart or create a revision after rotating.

5. AKS and VMs

On AKS, a SecretProviderClass with workload identity mounts secrets as files and can sync them into a Kubernetes Secret for environment variables. On VMs or anywhere else, read secrets in settings:

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

_kv = SecretClient(vault_url=os.environ["KEY_VAULT_URL"], credential=DefaultAzureCredential())
SECRET_KEY = os.environ.get("SECRET_KEY") or _kv.get_secret("django-secret-key").value

DefaultAzureCredential uses the managed identity in Azure and your az login session locally.

rotation without code changes1Set new secret versionaz keyvault secret set2Old SECRET_KEY to fallbackssessions stay valid3Restart or new revisionreads new value4Verify in app logsno auth errors5Disable old versionwhen unusedUnversioned references always resolve to the latest value on restartdjango-deployment.com
Azure Key Vault can also emit events when secrets near expiry.

Explanation

Key Vault stores secrets as versioned objects protected by Azure RBAC and logged through diagnostic settings. Azure's managed hosting services understand Key Vault references and resolve them using the app's managed identity, so Django receives plain environment variables. Where references are not available, the azure-identity library obtains tokens from the same managed identity, keeping credentials out of configuration entirely.

Edge cases / notes

  • Network restrictions. If the vault uses private endpoints or firewall rules, the app must reach it through VNet integration, or references fail to resolve.
  • Soft delete. Deleted secrets are recoverable for a retention period; reusing a name may require purging first.
  • Caching. Fetch secrets once at startup; per-request vault calls add latency and can hit throttling limits.

Next steps

FAQ

Do I need code changes to use Key Vault on App Service?

No. Key Vault references resolve to environment variables automatically.

How does the app authenticate to Key Vault?

With a managed identity granted the Key Vault Secrets User role.

Why does my reference show an error in the portal?

Usually the identity lacks access, the secret name is wrong, or network rules block the vault.

Do running apps see a new secret version immediately?

Not always. Restart the app or create a new revision to be sure it reads the new value.

Keep going