Skip to content

Instantly share code, notes, and snippets.

@johndowns
Created February 21, 2022 08:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johndowns/ea7aeec923e008d7b340815d054bfc0c to your computer and use it in GitHub Desktop.
Save johndowns/ea7aeec923e008d7b340815d054bfc0c to your computer and use it in GitHub Desktop.
Create a key vault, managed identity, and role assignment to grant the managed identity the 'Key Vault Administrator' role on the vault
param keyVaultName string = uniqueString(resourceGroup().id)
param location string = resourceGroup().location
var managedIdentityName = 'my-mi'
resource keyVault 'Microsoft.KeyVault/vaults@2019-09-01' = {
name: keyVaultName
location: location
properties: {
enableRbacAuthorization: true
tenantId: tenant().tenantId
sku: {
name: 'standard'
family: 'A'
}
}
}
resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
name: managedIdentityName
location: location
}
@description('This is the built-in Key Vault Administrator role. See https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#key-vault-administrator')
resource keyVaultAdministratorRoleDefinition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
scope: subscription()
name: '00482a5a-887f-4fb3-b363-3b7fe8e74483'
}
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
name: guid(resourceGroup().id, managedIdentityName, keyVaultAdministratorRoleDefinition.id)
properties: {
roleDefinitionId: keyVaultAdministratorRoleDefinition.id
principalId: managedIdentity.properties.principalId
principalType: 'ServicePrincipal'
}
}
@gsuttie
Copy link

gsuttie commented Mar 23, 2022

Hi John

There appears to be a bug here - If I run this in and then remove the Managed Identity - the Role assignments are orphaned - they still exist at the subscription level.

If I then try to recreate the managed identity with the role Assignment and it doesn't work.

If I then delete the orphaned role assignments (from the subscription level) it then works again.

I think the bug is in the Azure Role assignments but not sure.

@johndowns
Copy link
Author

@gsuttie Yes, this is unfortunately the behaviour of role assignments. The issue is that, after you delete the managed identity and then redeploy the template, the role assignment resource definition ends up with the same name - the GUID is created using the same seed values for the guid() function. Because you can't update some of the role assignment properties after it's deployed, it unfortunately puts it into an orphaned state. Azure doesn't have do any "cleanup" of orphaned resources like this.

This isn't an issue with Bicep, it's more of a role assignment issue/behaviour, but I certainly have run into it myself in the past.

There are a couple of workarounds:

  • You can add another seed value to the guid() function on line 32, which means you'll get a new GUID, and therefore end up with a new role assignment when you redeploy.
  • You can also change the guid() function's seed values so that they use the managed identity's principal ID, which will be different for each new managed identity even if they have the same name or resource ID. However, because of a limitation in Bicep/ARM templates, where resources must have names that are available when the deployment starts, you'd need to do this with a module. Here's an example:

main.bicep

param keyVaultName string = uniqueString(resourceGroup().id)

param location string = resourceGroup().location

var managedIdentityName = 'my-mi'

resource keyVault 'Microsoft.KeyVault/vaults@2019-09-01' = {
  name: keyVaultName
  location: location
  properties: {
    enableRbacAuthorization: true
    tenantId: tenant().tenantId
    sku: {
      name: 'standard'
      family: 'A'
    }
  }
}

resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
  name: managedIdentityName
  location: location
}

@description('This is the built-in Key Vault Administrator role. See https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#key-vault-administrator')
resource keyVaultAdministratorRoleDefinition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
  scope: subscription()
  name: '00482a5a-887f-4fb3-b363-3b7fe8e74483'
}

module roleAssignment 'role-assignment.bicep' = {
  name: 'role-assignment'
  params: {
    roleAssignmentName: guid(resourceGroup().id, managedIdentity.properties.principalId, keyVaultAdministratorRoleDefinition.id)
    roleDefinitionId: keyVaultAdministratorRoleDefinition.id
    principalId: managedIdentity.properties.principalId
  }
}

role-assignment.bicep

param roleAssignmentName string

param roleDefinitionId string

param principalId string

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  name: roleAssignmentName
  properties: {
    roleDefinitionId: roleDefinitionId
    principalId: principalId
    principalType: 'ServicePrincipal'
  }
}

I know this is hard - role assignments are one of the trickier resources and require quite a lot of understanding of what's going on before you can make them work :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment