AZ-104Chapter 52 of 168Objective 1.1

Custom RBAC Role Definitions

This chapter covers custom Azure RBAC role definitions, a critical skill for implementing least-privilege access in Azure. You will learn how to create, configure, and manage custom roles using the Azure portal, PowerShell, and Azure CLI. This topic is tested in the Identity Governance domain (objective 1.1) and appears in approximately 15-20% of AZ-104 exam questions, often in scenario-based items requiring you to design a custom role to meet specific access requirements.

25 min read
Intermediate
Updated May 31, 2026

Custom RBAC: Tailoring Access Like a Building Pass System

Imagine a large corporate building with multiple floors, each containing different departments. The standard building pass grants access to the lobby and the cafeteria. However, the IT department needs access to the server room on floor 3, HR needs access to the records room on floor 2, and executives need access to the boardroom on floor 5. The building manager cannot issue a single pass that fits all; instead, they create custom passes. Each custom pass is a set of permissions (e.g., 'open door to server room', 'open door to records room') grouped together. The manager defines a new pass type by listing exactly which doors can be opened. Each pass is then assigned to specific employees. The security system checks the pass whenever someone tries to enter a door: if the pass includes that door, access is allowed; otherwise, it is denied. This is exactly how custom RBAC roles work in Azure. Built-in roles are like standard passes—they grant broad access to many resources. Custom roles let you define precise permissions (actions) like 'read virtual machines' or 'start virtual machines' and assign them to users or groups. Azure's authorization engine evaluates each request against the custom role's permissions, just like the security system checks the pass.

How It Actually Works

What is a Custom RBAC Role?

Azure Role-Based Access Control (RBAC) uses role definitions to determine what actions a security principal (user, group, or service principal) can perform on a resource. Azure provides over 70 built-in roles like Owner, Contributor, and Reader. However, these roles often grant more permissions than necessary. Custom RBAC roles allow you to define a precise set of permissions tailored to your organization's needs. A custom role is defined by a JSON document that specifies: - Name: A user-friendly name for the role. - Description: A brief explanation of the role's purpose. - Actions: A list of allowed control plane operations (e.g., Microsoft.Compute/virtualMachines/start/action). - NotActions: A list of operations explicitly excluded from the allowed actions. - DataActions: A list of allowed data plane operations (e.g., reading blob data). - NotDataActions: A list of data operations explicitly excluded. - AssignableScopes: The scopes (management groups, subscriptions, or resource groups) where the role can be assigned.

Why Custom Roles Exist

The primary reason for custom roles is the principle of least privilege. Built-in roles are often too broad. For example, the Contributor role allows full management of all resources but cannot grant access to the Azure RBAC permissions themselves. If you need a role that can only start and stop virtual machines but not delete them, you must create a custom role. Custom roles also allow you to combine permissions from multiple built-in roles or restrict specific actions.

How Custom Roles Work Internally

When a user attempts an operation (e.g., creating a virtual machine), Azure’s authorization engine checks all role assignments that include the user (directly or via group membership). For each assigned role, the engine evaluates the role definition's actions and notActions. The engine computes the effective permissions as:

Effective Actions = (All Actions) - (All NotActions)

Similarly for DataActions and NotDataActions. If the requested operation matches any effective action, access is granted; otherwise, it is denied. Note that NotActions are subtracted from Actions, so they can only restrict permissions, not grant them.

Key Components and Values

