wiki.getshifting.com

--- Sjoerd Hooft's InFormation Technology ---

User Tools

Site Tools


bicepmoduleappconfiguration

Bicep Module for Azure App Configuration

Summary: This is a bicep module that I use to deploy Azure App Configurations, a cloud service I use to store variables.
Date: 4 January 2025
Refactor: 9 January 2025: Added deployment information and an additional module to assign roles.

Read the post to learn more about Azure App Configuration and:

  • How to deploy an Azure App Configuration Store using a Bicep module
    • How to set the name and sku based on the environment parameter
  • How to deploy a private endpoint for an Azure App Configuration Store using a Bicep module
  • How to set permissions on the Azure App Configuration Store using a Bicep module
    • Permissions are set on an array of teams which are defined in a separate parameter file
Check here for an additional post for a dashboard to monitor the Azure App Configuration Store.

What is Azure App Configuration

Azure App Configuration is a service that allows you to centralize your application settings and feature flags. It provides a way to manage the settings of your application in a single place, and it can be used to store key-value pairs that can be accessed by your application at runtime. I found it very useful as it also allows you to import variables into your Azure DevOps pipeline, allowing you to also manage your pipeline variables in a single place.

Important to Know about Azure App Configuration

Some settings are not available for the free sku. For example, you can't configure a replica and it's also not possible to enable a private endpoint. The free sku is also limited in the amount of requests you can make. Usually I recommend to start with the free sku and then upgrade if needed. Also, when using Infrastructure as Code such as Bicep or Terraform, I would deploy the free SKU as a test deployment and use the standard edition for your production environment. Note that you are only allowed to deploy one free SKU per subscription.

Bicep Module App Configuration

The module below deploys an Azure App Configuration Store. Notice that some settings are dependent on the SKU. For example, the replica is only deployed when the SKU is set to standard. The module also deploys a diagnostic setting to log all logs and audit logs to a Log Analytics Workspace.

/*
DESCRIPTION
  Deploys a App Configuration Store
 
LINKS
  Resource: https://learn.microsoft.com/en-us/azure/templates/microsoft.appconfiguration/configurationstores
  Resource replica: https://learn.microsoft.com/en-us/azure/templates/microsoft.appconfiguration/configurationstores/replicas
  Some settings are not available for the free sku: https://azure.microsoft.com/en-us/pricing/details/app-configuration/
 
NOTES
  If your delete the replica you have to pick a new name as the old one is purge protected.
  The networking setup for a app configuration is set by default as:
    "With a private endpoint, public network access will be automatically disabled. If there is no private endpoint present,
    public network access is automatically enabled."
*/
*/
 
// input parameters
param location string
param appConfigurationName string
param lawSubscriptionId string
param lawResourceGroup string
param lawName string
@description('Specifies the SKU of the app configuration store.')
param skuName string
 
// deploy app configuration store
resource configStore 'Microsoft.AppConfiguration/configurationStores@2023-03-01' = {
  name: appConfigurationName
  location: location
  sku: {
    name: skuName
  }
  properties: (skuName == 'standard') ? {
    disableLocalAuth: true
    softDeleteRetentionInDays: 7
    enablePurgeProtection: true
  } : {
    disableLocalAuth: true
  }
}
 
// replica
resource configStoreReplica 'Microsoft.AppConfiguration/configurationStores/replicas@2023-08-01-preview' = if (skuName == 'standard') {
  parent: configStore
  name: 'eunorthreplica'
  location: 'northeurope'
}
 
resource diagnosticLogs 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {
  scope: configStore
  name: 'diag-${appConfigurationName}'
  properties: {
    workspaceId: resourceId(lawSubscriptionId, lawResourceGroup, 'Microsoft.OperationalInsights/workspaces', lawName)
    logs: [
      {
        categoryGroup: 'alllogs'
        enabled: true
      }
      {
        categoryGroup: 'audit'
        enabled: true
      }
    ]
    metrics: [
      {
        category: 'AllMetrics'
        enabled: true
      }
    ]
  }
}
 
output appConfigurationName string = configStore.name

Deploy Example

