Create Azure RBAC resources by using Bicep

Azure has a powerful role-based access control (RBAC) system. For more information on Azure RBAC, see What is Azure Role-based access control (Azure RBAC)? By using Bicep, you can programmatically define your RBAC role assignments and role definitions.

Role assignments

Role assignments enable you to grant a principal (such as a user, a group, or a service principal) access to a specific Azure resource.

To define a role assignment, create a resource with type Microsoft.Authorization/roleAssignments. A role definition has multiple properties, including a scope, a name, a role definition ID, a principal ID, and a principal type.

Scope

Role assignments apply at a specific scope, which defines the resource or set of resources that you're granting access to. For more information, see Understand scope for Azure RBAC.

Role assignments are extension resources, which means they apply to another resource. The following example shows how to create a storage account and a role assignment scoped to that storage account:

param location string = resourceGroup().location
param storageAccountName string = 'stor${uniqueString(resourceGroup().id)}'
param storageSkuName string = 'Standard_LRS'
param roleDefinitionResourceId string
param principalId string

resource storageAccount 'Microsoft.Storage/storageAccounts@2021-04-01' = {
  name: storageAccountName
  location: location
  kind: 'StorageV2'
  sku: {
   name: storageSkuName
  }
}

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  scope: storageAccount
  name: guid(storageAccount.id, principalId, roleDefinitionResourceId)
  properties: {
    roleDefinitionId: roleDefinitionResourceId
    principalId: principalId
    principalType: 'ServicePrincipal'
  }
}

If you don't explicitly specify the scope, Bicep uses the file's targetScope. In the following example, no scope property is specified, so the role assignment is scoped to the subscription:

param roleDefinitionResourceId string
param principalId string

targetScope = 'subscription'

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  name: guid(subscription().id, principalId, roleDefinitionResourceId)
  properties: {
    roleDefinitionId: roleDefinitionResourceId
    principalId: principalId
    principalType: 'ServicePrincipal'
  }
}

Tip

Use the smallest scope that you need to meet your requirements.

For example, if you need to grant a managed identity access to a single storage account, it's good security practice to create the role assignment at the scope of the storage account, not at the resource group or subscription scope.

Name

A role assignment's resource name must be a globally unique identifier (GUID).

Role assignment resource names must be unique within the Microsoft Entra tenant, even if the scope is narrower.

For your Bicep deployment to be repeatable, it's important for the name to be deterministic - in other words, to use the same name every time you deploy. It's a good practice to create a GUID that uses the scope, principal ID, and role ID together. It's a good idea to use the guid() function to help you to create a deterministic GUID for your role assignment names, like in this example:

name: guid(subscription().id, principalId, roleDefinitionResourceId)

Role definition ID

The role you assign can be a built-in role definition or a custom role definition. To use a built-in role definition, find the appropriate role definition ID. For example, the Contributor role has a role definition ID of b24988ac-6180-42a0-ab88-20f7382dd24c.

When you create the role assignment resource, you need to specify a fully qualified resource ID. Built-in role definition IDs are subscription-scoped resources. It's a good practice to use an existing resource to refer to the built-in role, and to access its fully qualified resource ID by using the .id property:

param principalId string

@description('This is the built-in Contributor role. See https://docs.azure.cn/role-based-access-control/built-in-roles#contributor')
resource contributorRoleDefinition 'Microsoft.Authorization/roleDefinitions@2018-01-01-preview' existing = {
  scope: subscription()
  name: 'b24988ac-6180-42a0-ab88-20f7382dd24c'
}

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  name: guid(resourceGroup().id, principalId, contributorRoleDefinition.id)
  properties: {
    roleDefinitionId: contributorRoleDefinition.id
    principalId: principalId
    principalType: 'ServicePrincipal'
  }
}

Principal

The principalId property must be set to a GUID that represents the Microsoft Entra identifier for the principal. In Microsoft Entra ID, this is sometimes referred to as the object ID.

The principalType property specifies whether the principal is a user, a group, or a service principal. Managed identities are a form of service principal.

Tip

It's important to set the principalType property when you create a role assignment in Bicep. Otherwise, you might get intermittent deployment errors, especially when you work with service principals and managed identities.

The following example shows how to create a user-assigned managed identity and a role assignment:

param location string = resourceGroup().location
param roleDefinitionResourceId string

var managedIdentityName = 'MyManagedIdentity'

resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = {
  name: managedIdentityName
  location: location
}

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = {
  name: guid(resourceGroup().id, managedIdentity.id, roleDefinitionResourceId)
  properties: {
    roleDefinitionId: roleDefinitionResourceId
    principalId: managedIdentity.properties.principalId
    principalType: 'ServicePrincipal'
  }
}

Resource deletion behavior

When you delete a user, group, service principal, or managed identity from Microsoft Entra ID, it's a good practice to delete any role assignments. They aren't deleted automatically.

Any role assignments that refer to a deleted principal ID become invalid. If you try to reuse a role assignment's name for another role assignment, the deployment will fail. To work around this behavior, you should either remove the old role assignment before you recreate it, or ensure that you use a unique name when you deploy a new role assignment. This quickstart template illustrates how you can define a role assignment in a Bicep module and use a principal ID as a seed value for the role assignment name.

Custom role definitions

Custom role definitions enable you to define a set of permissions that can then be assigned to a principal by using a role assignment. For more information on role definitions, see Understand Azure role definitions.

To create a custom role definition, define a resource of type Microsoft.Authorization/roleDefinitions. See the Create a new role def via a subscription level deployment quickstart for an example.

Note

Some services manage their own role definitions and assignments. For example, Azure Cosmos DB maintains its own Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments and Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions resources. For more information, see the specific service's documentation.