Actions: Use the format {ResourceProvider}/{ResourceType}/{Operation}. For example, Microsoft.Compute/virtualMachines/start/action. Wildcards are supported: Microsoft.Compute/*/read allows read operations for all Compute resources.

NotActions: Same format as Actions. Used to exclude specific operations from a wildcard. For example, if Actions includes Microsoft.Compute/* and NotActions includes Microsoft.Compute/virtualMachines/delete, the role allows all Compute operations except deleting VMs.

DataActions: For data plane operations, e.g., Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read. These are separate from control plane actions.

AssignableScopes: Must be specified as one or more scope strings: /subscriptions/{subscription-id} or /subscriptions/{subscription-id}/resourceGroups/{resource-group-name} or /providers/Microsoft.Management/managementGroups/{management-group-id}. The role can only be assigned at or below the specified scopes.

Creating a Custom Role – Step-by-Step

#### Using Azure Portal 1. Navigate to Azure Active Directory > Roles and administrators (for Azure AD roles) or Subscriptions > Access control (IAM) > Roles (for Azure RBAC roles). Note: Custom Azure RBAC roles are managed at the subscription or management group scope. 2. Click "Add" > "Add custom role". 3. Provide a name and description. 4. Under "Permissions", click "Add permissions" and select the desired actions. You can also add exclusions via NotActions. 5. Under "Assignable scopes", specify the management group, subscription, or resource group where the role can be assigned. 6. Review and create.

#### Using Azure PowerShell

$roleDefinition = @{
    Name = "Virtual Machine Operator"
    Description = "Can start and stop VMs but not delete"
    Actions = @(
        "Microsoft.Compute/virtualMachines/start/action",
        "Microsoft.Compute/virtualMachines/restart/action",
        "Microsoft.Compute/virtualMachines/deallocate/action",
        "Microsoft.Compute/virtualMachines/read"
    )
    NotActions = @()
    AssignableScopes = @("/subscriptions/00000000-0000-0000-0000-000000000000")
}
New-AzRoleDefinition @roleDefinition

#### Using Azure CLI

az role definition create --role-definition '{
  "Name": "Virtual Machine Operator",
  "Description": "Can start and stop VMs but not delete",
  "Actions": [
    "Microsoft.Compute/virtualMachines/start/action",
    "Microsoft.Compute/virtualMachines/restart/action",
    "Microsoft.Compute/virtualMachines/deallocate/action",
    "Microsoft.Compute/virtualMachines/read"
  ],
  "NotActions": [],
  "AssignableScopes": ["/subscriptions/00000000-0000-0000-0000-000000000000"]
}'

Verification Commands

List all custom roles: Get-AzRoleDefinition | Where-Object {$_.IsCustom -eq $true} (PowerShell) or az role definition list --custom-role-only true (CLI).

View a specific role: Get-AzRoleDefinition -Name "Virtual Machine Operator" or az role definition list --name "Virtual Machine Operator".

Test effective permissions: Use Get-AzRoleAssignment to see assignments, but for effective permissions, use Get-AzRoleAssignment -SignInName user@domain.com -ExpandPrincipalGroups and then compute manually.

Interaction with Related Technologies

Azure Policy: Custom RBAC roles control who can perform actions, while Azure Policy controls what resources can be created or modified. They work together: even if a user has permission to create a VM (via RBAC), Azure Policy can block the creation if it violates a policy.

Azure AD Roles: Azure AD roles (e.g., Global Administrator) manage access to Azure AD itself, not Azure resources. Custom RBAC roles are for Azure resource access.

Managed Identities: Custom roles can be assigned to managed identities, allowing them to access resources like Key Vault or storage accounts.

Important Limits and Defaults

Maximum number of custom roles per directory: 5000 (Azure AD Free) or 5000 (Azure AD Premium P1/P2).

Maximum number of actions per role: 4096 characters for the Actions array (combined length).

Maximum number of assignable scopes per role: 2000.

AssignableScopes must include the scope where the role is created; you cannot create a role that is assignable only to a child scope without including the parent.

Common Pitfalls

Forgetting to add */read or specific read actions: Without read permissions, the user cannot see resources in the portal or via CLI.

Using NotActions incorrectly: NotActions only subtract from Actions; they cannot grant permissions. For example, if Actions is empty, NotActions does nothing.

AssignableScopes too restrictive: If you create a role at subscription scope but only assign it at resource group scope, the role definition must include that resource group in its AssignableScopes.

DataActions vs Actions: Confusing control plane (Actions) with data plane (DataActions). For example, reading a blob requires Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read in DataActions, not Actions.

Walk-Through

1

Define Role Requirements

Identify the specific permissions needed. For example, a role for backup operators might need to read VMs and trigger backups but not delete resources. Document the required actions, notActions, and dataActions. Determine the assignable scopes: typically the subscription or a management group covering all relevant resources.

2

Create Role Definition JSON

Write a JSON document that defines the role. Include the Name, Description, Actions, NotActions, DataActions (if needed), NotDataActions, and AssignableScopes. Use the Azure resource provider operations list (e.g., from Microsoft docs) to find exact action strings. Validate the JSON syntax.

3

Create Role via Portal, PowerShell, or CLI

Use the Azure portal (Access control > Roles > Add custom role), PowerShell (New-AzRoleDefinition), or Azure CLI (az role definition create). The role is created at the scope specified in AssignableScopes. After creation, the role appears in the list of roles for that scope.

4

Assign the Custom Role

Assign the role to a user, group, or service principal at the desired scope (management group, subscription, resource group, or resource). Use the portal (Access control > Add role assignment), PowerShell (New-AzRoleAssignment), or CLI (az role assignment create). The assignment grants the permissions defined in the role.

5

Test and Verify Permissions

Sign in as the assigned user and attempt the allowed and disallowed operations. Use the Azure portal, CLI, or PowerShell to verify. For example, try to start a VM (should succeed) and delete a VM (should fail). Check effective permissions using the 'Check access' tab in the portal or Get-AzRoleAssignment with the -ExpandPrincipalGroups parameter.

What This Looks Like on the Job

Enterprise Scenario 1: Database Administrator Role

