Bicep Role Assignments

A role assignment gives an identity permission to act on an Azure resource. A web app that reads files from storage needs such a permission. Bicep creates both the identity and the permission, so no person ever copies a password into the app.

Think of an office badge system. Each badge belongs to one person, and the badge opens only certain doors. A managed identity is the badge, a role is the list of doors, and the role assignment is the act of programming the badge.

The Three Parts

  Who?                 What can they do?          Where?
 ┌──────────────┐     ┌───────────────────┐     ┌───────────────┐
 │ Managed      │  +  │ Role              │  +  │ Scope         │
 │ identity     │     │ (Storage Blob     │     │ (one storage  │
 │ (principal)  │     │ Data Contributor) │     │ account)      │
 └──────────────┘     └───────────────────┘     └───────────────┘
              └───────────── Role assignment ─────────────┘

Create a Managed Identity

A system-assigned identity lives and dies with its resource. Turn it on with one property.

resource webApp 'Microsoft.Web/sites@2023-01-01' = {
  name: 'app-shop-001'
  location: 'eastus'
  identity: {
    type: 'SystemAssigned'
  }
  properties: {
    serverFarmId: plan.id
  }
}

A user-assigned identity exists as its own resource and serves several apps at once.

resource appIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
  name: 'id-shop'
  location: 'eastus'
}

Assign a Role

Each built-in role has a fixed ID. The assignment name must be a GUID, and the guid() function builds a stable one from the scope, identity, and role.

var storageBlobContributor = 'ba92f5b4-2d11-453d-a403-e96b0029c9fe'

resource roleAssign 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(storage.id, webApp.id, storageBlobContributor)
  scope: storage
  properties: {
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', storageBlobContributor)
    principalId: webApp.identity.principalId
    principalType: 'ServicePrincipal'
  }
}

The scope: storage line limits the permission to that single storage account. The app cannot touch any other resource.

Common Built-In Roles

RoleRole IDGives
Readeracdd72a7-3385-48ef-bd42-f606fba81ae7View resources
Contributorb24988ac-6180-42a0-ab88-20f7382dd24cCreate and edit resources
Storage Blob Data Contributorba92f5b4-2d11-453d-a403-e96b0029c9feRead and write blob data

Principle of Least Privilege

Grant the smallest role at the smallest scope. A reader role on one resource beats a contributor role on the whole subscription. Narrow permissions limit damage when something goes wrong.

Requirements to Deploy Role Assignments

The deploying account needs permission to write role assignments, such as the Role Based Access Control Administrator role or the Owner role at the target scope. A deployment with only Contributor rights fails with an authorization message.

Why Managed Identities Beat Stored Passwords

A password in a configuration file can leak through a screenshot, a backup, or a shared repository. A managed identity has no password to leak. Azure issues short-lived tokens to the app automatically and rotates them without human effort. Removing an app removes its identity, so no orphaned credentials remain.

Assigning Roles to People and Groups

Role assignments work for users and groups as well. Pass the object ID of the person or group as principalId, and set principalType to User or Group. Groups keep the template short, because adding a person to the group grants access without a code change.

Summary

Role assignments connect an identity, a role, and a scope. Managed identities remove stored passwords, and guid() creates stable assignment names. Least privilege keeps access narrow, and the deploying account needs rights to write role assignments.