Skip to main content

Theoretical Foundation: Assign roles at different scopes


1. Initial Intuition​

Imagine you are the security manager of a large university campus with several buildings: Administration, Library, Laboratories, and Restaurant. You need to define who can access what.

Some people need access to everything: the security director moves throughout the entire campus. Others have access to only a specific building: the librarian only enters the Library. Still others have restricted access to a single laboratory within the Laboratories building.

In Azure, this logic is exactly the concept of scope in RBAC role assignment. Scope defines the perimeter within which a permission applies. Assigning the Contributor role to an entire subscription is like giving the key to the entire campus. Assigning the same role to a single Resource Group is like giving the key to a single building.

The difference is not in the role itself, but where it applies.


2. Context​

In the previous module, we learned what Azure built-in roles are and how they work. Now the focus shifts to the spatial dimension of RBAC: where permissions apply.

Scope is the second of three fundamental elements of any role assignment:

100%
Scroll para zoom Β· Arraste para mover Β· πŸ“± Pinch para zoom no celular

Scope determines how far the permission "reaches". And since scopes in Azure form a hierarchy, a permission assigned at a higher level automatically propagates to all levels below. This mechanism is called permission inheritance.

Understanding scopes is fundamental for:

  • Applying the principle of least privilege precisely
  • Avoiding accidental granting of excessive access
  • Structuring access control scalably
  • Diagnosing access issues correctly

3. Building Concepts​

3.1 Azure's Scope Hierarchy​

Azure organizes all its resources in a four-level hierarchy, from most comprehensive to most specific:

100%
Scroll para zoom Β· Arraste para mover Β· πŸ“± Pinch para zoom no celular

Each level of this hierarchy is a scope where roles can be assigned:

LevelScopeScope ID Format
RootTenant root/
Management GroupManagement group/providers/Microsoft.Management/managementGroups/{mgId}
SubscriptionSubscription/subscriptions/{subscriptionId}
Resource GroupResource group/subscriptions/{subId}/resourceGroups/{rgName}
ResourceIndividual resource/subscriptions/{subId}/resourceGroups/{rgName}/providers/{provider}/{type}/{name}

3.2 Management Groups: The Highest Level​

Management Groups are containers that organize subscriptions. They don't contain resources directly; they contain subscriptions (and other nested Management Groups).

Each tenant automatically has a Root Management Group created when Entra ID is provisioned. All tenant subscriptions are children of the Root Management Group, either directly or through intermediate Management Groups.

What are Management Groups for?

Imagine a company with 50 subscriptions organized by: environment (production, dev, staging), region (Brazil, Europe, USA), and business unit (Retail, B2B, Corporate). Without Management Groups, applying a security policy or role assignment to all production subscriptions would require 50 individual operations. With Management Groups, a single assignment on the "Production" Management Group automatically propagates to all subscriptions within it.

3.3 The Inheritance Principle​

Inheritance means that a permission granted at a higher scope is automatically inherited by all scopes below in the hierarchy. No additional configuration is needed; inheritance happens automatically.

100%
Scroll para zoom Β· Arraste para mover Β· πŸ“± Pinch para zoom no celular

Important consequence: inheritance cannot be "blocked" at the lower level. If a group receives Reader on the root Management Group, it can read resources in all tenant subscriptions, without exception. There's no mechanism to say "inherit this role in all child scopes EXCEPT this specific Resource Group" using only role assignments.

The only way to explicitly deny access is through Deny Assignments, which as we saw are created by Blueprints and Managed Applications, not directly by the administrator.

3.4 Combining Permissions from Multiple Scopes​

A user can have multiple role assignments at different scopes. Permissions are additive: the effective permission set is the union of all permissions from all roles in all applicable scopes.

Example:

100%
Scroll para zoom Β· Arraste para mover Β· πŸ“± Pinch para zoom no celular