A large enterprise has a dedicated team of database administrators (DBAs) who need to manage Azure SQL databases but should not have access to other resources like virtual machines or storage accounts. The built-in Contributor role gives too much access. The solution is to create a custom role named 'SQL DB Administrator' that includes actions such as Microsoft.Sql/servers/databases/read, Microsoft.Sql/servers/databases/write, Microsoft.Sql/servers/databases/delete, and Microsoft.Sql/servers/databases/backupLongTermRetentionPolicies/action. The role is assigned at the subscription scope, but only to the DBAs group. This ensures DBAs can fully manage SQL databases but cannot touch compute or network resources. In production, the role definition is stored in a Git repository for version control. A common issue is forgetting to include read permissions for the server itself (Microsoft.Sql/servers/read), which prevents DBAs from seeing the server in the portal.

Enterprise Scenario 2: Application-Specific Service Principal

A microservices application running on Azure Kubernetes Service (AKS) needs to access an Azure Key Vault to retrieve secrets. The application uses a managed identity. Instead of assigning the built-in Key Vault Contributor role (which allows full management of the vault), a custom role is created with only Microsoft.KeyVault/vaults/secrets/getSecret/action in DataActions. The assignable scope is the specific Key Vault resource group. This follows least privilege. In production, the role is assigned to the managed identity using Azure CLI. A common misconfiguration is using Actions instead of DataActions for secret retrieval, which does not work because secret access is a data plane operation.

Enterprise Scenario 3: Read-Only Auditors

External auditors need read-only access to all resources in a subscription but must not see certain cost data or security policies. The built-in Reader role includes read access to everything. To exclude specific areas, a custom role is created with Actions = */read and NotActions = Microsoft.CostManagement/*/read and Microsoft.Security/*/read. This gives broad read access but hides cost and security information. The role is assigned at the subscription scope. A common pitfall is that NotActions only subtract from Actions; if the built-in Reader has additional permissions like Microsoft.Authorization/*/read, those are not included unless explicitly added. So the custom role must include all desired read actions explicitly or use wildcards carefully.

How AZ-104 Actually Tests This

What AZ-104 Tests on Custom RBAC Roles

AZ-104 exam objective 1.1 includes 'Create custom RBAC roles' and 'Assign RBAC roles'. You must be able to:

Identify when a custom role is needed (scenarios where built-in roles are too permissive or not granular enough).

Create a custom role using Azure portal, PowerShell, or Azure CLI.

Understand the JSON structure: Actions, NotActions, DataActions, NotDataActions, AssignableScopes.

Know the difference between Actions and DataActions.

Understand that NotActions only subtract from Actions, not grant permissions.

Know that custom roles can be assigned only at or below the scope specified in AssignableScopes.

Know the maximum number of custom roles per directory (5000) and assignable scopes per role (2000).

Common Wrong Answers and Why Candidates Choose Them

1.

Choosing 'Contributor' when a more restrictive role is needed: Candidates often assume Contributor is the minimum for management tasks, but it includes delete permissions. The correct answer is a custom role with specific actions.

2.

Selecting 'Reader' for read-only access but needing to exclude certain areas: Reader grants read to everything. To exclude specific resource types, a custom role with NotActions is required.

3.

Using DataActions for control plane operations: For example, using Microsoft.Storage/storageAccounts/read in DataActions instead of Actions. DataActions are for data plane, not control plane.

4.

Assuming NotActions can grant permissions: A role with only NotActions grants nothing. NotActions must accompany Actions.

5.

Forgetting to include read permissions: A custom role that only includes write actions (e.g., Microsoft.Compute/virtualMachines/write) but not read (Microsoft.Compute/virtualMachines/read) will prevent the user from seeing VMs in the portal, even though they can modify them.

Specific Numbers and Terms That Appear on the Exam

5000: Maximum custom roles per Azure AD tenant.

2000: Maximum assignable scopes per custom role.

4096 characters: Maximum length of the Actions array combined.

AssignableScopes: Must be specified; cannot be empty.

NotActions: Only subtract; they do not grant.

DataActions: Required for data plane access (e.g., reading blobs, writing queues).

Edge Cases and Exceptions

Role creation at management group scope: Custom roles can be created at management group scope, but the AssignableScopes must include that management group. The role can then be assigned to any child subscription or resource group.

Wildcard usage: Microsoft.Compute/* includes all operations for Compute. To exclude a specific operation, use NotActions. But wildcards cannot be used in AssignableScopes.

Duplicate role names: Role names must be unique within the tenant.

Updating a custom role: Use Set-AzRoleDefinition (PowerShell) or az role definition update (CLI). Changes propagate immediately to all assignments.

How to Eliminate Wrong Answers

If a scenario requires granular permissions, eliminate any answer that uses a built-in role unless it exactly matches.

If the scenario mentions data plane access (e.g., reading a blob), look for DataActions in the role definition.

If the scenario says 'exclude' or 'except', the role must have NotActions.

If the role needs to be assigned at multiple scopes, ensure AssignableScopes includes all those scopes (or a parent scope).

Key Takeaways

Custom RBAC roles are defined by a JSON document with Actions, NotActions, DataActions, NotDataActions, and AssignableScopes.

NotActions only subtract from Actions; they never grant permissions.

DataActions are required for data plane access (e.g., reading blobs).

AssignableScopes determines where the role can be assigned; must include at least one scope.

Maximum 5000 custom roles per Azure AD tenant.

Maximum 2000 assignable scopes per custom role.

Use PowerShell (New-AzRoleDefinition) or Azure CLI (az role definition create) to create custom roles.

Always include read permissions (e.g., */read) if users need to see resources in the portal.

