Theoretical Foundation: Manage built-in Azure roles
1. Initial Intuitionβ
Imagine a corporate building with different areas: the server room, financial archive, HR office, and reception. Each employee has a badge that only grants access to the doors they need to do their job. The security guard has access to all doors. The accountant has access to the financial archive but not the server room. The intern only has access to reception.
In Azure, this badge system is RBAC (Role-Based Access Control), and the "badge templates" are roles. Instead of manually defining what each person can do, you assign a role that already defines a set of permissions. Built-in roles are pre-defined templates by Microsoft that cover the most common use cases.
Azure has over 300 built-in roles, but in practice, a small set covers the vast majority of situations. Understanding how these roles work, how they are hierarchically organized, and how they are assigned is fundamental to controlling who can do what in your resources.
2. Contextβ
Azure RBAC is the access control system for Azure resources (VMs, storage accounts, networks, databases, etc.). It's different from Entra ID roles we saw earlier: Entra ID roles control who can administer the identity directory; Azure RBAC controls who can act on infrastructure resources.
The two systems coexist and are complementary, but they are independent. Being a Global Administrator in Entra ID doesn't automatically grant access to VMs or Storage Accounts. And being an Owner of an Azure subscription doesn't make the user a Global Administrator of Entra ID.
Important exception: a Global Administrator can "elevate" their own access to User Access Administrator at the Azure root scope (Root Management Group), which gives them the ability to manage RBAC assignments throughout the entire hierarchy. This elevation should be temporary and audited.
3. Building the Conceptsβ
3.1 The Three Elements of a Role Assignmentβ
A role assignment in Azure is always the combination of three elements:
Security Principal (who): can be a user, group, service principal (application identity), or managed identity (Azure resource managed identity).
Role Definition (what): the role definition that specifies which actions are allowed and which are denied. It's a JSON with lists of Actions, NotActions, DataActions, and NotDataActions.
Scope (where): the resource or resource container to which the permission applies.
3.2 The Scope Hierarchyβ
Azure organizes resources in a four-level hierarchy. Permissions assigned at a higher level are inherited by lower levels:
Inheritance example: if you assign the Reader role to a user at the subscription scope, they can read all resources in all resource groups of that subscription. If you assign Contributor to a group at the scope of a specific Resource Group, all members of that group can create and manage resources in that Resource Group, but not in others.
This inheritance is always downward in the hierarchy, never upward.
3.3 The Structure of a Role Definitionβ
To understand built-in roles, you need to understand what composes a role definition:
| Field | Description | Example |
|---|---|---|
| Actions | Allowed management operations | Microsoft.Compute/virtualMachines/start/action |
| NotActions | Exceptions within Actions | Microsoft.Authorization/*/Delete |
| DataActions | Allowed data operations | Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read |
| NotDataActions | Exceptions within DataActions | none in common roles |
| AssignableScopes | Scopes where the role can be assigned | /subscriptions/{id}, / (global) |
The difference between Actions and DataActions is fundamental:
- Actions control management operations: creating a VM, modifying network settings, creating a storage account. They are the "control plane".
- DataActions control operations on data within resources: reading blobs from storage, writing messages to a queue, accessing Key Vault secrets. They are the "data plane".
A user can have permission to manage a storage account (Actions) but not to read the data stored in it (DataActions), and vice versa. This separation is an additional layer of security.
The effective permission is: (Actions - NotActions). NotActions is not an explicit denial; it's a subtraction from Actions. If role A has * in Actions and Microsoft.Authorization/*/Delete in NotActions, it means they can do everything except delete role assignments.
3.4 The Four Fundamental Rolesβ
Azure has over 300 built-in roles, but four are the foundation of the entire structure and are the most tested in AZ-104:
| Role | Actions | NotActions | Can manage access? | Creates resources? | Reads resources? |
|---|---|---|---|---|---|
| Owner | * (everything) | None | Yes | Yes | Yes |
| Contributor | * (everything) | Microsoft.Authorization/*/Write, Microsoft.Authorization/*/Delete | No | Yes | Yes |
| Reader | */read | None | No | No | Yes |
| User Access Administrator | Microsoft.Authorization/* | None | Yes | No | Minimum |
The critical distinction between Owner and Contributor: both can create and manage any type of Azure resource. The only difference is that Contributor cannot manage RBAC role assignments (cannot grant or revoke access to other users). The Owner can.
This is essential for the principle of least privilege: if someone needs to create and manage resources but doesn't need to administer who has access, Contributor is the correct role. Giving Owner would be excessive.
The User Access Administrator role is specific: it can only manage role assignments but cannot create or configure resources. It's useful when you want to delegate access management without giving permission to modify resources.
3.5 Service-Specific Rolesβ
In addition to the four fundamental roles, Azure has built-in roles specific to each service. Some important examples:
| Role | Service | What it allows |
|---|---|---|
| Virtual Machine Contributor | Compute | Manage VMs, but not the associated network or storage |
| Virtual Machine Administrator Login | Compute | Log in as administrator on VMs via Azure AD |
| Network Contributor | Networking | Manage networks, but not VMs or access |
| Storage Account Contributor | Storage | Manage storage accounts (not the data) |
| Storage Blob Data Reader | Storage | Read blob data (DataActions, not Actions) |
| Storage Blob Data Contributor | Storage | Read and write blob data |
| Key Vault Administrator | Key Vault | Manage the vault and its secrets/keys/certificates |
| Key Vault Secrets User | Key Vault | Only read secrets (DataActions) |
| SQL DB Contributor | SQL | Manage SQL databases, but not access or data |
| Monitoring Reader | Monitor | Read monitoring metrics and logs |
| Backup Contributor | Backup | Manage backups, but not delete vaults |
The existence of granular roles like Virtual Machine Contributor versus Contributor reflects the principle of least privilege in action: an operations team that only manages VMs doesn't need access to create storage accounts or configure networks.
4. Structural Viewβ
Permission Evaluation Flowβ
When a user attempts to perform an action on an Azure resource, the system follows this flow:
Deny Assignments are explicit denial assignments. They are rarer (created mainly by Azure Blueprints and Azure Managed Applications), but have absolute priority over any permission. If a deny assignment exists, not even the Owner can perform the action.
Inheritance in Action: Concrete Exampleβ
In this example:
- The Audit-Group can read resources throughout the entire hierarchy (Management Group inherits downward)
- The DevOps-Group can create and manage resources in the entire Production subscription, but not in the Dev subscription
- The Support-Group can read the App-Frontend RG and all resources within it
- joao@contoso.com can specifically manage the frontend-01 VM, but not other resources in the same RG
5. Practical Functioningβ
Role Assignment Lifecycleβ
Propagation: when a role assignment is created or removed, it can take up to 30 minutes for the change to fully propagate. In practical terms, this means a newly authorized user may take a few minutes to access the resource, and a user who had access revoked may still be able to access for a few minutes after revocation.
Check Effective Permissionsβ
Azure allows you to check what permissions a user effectively has on a resource, taking into account all assignments and inheritances:
In the portal: go to the resource > Access control (IAM) > Check access tab > select the user.
This shows all role assignments that affect that user in that scope, including those inherited from higher scopes.
6. Implementation Methodsβ
6.1 Azure Portalβ
When to use: one-off assignments, access verification, visualizing who has access to a resource.
Path: any resource, resource group, or subscription > Access control (IAM) > Add role assignment
The portal flow has three steps:
- Role: select the role from the list (filtering by name helps a lot)
- Members: select the security principal (user, group, managed identity)
- Conditions (optional): add ABAC (Attribute-Based Access Control) conditions for roles like Storage Blob Data Reader/Contributor
Advantages: visual, shows role description, allows checking permissions before confirming.
Limitations: doesn't scale for multiple assignments; doesn't allow automation.
6.2 Azure CLIβ
When to use: scripts, bash automation, CI/CD pipelines.
Check role assignments in a resource group:
az role assignment list \
--resource-group rg-producao \
--output table
Assign a role to a user in a resource group:
az role assignment create \
--assignee joao.silva@contoso.com \
--role "Contributor" \
--resource-group rg-producao
Assign role to a group in a subscription:
az role assignment create \
--assignee-object-id <object-id-do-grupo> \
--assignee-principal-type Group \
--role "Reader" \
--scope "/subscriptions/<subscription-id>"
Remove a role assignment:
az role assignment delete \
--assignee joao.silva@contoso.com \
--role "Contributor" \
--resource-group rg-producao
List all available roles (built-in and custom):
az role definition list --output table
Inspect the definition of a specific role:
az role definition list --name "Contributor" --output json
Advantages: scriptable, integrable with pipelines, clear syntax.
Limitations: less verbose than PowerShell for complex operations.
6.3 PowerShell (Az Module)β
When to use: complex scripts, Windows automation, detailed reports.
List role assignments in a scope:
Get-AzRoleAssignment -ResourceGroupName "rg-producao"
Assign role:
New-AzRoleAssignment `
-SignInName "joao.silva@contoso.com" `
-RoleDefinitionName "Contributor" `
-ResourceGroupName "rg-producao"
Assign role to a group by Object ID:
New-AzRoleAssignment `
-ObjectId "<object-id-do-grupo>" `
-RoleDefinitionName "Reader" `
-Scope "/subscriptions/<subscription-id>"
Remove assignment:
Remove-AzRoleAssignment `
-SignInName "joao.silva@contoso.com" `
-RoleDefinitionName "Contributor" `
-ResourceGroupName "rg-producao"
Check a user's effective permissions:
# Lists all assignments affecting a user in a subscription
Get-AzRoleAssignment -SignInName "joao.silva@contoso.com" `
-Scope "/subscriptions/<subscription-id>" `
-ExpandPrincipalGroups
The -ExpandPrincipalGroups parameter is important: it includes assignments inherited through groups the user is a member of, not just direct assignments.
6.4 Microsoft Graph and ARM APIβ
For advanced automation and integration with external systems, role assignments are Azure Resource Manager resources accessible via REST API:
PUT https://management.azure.com/{scope}/providers/Microsoft.Authorization/roleAssignments/{roleAssignmentId}?api-version=2022-04-01
Content-Type: application/json
{
"properties": {
"roleDefinitionId": "/subscriptions/{subId}/providers/Microsoft.Authorization/roleDefinitions/{roleDefId}",
"principalId": "{object-id-do-security-principal}",
"principalType": "Group"
}
}
The {roleAssignmentId} is a client-generated GUID (can be a random UUID). The roleDefinitionId can be obtained with az role definition list --name "Contributor".
6.5 Azure Policy and Blueprints for Assignment at Scaleβ
To ensure that certain roles are always assigned on new resources or subscriptions, Azure Policy (with deployIfNotExists effect) can create role assignments automatically. This is particularly useful for ensuring that every new subscription has a standard set of role assignments.
7. Control and Securityβ
Role Assignment Limitsβ
| Limit | Value |
|---|---|
| Role assignments per subscription | 4,000 |
| Custom roles per tenant | 5,000 |
| Role assignments per Management Group | 500 |
The limit of 4,000 role assignments per subscription is frequently reached in environments with many granular direct assignments to individual users. The solution is to use groups instead of direct assignments to users: a single role assignment to a group serves all group members, consuming only 1 of the 4,000 slots.
Deny Assignmentsβ
Deny assignments cannot be created directly by the administrator via portal or CLI. They are created automatically by:
- Azure Blueprints: when applying a blueprint with lock, creates deny assignments to protect managed resources
- Azure Managed Applications: protects resources managed by the application publisher
- Azure Lighthouse: in delegated management scenarios between tenants
To view deny assignments:
az role assignment list --include-deny-assignments --output table
Privileged Identity Management (PIM)β
In environments with Entra ID P2 license, Privileged Identity Management adds a control layer over role assignments:
- Eligible assignments: the user has the eligible role but needs to explicitly "activate" it when needed, with justification and for a limited time.
- Active assignments: the role is permanently active, like the default RBAC behavior.
With PIM, a developer can have the Contributor role as eligible in production, activating it only when needing to make an emergency change, with configured maximum duration (e.g., 8 hours) and automatic justification logging.
8. Decision Makingβ
Which role to assign in each situation?β
| Situation | Recommended Role | Reason |
|---|---|---|
| Admin who manages everything and needs to give access to others | Owner | Only role with RBAC control + resource management |
| DevOps team that creates and manages infrastructure | Contributor | Manages resources without being able to change who has access |
| Auditor or analyst who only needs to view | Reader | Read-only, no risk of alteration |
| Responsible for access management without creating resources | User Access Administrator | Manages RBAC without creating/modifying resources |
| Operations that only manages VMs | Virtual Machine Contributor | Reduced scope to what's necessary |
| Application that needs to read storage blobs | Storage Blob Data Reader | Specific DataActions, no control plane access |
| CI/CD pipeline that deploys apps | Contributor on specific RG | Scope limited to what's necessary for pipeline |
| Developer in sensitive production environment | Eligible Contributor via PIM | Just-in-time access with audit and time limit |
At which scope to assign?β
| Situation | Recommended Scope | Reason |
|---|---|---|
| Access to a specific resource (e.g., one VM) | Individual resource | Smallest access surface |
| Team that manages all resources of a project | Resource Group | Groups related resources without affecting other groups |
| Cross-cutting access to all resources in a subscription | Subscription | Necessary for roles like Monitoring Reader |
| Corporate policy that applies to all subscriptions | Management Group | Assignment automatically propagated |
9. Best Practicesβ
Assign roles to groups, never directly to individual users: an assignment to a group serves all members, uses only 1 slot of the 4,000 available, and greatly facilitates management: adding or removing someone from the group is sufficient, without needing to manage multiple role assignments.
Use the most restrictive scope possible: if the user only needs to manage VMs in a Resource Group, don't assign Contributor on the entire subscription. The most restrictive scope minimizes the impact of an error or credential compromise.
Prefer service-specific roles over the generic Contributor role: Virtual Machine Contributor instead of Contributor; Storage Blob Data Reader instead of Reader when the focus is data. This ensures access is exactly what's needed.
Use PIM for privileged roles: Owner and User Access Administrator especially should be eligible assignments via PIM, not permanent active assignments. Elevated access should be used only when necessary and for limited time.
Document the reason for each assignment: when creating a role assignment, use the description field (available via API and PowerShell) to record the reason. This greatly facilitates future reviews: "why does this group have Owner here?" shouldn't be an unanswered question.
Implement periodic access reviews: with Entra ID P2, Azure RBAC Access Reviews allow managers to periodically confirm if role assignments are still necessary. This combats privilege accumulation over time.
10. Common Mistakesβ
Assigning Owner when Contributor would be sufficient
This is the most frequent mistake. "To ensure they can do everything they need" is the typical justification. The result is that the person can also change who has access, potentially granting excessive privileges to others. Always evaluate if the user really needs to manage role assignments or just manage resources.
Confusing Entra ID roles with Azure RBAC roles
Global Administrator is not Owner. Owner is not Global Administrator. They are completely different systems. A developer who is Owner of the subscription doesn't have access to create users in Entra ID. A Global Administrator cannot create VMs unless they also have an RBAC role assignment.
Assigning role directly to user instead of group
Over time, this consumes the 4,000 role assignment slots per subscription and makes management unfeasible. Each new employee who needs access consumes more slots, and when someone leaves the company, it's necessary to remember to remove all direct assignments scattered across multiple scopes.
Not checking effective permissions before terminating access
An administrator removes a role assignment from a user, thinking they revoked access. But the user was a member of a group that had another assignment at the same scope. Access continues. Always use "Check access" in the portal or -ExpandPrincipalGroups in PowerShell to verify effective access, not just direct assignments.
Forgetting that NotActions is not explicit denial
If role A has * in Actions and Microsoft.Authorization/*/Delete in NotActions, this means the role doesn't include the ability to delete assignments, not that it's explicitly denied. If the user has another role that includes this action, they can do it. NotActions subtracts from the current role; it doesn't block other permission sources.
Reaching the 4,000 role assignment limit
Fast-growing organizations that assign roles directly to individual users reach this limit. When the limit is reached, new assignments fail with an error and access cannot be granted. The solution is a laborious migration to group-based assignments.
11. Operation and Maintenanceβ
Role Assignment Auditingβ
All role assignment creations and removals are logged in the Azure Activity Log:
Path: Monitor > Activity log > filter by Operation: Create role assignment or Delete role assignment
To query via PowerShell:
Get-AzLog -ResourceGroupName "rg-producao" `
-StartTime (Get-Date).AddDays(-30) |
Where-Object { $_.OperationName -like "*role*assignment*" } |
Select-Object EventTimestamp, Caller, OperationName, Status
Complete Access Inventoryβ
To get a report of all role assignments in a subscription:
Get-AzRoleAssignment -Scope "/subscriptions/<subscription-id>" |
Select-Object DisplayName, SignInName, RoleDefinitionName, Scope |
Export-Csv -Path "role-assignments-report.csv" -NoTypeInformation
Detect Orphaned Role Assignmentsβ
Role assignments for users that were deleted from Entra ID appear with an Object ID without an associated name. They consume slots and should be removed:
$assignments = Get-AzRoleAssignment -Scope "/subscriptions/<subscription-id>"
$orphaned = $assignments | Where-Object {
$_.DisplayName -eq $null -and $_.SignInName -eq $null
}
$orphaned | ForEach-Object {
Write-Output "Orphaned: $($_.ObjectId) - Role: $($_.RoleDefinitionName) - Scope: $($_.Scope)"
}
Check Role Assignment Slot Usageβ
$assignments = Get-AzRoleAssignment -Scope "/subscriptions/<subscription-id>"
Write-Output "Total role assignments: $($assignments.Count) / 4000"
12. Integration and Automationβ
Automatic Assignment in Infrastructure Pipelinesβ
In Infrastructure as Code projects with Terraform or Bicep, role assignments are resources managed as code:
Bicep:
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(resourceGroup().id, principalId, contributorRoleId)
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', contributorRoleId)
principalId: principalId
principalType: 'Group'
}
}
Managing role assignments as code ensures that the desired state is always reproducible and auditable via version control.
Azure Policy Integrationβ
Azure Policy can ensure that certain roles are always assigned on created resources:
- deployIfNotExists: when a Resource Group is created, automatically assigns a role to an audit group.
- modify: modifies existing assignments for compliance.
Managed Identities and Automatic Assignmentsβ
When a Managed Identity is created for an Azure resource (like a VM or Function App), it frequently needs role assignments to interact with other resources. For example, a VM that needs to read Key Vault secrets needs the Key Vault Secrets User role assigned to its Managed Identity.
This assignment can be automated in the deployment template:
# Create VM with system-assigned managed identity
az vm create --name minha-vm \
--resource-group rg-producao \
--assign-identity '[system]' \
...
# Get the object ID of the managed identity
IDENTITY_ID=$(az vm identity show --name minha-vm \
--resource-group rg-producao \
--query principalId -o tsv)
# Assign role to Key Vault
az role assignment create \
--assignee-object-id $IDENTITY_ID \
--assignee-principal-type ServicePrincipal \
--role "Key Vault Secrets User" \
--scope "/subscriptions/<sub-id>/resourceGroups/rg-producao/providers/Microsoft.KeyVault/vaults/meu-keyvault"
13. Final Summaryβ
Essential points:
- Azure RBAC controls access to resources (VMs, storage, networks). It's different from Entra ID roles, which control the identity directory.
- A role assignment is always the combination of: security principal (who) + role definition (what) + scope (where).
- Permissions are inherited from top to bottom in the hierarchy: Management Group > Subscription > Resource Group > Resource.
- Actions control management operations (control plane). DataActions control data operations (data plane).
- NotActions doesn't explicitly deny; it subtracts actions from the current role's set.
Critical differences:
- Owner vs. Contributor: both manage resources. Owner can also manage RBAC assignments; Contributor cannot.
- Actions vs. DataActions: a user can manage a storage account (Actions) without being able to read the data in it (DataActions), and vice versa.
- Deny Assignment vs. NotActions: Deny Assignment is explicit denial with maximum priority, created by Blueprints/Managed Apps, not by the administrator. NotActions only subtracts actions from a role.
- Entra ID roles vs. Azure RBAC roles: independent systems. Global Admin is not Owner. Owner is not Global Admin.
What needs to be remembered:
- Always assign roles to groups, never directly to individual users. This scales better and respects the 4,000 role assignment limit.
- Use the most restrictive scope possible for each assignment.
- The limit of 4,000 role assignments per subscription is real and can be reached in large environments with direct assignments to users.
- After creating or removing a role assignment, it can take up to 30 minutes to propagate.
- Role assignments for users deleted from Entra ID become orphaned in the system and consume slots. Remove them periodically.
- The User Access Administrator role allows managing RBAC without creating resources. It's different from Owner, which does both.
- In environments with Entra ID P2, use PIM to make privileged roles (Owner, User Access Administrator) eligible instead of permanently active.