AZ-204Chapter 25 of 102Objective 3.1

Custom RBAC Roles in Azure

This chapter covers custom RBAC roles in Azure, a critical skill for AZ-204 developers who need to implement fine-grained access control beyond built-in roles. Custom roles allow you to define precise permissions tailored to your application's security requirements. Approximately 10-15% of exam questions touch on RBAC, with custom roles being a key subtopic. Mastering this chapter will help you design secure, least-privilege access models for Azure resources.

25 min read
Intermediate
Updated May 31, 2026

Custom RBAC Roles: Tailored Access Permissions

Imagine a large corporate building with multiple floors and rooms. The built-in roles are like standard key cards: a 'Visitor' card only opens the lobby, an 'Employee' card opens most office doors but not the server room, and an 'Admin' card opens every door. However, a project team needs access to a specific lab on floor 3 from 9 AM to 5 PM, plus read-only access to the document archive on floor 2. No standard card matches exactly. The security office creates a custom key card: it encodes exactly those permissions—floor 3 lab entry during business hours, floor 2 archive read-only. The card is issued only to team members. When a team member swipes at the floor 3 lab door at 10 AM, the lock checks the card's encoded permissions and grants access. At 6 PM, the same card is denied because the time condition fails. This custom card is analogous to a custom RBAC role: you define specific actions (like 'read' or 'write') on specific resources (like VMs or storage accounts) and assign it to users or groups. The Azure RBAC system evaluates each request against the custom role's permissions, just like the lock checks the card's encoded rules.

How It Actually Works

What Are Custom RBAC Roles?

Azure Role-Based Access Control (RBAC) uses roles to define sets of permissions that can be assigned to security principals (users, groups, service principals, managed identities). Built-in roles like Contributor, Reader, and Owner cover common scenarios, but many applications require specific permissions that don't match any built-in role. For example, you might want to grant a service principal permission to restart VMs but not delete them, or allow read access to a storage account but only to a specific container. Custom RBAC roles fill this gap by letting you define your own role with exactly the actions you need.

Anatomy of a Custom Role

A custom role is defined in JSON using the Azure Resource Manager (ARM) schema. The JSON structure includes: - Name: A unique role name within the directory. - Description: A human-readable description of the role's purpose. - Actions: A list of allowed actions (e.g., Microsoft.Compute/virtualMachines/start/action). - NotActions: A list of actions that are excluded from the allowed actions (subtractive permissions). - DataActions: Permissions for data plane operations (e.g., reading blob data). - NotDataActions: Excluded data plane actions. - AssignableScopes: The scopes (management group, subscription, resource group) where the role can be assigned.

How Permissions Are Evaluated

Azure RBAC uses an allow + deny model. When a principal attempts an operation, the system evaluates all role assignments at the effective scope. The evaluation logic is: 1. Deny assignments (if any) are evaluated first. If a deny matches, access is blocked. 2. All role assignments (built-in and custom) are aggregated. The effective permissions are the union of all Actions minus the union of all NotActions. 3. If the requested action matches an allowed action and is not excluded by a NotAction, access is granted.