Custom roles can be updated with Set-AzRoleDefinition or az role definition update; changes apply immediately.

Common exam scenario: create a role that can start/stop VMs but not delete them.

Easy to Mix Up

These come up on the exam all the time. Here's how to tell them apart.

Built-in Roles

Provided by Microsoft; cannot be modified.

Cover common scenarios (Owner, Contributor, Reader, etc.).

No need to define permissions; ready to use.

May grant more permissions than needed.

Can be assigned at any scope.

Custom Roles

Created by administrators; fully customizable.

Tailored to specific job functions.

Require defining Actions, NotActions, DataActions.

Follow least privilege precisely.

Assignable only within specified scopes.

Watch Out for These

Mistake

Custom roles can be assigned to any scope regardless of AssignableScopes.

Correct

Custom roles can only be assigned at scopes that are within the AssignableScopes list. For example, if AssignableScopes is set to a specific subscription, you cannot assign the role to a resource group in a different subscription.

Mistake

NotActions can be used to grant permissions.

Correct

NotActions only subtract from the Actions list. They never grant permissions. A role with only NotActions and no Actions grants nothing.

Mistake

DataActions are the same as Actions for storage accounts.

Correct

Actions control management plane operations (e.g., creating a storage account), while DataActions control data plane operations (e.g., reading a blob). They are separate and must be specified correctly.

Mistake

Custom roles can be created at the resource level.

Correct

Custom roles are defined at the tenant level but have an AssignableScopes property that limits where they can be assigned. You cannot create a role that is only assignable to a single resource; you must specify at least a resource group or higher.

Mistake

You can assign a custom role without specifying AssignableScopes.

Correct

AssignableScopes is mandatory. If you omit it, the role creation fails. You must specify at least one scope.

Do You Actually Know This?

Reveal each answer, then mark whether you got it right. Score 60%+ to unlock the next chapter.

Frequently Asked Questions

How do I create a custom RBAC role in Azure?

You can create a custom RBAC role using the Azure portal, Azure PowerShell, or Azure CLI. In the portal, go to Subscriptions > Access control (IAM) > Roles > Add custom role. For PowerShell, use the New-AzRoleDefinition cmdlet with a JSON definition. For CLI, use 'az role definition create' with a JSON file. The role definition must include Name, Description, Actions, NotActions (if any), and AssignableScopes.

What is the difference between Actions and DataActions in a custom RBAC role?

Actions specify control plane operations, such as creating or deleting resources (e.g., Microsoft.Compute/virtualMachines/write). DataActions specify data plane operations, such as reading data within a resource (e.g., Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read). Most built-in roles do not include DataActions; you must add them explicitly in custom roles for data access.

Can I use wildcards in custom RBAC role definitions?

Yes, wildcards are allowed in Actions and NotActions. For example, 'Microsoft.Compute/*/read' grants read access to all Compute resource types. However, wildcards cannot be used in AssignableScopes. Also, be cautious with wildcards as they may grant unintended permissions.

How do I update an existing custom RBAC role?

You can update a custom role using PowerShell (Set-AzRoleDefinition) or Azure CLI (az role definition update). You must provide the updated JSON definition. Changes take effect immediately for all assignments. You cannot update built-in roles.

What happens if I delete a custom RBAC role that is currently assigned?

If you delete a custom role, all role assignments using that role become invalid. Users will lose the permissions granted by that role. You should first remove all assignments or replace them with another role before deleting.

Can I create a custom role that is assignable only to a specific resource?

No, custom roles must have AssignableScopes that are at least a resource group or higher. You cannot specify a single resource as an assignable scope. However, you can assign the role at the resource group scope and then apply it to individual resources within that group.

How many custom roles can I have in Azure?

You can have up to 5000 custom roles per Azure AD tenant (directory). This is a hard limit. If you need more, consider consolidating roles or using groups.

Terms Worth Knowing

Ready to put this to the test?

You've just covered Custom RBAC Role Definitions — now see how well it sticks with free AZ-104 practice questions. Full explanations included, no account needed.

Done with this chapter?