Azure RBAC Role Definition Analyzer

Read an Azure custom role definition and see what it actually grants. NotActions subtracts from this role and denies nothing, which is why a role written to withhold an action usually withholds it from nobody.

Paste below, or drop a file anywhere on this panel

Or drop a file anywhere on this panel. Nothing is uploaded: the analysis runs in this tab.

The answer appears here

Paste on the left and press Analyze the role. Nothing leaves this tab.

Wanted a different tool?

  • Azure Resource ID Parser to check the assignableScopes, because a scope one level higher than intended reaches every resource beneath it.
  • Azure NSG Rule Analyzer for the network half: RBAC decides what a caller may do, the NSG decides whether the packet arrives at all.

Examples

Real input you can load into the tool above. Each one shows a different thing going wrong, because that is what the tool is for.

The role that denies nothing

A custom role written to withhold delete. NotActions subtracts from this role alone, so anyone who also holds Contributor can still delete, and nothing about this definition changes that.

{
  "roleName": "Contributor without delete",
  "assignableScopes": ["/subscriptions/00000000-0000-0000-0000-000000000000"],
  "permissions": [
    {
      "actions": ["*"],
      "notActions": ["Microsoft.Compute/virtualMachines/delete"],
      "dataActions": [],
      "notDataActions": []
    }
  ]
}

Escalation through a wildcard

The role never names role assignment explicitly. Microsoft.Authorization/* covers it, so this principal can assign Owner to itself and every other bound in the role is advisory.

{
  "roleName": "Platform operator",
  "assignableScopes": ["/subscriptions/00000000-0000-0000-0000-000000000000"],
  "permissions": [
    {
      "actions": ["Microsoft.Compute/*", "Microsoft.Authorization/*"],
      "notActions": []
    }
  ]
}

Assignable at a management group

Anything assigned at a management group applies to every subscription beneath it, and inheritance is additive: no assignment lower down can remove it.

{
  "roleName": "Org reader",
  "assignableScopes": ["/providers/Microsoft.Management/managementGroups/contoso"],
  "permissions": [{ "actions": ["*/read"], "notActions": [] }]
}

Common mistakes

These are the ones that fail silently. The config is accepted, nothing raises an error, and the consequence arrives later.

  1. Writing a custom role with `NotActions` to prevent an action

    It subtracts from THAT role only. A principal who also holds Contributor, or any other assignment granting the action, still has it, and nothing about the custom role changes that.

    Instead:Remove the assignments that grant it. Azure's only real deny is a deny assignment, which comes from Blueprints or managed applications and cannot be authored in RBAC.

  2. Auditing the assignments at one scope

    Scope is inherited downward and is additive. A role at a management group applies to every subscription, resource group and resource beneath it, and nothing lower can revoke it.

    Instead:Check every scope above the resource, or use the portal's Check access, which computes the effective set.

  3. Expecting a control-plane role to read data

    `Actions` cover the resource and `DataActions` cover its contents. Storage Account Contributor can manage the account and cannot read a blob.

    Instead:Add `dataActions` when the role needs the contents. Note that a role able to list account keys reaches the data anyway.

  4. Copying the built-in Contributor shape into a custom role

    Contributor is `*` minus a few NotActions, which works because Azure controls the whole set. In a custom role it reproduces the appearance of a bound without the substance of one.

    Instead:Enumerate the resource providers the role needs. `Microsoft.Compute/*` is still broad and is at least bounded.

  5. Granting `Microsoft.Authorization/roleAssignments/write`

    That principal can assign any role to anyone, including Owner to itself, so every other limit in the role is advisory.

    Instead:Treat it as equivalent to Owner at whatever scope it is assigned, and scope it as narrowly as the job allows.

NotActions is a subtraction, not a deny

This is the single most misread thing in Azure RBAC, and a custom role written on the wrong reading withholds nothing at all from the person it was written for.

It subtracts from this role, and only this role

A role definition grants Actions minus NotActions. That subtraction applies within the definition. If the same principal holds any other assignment granting the action, they have it, and this role cannot take it away. A custom role that removes virtual machine delete, given to somebody who is also Contributor at the subscription, removes nothing.

Custom role:  actions ["*"]  notActions ["*/delete"]
Also holds:   Contributor at the subscription

Effective:    can delete. The NotActions removed it from the
              custom role and from nowhere else.

The only real deny is a deny assignment, and you cannot create one

Deny assignments do override role assignments, and they come from Azure Blueprints and managed applications rather than from RBAC. There is no way to author one through role definitions, so if the requirement is genuinely to prevent an action, the answer is to remove the assignments that grant it rather than to write a role that appears to withhold it.

Scope is inherited downward and is additive

A role assigned at a management group applies to every subscription beneath it, then every resource group, then every resource. Nothing at a lower scope can revoke it. So the effective permissions on a resource are the union of every assignment at every scope above it, and a resource group policy that looks tight tells you nothing on its own.

Actions and DataActions are different planes

Actions cover the resource: creating a storage account, reading its configuration. DataActions cover the contents: reading a blob, reading a secret. Storage Account Contributor cannot read a blob. The catch is that a control-plane role able to list account keys reaches the data anyway, which is why key access is worth more attention than the data role assignments.

A wildcard plus NotActions is how the built-in roles are made

Contributor is Actions of star minus a handful of authorization NotActions. That shape is fine for a built-in role because Azure controls the whole set. Copying it into a custom role reproduces the appearance of a bound without the substance of one, for the reason at the top of this page.

What this cannot see

It reads one role definition. It does not know what else the principal holds, and since NotActions only subtracts within a role, the other assignments are exactly what decides the answer. It cannot see deny assignments, which are the only real block and are invisible to RBAC. It also cannot expand a wildcard against the live provider list, so a role written as a wildcard is reported as broad rather than enumerated. For effective access on a specific resource, use the portal's Check access rather than any static reading.