Key Vault References¶
Inject secrets directly into App Service environment variables using Key Vault References, while keeping Flask code simple.
Architecture¶
flowchart TD
App[App Service platform]
Setting[Key Vault reference app setting]
Env[Resolved environment variable]
MI[Managed Identity]
KV[(Azure Key Vault)]
App --> Setting
App --> Env
App -.-> MI
MI -.-> KV
KV --> Env Solid arrows show runtime data flow. Dashed arrows show identity and authentication.
Prerequisites¶
- Managed identity enabled on App Service
- Key Vault with required secrets
- Key Vault RBAC role:
Key Vault Secrets Userfor the app identity
Step-by-Step Guide¶
Step 1: Configure Key Vault reference app settings¶
Reference syntax:
@Microsoft.KeyVault(SecretUri=https://<vault-name>.vault.azure.net/secrets/<secret-name>)@Microsoft.KeyVault(VaultName=<vault-name>;SecretName=<secret-name>)
az webapp config appsettings set \
--resource-group "$RG" \
--name "$APP_NAME" \
--settings \
DB_PASSWORD="@Microsoft.KeyVault(VaultName=<vault-name>;SecretName=db-password)" \
REDIS_ACCESS_KEY="@Microsoft.KeyVault(SecretUri=https://<vault-name>.vault.azure.net/secrets/redis-access-key)"
| Flag | Description |
|---|---|
--resource-group "$RG" | Targets the resource group that contains the web app. |
--name "$APP_NAME" | Selects the web app that should receive the Key Vault reference settings. |
--settings DB_PASSWORD="@Microsoft.KeyVault(VaultName=<vault-name>;SecretName=db-password)" REDIS_ACCESS_KEY="@Microsoft.KeyVault(SecretUri=https://<vault-name>.vault.azure.net/secrets/redis-access-key)" | Writes app settings whose values are resolved from the specified Key Vault secrets. |
Step 2: Read secrets from os.environ in Python¶
import os
from flask import Flask, jsonify
app = Flask(__name__)
@app.get("/api/config/check")
def config_check():
db_password = os.environ.get("DB_PASSWORD")
redis_key = os.environ.get("REDIS_ACCESS_KEY")
return jsonify({
"db_password_loaded": bool(db_password),
"redis_key_loaded": bool(redis_key)
})
Complete Example¶
import os
import pyodbc
def build_connection_string() -> str:
return (
f"Driver={{{os.environ.get('SQL_DRIVER', 'ODBC Driver 18 for SQL Server')}}};"
f"Server=tcp:{os.environ['SQL_SERVER']},1433;"
f"Database={os.environ['SQL_DATABASE']};"
f"Uid={os.environ['SQL_USER']};"
f"Pwd={os.environ['DB_PASSWORD']};"
"Encrypt=yes;TrustServerCertificate=no;"
)
def connect_with_secret():
return pyodbc.connect(build_connection_string())
Troubleshooting¶
- Environment variable contains literal
@Microsoft.KeyVault(...):- Reference resolution failed; verify identity and Key Vault permissions.-
Secret not foundor stale value: - Check secret name/version and remember updates may take time to refresh.- Works in one slot, fails in another:
- Confirm slot-specific app settings and identity assignments.
- Reference resolution failed; verify identity and Key Vault permissions.-
Advanced Topics¶
- Combine with slot settings to isolate staging vs production secrets.
- Prefer Key Vault References for non-SDK consumers; use SDK + managed identity for dynamic secret operations.
- Rotate secrets in Key Vault without code changes or repo updates.
Run It in the Portal¶
After granting the app's managed identity access to the vault, use Pull reference values or Refresh in the Environment variables toolbar to re-evaluate reference state. Use Show value on a reference row to confirm the resolved secret is returned instead of the literal @Microsoft.KeyVault(...) syntax.