Received Microsoft MVP Award in Developer Technologies
July 11, 2025Cumulative Update #20 for SQL Server 2022 RTM
July 11, 2025Azure role-based access control (RBAC) roles are essential in any organization to create granular access to resources across subscriptions.
Azure RBAC lets you define your roles, allowing you to create fine-grained permissions that you can’t find in built-in roles.
A custom role is defined by an ID, a name, an assignable scope (such as subscriptions or management groups), a description, and specific permissions. There are several kinds of permission; the most important is “Actions” (it is mandatory when creating a costume role), there are also “noActions”, “DataActions”, and “noDataActions” properties.
“Actions” list what you can do on the control plane of resources. Thinks about all actions on a resource like a virtual machine or a storage action that do not include accessing data. DataActions list what you can do on the data plate of resources, think about what is inside an Azure Key Vault, or data in a storage account.
The purpose of noActions and noDataActions is to remove a permission that is listed in the “Actions” or “DataActions” properties. Because permissions are a hierarchy of actions, starting with a resource type and subtype.
For example, this is the list of all actions for virtual machines
"Microsoft.Compute/virtualMachines/read",
"Microsoft.Compute/virtualMachines/write",
"Microsoft.Compute/virtualMachines/delete",
"Microsoft.Compute/virtualMachines/start/action", "Microsoft.Compute/virtualMachines/powerOff/action",
"Microsoft.Compute/virtualMachines/reapply/action",
"Microsoft.Compute/virtualMachines/redeploy/action",
"Microsoft.Compute/virtualMachines/restart/action",
"Microsoft.Compute/virtualMachines/retrieveBootDiagnosticsData/action",
"Microsoft.Compute/virtualMachines/deallocate/action",
"Microsoft.Compute/virtualMachines/generalize/action",
"Microsoft.Compute/virtualMachines/capture/action",
"Microsoft.Compute/virtualMachines/runCommand/action",
"Microsoft.Compute/virtualMachines/convertToManagedDisks/action",
"Microsoft.Compute/virtualMachines/performMaintenance/action",
"Microsoft.Compute/virtualMachines/reimage/action",
"Microsoft.Compute/virtualMachines/installPatches/action",
"Microsoft.Compute/virtualMachines/assessPatches/action",
"Microsoft.Compute/virtualMachines/cancelPatchInstallation/action",
"Microsoft.Compute/virtualMachines/simulateEviction/action",
"Microsoft.Compute/virtualMachines/osUpgradeInternal/action",
"Microsoft.Compute/virtualMachines/rollbackOSDisk/action",
"Microsoft.Compute/virtualMachines/deletePreservedOSDisk/action",
"Microsoft.Compute/virtualMachines/upgradeVMAgent/action",
"Microsoft.Compute/virtualMachines/attachDetachDataDisks/action",
"Microsoft.Compute/virtualMachines/patchAssessmentResults/latest/read",
"Microsoft.Compute/virtualMachines/patchAssessmentResults/latest/softwarePatches/read",
"Microsoft.Compute/virtualMachines/patchInstallationResults/read",
"Microsoft.Compute/virtualMachines/patchInstallationResults/softwarePatches/read",
"Microsoft.Compute/virtualMachines/providers/Microsoft.Insights/logDefinitions/read",
"Microsoft.Compute/virtualMachines/providers/Microsoft.Insights/diagnosticSettings/read",
"Microsoft.Compute/virtualMachines/providers/Microsoft.Insights/diagnosticSettings/write",
"Microsoft.Compute/virtualMachines/extensions/read",
"Microsoft.Compute/virtualMachines/extensions/write",
"Microsoft.Compute/virtualMachines/extensions/delete",
"Microsoft.Compute/virtualMachines/instanceView/read",
"Microsoft.Compute/virtualMachines/providers/Microsoft.Insights/metricDefinitions/read",
"Microsoft.Compute/virtualMachines/runCommands/read",
"Microsoft.Compute/virtualMachines/runCommands/write",
"Microsoft.Compute/virtualMachines/runCommands/delete",
"Microsoft.Compute/virtualMachines/vmSizes/read"
You see that you see the hierarchy (Microsoft.Compute, then virtual machine, then a child resource, and an action or an action).
Because it can be error-prone and boring to write every single permission for virtual machines (about 40 possible actions), you can use a wildcard.
“Microsoft.Compute/virtualMachines/“
You can see here the utility of no action. If you want to give all permissions except one, you can use noAction to remove a permission. For example, if you want to give all actions except “Microsoft.Compute/virtualMachines/runCommands/delete”, and “Microsoft.Compute/virtualMachines/extensions/delete”, you can add it the the noAction property.
To get all the possible permissions from a resource, you can use PowerShell:
`Get-AzProviderOperation “Microsoft.Compute/virtualMachines//*” | select-object OperationName, Operation, Description`
PowerShell can create a custom role by using a JSON file defining the role.
{
"Name": "Demo Role 01",
"Id": null,
"IsCustom": true,
"Description": "Allows all actions on VM",
"Actions": [
"Microsoft.Compute/virtualMachines/*"
],
"NotActions": [],
"AssignableScopes": [
"/providers/Microsoft.Management/managementGroups/test-mg"
]
}
To create the role
New-AzRoleDefinition -InputFile "./role1.json"
Now, if we want to restrict the role to perform delete operations on VM extensions and runCommands we can add these two actions to the noActions parameter.
{
"Name": "Demo Role 02",
"Id": null,
"IsCustom": true,
"Description": "Allows all actions on VM",
"Actions": [
"Microsoft.Compute/virtualMachines/*"
],
"NotActions": [
"Microsoft.Compute/virtualMachines/runCommands/delete",
"Microsoft.Compute/virtualMachines/extensions/delete"
],
"AssignableScopes": [
"/providers/Microsoft.Management/managementGroups/group01"
]
}
Now, if a role needs to allow all actions on VMs (Microsoft.Compute/virtualMachines) and VMSSs (Microsoft.Compute/virtualMachineScaleSets), we can add both resources to the “Actions” parameter.
{
"Name": "Demo Role 03",
"Id": null,
"IsCustom": true,
"Description": "Allows all actions on VM and VMSS",
"Actions": [
"Microsoft.Compute/virtualMachines/*",
"Microsoft.Compute/virtualMachineScaleSets/*"
],
"NotActions": [],
"AssignableScopes": [
"/providers/Microsoft.Management/managementGroups/group01"
]
}
Or use a wildcard on Microsoft.compute
{
"Name": "Demo Role 04",
"Id": null,
"IsCustom": true,
"Description": "Allows all actions on MS Compute with wildcard",
"Actions": [
"Microsoft.Compute/*"
],
"NotActions": [],
"AssignableScopes": [
"/providers/Microsoft.Management/managementGroups/group01"
]
}
This will allow 279 different actions, and that could be a problem. The role created by this JSON file will have every permission possible from the Microsoft.compute service, including actions that may be added in the future. This is the opposite of a fine-grained security policy. It is just like using a medieval axe to perform microsurgery.
By using Microsoft.compute/* alone, I get 279 possible actions. What about using “*/read”? The number is 9840 possible actions! This leaves a place for malicious actions.
But this is the case with some built-in roles, the reader role.
{
"id": "/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7",
"properties": {
"roleName": "Reader",
"description": "View all resources, but does not allow you to make any changes.",
"assignableScopes": [
"/"
],
"permissions": [
{
"actions": [
"*/read"
],
"notActions": [],
"dataActions": [],
"notDataActions": []
}
]
}
}
Or User Access Administrator
{
"id": "/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9",
"properties": {
"roleName": "User Access Administrator",
"description": "Lets you manage user access to Azure resources.",
"assignableScopes": [
"/"
],
"permissions": [
{
"actions": [
"*/read",
"Microsoft.Authorization/*",
"Microsoft.Support/*"
],
"notActions": [],
"dataActions": [],
"notDataActions": []
}
]
}
}
Several built-in roles are too permissive. Custom roles, with fewer actions, should be used instead. It can be long and boring, but it will limit your attack surface.