- Overview
- Evaluation
- Considerations
- Attribute-based access control (ABAC)
- Azure RBAC roles vs. Azure AD roles
- CLI
RBAC allows you to grant access to Azure resources that you control. You do this by creating role assignments, which control how permissions are enforced. There are three elements in a role assignment:
-
Security principal (who)
-
Role definition (what)
Four fundamental built-in roles:
- Owner - full access, including the right to delegate access to others
- Contributor - create and manage, but can't delegate access to others
- Reader - view existing resources
- User Access Administrator - manage user access to resources, rather than to managing resources
Definition for
Contributor
:-
NotActions
are subtracted fromActions
-
dataActions
refer to actions on data within an object, built-in role "Storage Blob Data Reader" has permissions shown below, it can read blob containers and data, but not write or delete them:"permissions": [ { "actions": [ "Microsoft.Storage/storageAccounts/blobServices/containers/read", "Microsoft.Storage/storageAccounts/blobServices/generateUserDelegationKey/action" ], "dataActions": [ "Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read" ],
-
All the built-in roles have
"assignableScopes": [ "/" ]
-
Scope (where)
-
Role Assignment
# create a role assignment az role assignment create \ --role "Virtual Machine Administrator Login" \ --assignee $userPrincipalName \ --scope $vm # query role assignment within a scope az role assignment list \ --assignee $userPrincipalName \ --scope $vm
Deny assignments take priority !!
- Better to assign roles to groups rather than individual users to minimize role assignments
- Use custom roles to control permissions more precisely
- RBAC is an additive model
- Azure policies always apply, no matter who created/updated a resource
- Limits:
- Up to 2000 role assignments in each subscription, including role assignments at the subscription, resource group, and resource scopes
- up to 500 role assignments in each management group.
Custom roles can't be assigned at tenant or resource level
Scope level | Built-in role | Custom role |
---|---|---|
MG (including Root MG), Subscription, Resource group | Yes | Yes |
Resource | Yes | No |
Example:
{
"properties": {
"roleName": "My Custom Role",
"description": "My custom role for ...",
"assignableScopes": [
"/providers/Microsoft.Management/managementGroups/mg-Gary"
],
"permissions": [
{
"actions": [
"*/read",
// ...
],
"notActions": [],
"dataActions": [],
"notDataActions": []
}
]
}
}
- They are scopes where this custom role could be assigned to, not where it is stored. The definition is actually tenant-scoped, the role name must be unique within a tenant.
- You could specify the assignable scopes: either management group, subscription or resource group, CAN'T be a resource
- You can only have one management group in the assignable scope of a custom role, this is to reduce the situation of disconnected role definition and assignment
- Resource provider data plane action's can't be defined in management group custom roles
- The existence of the assignable scope is not validated when you create the role definition
- Custom role definition's full ID format is like
/providers/Microsoft.Authorization/roleDefinitions/<guid>|/providers/Microsoft.Management/managementGroups/<name>
(when defined at a management group level)
Conditions can be added to built-in or custom role assignments that have blob storage or queue storage data actions. Such as assignment of "Storage Blob Data Contributor".
There are several types of attributes you could use:
@Resource
- Resource attributes: Storage Account name, Blob Container name, tags
@Principal
- Custom security attributes assigned to users or service principals
@Request
- Access request attribute, eg. prefix of blobs to be listed
@Environment
:isPrivateLink
Microsoft.Network/privateEndpoints
, restrict access over a specific PEPMicrosoft.Network/virtualNetworks/subnets
UtcNow
See full list here
- Read access to blobs
- with the tag
Project=Apollo
- and a path of
logs/2024
- with the tag
- Read access to blobs
- with the tag
Project=Apollo
- and the user has a matching attribute
Project=Apollo
- with the tag
- Read access to blobs during a specific date/time range
- Write access to blobs only over a private link or from a specific subnet
- New blobs must include the tag
Project=Apollo
- Read, write, or delete blobs in containers named
blobs-example-container
Example code:
(
(
!(ActionMatches{'Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read'} AND NOT SubOperationMatches{'Blob.List'})
)
OR
(
@Resource[Microsoft.Storage/storageAccounts/blobServices/containers/blobs/tags:Project<$key_case_sensitive$>] ForAnyOfAnyValues:StringEquals @Principal[Microsoft.Directory/CustomSecurityAttributes/Id:Engineering_Project]
)
)
Operation allowed when:
- Not a blob read operation
- Or suboperation is
Blob.List
- Or blob's
Project
key value matches any values in the user's custom security attributeEngineering_Project
Some builtin roles have condition in role definition. eg.
- Key Vault Data Access Administrator
- Virtual Machine Data Access Administrator (preview)
Seems can't do this in a custom role definition yet
"Key Vault Data Access Administrator" role allows role assignment, but only for the specified roles, not any role.
Example definition:
{
"id": "...",
"properties": {
"permissions": [
{
"..."
"condition": "
(
(
!(ActionMatches{'Microsoft.Authorization/roleAssignments/write'})
)
OR
(
@Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId]
ForAnyOfAnyValues:GuidEquals{
00482a5a-887f-4fb3-b363-3b7fe8e74483,
a4417e6f-fecd-4de8-b567-7b0420556985,
...
}
)
)
AND
(
(
!(ActionMatches{'Microsoft.Authorization/roleAssignments/delete'})
)
OR
(
@Resource[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals{
00482a5a-887f-4fb3-b363-3b7fe8e74483,
a4417e6f-fecd-4de8-b567-7b0420556985,
...
}
)
)
"
}
]
}
}
The above condition is in role definition, when you assign this role, you can add more conditions in the role assignment object
Add principal type condition in role assignment
Restrict roles and principal IDs
When you assign privileged administrator roles (roleAssignments/write
), you can add conditions to the assignment.
Apply to these roles:
- Owner
- User Access Administrator
- Role Based Access Control Administrator:
- Similar to UAA, can assign roles
- Can't define roles, add locks, polices, diagnostic settings
- Custom roles with permissions for role assignments (
roleAssignments/write
)
Available conditions:
- Constraint roles
- Constraint principal types
- Constraint principal IDs
- Allow all except specific roles
- By default, it excludes these built-in roles: "Owner", "User Access Administrator", "Role Based Access Control Administrator"
- You should add any built-in or custom role with admin permission
roleAssignments/write
, otherwise the user could use this role to elevate his permission
See code examples here: Examples to delegate Azure role assignment management with conditions - Azure ABAC | Microsoft Learn
Three different types of roles in Azure:
-
Azure AD roles
-
RBAC roles
The new Authorization system, find them in the "Access Control (IAM)" menu under management groups, subscriptions, resource groups or resources
-
Classic subscription administrator roles (Legacy)
The three administrator roles when Azure was initially released: Account Administrator, Service Administrator and Co-Administrator
Azure RBAC roles | Azure AD roles | |
---|---|---|
For | Azure resources | Azure Active Directory |
Scope | management group, subscription, resource group, resource | tenant level |
How to get role information | Azure portal, Azure CLI (az role definition list ), Azure PowerShell, Azure Resource Manager templates, REST API |
Azure admin portal, Microsoft 365 admin center, Microsoft Graph, AzureAD PowerShell |
- Azure AD roles and Azure RBAC roles are independent from one another, AD role assignment does not grant access to Azure resources and vice versa
- As an Azure AD Global Administrator, you might not have access to all subscriptions and management groups, but you could elevate your access:
- This will give yourself the "User Access Administrator" role in Azure at root scope(
/
, this seems to be a level higher than root MG, but effectively equal to it) - View and assign access in any management group or subscription (e.g. assign yourself the Owner role of the root MG)
- You should remove this elevated access once you have made the changes needed
- This will give yourself the "User Access Administrator" role in Azure at root scope(
- Each directory is given a single top-level management group called Tenant Root Group
- has the same id as the tenant
- allows for global policies and role assignments
To enable the elevated access:
-
In Azure Portal ("AAD" -> "Properties" -> "Access management for Azure resources")
-
CLI
az rest --method post --url "/providers/Microsoft.Authorization/elevateAccess?api-version=2016-07-01" # you need to login again to see the new role assignment az logout az login az role assignment list --role "User Access Administrator" --scope "/" # remove the elevated access az role assignment delete --role "User Access Administrator" --scope "/"
-
List role assignments in a scope
# on a subscription # `--all` only works with `--subscription` # to include assignments above (management groups) and below (RG, resource) az role assignment list \ --assignee <SP name or object id> \ --subscription sub-test \ --all \ -otable # on a management group # does NOT include assignments on descendant scopes # with `--include-inherited`, show inherited assignments if no assignment at current scope az role assignment list \ --assignee '<sp-object-id>' \ --scope "/providers/Microsoft.Management/managementGroups/mg-test" \ --include-groups \ --include-inherited \ -otable
Much easier to use Resource Graph to query assignments for a principal at all scopes all at once:
// *********** CAUTION *********** // Set authorization scope to "At, above and below" authorizationresources | where type == "microsoft.authorization/roleassignments" | where properties.principalId in ( "<prinicpal-obj-id-1>", "<prinicpal-obj-id-2>" ) | project resourceGroup, subscriptionId, roleId = tostring(properties.roleDefinitionId), principalId = tostring(properties.principalId), scope = tostring(properties.scope) | extend principalName = case( principalId == "<prinicpal-obj-id-1>", "<principal-name-1>", principalId == "<prinicpal-obj-id-2>", "<principal-name-2>" "Unknown") | extend scopeLevel = case( scope startswith "/providers", "MG", array_length(split(scope, "/")) == 3, "Subscription", array_length(split(scope, "/")) == 5, "Resource Group", array_length(split(scope, "/")) == 9, "Resource", "to-do" ) | join kind = leftouter ( // get MG, subscription name resourcecontainers | where type in ("microsoft.management/managementgroups", "microsoft.resources/subscriptions") | project id, mgName = tostring(properties.displayName), subName = name ) on $left.scope == $right.id | join kind = leftouter ( // get role name authorizationresources | where type == "microsoft.authorization/roledefinitions" | project id, roleName = tostring(properties.roleName), type = tostring(properties.type) ) on $left.roleId == $right.id | extend scopeName = case( scopeLevel == "MG", mgName, scopeLevel == "Subscription", subName, scopeLevel == "Resource Group", resourceGroup, scopeLevel == "Resource", split(scope, "/")[8], "todo" ) | project principalName, type, roleName, scopeLevel, scopeName | order by principalName asc, scopeLevel asc