# Role Assignment

Source: /azure/services/role-assignment/

## Introduction

Azure Role Assignments grant an identity (user, group, or service principal) the permissions defined by a role definition at a specific scope.
Together with Role Definitions, Role Assignments form the foundation of Azure RBAC.
They are commonly used to grant managed identities access to storage accounts, key vaults, and other Azure resources in infrastructure automation scenarios. For more information, see [Assign Azure roles using the Azure CLI](https://learn.microsoft.com/en-us/azure/role-based-access-control/role-assignments-cli).

LocalStack for Azure provides a local environment for building and testing applications that make use of Azure Role Assignments.
The supported APIs are available on our [API Coverage section](#api-coverage), which provides information on the extent of Role Assignments' integration with LocalStack.

## Getting started

This guide walks you through assigning a built-in role to a managed identity, listing assignments, and removing the assignment.

Launch LocalStack using your preferred method. For more information, see [Introduction to LocalStack for Azure](/azure/getting-started/). Once the container is running, enable Azure CLI interception by running:

```bash
lstk az start-interception
```

This command points the `az` CLI away from the public Azure management REST API and toward the LocalStack for Azure emulator API.
To revert this configuration, run:

```bash
lstk az stop-interception
```

This reconfigures the `az` CLI to send commands to the official Azure management REST API.

### Create a resource group

Create a resource group to hold all resources created in this guide:

```bash
az group create --name rg-rbac-demo --location westeurope
```

```bash title="Output"
{
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo",
  "location": "westeurope",
  "managedBy": null,
  "name": "rg-rbac-demo",
  "properties": {
    "provisioningState": "Succeeded"
  },
  "tags": null,
  "type": "Microsoft.Resources/resourceGroups"
}
```

### Create a user-assigned managed identity

Create a user-assigned managed identity to use as the role assignee:

```bash
az identity create \
  --name my-identity \
  --resource-group rg-rbac-demo
```

```bash title="Output"
{
  "clientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo/providers/Microsoft.ManagedIdentity/userAssignedIdentities/my-identity",
  "isolationScope": "None",
  "location": "westeurope",
  "name": "my-identity",
  "principalId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "resourceGroup": "rg-rbac-demo",
  "systemData": null,
  "tags": {},
  "tenantId": "00000000-0000-0000-0000-000000000000",
  "type": "Microsoft.ManagedIdentity/userAssignedIdentities"
}
```

Capture the identity's principal ID:

```bash
PRINCIPAL_ID=$(az identity show \
  --name my-identity \
  --resource-group rg-rbac-demo \
  --query principalId \
  --output tsv)
```

### Assign a built-in role

Assign the `Contributor` role to the identity at the resource group scope:

```bash
SUBSCRIPTION_ID=$(az account show --query id --output tsv)
az role assignment create \
  --assignee "$PRINCIPAL_ID" \
  --role Contributor \
  --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/rg-rbac-demo"
```

```bash title="Output"
{
  "condition": null,
  "conditionVersion": null,
  "createdBy": null,
  "createdOn": null,
  "delegatedManagedIdentityResourceId": null,
  "description": null,
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo/providers/Microsoft.Authorization/roleAssignments/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "name": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "principalId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "principalType": "ServicePrincipal",
  "roleDefinitionId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c",
  "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo",
  "type": "Microsoft.Authorization/roleAssignments",
  "updatedBy": null,
  "updatedOn": null
}
```

### List role assignments

List all role assignments scoped to the resource group:

```bash
az role assignment list \
  --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/rg-rbac-demo"
```

```bash title="Output"
[
  {
    "condition": null,
    "conditionVersion": null,
    "createdBy": null,
    "createdOn": null,
    "delegatedManagedIdentityResourceId": null,
    "description": null,
    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo/providers/Microsoft.Authorization/roleAssignments/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "name": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "principalId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "principalName": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "principalType": "ServicePrincipal",
    "roleDefinitionId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c",
    "roleDefinitionName": "Contributor",
    "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo",
    "type": "Microsoft.Authorization/roleAssignments",
    "updatedBy": null,
    "updatedOn": null
  }
]
```

### Filter by assignee

Filter the role assignments to show only assignments for the managed identity's principal ID:

```bash
az role assignment list \
  --assignee "$PRINCIPAL_ID" \
  --all
```

```bash title="Output"
[
  {
    "condition": null,
    "conditionVersion": null,
    "createdBy": null,
    "createdOn": null,
    "delegatedManagedIdentityResourceId": null,
    "description": null,
    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo/providers/Microsoft.Authorization/roleAssignments/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "name": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "principalId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "principalName": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "principalType": "ServicePrincipal",
    "roleDefinitionId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c",
    "roleDefinitionName": "Contributor",
    "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo",
    "type": "Microsoft.Authorization/roleAssignments",
    "updatedBy": null,
    "updatedOn": null
  }
]
```

### List all role assignments for the subscription

List every role assignment across the entire subscription:

```bash
az role assignment list --all
```

```bash title="Output"
[
  {
    "condition": null,
    "conditionVersion": null,
    "createdBy": null,
    "createdOn": null,
    "delegatedManagedIdentityResourceId": null,
    "description": null,
    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo/providers/Microsoft.Authorization/roleAssignments/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "name": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "principalId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "principalName": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "principalType": "ServicePrincipal",
    "roleDefinitionId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c",
    "roleDefinitionName": "Contributor",
    "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo",
    "type": "Microsoft.Authorization/roleAssignments",
    "updatedBy": null,
    "updatedOn": null
  }
]
```

### Assign a Storage Blob Data Owner role on a storage account

Create a storage account and assign the `Storage Blob Data Owner` role to the managed identity at the storage account scope.
This is a common pattern in infrastructure automation where a function app or container needs full access to a specific storage account.

```bash
az storage account create \
  --name strblobdataowner \
  --resource-group rg-rbac-demo \
  --location westeurope \
  --sku Standard_LRS
```

Capture the storage account resource ID:

```bash
STORAGE_ID=$(az storage account show \
  --name strblobdataowner \
  --resource-group rg-rbac-demo \
  --query id \
  --output tsv)
```

Assign `Storage Blob Data Owner` at the storage account scope:

```bash
az role assignment create \
  --assignee "$PRINCIPAL_ID" \
  --role "Storage Blob Data Owner" \
  --scope "$STORAGE_ID"
```

```bash title="Output"
{
  "condition": null,
  "conditionVersion": null,
  "createdBy": null,
  "createdOn": null,
  "delegatedManagedIdentityResourceId": null,
  "description": null,
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo/providers/Microsoft.Storage/storageAccounts/strblobdataowner/providers/Microsoft.Authorization/roleAssignments/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "name": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "principalId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "principalType": "ServicePrincipal",
  "roleDefinitionId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleDefinitions/b7e6dc6d-f1e8-4753-8033-0f276bb0955b",
  "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo/providers/Microsoft.Storage/storageAccounts/strblobdataowner",
  "type": "Microsoft.Authorization/roleAssignments",
  "updatedBy": null,
  "updatedOn": null
}
```

List assignments scoped to the storage account to verify:

```bash
az role assignment list --scope "$STORAGE_ID"
```

```bash title="Output"
[
  {
    "condition": null,
    "conditionVersion": null,
    "createdBy": null,
    "createdOn": null,
    "delegatedManagedIdentityResourceId": null,
    "description": null,
    "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo/providers/Microsoft.Storage/storageAccounts/strblobdataowner/providers/Microsoft.Authorization/roleAssignments/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "name": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "principalId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "principalName": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "principalType": "ServicePrincipal",
    "roleDefinitionId": "/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleDefinitions/b7e6dc6d-f1e8-4753-8033-0f276bb0955b",
    "roleDefinitionName": "Storage Blob Data Owner",
    "scope": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg-rbac-demo/providers/Microsoft.Storage/storageAccounts/strblobdataowner",
    "type": "Microsoft.Authorization/roleAssignments",
    "updatedBy": null,
    "updatedOn": null
  }
]
```

### Delete a role assignment

Delete the role assignment and confirm it no longer appears in the list:

```bash
az role assignment delete \
  --assignee "$PRINCIPAL_ID" \
  --role Contributor \
  --scope "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/rg-rbac-demo"
```

## Enabling RBAC enforcement

By default, Azure RBAC on LocalStack is **not enforced**: role assignments and role definitions are stored, but every operation succeeds regardless of the assigned roles. Set `LS_AZURE_ENFORCE_RBAC` to `true`, `yes`, or `1` when starting the emulator to turn on enforcement.

With enforcement enabled:

- **Control plane**: every ARM request, across all Azure services and resource types, is checked against the caller's role assignments at the target scope and denied with a `403` if unauthorized.
- **Data plane**: checked for [Blob](/azure/services/blob-storage/), [Queue](/azure/services/queue-storage/), and [Table](/azure/services/table-storage/) Storage, RBAC-mode [Key Vault](/azure/services/key-vault/) vaults (secrets and certificates only), [App Configuration](/azure/services/app-configuration/) key-values and snapshots (bearer callers only, since access-key callers are never evaluated), and Event Grid publish/receive. Denials match the shape Azure returns for each service, for example a Storage `AuthorizationPermissionMismatch` XML error or a Key Vault `ForbiddenByRbac` error.
- **Not covered yet**, even with enforcement enabled: Storage File, the Service Bus data plane, Cosmos DB's data plane, and Microsoft Entra database authentication for Azure SQL, PostgreSQL, and MySQL flexible servers. Requests to these continue to succeed regardless of role assignments.

The default SDK/Terraform service principal and the `az` CLI's `any-app` principal are always treated as a Global Administrator and subscription Owner, and bypass data-plane checks by default too. To observe a deny, use a managed identity or service principal that assumes neither role — for example, the identity created in [Create a user-assigned managed identity](#create-a-user-assigned-managed-identity) without a role assigned at the target scope.

## Features

- **Role assignment creation:** Create role assignments by specifying an assignee principal ID, role name or ID, and scope.
- **Assignment listing:** List role assignments at subscription scope, resource group scope, or filtered by assignee.
- **Assignee filtering:** Filter assignments by principal ID or display name.
- **Subscription-wide listing:** Retrieve all role assignments across a subscription via `--all`.
- **Role assignment deletion:** Delete assignments by role name, assignee, and scope.
- **Custom role support:** Assign custom role definitions alongside built-in roles.

## Limitations

- **RBAC enforcement is opt-in:** By default, role assignments are stored but not evaluated, and all operations succeed regardless of assigned roles. Set `LS_AZURE_ENFORCE_RBAC` to enable enforcement.
- **Data-plane coverage is partial:** Enforced for Storage (Blob/Queue/Table), Key Vault (secrets and certificates), App Configuration (key-values and snapshots, for bearer callers only), and Event Grid. Not yet enforced for Storage File, the Service Bus data plane, or Cosmos DB. Azure SQL Database and Azure Database for PostgreSQL/MySQL flexible servers don't use RBAC data actions (their data-plane authorization is Microsoft Entra database authentication), so they're out of scope for RBAC.
- **Key Vault keys:** Only the secrets and certificates data planes are enforced; the keys data plane is not yet implemented.
- **Condition-based assignments:** Attribute-based access control (ABAC) conditions in assignments are accepted at the model level but are not evaluated.
- **Deny assignments:** `Microsoft.Authorization/denyAssignments` are not supported.
- **Management group scopes:** Assignments at management group scope are not supported. Subscription, resource group, and resource scopes are supported, including inheritance down the hierarchy — a role assigned at a broader scope applies to narrower scopes beneath it.
- **Groups and transitive membership:** A role assigned to a group is not expanded to its members; only assignments made directly to the calling principal are evaluated.

## Samples

The following samples demonstrate how to use Azure Role Assignments with LocalStack for Azure:

- [Function App and Service Bus](https://github.com/localstack/localstack-azure-samples/samples/function-app-service-bus/dotnet/README.md)
- [Web App and Cosmos DB for MongoDB API ](https://github.com/localstack/localstack-azure-samples/samples/web-app-cosmosdb-mongodb-api/python/README.md)

## API Coverage


### Role Assignment API coverage

Source service: `role-assignment`. 6 of 7 tracked operations are implemented.

Service documentation: /azure/services/role-assignment/

| Operation | Status |
| --- | --- |
| RoleAssignments.Create | Implemented |
| RoleAssignments.Delete | Implemented |
| RoleAssignments.Get | Implemented |
| RoleAssignments.ListForResource | Not implemented |
| RoleAssignments.ListForResourceGroup | Implemented |
| RoleAssignments.ListForScope | Implemented |
| RoleAssignments.ListForSubscription | Implemented |
