Practical engineering guidance
Azure RBAC scope decisions you cannot easily undo
Role assignments inherit downward and there is no deny. Where you assign a role matters more than which role you assign, and the subscription limit is closer than you think.
Series: Azure architecture
Azure role-based access control is simple to describe and easy to get structurally wrong. Three elements — a security principal, a role definition and a scope — combine into an assignment, and the assignment applies to that scope and everything beneath it.
The part that causes lasting trouble is that inheritance is additive and there is no ordinary deny. You cannot grant broadly and then carve out an exception, the way you can with a file system ACL. That single property should shape every decision below.
The problem: additive inheritance
The scope hierarchy runs management group, subscription, resource group, resource. An assignment at any level applies to everything under it, and a principal’s effective permission is the union of everything assigned at every level.
So there is no way to say “Contributor on this subscription, except that resource group”. If you make that assignment, it covers the exception too. The only ways out are to stop making the broad assignment, or to use one of the two narrow mechanisms that can subtract:
- Deny assignments, which are created by Azure — chiefly by Blueprints and by managed applications — and cannot be created directly by you.
- ABAC conditions on a role assignment, which constrain it by attributes. These are genuinely useful, and they are supported for a limited set of actions, principally storage data actions. They are not a general-purpose exception mechanism.
The practical rule follows directly: assign at the narrowest scope that does the job, and treat every broad assignment as a decision that needs justifying.
Design choice one: where the hierarchy does its work
Management groups exist so that policy and access can be applied consistently to many subscriptions. That is valuable, and it is also where the largest mistakes get made, because an assignment at the root management group applies to every subscription in the tenant.
What belongs at management group scope:
- Assignments that genuinely must apply everywhere, such as a platform team’s read access for inventory.
- Azure Policy assignments, which is really what management groups are for.
What does not:
- Owner or Contributor for an application team. That is a subscription-level or resource group-level decision.
- Anything you might later need to except. See above — you will not be able to.
Keep the hierarchy shallow. A deep management group tree looks organised and makes effective permissions hard to reason about, which is the opposite of the goal.
Design choice two: which role, and the three that are not interchangeable
Most work is done by three built-in roles, and the differences matter.
Reader grants read access to everything in scope. Low risk, and worth granting generously because it removes most of the reason people ask for more.
Contributor grants full management of resources — create, modify, delete — but cannot grant access to others. That restriction is the whole point: a Contributor can build and break things, but cannot expand who else can.
Owner is Contributor plus the ability to assign roles. That second capability is what makes Owner a privileged-access decision rather than a resource-management one. An Owner can grant themselves or anyone else anything, at that scope and below, permanently.
User Access Administrator grants role assignment without resource management. It is worth knowing because it is the right answer when someone needs to manage access and nothing else, and because it carries the same escalation property as Owner.
The rule I would apply: Owner is a Tier 0-equivalent assignment. Treat it with the same seriousness as a directory role, keep the count small, and prefer Privileged Identity Management for it so that it is eligible rather than standing.
Where a built-in role is too broad, a custom role is usually better than an Owner assignment with good intentions. Custom roles cost maintenance, so use them where the need is durable rather than for a one-off.
Design choice three: never assign to users
Assign roles to groups, not to individuals. This is stated everywhere and ignored constantly, and the reasons are more practical than philosophical.
An estate with user-level assignments cannot be audited — you cannot answer “who can write to production” without enumerating every scope. It also cannot be maintained: when somebody changes role, their access is scattered across assignments nobody can find.
Group-based assignment additionally keeps you away from the limit, which is the next problem.
The limit that arrives sooner than expected
Azure supports 4,000 role assignments per subscription. That figure covers assignments at subscription, resource group and resource scope — management group assignments are counted separately, at 500 per management group.
Two things worth knowing:
- The 4,000 limit is fixed and cannot be raised. This is unusual for an Azure limit and it catches people out. A large estate that assigns roles to individual users at resource scope will reach it, and the remedy at that point is a restructuring exercise under time pressure.
- Eligible assignments and assignments scheduled in the future do not count. So moving standing assignments to eligible assignments through Privileged Identity Management relieves the limit as well as improving the security position.
If you are anywhere near the limit, the causes are almost always user-level assignments and resource-scope assignments that should have been resource group-scope. Both are fixable and neither is quick.
The reversal costs
This is the part to internalise before designing anything.
| Decision | Cost to change later |
|---|---|
| Management group hierarchy shape | High — moving subscriptions changes inherited policy and access at once |
| Subscription boundaries | High — resources cannot always move between subscriptions, and some carry regional or networking constraints |
| Resource group boundaries | Moderate — many resources move, some do not |
| Individual role assignments | Low — remove and reassign |
| Group-based versus user-based assignment | Low individually, high in aggregate once thousands exist |
The top two rows are why landing zone design deserves real attention before the first production workload arrives, rather than after.
Implementation considerations
Resource groups are a lifecycle and access boundary, not a filing system. The useful question when creating one is “will everything in here be deployed, managed and deleted together, by the same people?” If the answer is no, it is two resource groups.
Subscriptions are the natural blast-radius boundary. They separate quota, policy and access cleanly, and they are cheap. Where a workload needs genuinely different governance, give it its own subscription rather than trying to express the difference through role assignments.
Audit assignments regularly, and specifically look for two things: assignments to individual users, and Owner assignments. Both grow quietly.
# Standing assignments at or below a subscription, with the broad ones surfaced first.
Get-AzRoleAssignment -Scope "/subscriptions/$($sub.Id)" |
Where-Object { $_.RoleDefinitionName -in 'Owner', 'User Access Administrator' } |
Select-Object DisplayName, ObjectType, RoleDefinitionName, Scope |
Sort-Object Scope
Filtering by ObjectType for User gives you the individual assignments that should be
group assignments.
Managed identities over service principals with secrets, wherever the service supports it. A managed identity removes the credential entirely, which removes its expiry, its storage and its rotation.
Do not grant Contributor at subscription scope to a deployment pipeline because it is convenient. A pipeline that can delete a production subscription’s contents is a supply-chain risk with a friendly name.
What RBAC does not do
RBAC controls the management plane — who can create, configure and delete resources. It is largely separate from data plane access: who can read a blob, query a database, or open a key vault secret. Some services bridge the two with data-plane roles, and some do not. Assuming that management-plane access implies data access, or that its absence prevents data access, is a frequent and consequential error.
It also does not constrain what a permitted action may configure. Preventing someone with Contributor from creating an unencrypted storage account or a public IP is a policy question, not an access question — which is where Azure Policy as a guardrail comes in. The two are complementary and neither substitutes for the other.
Verification and limits
The scope hierarchy and additive inheritance, deny assignments being Azure-created only, ABAC condition support, the capability differences between Reader, Contributor, Owner and User Access Administrator, the 4,000 role assignments per subscription and 500 per management group limits, and the exclusion of eligible assignments from those counts were checked against current Microsoft documentation on 20 September 2026.
No changes were made to an Azure environment for this article. The query above is read-only. Removing a role assignment can break a running workload or a pipeline — identify what uses an assignment before removing it, and change access in a window where a failure is visible. Service limits change, so confirm current figures before designing to a number.
References
Reader feedback
Was this article useful?
No ratings yet. Be the first to rate this article.
