Skip to main content

Azure RBAC

Volume 4 — Azure Foundations

Azure RBAC (Role-Based Access Control) governs who can do what to which resources across an Azure subscription. Nearly every "Forbidden" or "does not have authorization" error traces back to a missing or misscoped role assignment — this chapter covers the model well enough to diagnose those quickly.

1. The Core Model: Three Parts

Every permission in Azure RBAC comes from a role assignment, which is always exactly three things bound together:

Role Assignment = Principal + Role Definition + Scope
PartWhat it is
PrincipalWho — a user, a group, a service principal, or a managed identity
Role DefinitionWhat they can do — a named set of permitted actions (e.g. "Contributor", "Reader")
ScopeWhere — which resource, resource group, subscription, or management group this applies to

There's no such thing as a role granted without a scope — "Pete has Contributor" is an incomplete sentence; the real statement is always "Pete has Contributor on the traxs-prod resource group."

2. The Scope Hierarchy

Role assignments inherit downward — a role granted at a subscription level applies to every resource group and resource beneath it, automatically. A role granted at a specific resource group applies only within that group.

This is the most common cause of "why does this person have access I didn't explicitly grant them" — trace upward through the hierarchy, not just at the specific resource, when auditing who has access to something.

az role assignment list --scope "/subscriptions/<sub-id>/resourceGroups/traxs-prod" --include-inherited

3. Built-In Roles

RoleGrants
OwnerFull control, including the ability to grant access to others
ContributorFull control over resources, but cannot grant access to others
ReaderView-only, no changes of any kind
User Access AdministratorCan manage role assignments specifically, without other resource permissions

Beyond these broad ones, Azure ships hundreds of narrowly-scoped built-in roles for specific services:

RoleGrants
SQL DB ContributorManage SQL databases, but not the underlying server's firewall/security config
Storage Blob Data ContributorRead/write blob data specifically — distinct from managing the storage account itself
Website ContributorManage App Service apps, without broader resource group control

Principle of least privilege: reach for the narrowest role that actually covers what's needed, rather than defaulting to Contributor or Owner because it's simpler to grant once. A CI/CD service principal that only ever deploys to one App Service has no legitimate reason to hold Contributor across the entire resource group.

4. Control-Plane vs. Data-Plane Access

This distinction causes real confusion because it's easy to assume RBAC governs everything, when for some services it only governs half the picture.

Control planeData plane
GovernsManaging the resource itself — creating, deleting, configuring an Azure SQL serverAccessing the data/content inside it — querying tables in that SQL database
Azure SQL exampleAzure RBAC role (e.g. SQL DB Contributor) controls who can manage the server/database resourceActual query access is controlled by SQL logins/Azure AD database users, configured inside SQL itself, separate from Azure RBAC entirely
Storage exampleAzure RBAC controls who can manage the storage account resourceBlob data access can be controlled by RBAC (Storage Blob Data Contributor) or by SAS tokens/connection strings, depending on configuration

The practical trap: someone can hold full Owner-level Azure RBAC on a SQL Server resource and still be completely unable to run a query against the database inside it, because query access is a data-plane concern governed by SQL's own authentication, not by the Azure RBAC role assignment at all.

5. Principals: Who Can Hold a Role

Principal typeWhat it represents
UserAn individual person's Entra ID identity
GroupAn Entra ID group — assigning a role to a group applies it to every current and future member
Service principalAn application's identity, typically used for CI/CD pipelines or external integrations (see the Microsoft Entra ID chapter)
Managed identityAn identity automatically tied to an Azure resource itself (like an App Service), with no credentials to manage at all (see the Microsoft Entra ID chapter)

Assigning roles to groups rather than individual users is the standard practice for anything beyond a single-person exception — it means onboarding/offboarding someone is a group membership change, not a hunt through every resource's individual role assignments.

6. Assigning Roles

Via CLI:

az role assignment create \
--assignee "user@traxsgroup.com" \
--role "Contributor" \
--scope "/subscriptions/<sub-id>/resourceGroups/traxs-prod"

Listing existing assignments — the first move when diagnosing a permission issue:

az role assignment list --assignee "user@traxsgroup.com" --all --output table

--all matters here — without it, the command only shows assignments at the exact scope you specify, missing anything inherited from a parent scope higher in the hierarchy.

7. Custom Roles

When no built-in role matches the exact set of permissions needed, a custom role definition can be created — a named set of specific Actions/NotActions bound to a set of allowed scopes:

{
"Name": "Traxs Deploy Only",
"Description": "Restart and view App Service, nothing else",
"Actions": [
"Microsoft.Web/sites/restart/action",
"Microsoft.Web/sites/read"
],
"NotActions": [],
"AssignableScopes": [
"/subscriptions/<sub-id>/resourceGroups/traxs-prod"
]
}

Custom roles add maintenance overhead (they need to be kept in sync as needs evolve) — worth reaching for only once a genuinely recurring, narrowly-scoped need shows up repeatedly, not for a one-off situation a built-in role covers well enough.

8. Propagation Delay

Role assignment changes are not always instantaneous — Azure documents propagation that can take up to several minutes in some cases, occasionally longer during high load. A permission that "should" now work but still returns a 403 immediately after the assignment was created is often just propagation lag, not a misconfiguration — worth a short wait and retry before assuming the assignment itself is wrong.

9. Troubleshooting Playbook

SymptomLikely causeWhat to check
403 Forbidden / "does not have authorization to perform action"No role assignment grants this specific action at this scopeaz role assignment list --assignee <principal> --all to see everything actually granted, at every inherited scope
Permission works for one resource but not a near-identical oneRole assigned at the specific-resource level, not inherited from the resource groupCheck scope on the existing assignment — it may be narrower than assumed
Just assigned a role, still getting 403Propagation delayWait a few minutes and retry before troubleshooting further
Have Owner/Contributor on a SQL Server resource, still can't query the databaseConfusing control-plane and data-plane accessData-plane query access needs a SQL login or Azure AD database user configured inside SQL itself — Azure RBAC alone doesn't grant it
Service principal works locally but fails identically-configured in a pipelineDifferent service principal being used than assumed, or role assignment scoped to the wrong resource groupConfirm exactly which principal the pipeline authenticates as, and check its role assignments specifically, not the interactive user's
Someone has access nobody remembers grantingInherited from a broader scope (subscription or management group) rather than the resource itselfTrace the scope hierarchy upward with --include-inherited

10. Quick Reference

CategoryItemDetail
ModelRole AssignmentPrincipal + Role Definition + Scope, always all three
ScopeInheritanceFlows downward: management group → subscription → resource group → resource
RoleOwnerFull control, can grant access to others
RoleContributorFull control, cannot grant access to others
RoleReaderView-only
ConceptControl planeManaging the resource itself
ConceptData planeAccessing data/content inside the resource — often governed separately from RBAC
PrincipalManaged identityAuto-tied to an Azure resource, no credentials to manage
Commandaz role assignment list --allList all assignments, including inherited
Commandaz role assignment createGrant a role

Part of the Traxs Engineering Handbook — Volume 4: Azure Foundations. Companion chapters in this volume: Azure CLI, Azure Networking, Azure Storage, Azure Key Vault, Microsoft Entra ID.