Fixing RBAC Access Denied Errors in Azure

Azure RBAC access denied errors are among the most common issues engineers encounter when working with Azure. While the basic diagnostic path is simple — find the missing role and assign it — there are several less-obvious causes that frustrate even experienced engineers: scope boundaries, Entra ID token caching, Deny assignments, and custom role definition errors. This guide covers all of them with exact commands for each step.

The exact error and what it tells you

Azure RBAC access denied errors always include the denied action and the scope:

The client 'user@company.com' with object id 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee'
does not have authorization to perform action 'Microsoft.KeyVault/vaults/write'
over scope '/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/myRG'
or the scope is invalid.
StatusCode: 403
ErrorCode: AuthorizationFailed

Extract three pieces of information from this error:

  1. The identity (object ID and UPN or app ID) that was denied.
  2. The action that was attempted (Microsoft.KeyVault/vaults/write).
  3. The scope where the action was attempted.

These three pieces tell you exactly what to check and what to assign.

Step 1: List all effective role assignments

Azure RBAC is hierarchical — roles can be assigned at management group, subscription, resource group, or resource level, and they are inherited downward. A role assigned at the subscription level is effective on all resource groups and resources within. List assignments at all levels to see the full picture.

# List all role assignments for the denied identity across the entire subscription
OBJECT_ID="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"

az role assignment list \
  --assignee $OBJECT_ID \
  --all \
  --include-inherited \
  --query "[].{Role:roleDefinitionName, Scope:scope, PrincipalType:principalType}" \
  --output table

# Also check group memberships that might carry the role
az ad user get-member-groups --id $OBJECT_ID --output table

# Check assignments on the specific resource
az role assignment list \
  --scope /subscriptions/SUB_ID/resourceGroups/myRG/providers/Microsoft.KeyVault/vaults/myVault \
  --all \
  --query "[].{Role:roleDefinitionName, Principal:principalName}" \
  --output table

Step 2: Map the denied action to the correct role

Once you know the denied action, find the minimum built-in role that grants it.

# Find all built-in roles that include the denied action
DENIED_ACTION="Microsoft.KeyVault/vaults/write"

az role definition list \
  --custom-role-only false \
  --query "[?contains(permissions[0].actions, '$DENIED_ACTION')].{Name:roleName, Description:description}" \
  --output table

# For a data plane action (e.g., reading a Key Vault secret)
# Data plane actions use a different permissions array
az role definition list \
  --custom-role-only false \
  --query "[?contains(permissions[0].dataActions, 'Microsoft.KeyVault/vaults/secrets/getSecret/action')].{Name:roleName}" \
  --output table

Assign the minimum sufficient role. For Key Vault write operations on the management plane (creating, configuring Key Vaults), assign Key Vault Contributor. For accessing secrets, keys, or certificates (data plane), assign Key Vault Secrets User, Key Vault Crypto User, or Key Vault Certificate User as appropriate.

# Assign the minimum required role
az role assignment create \
  --assignee $OBJECT_ID \
  --role "Key Vault Contributor" \
  --scope /subscriptions/SUB_ID/resourceGroups/myRG

Step 3: Check for Deny assignments

If the role assignment looks correct but access is still denied, check for Deny assignments. A Deny assignment explicitly blocks specific actions and overrides any Allow role assignments.

# List deny assignments at the subscription level
az rest \
  --method GET \
  --url "https://management.azure.com/subscriptions/SUB_ID/providers/Microsoft.Authorization/denyAssignments?api-version=2022-04-01" \
  --query "value[].{Name:properties.denyAssignmentName, Actions:properties.permissions[0].actions, Scope:properties.scope}" \
  --output table

# List deny assignments at a specific resource group
az rest \
  --method GET \
  --url "https://management.azure.com/subscriptions/SUB_ID/resourceGroups/myRG/providers/Microsoft.Authorization/denyAssignments?api-version=2022-04-01"

Deny assignments are read-only for most users — they are created and managed by Azure Blueprints, Managed Applications, or Azure Lighthouse. If you find a Deny assignment blocking a legitimate operation, you must modify or remove it through the system that created it (Blueprints assignment, Managed Application, etc.) rather than directly.

Step 4: Force token refresh for propagation delays

RBAC assignments propagate within 5–10 minutes. Entra ID group membership changes can take up to 60 minutes to appear in new tokens. If you have just made a change and the error persists, wait and then force a fresh token.