The module above can be deployed using the code below. Note that both the App Configuration name and the sku are set based on the environment:

targetScope = 'resourceGroup'
 
// parameters
param location string = resourceGroup().location
param environment string
 
// log analytics workspace
param lawSubId string
param lawRg string
param lawName string
 
// App Configuration parameters
var appConfigurationName = {
  'dev': 'appcs-dev'
  'prd': 'appcs-prd'
}[environment]
var appConfigSkuName = {
  'dev': 'free'
  'prd': 'standard'
}[environment]
 
// deploy app configuration
module appConfig '../modules/appconfiguration.bicep' = {
  name: 'appc-${resourceGroupName}-${deploymentSuffix}'
  params: {
    location: location
    appConfigurationName: appConfigurationName
    skuName: appConfigSkuName
    lawSubscriptionId: lawSubId
    lawResourceGroup: lawRg
    lawName: lawName
  }
}

Bicep Module App Configuration Private Endpoint

The module below deploys a private endpoint for an Azure App Configuration Store. The private endpoint allows you to access the App Configuration Store from your virtual network. Note that this module requires the vnet, subnet, and app configuration to be deployed before deploying the private endpoint. The module also deploys a DNS record so the private endpoint can be resolved. Note that the private DNS zone also already must be deployed.

/*
DESCRIPTION
  Deploys a app configuration private endpoint
 
LINKS
  Resource Private Endpoint: https://learn.microsoft.com/en-us/azure/templates/microsoft.network/privateendpoints
  Resource Private DNS Zonegroup: https://learn.microsoft.com/en-us/azure/templates/microsoft.network/privateendpoints/privatednszonegroups
  GroupId private links: https://learn.microsoft.com/en-us/azure/private-link/private-endpoint-overview
 
NOTES
  DNS Zone forwarding: https://learn.microsoft.com/en-us/azure/private-link/private-endpoint-dns
 
*/
 
// input parameters
param location string
// app configuration
param appConfigurationName string
// network - the virtual network where the pep/nic comes
@description('The subscription id that hosts the virtual network for the pep')
param vnetSubscriptionId string
@description('The resource group that hosts the virtual network for the pep')
param vNetRg string
@description('The name of the virtual network that hosts the private endpoints subnet')
param vnetName string
@description('The name of the private endpoints subnet')
param subnetName string
// dns
param subIdDNS string
param rgDNS string
 
// defined parameters
param privateLinkZone string = 'privatelink.azconfig.io'
 
// variables
var pepName = 'pep-${appConfigurationName}'
var nicName = 'nic-${pepName}'
var pepConnectionName = 'pep-con-${appConfigurationName}'
 
// existing
resource vNet 'Microsoft.Network/virtualNetworks@2020-11-01' existing = {
  scope: resourceGroup(vnetSubscriptionId, vNetRg)
  name: vnetName
}
resource subnetPrivateEndpoints 'Microsoft.Network/virtualNetworks/subnets@2022-09-01' existing = {
  parent: vNet
  name: subnetName
}
resource appConfig 'Microsoft.AppConfiguration/configurationStores@2023-03-01' existing = {
  name: appConfigurationName
}
 
// deploy private endpoint
resource saPrivateEndpoint 'Microsoft.Network/privateEndpoints@2022-01-01' = {
  name: pepName
  location: location
  properties: {
    privateLinkServiceConnections: [
      {
        name: pepConnectionName
        properties: {
          groupIds: [
            'configurationStores'
          ]
          privateLinkServiceId: appConfig.id
        }
      }
    ]
    customNetworkInterfaceName: nicName
    subnet: {
      id: subnetPrivateEndpoints.id
    }
  }
}
 
// deploy dns record
resource privateDnsZoneGroup 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2022-09-01' = {
  parent: saPrivateEndpoint
  name: 'dnsgroup'
  properties: {
    privateDnsZoneConfigs: [
      {
        name: 'config'
        properties: {
          privateDnsZoneId: resourceId(subIdDNS, rgDNS, 'Microsoft.Network/privateDnsZones', privateLinkZone)
        }
      }
    ]
  }
}