For user Ana:

  • In RG Dev: only Reader (inherited from subscription)
  • In RG Production: Reader (inherited) + Contributor (directly assigned) = effectively Contributor
  • In VM prod-01: Reader (inherited from subscription) + Contributor (inherited from RG Production) = effectively Contributor

The broader permission prevails when there's overlap. If someone has Reader in one scope and Contributor in a child scope, in the child scope the effective permission is Contributor.

3.5 Individual Resource Scope​

The most granular scope is the individual resource. An assignment at this level affects only that specific resource.

Example scope for a specific VM:

/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/rg-producao/providers/Microsoft.Compute/virtualMachines/vm-frontend-01

This level is useful when:

  • A person or team manages only a specific resource
  • A script or application needs access to only one storage account or Key Vault
  • You want to give temporary and precise access to a resource for debugging

4. Structural View​

Complete Map of Inheritance and Combination​

100%
Scroll para zoom Β· Arraste para mover Β· πŸ“± Pinch para zoom no celular

Analysis of effective permissions in this scenario:

PrincipalIn RG App-AlphaIn VM alpha-web-01In Storage alphalogs
Audit-GroupReader (inherited from MG)Reader (inherited)Reader (inherited)
SecOps-GroupSecurity Admin (inherited)Security Admin (inherited)Security Admin (inherited)
DevOps-GroupContributor (inherited from Sub)Contributor (inherited)Contributor (inherited)
joao@contoso.comOwner (inherited from Sub)Owner (inherited)Owner (inherited)
Ops-GroupVirtual Machine Contributor (direct on RG)Virtual Machine Contributor (inherited from RG)No additional permissions beyond inherited
maria@contoso.comNo assignment on RGReader (direct on resource)No access
Analytics-GroupNo assignment on RGNo accessStorage Blob Data Reader (direct on resource, DataActions)

5. How It Works in Practice​

How Azure Resolves Scope in Real Time​

When a user tries to execute an operation, Azure evaluates permissions by traversing the hierarchy from top to bottom:

100%
Scroll para zoom Β· Arraste para mover Β· πŸ“± Pinch para zoom no celular

Non-obvious behavior: Azure doesn't evaluate just the closest role assignment (the one on the resource itself). It collects all role assignments that affect that user in all applicable scopes (the resource, the parent RG, the parent subscription, the parent Management Group, up to root). The effective permission is the sum of all of them (minus NotActions and Deny Assignments).

Change Propagation​

When you create or remove a role assignment, the change needs to propagate through Azure's distributed system. Under normal conditions, it takes a few minutes. In extreme cases (high system load, large-scale changes), it can take up to 30 minutes.

During this propagation period:

  • A newly authorized user may receive access denied errors for a few minutes
  • A user who had access revoked may still be able to access for a few minutes

In security operations where revocation needs to be immediate (e.g., credential compromise), this is a factor to consider. The most effective mechanism for immediate revocation in emergency situations is to disable the account in Entra ID, not just remove the role assignment.


6. Implementation Methods​

6.1 Azure Portal​

When to use: one-off assignments at any hierarchy level.

The path for assignment varies according to the desired scope:

Desired scopePortal path
Management GroupManagement Groups > [select MG] > Access control (IAM)
SubscriptionSubscriptions > [select Sub] > Access control (IAM)
Resource GroupResource Groups > [select RG] > Access control (IAM)
Individual resource[Navigate to resource] > Access control (IAM)

In any of these paths, the process is identical: Add > Add role assignment > [select role] > [select principal].

View inherited assignments: in the Role assignments tab of any resource's IAM, you can filter by Type: Inherited to see only assignments inherited from higher scopes. This is very useful for diagnostics.

6.2 Azure CLI​

Assignment by explicit scope via --scope parameter:

# Management Group
az role assignment create \
--assignee-object-id <group-object-id> \
--assignee-principal-type Group \
--role "Reader" \
--scope "/providers/Microsoft.Management/managementGroups/mg-corporativo"

