Creating Custom RBAC Roles
Complete the full lesson to earn 25 points
Work through each section, then tap “Mark as Complete” on the last one.
✦ Skip the page breaks and see fewer ads — read each lesson on a single page with Pro
Mastering Custom Role-Based Access Control (RBAC) in Azure
Introduction: The Philosophy of Least Privilege
In the modern cloud landscape, security is not merely about locking the front door; it is about defining exactly what every individual and service can do once they are inside. Azure Role-Based Access Control (RBAC) is the primary mechanism for managing this granular access. While Azure provides a vast library of built-in roles—such as Owner, Contributor, and Reader—these roles are intentionally broad. They are designed to cover general operational needs, but they often grant more permissions than a specific task requires.
This is where the concept of the "Principle of Least Privilege" comes into play. This principle dictates that every user, service principal, or managed identity should possess only the minimum level of access necessary to perform their specific job functions. When you grant broad permissions, you increase your security surface area. If a user with "Contributor" access on a subscription is compromised, an attacker could potentially delete resources, modify network security groups, or create new administrative accounts. By creating custom RBAC roles, you tighten this surface area, ensuring that a database administrator can manage databases without having the ability to modify the virtual network or delete storage accounts.
Understanding how to craft, deploy, and manage custom roles is the hallmark of a mature cloud governance strategy. It allows your organization to move away from "one-size-fits-all" permissions and toward a precise, intent-based security model. In this lesson, we will explore the architecture of RBAC, the anatomy of a custom role definition, and the practical workflows required to implement these controls effectively in your Azure environment.
The Anatomy of an Azure RBAC Role
Before we dive into creating custom roles, it is essential to understand the four core components that constitute any role definition in Azure. Whether you are using a built-in role or a custom one, every role is essentially a JSON document that defines a set of permissions.
1. Actions
The Actions array defines the operations that the role is permitted to perform. These are expressed as strings in the format Provider/ResourceType/Action. For example, Microsoft.Compute/virtualMachines/start/action allows a user to start a virtual machine. You can use wildcards (*) to grant broad permissions, but in a custom role, you should strive to be as specific as possible.
2. NotActions
The NotActions array is a powerful tool for exclusion. It allows you to grant a broad set of permissions while specifically stripping away certain dangerous or sensitive operations. For example, you might grant Microsoft.Compute/* but set NotActions to Microsoft.Compute/virtualMachines/delete/action. This ensures the user can manage VMs but cannot destroy them.
3. DataActions and NotDataActions
While Actions relate to the Azure Resource Manager (ARM) plane—such as creating, updating, or deleting resources—DataActions relate to the data plane. These permissions govern what a user can do inside the resource. For example, Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read allows a user to read the actual content of a blob. This distinction is critical because standard ARM permissions do not automatically grant data plane access.
4. AssignableScopes
This defines where the role can be assigned. You can set this to a subscription ID, a resource group, or a management group. If you create a role and set the scope to a specific subscription, that role will only be visible and selectable when you are assigning permissions within that specific subscription.
Callout: ARM Plane vs. Data Plane It is vital to distinguish between the Management Plane (ARM) and the Data Plane. Management Plane actions involve the control of the resource itself (e.g., resizing a VM, changing firewall settings). Data Plane actions involve the content stored within or processed by the resource (e.g., reading a file in a storage account, querying a SQL table). Custom roles must explicitly define which plane they are targeting to be effective.
Step-by-Step: Creating a Custom Role
Creating a custom role involves defining the JSON structure and then registering that role in your Azure tenant. While you can use the Azure Portal, using the Azure CLI or PowerShell is the industry standard for repeatability and version control.
Step 1: Identify the Required Permissions
Before you write a single line of code, document exactly what the user needs to do. Do not guess. If a user needs to restart a server, they need Microsoft.Compute/virtualMachines/restart/action. If they need to check the status, they need Microsoft.Compute/virtualMachines/read.
Step 2: Define the JSON Template
Create a file named CustomRole.json. Here is a practical example of a "Virtual Machine Operator" role that allows starting, stopping, and restarting VMs, but prevents deletion.
{
"Name": "VM Operator Limited",
"IsCustom": true,
"Description": "Allows users to start, stop, and restart VMs without deletion rights.",
"Actions": [
"Microsoft.Compute/virtualMachines/read",
"Microsoft.Compute/virtualMachines/start/action",
"Microsoft.Compute/virtualMachines/stop/action",
"Microsoft.Compute/virtualMachines/restart/action"
],
"NotActions": [
"Microsoft.Compute/virtualMachines/delete"
],
"AssignableScopes": [
"/subscriptions/{your-subscription-id}"
]
}
Step 3: Register the Role
Use the Azure CLI to create the role definition based on your JSON file. Open your terminal and run the following command:
az role definition create --role-definition @CustomRole.json
Once this command executes, the role is registered in your subscription. You can now go to the Azure Portal, navigate to your resource group or subscription, and assign this role to a specific user or group under the Access Control (IAM) blade.
Tip: Use Existing Roles as a Base Instead of starting from scratch, you can export an existing built-in role using the Azure CLI. This gives you a valid JSON template that you can then modify to suit your specific needs. Use
az role definition list --name "Virtual Machine Contributor" > base-role.jsonto get started.
Best Practices for Role Design
Designing custom roles is an exercise in restraint. The more complex your roles become, the harder they are to audit and maintain. Follow these industry-standard best practices to keep your RBAC implementation clean.
1. Avoid Wildcards Whenever Possible
Using * in your Actions list is a common pitfall. While it makes the role easy to define, it effectively grants full administrative control over that resource type. If a new sub-action is added to the Azure API in the future, your * role will automatically gain that permission, potentially creating an unintended security hole. Always list the specific actions required.
2. Group Permissions by Functional Intent
Create roles based on job functions rather than individual users. For example, create a "Database Backup Admin" role rather than "John's Role." This allows you to assign the role to multiple people or service principals and ensures that if a person leaves the team, the role remains valid for their successor.
3. Keep Assignable Scopes Tight
If a role is only intended for a specific development environment, set the AssignableScopes to that specific subscription or resource group. This prevents the role from appearing in the dropdown menus of production subscriptions, reducing the risk of accidental assignment in sensitive environments.
4. Implement Naming Conventions
Adopt a strict naming convention for your custom roles. Prefixing them with your organization's acronym or a project code makes it easier to distinguish them from built-in roles. For example: ORG-VM-Operator, ORG-Network-Readonly.
5. Regularly Audit Assignments
Permissions tend to accumulate over time—a phenomenon known as "permission creep." Schedule quarterly reviews to check who has what roles. Use tools like Azure AD Access Reviews to automate this process and ensure that users still require the access they were granted months or years ago.
Warning: The Dangers of NotActions Be extremely careful when using
NotActions. If you include*in yourActionslist and then useNotActionsto exclude specific operations, you must be 100% certain you have identified all sensitive actions. If a new action is introduced to the API that is not explicitly denied inNotActions, the user will automatically have access to it. Always prefer an "Allow-list" approach (listing only permitted actions) over a "Deny-list" approach whenever possible.
Comparison of Access Control Methods
It is helpful to understand how custom RBAC fits into the broader Azure security ecosystem. Azure offers several ways to control access, and choosing the right one depends on your specific use case.
| Method | Best For | Complexity |
|---|---|---|
| Built-in RBAC Roles | Standard administrative tasks (Owner, Contributor) | Low |
| Custom RBAC Roles | Granular, task-specific security requirements | Medium |
| Azure AD PIM | Just-in-time, elevated access for sensitive tasks | High |
| Attribute-Based Access Control (ABAC) | Dynamic access based on tags or resource attributes | High |
Custom RBAC roles are the "workhorse" of security. They provide the most balance between precision and manageability for everyday operational tasks. Azure AD Privileged Identity Management (PIM) is a layer on top of RBAC, allowing you to make these roles "eligible" rather than permanently assigned. ABAC is an emerging feature that allows for even more dynamic control, but it is typically reserved for highly complex, large-scale environments.
Handling Common Pitfalls
Even experienced cloud architects encounter issues when deploying custom roles. Being aware of these pitfalls can save you hours of troubleshooting.
The "Permission Propagation" Delay
After you assign a custom role, it may take a few minutes for the permissions to propagate across the Azure control plane. If a user tries to perform an action immediately after assignment and receives an "Access Denied" error, ask them to wait five minutes and try again. If the issue persists, verify that the assignment was made at the correct scope.
The "Missing Nested Permission" Error
Sometimes you grant a user a specific action, but they still cannot perform the task. This is often because the task requires a prerequisite permission. For example, to list the keys of a storage account, the user needs Microsoft.Storage/storageAccounts/listKeys/action. If they only have read permissions on the storage account, the listKeys operation will fail because it is a separate, sensitive action. Always check the official Azure documentation for the specific actions required for complex tasks.
Circular Dependencies
When using Management Groups to manage roles, be careful not to create circular dependencies. If you define a role at the Management Group level and then attempt to restrict it in a way that conflicts with a child subscription's policy, you may encounter unexpected behavior. Keep your hierarchy flat where possible to avoid complex inheritance issues.
Over-Reliance on "Owner"
A common mistake is assigning the "Owner" role to users simply because they complained that they couldn't do their job. This is a failure of both governance and role design. If a user needs to perform a specific task, take the time to identify the missing actions and update the custom role rather than giving them "Owner" access. The "Owner" role is effectively a "God Mode" and should be restricted to a very small number of highly trusted identities.
Practical Scenario: The "Read-Only Storage" Identity
Let us walk through a concrete scenario. You have a data processing application that needs to read data from a specific container in an Azure Storage Account, but it should not be able to list other containers or modify the account settings.
Step 1: Analyze the Requirements
To read a blob, the identity needs Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read. To list the blobs in a container, it needs Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read and potentially metadata access.
Step 2: Define the JSON
{
"Name": "Blob Reader Only",
"IsCustom": true,
"Description": "Allows reading blobs but no account management.",
"Actions": [
"Microsoft.Storage/storageAccounts/read"
],
"DataActions": [
"Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read"
],
"AssignableScopes": [
"/subscriptions/{sub-id}/resourceGroups/{rg-name}"
]
}
Step 3: Deployment and Verification
Deploy this using the CLI as shown previously. Once deployed, assign this role specifically to the managed identity of your application. By testing this, you ensure the application can fetch the data it needs, but any attempt to change the storage account firewall or delete the container will result in a clear "Access Denied" error, confirming your security boundary is intact.
Advanced Topic: Using PowerShell for Role Management
While the CLI is excellent for one-off tasks, PowerShell is often preferred by enterprise teams for automation. Here is how you can retrieve and update a custom role using the Az module.
Retrieving a Custom Role
Get-AzRoleDefinition -Name "VM Operator Limited" | ConvertTo-Json
Updating a Custom Role
If you decide to add a new permission (e.g., the ability to view metrics), you can modify the definition object directly in PowerShell:
$role = Get-AzRoleDefinition -Name "VM Operator Limited"
$role.Actions.Add("Microsoft.Insights/metrics/read")
Set-AzRoleDefinition -Role $role
This programmatic approach is highly recommended for larger organizations. You can store your role definitions in a Git repository, treat them as "Infrastructure as Code" (IaC), and use a CI/CD pipeline to deploy updates across multiple subscriptions. This ensures that your RBAC configuration is consistent, versioned, and auditable.
Auditing and Governance: The Role of Azure Policy
Custom RBAC roles define what a user can do, but Azure Policy defines what a resource must be. While these are distinct, they often work together. For instance, you might use a custom RBAC role to prevent a user from deleting a resource, but you could also use Azure Policy to prevent the resource from being deleted by anyone by applying a "Resource Lock."
When planning your identity strategy, ask yourself: "Should I control this via RBAC or via Policy?"
- Use RBAC when you want to control user behavior and access.
- Use Azure Policy when you want to enforce compliance, configuration standards, or organizational guardrails.
By combining these two, you create a layered defense. Even if a user somehow gains higher permissions than intended, Azure Policy can act as a safety net, preventing them from creating non-compliant resources or modifying core infrastructure settings.
Common Questions (FAQ)
Q: Can I assign a custom role to a user that exists in a different Azure AD tenant?
A: Generally, no. RBAC assignments are scoped to the identity within the same tenant. If you need to provide access to an external user, you should use Azure AD B2B Guest accounts. Once they are a guest in your tenant, you can assign them custom roles just like any other user.
Q: How many custom roles can I create?
A: There is a limit of 5,000 custom role definitions per Azure AD tenant. While this may seem like a high number, it is a reminder to avoid creating redundant roles. Always search for existing roles before creating a new one to avoid "role sprawl."
Q: What happens to a custom role if I delete the resource group where it was assigned?
A: The role definition itself exists at the subscription (or management group) level, so it will remain available. However, the role assignments (the links between the users and the role) will be deleted because the resource group they were associated with no longer exists.
Q: Can I use wildcards in DataActions?
A: Yes, but with the same caution as Actions. Using Microsoft.Storage/storageAccounts/blobServices/containers/blobs/* gives full access to all blob operations, including delete and write. Use this only when absolutely necessary.
Key Takeaways for Successful Governance
- Start with Least Privilege: Always default to the most restrictive permissions possible and expand only when a documented business need arises.
- Document Everything: Treat your RBAC JSON files as code. Store them in a version-controlled repository (like GitHub or Azure DevOps) and document why each role was created and who it is intended for.
- Avoid Wildcards: Explicitly define the actions required.
*is the enemy of a secure, predictable environment. - Use Scoping Wisely: Assign roles at the lowest level of the resource hierarchy (e.g., a specific Resource Group) rather than at the Subscription level whenever possible.
- Automate Management: Use CLI or PowerShell to manage roles. Manual configuration in the portal is prone to error and difficult to track over time.
- Regular Audits: Use Access Reviews and periodic manual audits to clean up "permission creep." If a user doesn't need access, remove it immediately.
- Layer Your Defenses: Use Custom RBAC for identity control and Azure Policy for configuration enforcement. The combination of the two provides a much stronger security posture than either one alone.
By following these principles, you transform RBAC from a burdensome administrative task into a powerful tool for maintaining the integrity and security of your Azure environment. Creating custom roles requires patience and attention to detail, but the result is a cloud infrastructure where every identity is empowered to do exactly what they need to do—and nothing more. This precision is the foundation upon which secure, scalable, and compliant cloud architectures are built.
Enjoying the courses?
Everything stays free. Pro shows fewer ads, doubles your daily points limit so you progress twice as fast, and lets you read each lesson on one page.
- ✓ Fewer advertisements
- ✓ 2× daily points limit
- ✓ Distraction-free lessons