Azure RBAC
Azure RBAC (role-based access control) is the authorisation system built into Azure Resource Manager. It answers one question — may this principal perform this operation on this resource? — by looking for a role assignment: a principal, a role definition, and a scope. Three fields, evaluated on every single Azure request.
Names: the service has always been called Azure RBAC, but the identity system it depends on was
renamed — Azure Active Directory (Azure AD) became Microsoft Entra ID in 2023. You will
still see "Azure AD role" used loosely to mean two entirely different things (an Entra directory
role and an Azure RBAC role), and that ambiguity is the source of more confusion than any other
naming issue in Azure. This topic uses "directory role" and "Azure role" and never blurs them. The
ARM resource provider is Microsoft.Authorization, and it has never been renamed.
What it is and where it fits
Every call to Azure Resource Manager arrives carrying a bearer token that
Microsoft Entra ID signed. Entra ID has already answered who are you.
Azure RBAC answers the next question, and only that question: is this identity permitted to do
this? It does so by collecting every role assignment that applies at or above the target scope,
unioning their permitted operations, and checking whether the requested operation string is in the
resulting set. If it is, the request proceeds. If it isn't, ARM returns AuthorizationFailed — and
helpfully tells you the principal, the action, and the scope it evaluated.
The problem it solves is the one every multi-team cloud estate hits within a year. Without a scoped authorisation model, access is binary: either you can administer the subscription or you can't. That produces one of two failure modes — everyone is a co-administrator and one mistake takes down production, or nobody has access and a ticket queue becomes the deployment mechanism. Azure RBAC replaces both with a grant that is narrow in three independent dimensions at once: who (a group, not a person), what (a role, not root), and where (a resource group, not the subscription).
Azure RBAC governs Azure resources and nothing else. This boundary is the most important thing on this page. It does not govern the directory — creating a user, registering an application, or assigning a licence are Entra ID operations controlled by directory roles, a separate system with separate assignments stored in a separate place. A Global Administrator has, by default, no access to any virtual machine. An Owner of a subscription cannot create a user. Both statements are true, both surprise people, and both follow from this one boundary. See Identity and RBAC for the shared groundwork this topic builds on, and the scope hierarchy for the tree that assignments inherit down.
The neighbours it gets confused with, separated in a line each:
- Entra directory roles (Global Administrator, User Administrator, Application Administrator) — govern the tenant: users, groups, app registrations, licences. Assigned through Entra ID, not ARM. Disjoint from Azure RBAC except for one deliberate bridge (elevate access, covered in Core Concepts).
- Azure Policy — decides whether a request shape is allowed at all, regardless of who is
asking. "Only these VM sizes, only in these regions, and every resource must carry a
CostCentretag." RBAC asks who; Policy asks what. A policy denial (RequestDisallowedByPolicy) is not an RBAC problem and no role will fix it. - Resource locks (
CanNotDelete,ReadOnly) — a blunt guard that blocks operations for everyone, including Owner, until the lock is removed. Fails withScopeLocked, which reads like a permissions error and isn't one. - Service-native data authorisation — SAS tokens, storage account keys, Key Vault access policies (the legacy model), SQL database users, Kubernetes RBAC inside AKS. These are parallel authorisation systems for the data plane. Some services let you turn them off so RBAC is the only path; where they're available, they route around every RBAC control you configured.
- Conditional Access — sits earlier, at token issuance: require MFA, a compliant device, or a trusted network before Entra will mint a token for the Azure management plane. Not authorisation, and licensed separately.
If you're coming from AWS: the closest analogue is IAM policy evaluation, and the transfer is partial in a way that catches everyone. What transfers: principals, permission strings, the idea of scoping a grant to a resource ARN. What breaks, and breaks hard:
- There is no deny. AWS IAM's evaluation logic is deny-by-default with explicit-deny-wins.
Azure RBAC is deny-by-default with no author-able deny at all — the effective permission set
is the pure union of everything assigned at or above the scope.
notActionslooks like a deny and is not (it subtracts from one role definition; another assignment grants it right back). - The grant is an object, not a document. An IAM policy is attached to a principal or a resource. An Azure role assignment is a separate ARM resource with its own ID that points at a principal, a role, and a scope. You list assignments, not policies.
- Inheritance is automatic and downward. A Reader at the subscription is a Reader on every resource group and every resource inside it, including ones created tomorrow. There's no permission boundary and no way to subtract lower down.
- Control plane and data plane are separately authorised. Being Owner does not let you read a
blob or a secret. AWS's
s3:GetObjectsits in the same policy ass3:CreateBucket; Azure splits them intoactionsanddataActions, and most built-in management roles carry only the former.
That last point is the single highest-value thing to internalise, and Architecture traces it end to end.
Key facts at a glance
| Category | Security & identity — authorisation for Azure resources (a built-in capability of ARM, not a deployed service) |
| Resource provider | Microsoft.Authorization — chiefly roleAssignments, roleDefinitions, denyAssignments, and roleAssignmentScheduleRequests (PIM) |
| Scope | Global control plane, hierarchical assignment. Assignable at four levels: management group → subscription → resource group → individual resource. Some services add sub-resource scopes (a blob container, a queue, a Key Vault secret) |
| Unit of grant | The role assignment — principal object ID + role definition ID + scope. Nothing else. It is itself an ARM resource with a GUID name |
| The SKU axis | Azure RBAC itself is free and always on — there is no tier. The tier axis lives in Entra ID, and it gates the governance features layered over RBAC: PIM (just-in-time, approval-gated activation) and access reviews require Microsoft Entra ID P2 or Entra ID Governance; everything else on this page works on the Free tier ⚠️ verify current feature-to-licence mapping against current Azure docs |
| Which one is the trap | Assuming standing Owner assignments are acceptable because PIM "costs extra". The licence is per privileged user, not per tenant, and the number of people who genuinely need standing Owner is usually zero |
| Control plane | ARM (management.azure.com) evaluates actions / notActions. Managing the resource |
| Data plane | The service's own endpoint (*.blob.core.windows.net, *.vault.azure.net, *.servicebus.windows.net) evaluates dataActions / notDataActions. Touching the contents. Separate roles |
| Unit of billing | None. RBAC is free; only the Entra licences for PIM, Conditional Access, and access reviews cost money |
| SLA posture | Covered by the Azure Resource Manager control-plane availability commitment rather than its own SLA. Note that assignment propagation is eventually consistent — a new assignment is not instantly effective everywhere ⚠️ verify current propagation guidance against current Azure docs |
| Usual companions | Microsoft Entra ID, managed identities, Key Vault, Azure Policy, Azure Monitor / Log Analytics (activity log), Microsoft Defender for Cloud, Terraform |
| Primary alternative | For the control plane, none — RBAC is the only authorisation model ARM has. For the data plane, the service-native alternatives (SAS, account keys, access policies) exist and should generally be disabled |
| AWS rough analogue | IAM policies and policy evaluation, and the analogy breaks at explicit deny, permission boundaries, and the control/data-plane split |
When Azure RBAC is the right tool
- Any standing grant of access to Azure resources. There is no alternative for the control plane. The only design question is which role, at which scope, to which group.
- Giving a workload permission to reach another Azure resource. A managed identity plus one narrow data-plane role assignment removes every connection string and account key from your configuration. This is the highest-value security change available in Azure and it is free.
- Separating duties between platform and application teams. Platform owns networking and policy at the management-group scope; application teams get Contributor on their own resource groups and cannot touch the shared VNet. RBAC expresses this cleanly because scope and role are independent.
- Delegating a specific operation without delegating the resource.
Virtual Machine Contributorfor a support team that must restart VMs,Storage Blob Data Readerfor an analyst who must read one container. There are hundreds of built-in roles and the narrow one usually already exists. - Time-bounding privilege. Where the licence allows it, PIM turns "who is an Owner" from a standing list into an activation log with justification and an expiry.
When it isn't
- To enforce a configuration standard. "No public IPs", "only UK South", "everything tagged" are Azure Policy, not RBAC. Trying to express them as permissions produces a custom role nobody can maintain and it still won't hold, because a Contributor can create a compliant resource and then make it non-compliant.
- To prevent accidental deletion of one critical resource. That's a
CanNotDeleteresource lock. RBAC can only remove delete permission from everyone in scope, which is usually too much. - To express "everyone except". There is no author-able deny. Design the grant to be narrow from the start; you cannot subtract at a lower scope. Platform-created deny assignments exist (Azure managed applications, formerly Blueprints) but you can't write them.
- As the only control on data access while key-based auth is still enabled. If a storage
account key or a SAS token can be used, your carefully scoped
dataActionsrole is decorative. Disable the alternative path, then rely on RBAC. - As a substitute for network isolation. RBAC governs authorised callers. Private endpoints,
firewall rules, and
publicNetworkAccessgovern reachability. They are different layers and neither replaces the other. - At fine per-object granularity, in most services. ABAC conditions on blob tags and path prefixes are genuinely useful, but coverage is per-service and incomplete ⚠️ verify current coverage against current Azure docs. Where conditions don't reach, the honest answer is often to reshape the resources rather than the permissions.
[Image Prompt: 2D minimalistic diagram of Azure RBAC positioned between an incoming authenticated request carrying a Microsoft Entra ID token and an Azure resource, showing the three inputs to the decision — principal, role definition, and scope — feeding an allow or deny outcome, with Azure Policy and resource locks shown as separate parallel gates, flat design, clean vector art style, white background]
What this topic covers
| Sub-topic | What it covers |
|---|---|
| What & Why | The problem scoped authorisation kills, why it is not Azure Policy and not directory roles, the IAM analogy and its four breaking points, and the honest anti-patterns |
| Core Concepts | Security principals, role definitions and their four permission arrays, scope and inheritance, built-in vs. custom roles, ABAC conditions, deny assignments, PIM, and the vocabulary traps |
| Architecture | An authorisation decision traced end to end, control plane vs. data plane with separate evaluators, the union-with-no-deny algorithm, propagation and token caching latency, throttling, and the failure modes |
| Getting Started | Grant a web app's managed identity read access to one blob container — portal, az CLI, PowerShell Az, and minimal Terraform — plus teardown |
| Deployment | A parameterised Terraform module for assignments and custom roles, remote state, an Ansible playbook, the Bicep equivalent and its guid() naming trick, OIDC-based CI/CD, environment strategy, rollback and blast radius, and drift |
| Integrations | Managed identities, Key Vault, Storage, Azure Policy, AKS, Azure SQL, Azure Monitor, and Terraform's own service principal — plus the two glue mechanisms that recur everywhere |
| Production | Least privilege in practice, the cost of the governance features, assignment and role-definition limits with the scope each is counted at, observability through the activity log and KQL, and reliability including propagation and break-glass accounts |
| Interview Questions | Three tiers with answer keys, from "what are the three parts of a role assignment" to "someone hand-edited a role assignment in the portal — how do you get back to a clean plan" |
| Glossary & Cheatsheet | Every term in one line, the commands you'll actually type, the resource ID shapes, and the limits worth memorising |
Four ideas worth carrying into every other topic
A role assignment is three fields and nothing else. Principal, role, scope. If access isn't working, exactly one of those three is wrong — or the token is stale. That framing turns most 403 debugging from guesswork into a three-item checklist.
There is no deny, so breadth is permanent until removed at its source. An over-broad assignment at the subscription cannot be walked back at the resource group. It has to be deleted where it was made. This makes the initial scope choice unusually consequential, and it's why "assign at the narrowest scope that works" is a rule rather than a preference.
Owner does not let you read a blob. Control-plane roles carry actions; data-plane access needs
dataActions. An Owner can grant it to themselves or read the account keys, which is exactly why
disabling key-based auth is a real control and not theatre. Every topic in this article that has a
data plane repeats this line, because it is the mistake people make twice.
Assign to groups, and assign the narrow role. Role assignments are ARM resources with a ceiling per subscription ⚠️ verify the current limit against current Azure docs, and thousands of per-user assignments are unauditable. Group-based assignment converts an access review — a question nobody can answer — into a membership review, which the business can.
Reading paths
- New to Azure RBAC: What & Why → Core Concepts → Getting Started.
- Interview preparation: Core Concepts → Architecture → Interview Questions.
- You need to ship something: Getting Started → Deployment → Integrations.
- Designing an access model for an estate: Core Concepts (scope and inheritance) → Production → Integrations.
- Debugging a 403 right now: Architecture, then the 403 checklist in foundations.
Start here: What & Why →