Bicep Module App Configuration Role Assignment

The module below assigns a role to a user, group, or identity on an Azure App Configuration Store. The module requires the app configuration store to be deployed before deploying the role assignment.

/*
DESCRIPTION
  Assigns a role to a user, group or identity on an azure app configuration store
 
LINKS
  Resource: https://learn.microsoft.com/en-us/azure/templates/microsoft.authorization/roleassignments
*/
 
targetScope = 'resourceGroup'
 
// input parameters
param appConfigurationName string
@allowed([
  'App Configuration Data Owner'
  'App Configuration Data Reader'
  'Contributor'
])
param roleName string
param principalId string
@allowed([
  'Device'
  'ForeignGroup'
  'Group'
  'ServicePrincipal'
  'User'
])
param principalType string
 
// variables
var roleIds = {
  'App Configuration Data Owner': resourceId('Microsoft.Authorization/roleAssignments', '5ae67dd6-50cb-40e7-96ff-dc2bfa4b606b')
  'App Configuration Data Reader': resourceId('Microsoft.Authorization/roleAssignments', '516239f1-63e1-4d78-a4de-a74fb236a071')
  'Contributor': resourceId('Microsoft.Authorization/roleAssignments', 'b24988ac-6180-42a0-ab88-20f7382dd24c')
}
 
// exists
resource appConfig 'Microsoft.AppConfiguration/configurationStores@2023-03-01' existing = {
  name: appConfigurationName
}
 
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  scope: appConfig
  name: guid(roleIds[roleName], principalId, resourceId('Microsoft.AppConfiguration/configurationStores', appConfigurationName))
  properties: {
    roleDefinitionId: roleIds[roleName]
    principalId: principalId
    principalType: principalType
  }
}

Deploy Example

The following code is used to deploy permissions to the app configuration store. Note that a uniqueString function is used on the devTeam.teamName to ensure that the role assignment name is not too long as the maximum length is 64 characters, and that the teamName is coming from an array which is defined in a separate parameter file:

// scrum teams
param scrumTeams array
// permissions
param AzureADEnterpriseAppId string
 
// Permissions for a set of teams
module roleAssignmentTeamAccess '../modules/role-assignment-appconfiguration.bicep' = [for devTeam in devTeams: {
  name: 'rbac-team-${uniqueString(devTeam.teamName)}'
  dependsOn: [ appConfig ]
  params: {
    appConfigurationName: appConfig.outputs.appConfigurationName
    roleName: 'App Configuration Data Reader'
    principalId: devTeam.objectId
    principalType: 'Group'
  }
}]
 
// Permissions for a service principal
module rolePipeline '../modules/role-assignment-appconfiguration.bicep' = {
  name: 'rbac-sp-${appConfigurationName}'
  dependsOn: [ appConfig ]
  params: {
    appConfigurationName: appConfig.outputs.appConfigurationName
    roleName: 'App Configuration Data Owner'
    principalId: AzureADEnterpriseAppId
    principalType: 'ServicePrincipal'
  }
}

This is the parameters file for the devTeams parameter above:

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        // these are the names and objectIds of the dev teams
        "devTeams": {
            "value": [
                {
                    "teamName": "Dev team frontend",
                    "objectId": "4e3b4ef3-4495-4cdc-a981-f009ad6f3ebf"
                },
                {
                    "teamName": "Dev team backend",
                    "objectId": "fecefe42-46bf-4ff7-af8a-cc0b7bf6ea85"
                },
                {
                    "teamName": "Dev team api",
                    "objectId": "a704c4a1-9397-43cd-a37f-3b210bf6eb04"
                }
            ]
        }
    }
}

As such, to deploy such a bicep file using the azure cli you would use the following command:

az deployment group create \
  --resource-group myResourceGroup \
  --name "appconfig-permissions" \
  --template-file appconfiguration.bicep \
  --parameters AzureADEntAppId="d60692dc-666c-410f-bb14-bb045fd36dd9" \
  --parameters devteams-parameterfile.jsonc
bicepmoduleappconfiguration.txt · Last modified: by 127.0.0.1