Azure App Configuration gets awkward once you need to seed defaults without duplicating keys that are already there. I used Azure deployment scripts and Bicep to query the current state first, then deploy only what was missing. This post walks through that pattern and the pieces that made it work.
Problem Statement
Azure App Configuration lets us manage configuration centrally, but once environments drift, seeding defaults becomes messy. Manual checks invite mistakes, and hardcoding resources does not age well. I needed a way to query what already existed and deploy only the missing pieces.
Solution Overview
Using Azure deployment scripts inside Bicep, I could:
- Query existing labels and keys in Azure App Configuration.
- Conditionally deploy default settings, environments, and configurations based on the query results.
- Keep the process automated without hardcoding the current state.
High-Level Architecture
- Deployment Script Modules: Query existing labels and keys in Azure App Configuration.
- Conditional Logic in Bicep: Deploy resources based on the query results.
- Managed Identity with Role Assignments: Securely enable deployment scripts to access Azure resources.
Step 1: Set Up a Managed Identity with Role Assignments
Deployment scripts require permissions to interact with Azure App Configuration. To enable this, we assign a User-Assigned Managed Identity with the App Configuration Contributor role.
| |
This Bicep template creates a User-Assigned Managed Identity and assigns the App Configuration Contributor role, granting the identity the necessary permissions to query configuration labels and keys.
Step 2: Query Existing Labels and Keys
Querying Labels
The configurationLabel.bicep module dynamically retrieves all labels in Azure App Configuration using a deployment script:
| |
Querying Keys
Similarly, the configurationKey.bicep module fetches all unique keys:
| |
The command az appconfig kv list --name $1 --query "[].key" | jq -r .[] | cut -d ":" -f 1 | sort -u | jq -R . | jq -s "{result: .}" performs several operations to list and process keys from an Azure App Configuration store:
az appconfig kv list --name $1 --query "[].key": This Azure CLI command lists all key-value pairs from the specified Azure App Configuration store (using the name provided as the first argument$1) and extracts only the keys.| jq -r .[]: The output from the previous command is piped tojq, a lightweight and flexible command-line JSON processor. The-rflag outputs raw strings instead of JSON texts, and.[]iterates over each element in the array, outputting each key on a new line.| cut -d ":" -f 1: Thecutcommand splits each key at the colon (:) delimiter and extracts the first field. This is useful if the keys have a namespace or prefix separated by a colon.| sort -u: Thesortcommand sorts the keys and the-uflag ensures that only unique keys are kept.| jq -R .: The sorted unique keys are then piped back tojqwith the-Rflag, which reads each line of input as a raw string and converts it to a JSON string.| jq -s "{result: .}": Finally, thejq -scommand slurps all the input lines into a single JSON array and wraps it in an object with aresultproperty.
The final output is a JSON object containing an array of unique keys, which is then stored in the result variable.
Step 3: Conditionally Deploy Resources
The configuration/environments.bicep module leverages the queried labels and keys to conditionally deploy resources. For example:
- Defaults: Ensures a default environment is created if the label does not exist.
- Environments: Deploys specific environments for missing labels.
- Settings: Adds configurations if the keys are not present.
| |
Conclusion
This pattern removes the manual step of checking what already exists before deploying. The deployment scripts query current state, the Bicep conditional logic handles the rest, and the managed identity keeps permissions scoped to what the script actually needs.
Related Posts
- Why I Started Building My Own DevOps Platform (And What I Learned)
- My DORA post on internal developer platforms
References:
