How to solve the 'role assignment already exists' error in Azure

When you create an RBAC role assignment on Azure from your Infrastructure-as-Code scripts, you might run into the “The role assignment already exists. The ID of the existing role assignment is xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.” error.

The question now is which identity (managed identity, user, etc.) is behind that ID. Let us first see what this ID from the error message is all about.

RBAC in one minute

A role assignment in Azure answers one question: who can do what, and where.

When you combine the three, Azure creates a role assignment and gives it a unique name in the form of a GUID.

Why the error happens

Azure does not allow duplicate assignments for the same principal, role and scope. If that assignment already exists under a different GUID, creating it again fails with the error above, whose code is RoleAssignmentExists.

This error is common with Bicep templates. The template builds the GUID with guid(...), but the existing assignment was created by hand in the portal, or by an older version of the template that used different values for the GUID.

Find the existing role assignment

The ID in the error message is the GUID name of the existing role assignment. First get the scope, in this example a storage account:

SCOPE=$(az storage account show \
  --name mystorageaccount \
  --resource-group my-resource-group \
  --query id -o tsv)

The error may print the GUID without dashes, but the name of the role assignment has them. This converts it to the usual 8-4-4-4-12 format, and leaves it as it is if it already has the dashes:

ID=<id-from-the-error>
GUID=$(echo "$ID" | sed -E 's/^(.{8})(.{4})(.{4})(.{4})(.{12})$/\1-\2-\3-\4-\5/')

Then list the assignments on that scope and keep only the one with that GUID:

az role assignment list \
  --scope "$SCOPE" \
  --query "[?name=='$GUID'].{principalId:principalId, principalType:principalType, role:roleDefinitionName}" \
  -o table

That gives you the principalId and the principalType, which tells you if you are looking at a user, a group or a service principal. Managed identities show up as service principals. For a managed identity, its display name is the name of the identity or of the resource it belongs to:

az ad sp show --id <principalId> --query displayName -o tsv

If the principal is a user instead, use az ad user show --id <principalId> --query userPrincipalName -o tsv.

Now you know which identity already has the role. If the assignment is correct, keep it: either use its existing GUID as the name in your Bicep template, or remove the duplicate from the template.

If you want the deployment to create its own assignment instead, delete the existing one and also check that nothing depends on that access.

Feel free to drop me a comment if you found this article helpful.

comments powered by Disqus