Manage Secrets with Azure Key Vault
Introduction
3 minAzure Key Vault centralizes storage of secrets, cryptographic keys, and TLS certificates for AI applications. Instead of hardcoding API keys for OpenAI, Cosmos DB, or Redis in source code or environment files, applications retrieve them at runtime using managed identity โ no credentials stored anywhere in code or config files.
Key Vault Object Types
7 minKey Vault Auth Flow: App MI โ Entra ID RBAC check โ Key Vault secret โ App (cached)
1. Secrets โ Arbitrary String Values
Store any opaque string value: API keys, connection strings, passwords, JWT signing secrets.
- Unique identifier format:
https://myvault.vault.azure.net/secrets/secret-name - Versioned: each update creates a new version. Old versions still retrievable.
- Activatable/deactivatable with date-based access control.
2. Keys โ Cryptographic Keys
RSA and EC keys for encryption, signing, and unwrapping. The private key material never leaves Key Vault โ your app sends data TO Key Vault for signing/decryption operations, never receives the raw key.
- HSM-backed keys (Premium tier) โ hardware security module protection. Highest compliance.
- Operations:
sign,verify,encrypt,decrypt,wrapKey,unwrapKey.
3. Certificates โ TLS/X.509
Full certificate lifecycle management: create, import, auto-renew (via DigiCert or Let's Encrypt integration). Private key stays in Key Vault. Integrates with App Service for custom domain TLS, API Management, and Application Gateway.
4. Object Type Summary
| # | Type | Contents | Use For |
|---|---|---|---|
| 1 | Secret | String value | API keys, passwords, connection strings |
| 2 | Key | Cryptographic key | Signing JWTs, encrypting data, key wrapping |
| 3 | Certificate | X.509 + private key | TLS certs for domains, mTLS |
Key Vault RBAC Roles
8 min1. Data Plane Roles โ Control What Objects Can Be Read/Written
- Key Vault Secrets User โ read secret values. Assign to managed identity of your AI app. Read-only access to secrets.
- Key Vault Secrets Officer โ full CRUD on secrets (create, update, delete, read, list). Assign to developers and CI/CD pipelines that manage secrets.
- Key Vault Crypto User โ perform crypto operations with keys (sign, decrypt). Does NOT allow reading the raw key material.
- Key Vault Crypto Officer โ manage keys (create, update, delete) + perform operations.
- Key Vault Certificate User โ read certificate values.
- Key Vault Administrator โ full access to ALL data plane operations (secrets + keys + certificates). Use sparingly.
2. Role Assignment Pattern
# Grant AI app read-only access to secrets
az role assignment create \\
--role "Key Vault Secrets User" \\
--assignee-object-id $(az containerapp identity show -n ai-api -g rg --query principalId -o tsv) \\
--scope $(az keyvault show -n myvault --query id -o tsv) 3. Scope Levels
- Vault level โ access to ALL secrets/keys/certs in the vault.
- Individual secret level โ access to only one secret:
/subscriptions/.../secrets/secret-name.
Implement Key Vault with the SDK
10 min1. Basic SDK Pattern
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
credential = DefaultAzureCredential() # Managed identity in prod, az CLI locally
client = SecretClient(
vault_url="https://myvault.vault.azure.net",
credential=credential
)
# Get latest version of a secret
secret = client.get_secret("openai-api-key")
api_key = secret.value
# Get a specific version
specific = client.get_secret("openai-api-key", version="abc123...") 2. Create, Update, and Delete Secrets
client.set_secret("openai-api-key", "sk-abc123") # Create/update
client.set_secret("openai-api-key", "sk-abc123", # Set properties
enabled=True, expires_on=datetime(2026, 12, 31, tzinfo=timezone.utc))
# Disable (deactivate) without deleting
client.update_secret_properties("openai-api-key", enabled=False)
# Delete (soft delete โ goes to deleted state, not permanently gone)
client.begin_delete_secret("openai-api-key").result()
# Purge permanently (only after deletion, if purge protection disabled)
client.purge_deleted_secret("openai-api-key") 3. Secret Versioning
Every set_secret() call creates a new version. Old versions remain accessible forever until explicitly deleted. The "latest" version is what get_secret(name) without a version returns.
# List all versions of a secret
versions = list(client.list_properties_of_secret_versions("openai-api-key"))
for v in versions:
print(v.version, v.enabled, v.expires_on) 4. Implement Caching (Avoid Throttling)
Key Vault has soft rate limits (2,000 secret reads/10 seconds per vault). Fetching secrets on every request causes throttling. Cache secrets locally with expiry:
import time
class SecretCache:
_cache = {}
_ttl_seconds = 300 # 5 minutes
def get(self, name: str) -> str:
cached = self._cache.get(name)
if cached and time.time() - cached["fetched_at"] < self._ttl_seconds:
return cached["value"]
value = secret_client.get_secret(name).value
self._cache[name] = {"value": value, "fetched_at": time.time()}
return value App Service Key Vault References
7 min1. Reference Syntax
# Always-latest version (recommended โ auto-rotates)
@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/openai-api-key/)
# Pinned to specific version (does NOT auto-rotate)
@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/openai-api-key/abc123) 2. Setup Steps (Both Required)
- Assign system-assigned managed identity to App Service
- Assign Key Vault Secrets User role to the MI on the vault
- Set app setting value to the
@Microsoft.KeyVault(...)reference string - App Service resolves the reference and injects the secret value as the env var
3. Soft Delete and Purge Protection
- Soft delete โ always enabled on new vaults. Deleted secrets move to deleted state for 7โ90 days before permanent removal. Prevents accidental deletion.
- Purge protection โ prevents permanent deletion during the soft-delete retention period, even by vault owners. Required for compliance (CMEK scenarios).
โก Key Vault Master Cheatsheet
Exercise โ Centralize AI App Secrets
30 min- Create a Key Vault and store openai-api-key, cosmos-db-connection as secrets
- Assign Secrets User role to a Container App's managed identity
- Use SecretClient with DefaultAzureCredential to retrieve secrets in code
- Implement the local caching class to avoid throttling
- Configure App Service Key Vault Reference (versionless URI) and verify secret resolves
- Update secret value and confirm App Service picks up new value without redeployment
Knowledge Check
5 min- Q: AI app needs to read the OpenAI API key at startup. Minimum required role? A: Key Vault Secrets User
- Q: A developer is Contributor on the subscription but can't read secrets. Why? A: Contributor is a management-plane role; secrets require a data-plane role (Secrets User/Officer)
- Q: App Service Key Vault reference shows the literal reference string, not the secret value. Fix? A: Assign Key Vault Secrets User role to the App Service's managed identity
- Q: Secret was deleted but needs to be recovered. How? A: Soft delete โ recover from deleted state within retention window
- Q: App makes 5,000 Key Vault calls/minute hitting rate limits. Fix? A: Implement local in-process secret cache with 5-minute TTL
Summary
2 minKey Vault is the central secret store for AI applications. Assign Secrets User role (not Contributor) to managed identities. Use versionless URIs in App Service references for auto-rotation. Cache secrets locally to avoid throttling. Soft delete is always on โ recover within the retention window. Never put private key material in env vars โ use Key Vault Crypto operations.
๐ง Memory Tricks
Three object types (SKC): Secrets (strings), Keys (crypto), Certificates (TLS)
Role ladder: Secrets User (read) โ Secrets Officer (CRUD) โ Administrator (everything)
"Contributor โ secret access" โ management plane and data plane are completely separate in Key Vault
Exam Summary Card
2 min| Scenario | Answer |
|---|---|
| App reads secrets | Key Vault Secrets User role on managed identity |
| CI/CD creates/updates secrets | Key Vault Secrets Officer role |
| Contributor can't read secrets | Add Key Vault Secrets User role (data plane) |
| Auto-rotating secret in App Service | Versionless URI reference |
| Rate limiting (too many KV calls) | Local cache with short TTL (5 min) |
| Reference string appears literally | MI missing Secrets User role |
| Prevent permanent deletion | Purge protection enabled |
| Compliance-grade key storage | HSM-backed keys (Premium tier) |
Azure Key Vault
๐ Key Facts
- Object types (SKC) โ Secrets (strings) | Keys (crypto) | Certificates (TLS)
- Secrets User role โ Read-only secret values โ assign to app managed identity
- Secrets Officer role โ Full CRUD on secrets โ CI/CD pipelines, developers
- Contributor โ data โ Management-plane role CANNOT read secrets (common trap)
- Versionless URI โ Auto-rotates โ always resolves to latest version
- Local cache 5 min โ In-process TTL avoids KV throttling (2,000 ops/10s)
- Soft delete โ Always on โ 7โ90 day recovery window. Prevents accidental delete.
- HSM keys โ Premium tier โ FIPS 140-2 Level 3, private key never leaves vault
๐ป Commands & Patterns
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
client = SecretClient(
vault_url="https://myvault.vault.azure.net",
credential=DefaultAzureCredential())
# Get latest version
api_key = client.get_secret("openai-api-key").value
# Cache to avoid throttling
import time; _cache = {}
def get_secret(name):
c = _cache.get(name)
if c and time.time() - c["t"] < 300: return c["v"]
v = client.get_secret(name).value
_cache[name] = {"v": v, "t": time.time()}; return v
# Role assignment
az role assignment create --role "Key Vault Secrets User" --assignee $MI_PRINCIPAL_ID --scope $VAULT_RESOURCE_ID
# App Service KV Reference (versionless = auto-rotates)
# @Microsoft.KeyVault(SecretUri=https://vault.../secrets/key/) Manage App Configuration and Feature Flags
Introduction to Azure App Configuration
3 minAzure App Configuration is a managed service for centralizing application settings and feature flags. Instead of environment variables scattered across deployments, all config lives in one place โ updatable without redeployment, with dynamic refresh and audit history.
Read Configuration with the Provider SDK
8 minLoad and Read Config
from azure.appconfiguration.provider import load
from azure.identity import DefaultAzureCredential
config = load(
endpoint="https://mystore.azconfig.io",
credential=DefaultAzureCredential(),
refresh_on=[WatchKey("sentinel")],
refresh_interval=30
)
# Read values like a dict
model = config["OpenAI:Model"]
endpoint = config["OpenAI:Endpoint"]
# Key Vault reference โ SDK resolves automatically
api_key = config["OpenAI:ApiKey"] # stored as KV ref DefaultAzureCredential. Feature Flags
7 minEnable and Check Feature Flags
from azure.appconfiguration.provider import load
config = load(
endpoint="https://mystore.azconfig.io",
credential=DefaultAzureCredential()
)
# Feature flag key format: .appconfig.featureflag/FlagName
semantic_cache_enabled = config.get(
".appconfig.featureflag/EnableSemanticCache", False
)
if semantic_cache_enabled:
result = semantic_cache_get(prompt)
if result:
return result
return call_llm(prompt) .appconfig.featureflag/{name} pattern. Toggle in the Azure portal โ changes propagate within the refresh interval without any redeployment. Sentinel Key Dynamic Refresh
6 minSentinel Pattern
Instead of polling every key, watch one sentinel key. Update all config values first, then update the sentinel last โ this triggers a refresh in all running instances atomically.
# Update all settings, then sentinel last
az appconfig kv set -n mystore --key "OpenAI:Model" --value "gpt-4o"
az appconfig kv set -n mystore --key "sentinel" --value "v2"
# SDK watches sentinel, refreshes all config on change
config = load(
endpoint="https://mystore.azconfig.io",
credential=DefaultAzureCredential(),
refresh_on=[WatchKey("sentinel")],
refresh_interval=30
) Summary
2 minAzure App Configuration: centralized settings + feature flags, updated without redeployment. Sentinel key pattern for atomic dynamic refresh. Feature flags at .appconfig.featureflag/Name โ toggle in portal. Key Vault references: App Config stores URI, SDK resolves to secret value. App Data Reader RBAC role required. refresh_interval controls max lag for config updates.