---
cuppy_hub: azure
cuppy_path: reference/rbac/role-assignments-and-scopes.md
cuppy_section: docs
cuppy_doc: G9BC-ENWQ
cuppy_doc_uuid: 9c01bd43-a4de-4f07-8027-580c72bcb67c
cuppy_permalink: https://cuppy.io/azure/d/G9BC-ENWQ
cuppy_version: 1
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/azure/docs/reference/rbac/role-assignments-and-scopes
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: 37ac3ed1d0f6ebe66d65a72b02833d59b333002cf13e930274b80175c0511220
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# Azure RBAC — scopes, roles and role assignments

**Access is a role assignment: a principal (user, group, service principal or managed identity), a role definition, and a scope.** An assignment applies at its scope and everything below it. Azure allows the call if any assignment grants the action and no deny assignment blocks it. Azure Policy is a separate check that can still refuse the request (`reference/policy/effects-and-errors.md`).

## Scopes

```
/providers/Microsoft.Management/managementGroups/{mg}
/subscriptions/{subscriptionId}
/subscriptions/{subscriptionId}/resourceGroups/{rg}
/subscriptions/{subscriptionId}/resourceGroups/{rg}/providers/{namespace}/{type}/{name}
```

Child resources append `/{subtype}/{name}` pairs. Get a resource's exact scope from its `id` (`az keyvault show --name kv --query id -o tsv`) rather than building the string by hand. Management groups sit above subscriptions; the tenant root group is the top.

## Role definitions: control plane vs data plane

A role lists `Actions` / `NotActions` (Resource Manager operations: create, configure, delete) and `DataActions` / `NotDataActions` (operations on the data inside: read a blob, get a secret, send a message). **Owner and Contributor have no data actions**, so they manage a storage account or key vault but can't read its contents through Entra auth. Data access needs the service's data role, such as Storage Blob Data Reader or Key Vault Secrets User.

| Built-in role | What it allows | Role definition ID |
|---|---|---|
| Owner | Everything, including assigning roles | `8e3af657-a8ff-443c-a75c-2fe8c4bcb635` |
| Contributor | Manage all resources; **not** assign roles or write policy (`NotActions` include `Microsoft.Authorization/*/Write` and `/*/Delete`) | `b24988ac-6180-42a0-ab88-20f7382dd24c` |
| Reader | View everything, change nothing | `acdd72a7-3385-48ef-bd42-f606fba81ae7` |
| Role Based Access Control Administrator | Create and delete role assignments (not policy) | `f58310d9-a9f6-439a-9e8d-f62e7b41a168` |
| User Access Administrator | Manage user access to Azure resources | `18d7d88d-d35e-4fb5-a5c3-7773c20a72d9` |
| Managed Identity Contributor / Operator | Create and manage user-assigned identities / assign them to resources | `e40ec5ca-96e0-45a2-b4ff-59039f2c2b59` / `f1a07417-d97a-45cb-824c-7a7467783830` |
| Key Vault Secrets User | Read secret contents (RBAC-model vaults) | `4633458b-17de-408a-b874-0445c86b69e6` |

The IDs are the same in every tenant. Infrastructure-as-code should reference them, not role names. Each service family in this hub lists its own data roles.

## Role assignments

- **Name:** every assignment is a resource whose `name` is a GUID that must be unique **globally**, not just in your subscription. Its properties can't change after creation. In Bicep or ARM, derive it: `guid(scope, principalId, roleDefinitionId)`. A random or reused name gives `RoleAssignmentUpdateNotPermitted` when the principal changes (`reference/rbac/errors.md`).
- **`principalId`** is the object ID (a managed identity's `principalId`, a service principal's `id`), never the app's client ID.
- **`principalType`** (`User`, `Group`, `ServicePrincipal`; the 2022-04-01 spec now also lists `AgentServicePrincipal` and `AgentUser` for Entra Agent ID, `reference/entra/workload-and-agent-identities.md`): set it whenever the principal was just created. It skips the directory lookup that fails with `PrincipalNotFound` during replication.
- **Propagation:** changes take up to about **10 minutes**. Sign out and in (CLI) or get a new token (code) to pick them up sooner. Group-based access for managed identities can take hours (`reference/managed-identity/errors.md`).
- **Resource moves don't move assignments** made directly on the resource; re-create them after the move. Transferring a subscription to another tenant **deletes all its role assignments**.

## Who can assign roles, and constraining them

Creating an assignment needs `Microsoft.Authorization/roleAssignments/write` at that scope: Owner, User Access Administrator or Role Based Access Control Administrator. Prefer **Role Based Access Control Administrator with a condition**, which limits the roles a delegate can assign (and to which principals). Conditions use role definition IDs:

```
((!(ActionMatches{'Microsoft.Authorization/roleAssignments/write'}))
 OR (@Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {4633458b-17de-408a-b874-0445c86b69e6}))
```

A pipeline identity that deploys role assignments is the typical delegate: give it this role with a condition naming only the data roles it deploys.

## Deny assignments

A deny assignment blocks actions even when a role allows them. Generally available ones are **created by Azure**, for example by a deployment stack with deny settings or a managed application. Customer-managed deny assignments are in private preview. List them with `az rest --method get --uri "https://management.azure.com/<scope>/providers/Microsoft.Authorization/denyAssignments?api-version=2022-04-01"`.

## Documented limits

Custom roles: 5,000 per tenant. A custom role's `AssignableScopes` can hold at most one management group, and a custom role with `DataActions` can't be assignable at management-group scope. The per-subscription role-assignment count has a limit (`RoleAssignmentLimitExceeded` when reached): read the current figure on the Azure subscription limits page rather than a number copied from elsewhere.

## Next

Assigning roles from CLI, Bicep and TypeScript: `guides/rbac/assign-roles.md`. Errors: `reference/rbac/errors.md`.


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 107 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/azure/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