# Subscription
az role assignment create \
--assignee-object-id <group-object-id> \
--assignee-principal-type Group \
--role "Contributor" \
--scope "/subscriptions/12345678-1234-1234-1234-123456789012"

# Resource Group
az role assignment create \
--assignee-object-id <group-object-id> \
--assignee-principal-type Group \
--role "Virtual Machine Contributor" \
--scope "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/rg-producao"

# Individual resource (specific VM)
az role assignment create \
--assignee-object-id <user-object-id> \
--assignee-principal-type User \
--role "Reader" \
--scope "/subscriptions/12345678-1234-1234-1234-123456789012/resourceGroups/rg-producao/providers/Microsoft.Compute/virtualMachines/vm-frontend-01"

List assignments in a specific scope (without inheritance):

az role assignment list \
--scope "/subscriptions/<sub-id>/resourceGroups/rg-producao" \
--output table

List assignments including inherited ones:

az role assignment list \
--scope "/subscriptions/<sub-id>/resourceGroups/rg-producao" \
--include-inherited \
--output table

The --include-inherited parameter is fundamental for understanding effective access, because without it you see only direct assignments in that scope, not the complete picture.

6.3 PowerShell (Az Module)​

# Assignment on Management Group
New-AzRoleAssignment `
-ObjectId "<group-object-id>" `
-RoleDefinitionName "Reader" `
-Scope "/providers/Microsoft.Management/managementGroups/mg-corporativo"

# Assignment on Subscription
New-AzRoleAssignment `
-ObjectId "<group-object-id>" `
-RoleDefinitionName "Contributor" `
-Scope "/subscriptions/<subscription-id>"

# Alternative for Resource Group (dedicated parameter)
New-AzRoleAssignment `
-ObjectId "<group-object-id>" `
-RoleDefinitionName "Virtual Machine Contributor" `
-ResourceGroupName "rg-producao"

# Individual resource (VM)
New-AzRoleAssignment `
-ObjectId "<user-object-id>" `
-RoleDefinitionName "Reader" `
-ResourceGroupName "rg-producao" `
-ResourceName "vm-frontend-01" `
-ResourceType "Microsoft.Compute/virtualMachines"

List all assignments including inherited ones for a user:

Get-AzRoleAssignment `
-SignInName "joao.silva@contoso.com" `
-Scope "/subscriptions/<sub-id>/resourceGroups/rg-producao" `
-ExpandPrincipalGroups |
Select-Object DisplayName, RoleDefinitionName, Scope

The -ExpandPrincipalGroups expands the groups the user is a member of to show assignments inherited via group, not just direct assignments.

6.4 Bicep and ARM Templates (Infrastructure as Code)​

When defining resources as code, role assignments at different scopes require different approaches in Bicep:

Role assignment in Resource Group scope (Bicep file in RG context):

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(resourceGroup().id, principalId, roleDefinitionId)
properties: {
roleDefinitionId: subscriptionResourceId(
'Microsoft.Authorization/roleDefinitions',
roleDefinitionId
)
principalId: principalId
principalType: 'Group'
}
}

Role assignment in Subscription scope (requires targetScope = 'subscription'):

targetScope = 'subscription'

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(subscription().id, principalId, roleDefinitionId)
properties: {
roleDefinitionId: subscriptionResourceId(
'Microsoft.Authorization/roleDefinitions',
roleDefinitionId
)
principalId: principalId
principalType: 'Group'
}
}

Role assignment in Management Group scope (requires targetScope = 'managementGroup'):

targetScope = 'managementGroup'

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(managementGroup().id, principalId, roleDefinitionId)
properties: {
roleDefinitionId: tenantResourceId(
'Microsoft.Authorization/roleDefinitions',
roleDefinitionId
)
principalId: principalId
principalType: 'Group'
}
}

The difference between subscriptionResourceId, tenantResourceId and the function without scope prefix is critical when working with Bicep at different hierarchy levels.


7. Control and Security​

Who Can Assign Roles at Each Scope?​

To create a role assignment in a scope, the user needs to have the Microsoft.Authorization/roleAssignments/write permission in that scope. The roles that grant this permission are:

RoleCan assign roles in:
OwnerThe scope where they have Owner, and all child scopes
User Access AdministratorThe scope where UAA exists, and all child scopes
Role Based Access Control AdministratorOnly manages RBAC, can be configured with conditions

Important: you can only assign roles whose permissions are a subset of your own permissions. It's not possible to use Owner to give someone a role that you yourself don't have. This prevents privilege escalation.

ABAC (Attribute-Based Access Control) Conditions​

For some specific roles (mainly Storage Blob Data Reader/Contributor and some queue roles), Azure supports conditions that add a control layer based on resource attributes.

Example: you want the Analytics-Group to have read access only to blobs in containers that have the tag confidentiality: public, and not to containers with confidentiality: restricted. With an ABAC condition, it's possible to express this:

(
(!(ActionMatches{'Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read'}))
OR
(
@Resource[Microsoft.Storage/storageAccounts/blobServices/containers:name] StringEqualsIgnoreCase 'logs-publicos'
)
)

ABAC conditions are a way to make scope assignments more granular without needing to create custom roles or multiple separate assignments.


8. Decision Making​

At which scope to assign?​

SituationRecommended scopeReason
Audit team that needs to read all company resourcesRoot Management Group with ReaderComplete coverage with a single assignment
Security team that applies policies across all production subscriptions"Production" Management GroupAdequate scope without affecting Dev and Staging
DevOps team that manages a specific subscriptionSubscriptionCorrect scope for cross-cutting management
Application team that manages a set of resources for a projectResource GroupIsolates access to the project without affecting others
Operator who manages only a specific VMIndividual resourceLeast privilege possible
CI/CD pipeline that deploys to a specific RGResource Group (Contributor on target RG)Scope restricted to what's necessary for deployment
Application that reads secrets from a specific Key VaultIndividual resource (Key Vault)Access only to the necessary vault

When to use direct assignment vs. inheritance?​

ApproachWhen to useConsiderations
Assignment at high scope + inheritanceCross-cutting roles like Reader for auditors, Security Admin for SecOpsCannot be blocked at child scopes
Assignment at low scope (RG or resource)Specific roles for teams or servicesMore control, more assignments to manage
Combination of bothMost real-world environmentsAuditor with Reader at MG + DevOps with Contributor at RG for each project

9. Best Practices​

Structure Management Groups before starting to assign roles: the Management Groups hierarchy determines how permissions propagate. Defining this structure after already having many assignments is much more laborious. Plan first: the most common criteria for organizing Management Groups is by environment (Production / NonProduction) or by business unit.

Use Resource Group scope as the default access unit: the Resource Group is the most natural scope for most operational scenarios. It groups related resources from a project or application, and assigning roles at the RG ensures that a team has access to everything they need for that project without affecting others.

Reserve Subscription scope for cross-cutting roles: roles assigned at the subscription should be for activities that genuinely cross all Resource Groups, such as monitoring, auditing, or security policies. Avoid assigning Contributor at subscription level for teams that only need to work on a subset of resources.

Reserve Management Group for corporate policies: assignments at Management Group should be for roles that the entire organization needs to have consistently, such as the audit group with Reader. Don't use Management Group to give operational access to specific teams.

Document the scope and reason for each critical assignment: especially for assignments at high scopes (MG and Subscription), document: who requested, why it was granted, when it should be reviewed. The absence of documentation transforms intentional inheritance into an audit mystery years later.

Implement access reviews by scope: configure Access Reviews (Entra ID P2) specific for groups with roles in broad scopes (like Contributor on an entire subscription). Frequent reviews for broader scopes help identify excessive access before it becomes a risk.


10. Common Errors​

Assigning role at Subscription scope when Resource Group would be sufficient

This is the most frequent error and comes from the intention to "ensure it works". The result is that the user or group gains access to all resources in all Resource Groups of the subscription, including those that weren't intended. In a subscription with 20 Resource Groups, this is a 20x larger access grant than necessary.

Not considering inherited permissions when diagnosing "excessive access"

An administrator identifies that a user has access to a resource they shouldn't and removes the direct role assignment. The access continues. Investigation reveals that the user is a member of a group that has an inherited assignment from a Management Group. Access removals need to consider the entire inheritance chain, not just the immediate scope.

Using --include-inherited as optional instead of default in diagnostics

When investigating access problems, many administrators list role assignments without --include-inherited and erroneously conclude there's no permission when actually the permission exists but is inherited. Always use --include-inherited (or the "Inherited" tab in the portal) when doing access diagnostics.

Creating role assignments at individual resource scope for many resources

An approach that seems precise (each application has access only to its storage account) quickly becomes unviable: hundreds of individual role assignments, difficult to audit, consuming the 4,000 available slots per subscription. The scalable solution is to group related resources in the same Resource Group and assign roles at the RG level.

Assuming that removing a role in a child scope revokes all permissions

If a user has inherited Contributor from a subscription and you later add a Reader directly to a Resource Group (perhaps trying to "downgrade" the permission in that scope), the result is not as expected. Permissions are additive: the user maintains Contributor in that RG by inheritance, and the direct Reader assignment doesn't "block" the inheritance. To reduce inherited permissions, it's necessary to act at the inheritance source scope.


11. Operation and Maintenance​

Inventory by Scope​

To get a consolidated view of all assignments at each level:

# All assignments at Management Group level
Get-AzRoleAssignment -Scope "/providers/Microsoft.Management/managementGroups/mg-corporativo" |
Select-Object DisplayName, RoleDefinitionName, Scope, ObjectType

# All direct assignments at subscription (without inherited)
Get-AzRoleAssignment -Scope "/subscriptions/<sub-id>" |
Where-Object { $_.Scope -eq "/subscriptions/<sub-id>" } |
Select-Object DisplayName, RoleDefinitionName, ObjectType

The second command filters only assignments directly at the subscription scope (without those inherited from MGs above or assigned in RGs below), which is useful for focused auditing.

Check Effective Access for a Specific User​

For a complete diagnosis of why a user does or doesn't have access to a resource:

# Check all role assignments that affect a user on a specific resource
az role assignment list \
--assignee joao.silva@contoso.com \
--scope "/subscriptions/<sub-id>/resourceGroups/rg-producao/providers/Microsoft.Compute/virtualMachines/vm-01" \
--include-inherited \
--include-groups \
--output table

The --include-groups includes assignments that the user inherits by being a member of groups, which is fundamental for complete diagnosis.

Detection of Duplicate Assignments​

In large environments, it's common to have the same permission granted at multiple scopes (e.g., Reader at an MG and Reader also at various subscriptions within that MG). The subscription assignments are redundant. A cleanup script can identify this:

$subAssignments = Get-AzRoleAssignment -Scope "/subscriptions/<sub-id>"
$mgAssignments = Get-AzRoleAssignment -Scope "/providers/Microsoft.Management/managementGroups/mg-corp"

# Find redundant assignments (same role, same principal)
foreach ($subAssign in $subAssignments) {
$duplicate = $mgAssignments | Where-Object {
$_.ObjectId -eq $subAssign.ObjectId -and
$_.RoleDefinitionName -eq $subAssign.RoleDefinitionName
}
if ($duplicate) {
Write-Output "Redundant: $($subAssign.DisplayName) - $($subAssign.RoleDefinitionName) at $($subAssign.Scope)"
}
}

12. Integration and Automation​

Scale Assignments with Azure Policy​

Azure Policy with deployIfNotExists effect can ensure that every new subscription or Resource Group automatically receives a standard set of role assignments:

{
"if": {
"field": "type",
"equals": "Microsoft.Resources/subscriptions"
},
"then": {
"effect": "deployIfNotExists",
"details": {
"type": "Microsoft.Authorization/roleAssignments",
"deploymentScope": "subscription",
"deployment": {
"properties": {
"mode": "incremental",
"template": {
// template that creates the default role assignment
}
}
}
}
}
}

With this approach, every subscription created in the Management Group automatically receives, for example, the audit group with Reader, without any manual action from the administrator.

Blueprints for Assignments in Landing Zones​

Azure Blueprints (and its evolution, Azure Deployment Environments) allows defining a "package" of configurations for a new subscription that includes:

  • Policies
  • Role assignments at multiple scopes
  • Pre-created Resource Groups
  • ARM/Bicep templates

When a new subscription is provisioned from the Blueprint, all defined role assignments are automatically created at the correct scopes, ensuring compliance from the first moment.

Terraform for Scope Management​

In Terraform, role assignments at different scopes are expressed with the same azurerm_role_assignment resource, varying only the scope argument:

# Scope: Subscription
resource "azurerm_role_assignment" "devops_contributor_sub" {
scope = "/subscriptions/${var.subscription_id}"
role_definition_name = "Contributor"
principal_id = var.devops_group_id
}

# Scope: Resource Group
resource "azurerm_role_assignment" "ops_vm_contributor_rg" {
scope = azurerm_resource_group.producao.id
role_definition_name = "Virtual Machine Contributor"
principal_id = var.ops_group_id
}

# Scope: Individual resource (Key Vault)
resource "azurerm_role_assignment" "app_kv_reader" {
scope = azurerm_key_vault.app_vault.id
role_definition_name = "Key Vault Secrets User"
principal_id = azurerm_user_assigned_identity.app_identity.principal_id
}

Managing these assignments as Terraform code ensures that the desired state is always documented, versioned, and reproducible.


13. Final Summary​

Essential points:

  • Scope defines where a permission applies in the hierarchy: Root > Management Group > Subscription > Resource Group > Resource.
  • Permissions are inherited from top to bottom: an assignment at a Management Group automatically propagates to all subscriptions, Resource Groups, and resources within it.
  • Permissions from multiple roles and scopes are additive: the effective permission is the sum of all applicable permissions.
  • Inheritance cannot be blocked at child scopes via role assignments. Deny Assignments can block, but are not created directly by the administrator.

Critical differences:

  • Direct assignment at scope vs. inherited assignment: visually distinct in the portal ("Inherited" tab), but operationally equivalent for the user.
  • Listing assignments without --include-inherited vs. with --include-inherited: the first shows only direct assignments at that scope; the second shows the complete picture of effective access.
  • Adding Reader at child scope doesn't reduce the inherited Contributor permission from parent scope: permissions are additive, not substitutive.
  • Management Group scope vs. Subscription scope: MG affects all subscriptions within it (present and future); Subscription affects only that specific subscription.

What needs to be remembered:

  • The correct scope for most teams' operational access is the Resource Group, not the Subscription.
  • Assignments at Management Groups and Subscriptions should be for cross-cutting roles (auditing, security, monitoring), not for operational access of specific teams.
  • When diagnosing access problems, always use --include-inherited and --include-groups to see the complete picture.
  • Role assignment change propagation can take up to 30 minutes.
  • The limit of 4,000 role assignments per subscription applies to assignments directly in that subscription and scopes within it (RGs and resources). Assignments at Management Groups don't count toward this limit.
  • In Infrastructure as Code (Bicep, Terraform), the file's targetScope must correspond to the assignment scope: use targetScope = 'subscription' for subscription assignments, targetScope = 'managementGroup' for Management Groups.