azureazure-resource-managerazure-cliazure-rm-templateazure-bicep

Use same GUID in bicep templates and Azure Portal


I'm deploying some RBAC roles for Service Principals and Users to access secrets from a Key Vault, at resource scope.

When choosing the name, I build the GUID for the resource name using a combination of GUIDs that uniquely describes the assignment, that is, the roleId, the Service Principal Id, and the KeyVault's Id:

//# kvRoles.bicep
@description('Assigns the Crypto Secrets user to the provided principal ID.')
resource kvRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(roleIds['Key Vault Secrets User'], principalId, keyVault.id)
  scope: keyVault
  properties: {
    roleDefinitionId: roleIds['Key Vault Secrets User']
    principalId: principalId
    principalType: 'Service Principal'
  }
}

This works well for first deployments and redeployments:

az deployment group create -g 'myGroup' -f 'kvRoles.bicep'

However, when these roles are already created via Azure Portal, the deployment of these RBAC roles fails with the usual RoleAssignmentExists error.

As explained in [AVM Question/Feedback]: Breaking Change - Role-Assignments name should be consistent & configurable #2008, this error is expected since Azure Portal deployed a RBAC assignment with the same scope, Service Principal and Role, but a different GUID in its resource.name property.

Existing role assignments will run into errors of the type 'RoleAssignment already exists' IF the same combination of scope, principalId & roleDefinitionId was deployed using a different 'resource' name

I want this template to be re-deployable even when the same role has been applied through command line or Azure Portal.

What can I do so that this resource has the same GUID as those of Azure Portal or azure-cli?

For example, when I query the name of the resource I deploy with azure-cli, it's always the same:

az role assignment create \
  --assignee $userId \
  --role 'Key Vault Crypto User' \
  --scope "/subscriptions/$subId/resourceGroups/$rgName/providers/Microsoft.KeyVault/vaults/$kvName" \
  --query 'name'
# name = "0000404d-0000-0000-0000-0000b7b90000"

Solution

  • I would suggest you create bicep similar as below:

    resource kvRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
      scope: keyVault
      name: guid(<yourkeyvaultresource>.id, <principal/resource Id>, kvSecretUserRole .id)
      properties: {
        roleDefinitionId: kvSecretUserRole.id
        principalId: <identity of the app / or user>
        principalType: 'ServicePrincipal'
      }
    }
    
    @description('Key Vault Secrets User. see https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles/security#key-vault-secrets-user')
    resource kvSecretUserRole 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
      scope: subscription()
      name: '4633458b-17de-408a-b874-0445c86b69e6'
    }
    

    The problem you are facing is because you re-generating guids and since the assignment already exists, it complains about it. However, your assignment previous and update can only work as update if the GUID (aka. name) is same.

    Handy reference MsDoc https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/scenarios-rbac#role-definition-id