Azure Bicep & User Assigned Managed Identity
This will be a quick one!
A colleague asked me if it was easier to use user assigned managed identities in Bicep versus ARM. Well, challenge accepted!
After about 45 minutes of hacking, I created the following:
@description('Web app name.')
@minLength(2)
param webAppName string = 'webApp-${uniqueString(resourceGroup().id)}'
@description('Location for all resources.')
param location string = resourceGroup().location
@description('The SKU of App Service Plan.')
param sku string = 'S1'
@description('The Runtime stack of current web app')
param linuxFxVersion string = 'DOTNETCORE|5.0'
param uaminame string = 'uamitest'
param kvName string = 'kv-${uniqueString(resourceGroup().id)}'
@secure()
param secretValue string = uniqueString(newGuid())
var appServicePlanPortalName_var = '${webAppName}-plan'
resource appServicePlanName 'Microsoft.Web/serverfarms@2020-06-01' = {
name: appServicePlanPortalName_var
location: location
sku: {
name: sku
}
kind: 'linux'
properties: {
reserved: true
}
}
resource webApp_resource 'Microsoft.Web/sites@2020-12-01' = {
name: webAppName
location: location
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${uami.id}': {}
}
}
properties: {
serverFarmId: appServicePlanName.id
siteConfig: {
linuxFxVersion: linuxFxVersion
}
keyVaultReferenceIdentity: uami.id
}
resource settings 'config' = {
name: 'appsettings'
properties: {
//SuperSecret: '@Microsoft.KeyVault(SecretUri=${keyVault::secret.properties.secretUriWithVersion})'
SuperSecret: '@Microsoft.KeyVault(SecretUri=${keyVault::secret.properties.secretUri})'
}
}
}
resource webAppSlot 'Microsoft.Web/sites/slots@2020-06-01' = {
name: '${webAppName}/staging'
location: location
kind: 'app'
properties: {
serverFarmId: appServicePlanPortalName_var
}
dependsOn: [
webApp_resource
]
}
// Create a keyvault, and use a nested resource to set a secret
resource keyVault 'Microsoft.KeyVault/vaults@2019-09-01' = {
name: kvName
location: resourceGroup().location
properties: {
enabledForDeployment: false
enabledForTemplateDeployment: false
enabledForDiskEncryption: false
tenantId: subscription().tenantId
enablePurgeProtection: false
accessPolicies: [
{
tenantId: subscription().tenantId
objectId: uami.properties.principalId
permissions: {
keys: [
'get'
]
secrets: [
'list'
'get'
]
}
}
]
sku: {
name: 'standard'
family: 'A'
}
}
resource secret 'secrets' = {
name: 'mysecret'
properties: {
value: secretValue
}
}
dependsOn: [
uami
]
}
// create user assigned managed identity
resource uami 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
name: uaminame
location: resourceGroup().location
}
// create role assignment
var KEY_VAULT_SECRETS_USER_ROLE_GUID = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')
resource keyVaultWebsiteUser 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
name: guid('SecretsUser', webAppName)
scope: keyVault
properties: {
principalId: uami.properties.principalId
roleDefinitionId: KEY_VAULT_SECRETS_USER_ROLE_GUID
}
}
Key things to point out here with the web app config:
- The set of lines
are where you associate the user-assigned identity id with the web appuserAssignedIdentities: { '${uami.id}': {} }
- You also need the line
keyVaultReferenceIdentity: uami.id
to tell the app service which identity to use when contacting the key vault
Cool stuff!