# Force Azure CLI to refresh its token
az account clear
az login

# Or for a specific tenant
az login --tenant TENANT_ID

# Verify the current token's claims (useful to confirm group membership is present)
az account get-access-token --query "tokenType" --output tsv

# For service principals in pipelines: ensure the token is not cached
# Clear the cached credentials and re-authenticate
az logout
az login --service-principal \
  --username APP_ID \
  --password CLIENT_SECRET \
  --tenant TENANT_ID

Step 5: Diagnose custom role issues

Custom roles sometimes cause unexpected denials when their action lists are incomplete or when they use wildcard patterns incorrectly.

# View a custom role definition in full
az role definition list \
  --name "My Custom Deployer Role" \
  --query "[0].{Name:roleName, Actions:permissions[0].actions, NotActions:permissions[0].notActions, DataActions:permissions[0].dataActions, AssignableScopes:assignableScopes}" \
  --output json

# Common issue: role is not assigned at a scope within its assignableScopes
# The assignableScopes list must contain the scope where you want to assign it
# If assignableScopes only has /subscriptions/A, you cannot assign the role in subscription B

# Update a custom role to add a missing action
az role definition update --role-definition '{
  "Name": "My Custom Deployer Role",
  "Id": "ROLE_ID",
  "IsCustom": true,
  "Description": "Allows deployment to Container Apps",
  "Actions": [
    "Microsoft.App/containerApps/write",
    "Microsoft.App/containerApps/read",
    "Microsoft.App/containerApps/delete",
    "Microsoft.App/managedEnvironments/read"
  ],
  "NotActions": [],
  "DataActions": [],
  "NotDataActions": [],
  "AssignableScopes": ["/subscriptions/SUB_ID"]
}'

Using Check Access for pre-flight verification

Before running an operation that you suspect might fail, you can verify access programmatically using the checkAccess API. This is particularly useful in CI/CD pipelines to validate service principal permissions before a deployment begins.

# Check if a principal has a specific permission (using the checkAccess API)
az rest \
  --method POST \
  --url "https://management.azure.com/subscriptions/SUB_ID/resourceGroups/myRG/providers/Microsoft.Authorization/permissions?api-version=2022-04-01" \
  --query "value[?contains(actions, 'Microsoft.App/containerApps/write')]" \
  --output table

Common mistakes

  1. Assigning roles at the resource level instead of the resource group. Resource-level role assignments are granular but create management overhead. If a service principal needs access to five resources in a resource group, a single role assignment at the resource group level is cleaner and easier to audit. Reserve resource-level assignments for when you genuinely need different permissions on different resources in the same group.
  2. Mixing up object ID and client ID for service principals. When assigning a role with —assignee, Azure expects the object ID (the ID in Entra ID) not the application ID (client ID). Using the client ID may appear to succeed but the assignment may not apply correctly. Use az ad sp show —id CLIENT_ID —query id to retrieve the object ID.
  3. Forgetting that NotActions can remove permissions from a wildcard. A role with Actions: [""] and NotActions: [“Microsoft.Authorization/”] grants everything except authorization management. If a role uses wildcard Actions, always audit the NotActions list — it may be stripping the permission you think you have.

Frequently asked questions

What is the maximum number of role assignments per subscription?

Azure allows a maximum of 4,000 role assignments per subscription. This includes assignments at all scopes within the subscription — management group, subscription, resource group, and resource level. If you reach this limit, you cannot create new role assignments and will see an error like "The number of role assignments has exceeded the maximum limit." Resolve this by removing unused assignments and using groups instead of individual user assignments wherever possible.

Why does a user who belongs to a group with the required role still get access denied?

Group membership changes in Entra ID can take up to 60 minutes to be reflected in Azure RBAC tokens. If a user was recently added to a group that has the required role, their existing token does not include the new group membership. Ask them to sign out and sign back in to obtain a fresh token with the updated group membership. The same applies to managed identity federated credentials — token caches can cause brief gaps.

Can a Deny assignment override an Allow role assignment?

Yes. Azure Deny assignments take precedence over all role assignments. If a user has Owner role but there is also a Deny assignment that denies the specific action they are attempting, the deny wins. Deny assignments are typically created by Blueprints or Azure Managed Applications and cannot be created directly by most users. Use az role assignment list with --include-deny-assignments to check for them.

Last verified: 19 March 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.