Recommend an Application Configuration Management Solution — Lesson
AZ-305 › Unit 4: Design infrastructure solutions › Design an application architecture › Recommend an application configuration management solution
Recommend an Application Configuration Management Solution — Lesson
A payments team rolls out a "5% discount" promotion at on Black Friday. The discount is meant to expire at . Three engineers are needed to coordinate the change: one to update the appsettings.json in source control, one to redeploy four services in two regions, one to verify the change took effect everywhere. The deployment takes 22 minutes; by traffic has spiked and the team is too busy to safely redeploy if anything needs adjusting. At the same dance repeats, this time without the luxury of a low-load window. The fix is one architectural change: move all promotion configuration into Azure App Configuration with feature flags. The next Black Friday, a single engineer toggles the flag at and again at — no redeploys, no source-control commits, no 22-minute lag. This lesson is about choosing the right config-management layer so changes that should be one toggle do not require a release train.
We will work through Azure's application-configuration story the way the AZ-305 exam expects you to: distinguishing Azure App Configuration from Key Vault, from App Service / Container Apps environment variables, from Kubernetes ConfigMaps and Secrets — and using them together. Reference: the AZ-305 exam study guide, particularly Chapter 4 Skill 4.2 on application configuration.
Why This Matters
Configuration is everywhere. Connection strings, feature flags, retry counts, regional toggles, A/B-test cohorts, environment-specific URLs, rate limits, feature gating per tenant. Without a managed store, configuration sprawls across appsettings.json files, environment variables in deployment YAML, hand-edited Helm values, and per-region overrides. Every change requires a redeploy; every redeploy risks an outage; every override hides a future maintenance bill. Done right, configuration is a managed, versioned, audited, refreshable asset — and changes that should be one toggle take one toggle, rolled back just as easily if they break something downstream.
The AZ-305 exam tests this LO because the right answer combines two services (App Configuration for non-secret config, Key Vault for secrets) and integrates them with the deployment host (App Service settings, Container Apps env vars, Kubernetes ConfigMaps / Secrets / CSI). Picking just Key Vault makes feature-flag flips slow; picking just App Configuration puts secrets in the wrong store; embedding values in source control creates audit and rotation problems. If you can map a workload to the right blend and configure refresh, RBAC, and identity correctly, you will pass this slice of the exam and design configuration like a senior architect.
Prerequisites
Before working through this lesson, make sure you can answer each prompt below in one or two sentences.
- App settings vs config files. Can you describe how App Service's "Application settings" feed environment variables to a web app? — Self-check: which 12-factor principle does this align with?
Key Vaultbasics. Are you familiar with secret, key, and certificate vault objects and RBAC access? — Self-check: which is meant for passwords / connection strings?- Feature flags. Do you know what a feature flag is and what problem it solves? — Self-check: name a common feature-flag use case.
- Managed identity. Can you describe how a workload reads from Key Vault without credentials? — Self-check: which identity Azure resources use to talk to Key Vault?
- Refresh semantics. Are you familiar with hot-reload vs restart-required configuration? — Self-check: how does App Service typically apply application-settings changes?
If any of these feels shaky, review the configuration and identity modules in Units 1 and 4 of the AZ-305 guide.
Learning Objectives
By the end of this lesson, you will be able to:
- Analyse a workload's configuration surface (non-secret config, secrets, feature flags, environment overrides) and translate it to the right managed store.
- Evaluate
Azure App Configuration(Standard / Free / Premium) vs alternatives —Key Vault, app settings, env vars, Kubernetes ConfigMaps. - Design a configuration topology that uses
App Configurationfor non-secret config withKey Vault referencesfor secrets and feature flags for runtime toggles. - Configure identity-based access to both stores via managed identity / workload identity (no embedded keys).
- Recognise anti-patterns — secrets in App Configuration, config in source control, missing refresh strategy, per-environment branches — and rewrite them.
- Implement label-based or key-prefix-based environment partitioning (
dev,staging,prod) within a single config store.
Building Blocks
Read this section as a glossary. Each term: analogy, formal definition, why it matters.
Azure App Configuration — Azure's managed key-value-and-feature-flag store. Like a centralised settings file every app reads. Formally, Microsoft.AppConfiguration/configurationStores resource available in Free / Developer / Standard / Premium tiers. Bundles key-value storage, feature flag schema, label-based environments, change-history, and Key Vault references. It matters because App Configuration is the canonical Azure answer for runtime config — most exam questions on this LO route to it.
Key Vault — Azure's managed secret / key / certificate store. Formally, Microsoft.KeyVault/vaults (Standard or Premium with HSM). RBAC-protected, audited, with soft-delete and purge protection. It matters because secrets do not belong in App Configuration — Key Vault is the supported store for credentials and certificates, and App Configuration can reference Key Vault secrets via its native reference format.
Key-value pair — The base unit of App Configuration. Like a Python dictionary entry. Formally, an entry with key, optional label, value, and contentType. It matters because the key-label combination identifies a unique configuration entry — the same key with different labels models environment-specific values.
Label — A secondary axis for App Configuration keys. Like a Git branch for configuration. Formally, an optional string that disambiguates the same key across environments (dev, staging, prod). It matters because labels are how a single store serves multiple environments without duplicate keys.
Feature flag — A typed key in App Configuration that represents a boolean / percentage / targeted feature toggle. Formally, a key with contentType: application/vnd.microsoft.appconfig.ff+json;charset=utf-8. Supports targeting (specific users), percentage rollout, and time windows. It matters because feature flags let teams ship dark code and toggle it on without redeploying.
Key Vault reference — A special App Configuration value that points to a Key Vault secret. Formally, contentType: application/vnd.microsoft.appconfig.keyvaultref+json with a value like {"uri":"https://kv.vault.azure.net/secrets/SqlConn"}. It matters because it lets one App Configuration store unify non-secret config and references to secrets — clients see one consistent surface.
Managed identity (system-assigned / user-assigned) — An Azure-managed identity that resources use to authenticate. Like the resource's own employee badge. Formally, a service principal automatically created (system-assigned) or explicitly created (user-assigned) and granted RBAC roles. It matters because both App Configuration and Key Vault access should be identity-based — no embedded credentials.
appsettings.json (App Service) — App Service's container of environment-variable-bound settings. Formally, surfaced in siteConfig.appSettings and siteConfig.connectionStrings on Microsoft.Web/sites. Each becomes an env var visible to the app at runtime. It matters because it is the deployment-time surface that most code reads from — App Configuration's value comes from feeding it.
ConfigMap / Secret (Kubernetes) — Kubernetes-native config objects. ConfigMap for non-secret config; Secret for secret material (base64-encoded). It matters because AKS workloads can use them, but they sprawl across namespaces and lack audit by default. Better pattern: pull from App Configuration / Key Vault via the CSI Secrets Store driver.
Refresh / sentinel key — A pattern where the application polls a single sentinel key in App Configuration to detect change. Formally, register a sentinel like app:settings:sentinel with the App Configuration provider; updating the sentinel causes the app to refresh all bound keys. It matters because without refresh, changes in the store do not take effect until restart.
Deep Dive
1. The three config tiers — App Configuration, Key Vault, host-native
Configuration data falls into three categories. Each has a different right answer.
| Category | Examples | Right answer |
|---|---|---|
| Non-secret runtime config | Feature flags, retry counts, regional toggles, URLs | Azure App Configuration |
| Secrets | DB connection strings, API keys, certificates | Azure Key Vault |
| Per-instance / build-time | Container image tag, deployment slot name | Host-native (App Service settings, Container Apps env vars, K8s manifests) |
[!TIP] The boundary between categories is identity. If the value should be visible to operators in plain text (a percentage rollout), it goes in App Configuration. If it must be auditably retrieved with no plain-text exposure, it goes in Key Vault. App Configuration's Key Vault references give you one unified surface to the application code.
2. Azure App Configuration tiers
| Tier | Storage limit | Requests/hour | Replicas | Geo-replication | Best for |
|---|---|---|---|---|---|
| Free | 10 MB | 1000 | 1 | No | Dev/test |
| Developer | 1 GB | varies | 1 | No | Small dev/test, costs less than Standard |
| Standard | 1 GB | 1 | Manual cross-region setup | Most production | |
| Premium | 4 GB | Up to 5 replicas | Yes (auto) | Mission-critical, multi-region, high-throughput |
[!IMPORTANT] Free tier is hard-limited to requests/hour — easy to exceed at startup if many app instances bootstrap simultaneously. Standard's rps handles most production. Use sentinel-based polling to minimise request volume.
3. Environment partitioning — labels vs separate stores
Two patterns the exam tests:
| Pattern | How it works | Pros | Cons |
|---|---|---|---|
| One store, labels | Same key across labels dev, staging, prod | Single source of truth, easy to compare | Cross-environment risk if labels are confused |
| Store per env | appcs-dev, appcs-staging, appcs-prod | Strong isolation; per-env RBAC | Duplicated key inventory; manual sync risk |
Most teams use labels within one store, with RBAC scoped per label group. The exam favours labels for single-tenant SaaS scenarios; separate stores for regulated workloads where prod must be isolated from non-prod.
4. Feature flags — flipping behaviour without redeploy
Feature flags are first-class in App Configuration. Three flag patterns the exam tests:
| Pattern | When |
|---|---|
| Simple boolean | feature.OrdersV2 = true/false |
| Percentage rollout | Enable for 25% of users (random sample) |
| Targeted | Enable for specific tenants / user lists |
| Time window | Enable between and on a given date |
{
"id": "OrdersV2",
"description": "New orders pipeline",
"enabled": true,
"conditions": {
"client_filters": [
{ "name": "Microsoft.Percentage", "parameters": { "Value": 25 } },
{ "name": "Microsoft.TimeWindow", "parameters": { "Start": "Fri, 14 Nov 2025 09:00:00 GMT", "End": "Fri, 14 Nov 2025 17:00:00 GMT" } }
]
}
}[!TIP] The Percentage filter uses a stable hash on the request context (user, tenant) so the same user gets a consistent answer across requests within the rollout. Combine with the Targeting filter to override specific accounts.
5. Key Vault references and identity flow
Apps should not have direct credentials to either store. The supported pattern:
- The app has a managed identity.
- The identity has
App Configuration Data Readeron the App Configuration store. - The same identity has
Key Vault Secrets Useron the Key Vault. - The app reads a value from App Configuration; if it is a Key Vault reference, the App Configuration provider transparently resolves it by calling Key Vault with the same identity.
The app code does not see Key Vault directly — it asks App Configuration for SqlConn and gets the resolved secret. RBAC is split: App Configuration controls "who can see what config exists"; Key Vault controls "who can resolve the secret value".
resource ac 'Microsoft.AppConfiguration/configurationStores@2024-05-01' = {
name: 'appcs-prod'
location: location
sku: { name: 'Standard' }
properties: {
disableLocalAuth: true
enablePurgeProtection: true
softDeleteRetentionInDays: 7
publicNetworkAccess: 'Disabled'
}
identity: { type: 'SystemAssigned' }
}
resource roleApp 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(ac.id, appPrincipalId, 'AppConfigurationDataReader')
scope: ac
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')
principalId: appPrincipalId
principalType: 'ServicePrincipal'
}
}[!IMPORTANT] Set
disableLocalAuth: trueto disable access keys. The only way in is via Entra-ID identity. This is the Microsoft-recommended production posture.
6. Kubernetes integration — CSI Secrets Store driver
When workloads run on AKS, the supported pattern for both config and secrets is the CSI Secrets Store driver with the Azure Key Vault provider. The driver mounts Key Vault secrets as files into pods and can sync them to Kubernetes Secret objects for in-cluster use. The same pattern works against App Configuration via the provider's auto-resolution of Key Vault references.
| Approach | Pros | Cons |
|---|---|---|
| CSI Secrets Store driver (Key Vault) | Audit at Key Vault layer, no static creds in cluster | Need to learn CSI semantics |
| Native ConfigMap / Secret | Familiar Kubernetes UX | Sprawl across namespaces, no per-secret audit |
| Reloader / external-secrets operator | Open-source community pattern | Self-managed |
Microsoft recommends the CSI Secrets Store driver for AKS workloads because it keeps secret material under Key Vault governance while still surfacing as ordinary Kubernetes volumes / Secrets to the application.
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
name: sqlconn-spc
spec:
provider: azure
parameters:
usePodIdentity: "false"
useVMManagedIdentity: "true"
userAssignedIdentityID: "<workload-mi-client-id>"
keyvaultName: "kv-prod"
objects: |
array:
- |
objectName: SqlConn
objectType: secret
tenantId: "<tenant-id>"[!TIP] Use the AKS workload-identity flow (federated credentials between the cluster's OIDC issuer and Entra ID) so that pods authenticate to Key Vault without storing secrets. This is the Microsoft-recommended modern pattern, replacing the older AAD Pod Identity preview.
7. Refresh — making changes visible without restart
By default, App Configuration values are loaded at app startup and never re-read. To pick up changes without restarting:
builder.Configuration.AddAzureAppConfiguration(options =>
{
options.Connect(endpoint, credential)
.Select(KeyFilter.Any, LabelFilter.Null)
.Select(KeyFilter.Any, "prod")
.ConfigureRefresh(refresh =>
{
refresh.Register("app:settings:sentinel", refreshAll: true)
.SetCacheExpiration(TimeSpan.FromSeconds(30));
})
.UseFeatureFlags(ff => ff.SetCacheExpiration(TimeSpan.FromSeconds(30)));
});The pattern: register a "sentinel" key. The app polls only the sentinel (cheap) on each request. When ops want to push a change, they bump the sentinel value. The provider then reloads all bound keys. Without the sentinel pattern, every key would require its own poll — expensive at scale.
// Find which keys changed in App Configuration over the last 24 hours
AzureDiagnostics
| where TimeGenerated > ago(24h)
| where ResourceType == "CONFIGURATIONSTORES"
| where OperationName has "KvSet" or OperationName has "KvDelete"
| project TimeGenerated, key=tostring(properties.key), label=tostring(properties.label), Caller, OperationName
| order by TimeGenerated descWorked Examples
Easy — pick the right store
Problem. A team needs to manage (a) the SQL connection string, (b) a list of allowed CORS origins, (c) a boolean "experimental UI" feature flag. Recommend storage for each.
Solution. All three live in App Configuration; the connection string is a Key Vault reference to a secret in Key Vault, the CORS origins are a regular key-value, and the feature flag is a feature-flag-typed key. The app reads all three from App Configuration; Key Vault is transparent.
Medium — environment partitioning
Problem. A SaaS app has dev, staging, and prod environments and shares the same code base. Recommend a config layout.
Solution. One App Configuration store with labels dev, staging, prod. Each environment-specific value is stored as (key, label) pair. The app's startup code selects the label matching its environment (builder.Configuration.AddAzureAppConfiguration(o => o.Select("*", env))). RBAC: a non-prod service principal has App Configuration Data Reader only at labels dev and staging; prod has its own SP. The store is in a separate non-prod subscription if regulatory isolation demands it.
Hard — multi-region with refresh
Problem. A global app runs in 3 regions and reads configuration from App Configuration. Operators need to flip a feature flag instantly worldwide. Recommend a topology.
Solution. App Configuration Premium tier with replicas in each of the 3 regions. Each region's app instances connect to their local replica (geo-replication is read-only fan-out from the primary). When operators bump a feature flag and the sentinel, the change propagates to replicas within seconds; apps polling the sentinel detect the change within their cache expiration. Total operator-action-to-globally-visible time is under 30 seconds with a 30-second cache expiration.
[!TIP] Premium tier supports up to 5 replicas across regions. Standard tier requires manual cross-region setup (multiple stores synced via an Action Group / Logic App) — possible but operationally heavier.
Visual Explanations
Figure 1 — Configuration decision flow
Figure 2 — Layered store topology
Figure 3 — Quick chooser
| Scenario | Right answer |
|---|---|
| Per-environment URLs (dev/stg/prod) | App Configuration with labels |
| DB password / API key | Key Vault, referenced from App Configuration |
| Feature flag with percentage rollout | App Configuration feature flag |
| Container image tag | Pipeline parameter / deployment manifest |
| Per-region toggle | App Configuration with label-or-key suffix per region |
| Build-time constant | Source code / compile-time |
| TLS certificate | Key Vault certificate |
Common Mistakes
❌ Myth: "Store secrets in App Configuration — they're encrypted at rest anyway." ✅ Reality: App Configuration is not a secret store. Plain-text values are readable by anyone with
App Configuration Data Reader. Secrets belong in Key Vault, referenced from App Configuration. Why it's tricky: Both are managed, encrypted-at-rest stores. The access model and audit are very different.
❌ Myth: "Restart picks up new config — that's fine." ✅ Reality: Restart-only config means changes require a release. The whole point of App Configuration is to support live refresh via the sentinel pattern. Why it's tricky: Many teams add App Configuration but never wire up refresh; they get a managed store but not the operational benefits.
❌ Myth: "Use one App Configuration store per environment." ✅ Reality: Labels in one store are usually better — they keep the key inventory aligned across environments. Separate stores fit regulated workloads where prod must be isolated. Why it's tricky: Operators conflate "isolation" with "separate resource"; labels with proper RBAC give equivalent isolation cheaper.
❌ Myth: "Use the access key for App Configuration — it's simpler." ✅ Reality: Access keys are a shared secret with no per-identity audit. Use Entra ID with managed identities. Disable local auth (
disableLocalAuth: true) in production. Why it's tricky: Access keys are visible in the portal and easy to copy-paste; managed identity requires a bit more setup but is the right pattern.
Practice Exercises
🟢 Exercise 1. A team needs to manage a database password and a JSON config object. Where does each live?
▶💡 Hint
Secrets vs non-secrets.
▶✅ Solution
Database password Key Vault as a secret. JSON config App Configuration (with contentType: application/json). If the JSON contains a secret field, store the secret in Key Vault and reference it from the JSON via App Configuration's Key Vault reference, or split the JSON into non-secret keys + a Key Vault reference for the secret part.
🟡 Exercise 2. A dev, staging, prod setup has the same SQL connection string template (Server=...) but different server names per env. Design.
▶💡 Hint
Same key, different labels.
▶✅ Solution
Three Key Vault secrets: SqlConn-dev, SqlConn-staging, SqlConn-prod. One App Configuration store with one key SqlConn and three labels (dev, staging, prod), each pointing to the appropriate Key Vault secret URI. The app at startup selects the label matching its env.
🟡 Exercise 3. A feature flag must be on for 10% of users, with 3 specific test accounts always on regardless. Design.
▶💡 Hint
Two filters: Percentage + Targeting.
▶✅ Solution
Configure the flag with two client_filters: Microsoft.Targeting listing the three test accounts (always-on), and Microsoft.Percentage with value 10. The Targeting filter evaluates first; users in the audience are on regardless of the percentage. Remaining users hit the 10% percentage roll.
🔴 Exercise 4. An app reads from App Configuration at startup. Operators bump a feature flag but the app doesn't pick it up. Diagnose.
▶💡 Hint
Refresh requires registration.
▶✅ Solution
The provider was configured without ConfigureRefresh / sentinel. Add the sentinel pattern: register a key like app:settings:sentinel, set a cache expiration, and bump the sentinel when feature flags change. The provider will then re-poll and refresh.
🔴 Exercise 5. A team uses App Configuration but stores a shared access key in source control. Recommend a fix.
▶💡 Hint
Disable local auth.
▶✅ Solution
(1) Set disableLocalAuth: true on the App Configuration store. (2) Assign the app's managed identity App Configuration Data Reader on the store. (3) Update the app's connect call to use DefaultAzureCredential instead of a connection string. (4) Rotate the keys (they should no longer work but rotate for audit hygiene). (5) Remove the key from source control history with git filter-repo / BFG.
🟢 Exercise 6. True or false: App Configuration Standard tier supports automatic geo-replication.
▶💡 Hint
Check the tier matrix.
▶✅ Solution
False. Automatic geo-replication is a Premium-tier feature. Standard tier supports a single store; cross-region high-availability requires either Premium (with replicas) or manually-synced multiple Standard stores.
🟡 Exercise 7. Design a Bicep snippet for an App Configuration Standard store with Entra-ID-only access and a Key Vault reference inserted for SqlConn.
▶💡 Hint
Microsoft.AppConfiguration/configurationStores/keyValues resource type.
▶✅ Solution
resource ac 'Microsoft.AppConfiguration/configurationStores@2024-05-01' = {
name: 'appcs-prod'
location: location
sku: { name: 'Standard' }
properties: { disableLocalAuth: true, publicNetworkAccess: 'Disabled' }
identity: { type: 'SystemAssigned' }
}
resource kvRef 'Microsoft.AppConfiguration/configurationStores/keyValues@2024-05-01' = {
parent: ac
name: 'SqlConn$prod'
properties: {
contentType: 'application/vnd.microsoft.appconfig.keyvaultref+json;charset=utf-8'
value: '{"uri":"https://kv-prod.vault.azure.net/secrets/SqlConn"}'
}
}Summary & Concept Map
- Three stores, three roles. App Configuration for non-secret runtime config; Key Vault for secrets; host env vars for build-time / deployment-time values.
- Use Key Vault references inside App Configuration so the app sees one unified config surface but secrets remain audited via Key Vault.
- Labels partition environments within a single store; reach for separate stores only when regulatory isolation demands it.
- Feature flags are first-class in App Configuration — boolean, percentage, targeting, time-window filters.
- Identity over keys. Disable local auth; let managed identities read both stores.
- Refresh is opt-in. Without the sentinel pattern, config changes only apply at restart.
- Premium tier adds geo-replication, more storage, more throughput.