Importantly, NotActions are subtractive, not additive. For example, if a role includes Microsoft.Compute/virtualMachines/* and NotActions includes Microsoft.Compute/virtualMachines/delete, the principal can perform all VM operations except delete. This is useful for creating roles that are almost like a built-in role but with specific exclusions.

Creating a Custom Role

You can create custom roles using the Azure portal, Azure CLI, Azure PowerShell, or ARM templates. The most common method for developers is the Azure CLI.

Using Azure CLI: 1. Create a JSON file, e.g., CustomRole.json:

{
  "Name": "VM Restart Operator",
  "Description": "Can restart VMs but not delete or create them",
  "Actions": [
    "Microsoft.Compute/virtualMachines/restart/action",
    "Microsoft.Compute/virtualMachines/read"
  ],
  "NotActions": [],
  "AssignableScopes": [
    "/subscriptions/12345678-1234-1234-1234-123456789abc"
  ]
}
2.

Run:

az role definition create --role-definition @CustomRole.json

Using Azure PowerShell:

$roleDefinition = @{
    Name = "VM Restart Operator"
    Description = "Can restart VMs but not delete or create them"
    Actions = @(
        "Microsoft.Compute/virtualMachines/restart/action",
        "Microsoft.Compute/virtualMachines/read"
    )
    AssignableScopes = @("/subscriptions/12345678-1234-1234-1234-123456789abc")
}
New-AzRoleDefinition @roleDefinition

Data Actions vs. Actions

A critical distinction in custom roles is between Actions (control plane) and DataActions (data plane). Control plane operations manage the resource itself (e.g., creating a storage account), while data plane operations access the data within (e.g., reading blobs). Built-in roles like Reader include read access to the control plane but not to data. For example, a Reader can see a storage account's properties but cannot read the blobs inside. To grant data plane access, you must use a role that includes DataActions, such as Storage Blob Data Reader. Custom roles can include both Actions and DataActions.

Important: When creating a custom role that includes data actions, you must explicitly specify DataActions and NotDataActions. The * wildcard in Actions does NOT cover data actions. For example, Microsoft.Storage/storageAccounts/* does not include Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read. You must list data actions separately.

Assignable Scopes

Custom roles must specify at least one assignable scope. This scope determines where the role can be assigned. Common scopes:

Management group: /providers/Microsoft.Management/managementGroups/{groupId}

Subscription: /subscriptions/{subscriptionId}

Resource group: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}

You cannot assign a custom role at a scope smaller than its assignable scopes. For example, if a custom role's assignable scope is a subscription, you can assign it at that subscription, any resource group within it, or any resource. But you cannot assign it at a management group above the subscription.

Wildcards and Permission Inheritance

Wildcards (*) are powerful but must be used carefully. Microsoft.Compute/* grants all compute actions. However, the evaluation engine expands wildcards at runtime. There is no performance penalty for using wildcards, but it can lead to overly permissive roles if not paired with NotActions.

Permissions are inherited through the scope hierarchy. If you assign a role at a subscription, the permissions apply to all resource groups and resources within that subscription. Assigning at a resource group applies only to that group and its resources. Assigning at a resource applies only to that specific resource.

Updating and Deleting Custom Roles

To update a custom role, you can use az role definition update with a JSON file containing the updated definition. The role's name and assignable scopes cannot be changed after creation. To delete a custom role, use az role definition delete --name "RoleName". You must first remove all assignments of that role.

Interactions with Other Azure Services

Custom roles integrate with: - Azure Policy: Policies enforce compliance, while RBAC grants access. They work together: a policy can deny creation of a resource even if RBAC allows it. - Azure AD Privileged Identity Management (PIM): PIM can provide just-in-time access to custom roles, reducing standing privileges. - Managed Identities: You can assign custom roles to managed identities to grant them specific permissions for accessing resources.

Best Practices

Use least privilege: Start with minimal actions and add more as needed.

Prefer built-in roles over custom roles when they meet your needs, as they are maintained by Microsoft.

Use NotActions sparingly; they can make permissions harder to audit.

Always test custom roles in a non-production environment.

Document the purpose of each custom role in its description.

Limitations

A single Azure subscription can have up to 5,000 custom roles.

Custom roles cannot be used across tenants unless the tenant is specified in assignable scopes (via cross-tenant role assignment, which is limited).

The role JSON size limit is 1 MB.

Custom roles cannot include permissions for Azure AD directory objects (e.g., users, groups). Those require Azure AD roles.

Walk-Through

1

Identify Required Permissions

Begin by listing the exact operations your principal needs to perform. For each Azure resource type, identify the specific actions (e.g., `Microsoft.Compute/virtualMachines/start/action`). Use Azure documentation or the Azure CLI command `az provider operation show` to find action names. Consider whether data plane permissions are needed (e.g., reading blob data) and include them in `DataActions`. Avoid overly broad wildcards unless necessary. Document the rationale for each permission to aid future audits.

2

Define the Role JSON

Create a JSON file that adheres to the RBAC role definition schema. Include required fields: `Name`, `Description`, `Actions`, `NotActions` (empty if none), `DataActions`, `NotDataActions`, and `AssignableScopes`. Use a unique name that reflects the role's purpose. Set `AssignableScopes` to the management group, subscription, or resource group where you plan to assign the role. Validate the JSON syntax to avoid deployment errors.

3

Create the Custom Role

Use Azure CLI, PowerShell, or the Azure portal to create the role. For CLI, run `az role definition create --role-definition @role.json`. The role is created at the tenant root scope but restricted to the assignable scopes. Verify creation with `az role definition list --custom-role-only true`. Ensure you have `Microsoft.Authorization/roleDefinitions/write` permission at the root scope (typically Owner or User Access Administrator).

4

Assign the Custom Role

Assign the custom role to a security principal (user, group, service principal, or managed identity) at a scope within the role's assignable scopes. For example: `az role assignment create --assignee <object-id> --role "VM Restart Operator" --scope /subscriptions/<sub-id>/resourceGroups/myRG`. The principal now has the permissions defined in the custom role at that scope and any child scopes.

5

Test and Validate Permissions

Sign in as the assigned principal and attempt the allowed and disallowed operations. Use tools like Azure CLI, PowerShell, or SDK to test. For example, try to restart a VM (should succeed) and delete a VM (should fail). Check the effective permissions using `az role assignment list --assignee <object-id> --include-groups --include-inherited`. Verify that `NotActions` are correctly blocking unwanted operations.

What This Looks Like on the Job

Scenario 1: Microservices with Managed Identities A company deploys a microservices application on Azure Kubernetes Service (AKS). Each microservice uses a managed identity to access Azure resources. For example, the 'order-service' needs to write to an Azure SQL database and read from a storage queue. Instead of assigning the built-in Contributor role (which grants excessive permissions), the team creates a custom role named 'OrderServiceRole' with only the necessary actions: Microsoft.Sql/servers/databases/write and Microsoft.Storage/storageAccounts/queueServices/queues/messages/read. The role is assigned to the managed identity at the resource group scope. This limits blast radius if the identity is compromised. The team uses infrastructure-as-code (Terraform) to define the role JSON and assignment, ensuring consistency across environments. A common pitfall is forgetting to include DataActions for storage queue read; they initially used Actions only, which didn't work. After adding DataActions, the microservice functioned correctly.

Scenario 2: External Auditors with Read-Only Access A financial institution needs to grant external auditors read-only access to specific Azure resources (e.g., storage accounts, SQL databases) but no write access. Built-in Reader role provides read access to control plane but not data plane. The team creates a custom role with Actions: ["Microsoft.Storage/storageAccounts/read", "Microsoft.Sql/servers/databases/read"] and DataActions: ["Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read", "Microsoft.Sql/servers/databases/data/read"]. However, they must be careful: DataActions for SQL require the data/read permission, which is not covered by the wildcard. They assign the role to a guest user from the auditing firm at the subscription scope. The auditors can now view blob data and query SQL databases but cannot modify anything. A common mistake is assigning the role at a resource group instead of subscription, causing auditors to miss resources in other groups.

Scenario 3: DevOps Pipeline with Least Privilege A DevOps team uses Azure Pipelines to deploy infrastructure. The service principal used by the pipeline needs to create and manage resources but not delete them. They create a custom role 'DeployOperator' with actions like Microsoft.Resources/deployments/*, Microsoft.Compute/virtualMachines/write (but not delete), and Microsoft.Network/networkInterfaces/write. They also add NotActions: ["Microsoft.Compute/virtualMachines/delete", "Microsoft.Network/networkInterfaces/delete"]. This ensures the pipeline can deploy but not destroy resources. They assign the role to the service principal at the resource group scope. A challenge is that some resource providers have different action names for delete; they must verify each one. Misconfiguration could allow accidental deletion if a delete action is not covered by NotActions.

How AZ-204 Actually Tests This

The AZ-204 exam tests custom RBAC roles primarily under objective 3.1 Implement secure cloud solutions. You should expect questions that require you to:

Identify the correct JSON structure for a custom role.

Distinguish between Actions and DataActions.

Determine the effective permissions when multiple roles are assigned.

Choose the appropriate assignable scope.

Common Wrong Answers: 1. *Using Actions for data plane operations.* Candidates often assume that Microsoft.Storage/storageAccounts/* in Actions grants blob read access. In reality, data plane operations require DataActions. The exam will present a scenario where a custom role needs to allow reading blobs, and the wrong answer lists only Actions. The correct answer must include DataActions. 2. *Assuming NotActions are additive.* Some candidates think that adding an action to NotActions grants that action. Actually, NotActions only excludes actions from the allowed set. The exam may ask about a role that has * in Actions and a specific action in NotActions; the principal can do everything except that action. 3. *Assigning a custom role at a scope smaller than its assignable scope.* For example, if a custom role is created with assignable scope of subscription, you cannot assign it at a resource group. The exam will test this limitation. 4. *Forgetting that custom roles can have multiple assignable scopes.* A role can be assignable at multiple management groups or subscriptions, but not at arbitrary scopes like a single resource unless that resource's scope is included.

Specific Exam Values: - Maximum custom roles per subscription: 5,000. - Role JSON size limit: 1 MB. - Permissions inheritance: from management group down to resource. - DataActions must be explicitly specified; they are not included in Actions wildcards.

Edge Cases: - When a principal has multiple role assignments with overlapping scopes, the effective permissions are the union of all allowed actions minus the union of all denied actions (from deny assignments). - Custom roles cannot be used with Azure AD roles; they are separate systems. - To update a custom role, you must have Microsoft.Authorization/roleDefinitions/write at the root scope, which is typically only held by Global Administrator or User Access Administrator.

How to Eliminate Wrong Answers: - If the scenario involves data access (blobs, queues, tables), look for DataActions in the role definition. If missing, eliminate that answer. - If the role needs to restrict a specific action, check for NotActions. If the role uses only Actions, it cannot subtract permissions. - Verify the assignable scope: if the role is assigned at a resource group, ensure the role's assignable scopes include that resource group or higher. - For effective permissions, compute the union of all allowed actions and subtract any NotActions. Deny assignments (from Azure Policy) override all allows.

Key Takeaways

Custom RBAC roles are defined in JSON with Actions, NotActions, DataActions, NotDataActions, and AssignableScopes.

DataActions are required for data plane access; wildcards in Actions do not cover data operations.

Assignable scopes determine where the role can be assigned; they cannot be changed after creation.

Effective permissions are the union of all allowed actions minus NotActions, with deny assignments taking precedence.

Maximum custom roles per subscription is 5,000; role JSON size limit is 1 MB.

Custom roles cannot manage Azure AD directory permissions; use Azure AD roles for that.

Easy to Mix Up

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

Custom RBAC Roles

Defined by user with specific actions and scopes.

Can include DataActions for data plane permissions.

Limited to 5,000 per subscription.

Must be manually maintained and updated.

Provide granular, least-privilege access.

Built-in RBAC Roles

Predefined by Microsoft with common permission sets.

Some built-in roles include DataActions (e.g., Storage Blob Data Reader).

No limit on number (but limited set).

Automatically updated by Microsoft with new actions.

May grant more permissions than needed.

Watch Out for These

Mistake

Custom roles can include permissions for Azure AD resources like users or groups.

Correct

Custom RBAC roles only apply to Azure resources (ARM resources). Azure AD directory roles are separate and cannot be defined via custom RBAC. To manage Azure AD permissions, use Azure AD roles like Global Administrator.

Mistake

Using a wildcard in Actions also grants data plane permissions.

Correct

Wildcards in Actions only cover control plane operations. Data plane operations require explicit DataActions. For example, `Microsoft.Storage/storageAccounts/*` does not include blob read; you need `Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read` in DataActions.

Mistake

NotActions can be used to grant permissions.

Correct

NotActions only subtract permissions from the Actions list. They cannot add new permissions. For example, a role with Actions: [] and NotActions: ["Microsoft.Compute/virtualMachines/read"] grants no permissions because there are no allowed actions to subtract from.

Mistake

Custom roles can be assigned at any scope regardless of assignable scopes.

Correct

Custom roles can only be assigned at scopes that are within their assignable scopes list. If a role's assignable scopes include a subscription, you can assign it at that subscription, any resource group in it, or any resource. You cannot assign it at a management group above the subscription.

Mistake

You can update a custom role's name or assignable scopes after creation.

Correct

Once created, the role's name and assignable scopes are immutable. To change them, you must delete the role and recreate it with the new values. However, you can update Actions, NotActions, DataActions, and NotDataActions.

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?

Create a JSON file defining the role with fields: Name, Description, Actions, NotActions, DataActions, NotDataActions, and AssignableScopes. Then use Azure CLI `az role definition create --role-definition @file.json` or PowerShell `New-AzRoleDefinition`. You need permission to write role definitions at the root scope (typically Owner or User Access Administrator).

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

Actions control plane operations (e.g., creating a VM, reading resource properties). DataActions control data plane operations (e.g., reading blob content, writing to a queue). They are separate because data access is more sensitive. A role must explicitly include DataActions to allow data operations; wildcards in Actions do not cover DataActions.

Can a custom role be assigned across multiple subscriptions?

Yes, if the role's assignable scopes include multiple subscriptions (or a management group containing them). You can specify multiple subscription IDs in the AssignableScopes array. Then you can assign the role at each subscription or child scopes.

How do I update a custom role's permissions?

Use `az role definition update --role-definition @updated.json` or PowerShell `Set-AzRoleDefinition`. You can update Actions, NotActions, DataActions, and NotDataActions. However, you cannot change the role's Name or AssignableScopes; you must delete and recreate the role for those changes.

What happens if a principal has multiple role assignments with overlapping permissions?

The effective permissions are the union of all allowed actions from all roles, minus any NotActions from each role. If any role assignment includes a deny assignment (via Azure Policy), that deny takes precedence and blocks the action regardless of allows.

Can I create a custom role that denies a specific action?

No, RBAC roles are allow-based. To deny an action, you must use a deny assignment (e.g., via Azure Policy with a deny effect). Custom roles can only subtract permissions using NotActions, but NotActions only work within the context of the role's allowed actions. They cannot deny actions that are not in the role's Actions.

Are custom roles supported for Azure AD resources?

No. Custom RBAC roles only apply to Azure resources (ARM resources). Azure AD has its own role system (Azure AD roles) which cannot be customized via RBAC. For Azure AD permissions, use built-in or custom Azure AD roles (via Azure AD PIM).

Terms Worth Knowing

Ready to put this to the test?

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

Done with this chapter?