Manage Microsoft Entra (Azure AD) directory roles: activate built-in roles, define custom directory roles, and assign either to users, groups or service principals, with optional scoping. The companion to terraform-azuread-service-principal for the directory-RBAC side of identity.
module "role_assignment" {
source = "libre-devops/role-assignment/azuread"
version = "~> 4.0"
activated_directory_roles = {
reader = { display_name = "Directory Readers" }
}
role_assignments = {
ci-reader = {
directory_role_key = "reader"
principal_object_id = "00000000-0000-0000-0000-000000000000" # a user, group or SP object id
}
}
}A role assignment points at its role in exactly one of three ways:
directory_role_key- a key fromactivated_directory_roles(assigns a built-in role by its template id)custom_role_key- a key fromcustom_directory_roles(assigns a custom role by its object id)role_id- a raw template id (built-in) or object id (custom), for roles managed elsewhere
graph_app_role_grants grants Microsoft Graph application permissions (admin consent) to
EXISTING principals, which is the shape managed identities need: a Logic App, Function App,
automation, or VM identity doing app-only Graph has no app registration of its own, so the
service-principal module's in-call grants cannot reach it and directory roles are the wrong tool.
Permissions are written as names and resolved against the tenant's Graph service principal:
module "graph_grants" {
source = "libre-devops/role-assignment/azuread"
version = "~> 4.2"
graph_app_role_grants = {
"logic-app-mi" = {
principal_object_id = module.logic_app_workflow.identities["logic-ldo-uks-prd-001"].principal_id
role_names = ["ServiceMessage.Read.All", "Tasks.ReadWrite.All"]
}
}
}A check block flags escalation-capable permissions (Directory.ReadWrite.All,
RoleManagement.ReadWrite.Directory, Application.ReadWrite.All, AppRoleAssignment.ReadWrite.All;
the set is caller-extendable) so a privileged grant is always a visible decision, never a quiet one.
Managing directory roles (activation, custom roles and assignments) needs the running principal to
hold Microsoft Graph RoleManagement.ReadWrite.Directory, that is the Privileged Role
Administrator directory role. graph_app_role_grants additionally needs
AppRoleAssignment.ReadWrite.All (each grant IS tenant-wide admin consent). A check block flags any
attempt to touch Global Administrator so it is never assigned by accident.
examples/minimal- the smallest valid call: one custom directory role.examples/complete- activate a built-in role, create a custom role, and assign both to a principal; plus a user-assigned managed identity granted a benign Graph application permission by name throughgraph_app_role_grants.
| Name | Version |
|---|---|
| terraform | >= 1.9.0, < 2.0.0 |
| azuread | >= 3.0.0, < 4.0.0 |
| Name | Version |
|---|---|
| azuread | >= 3.0.0, < 4.0.0 |
No modules.
| Name | Type |
|---|---|
| azuread_app_role_assignment.graph | resource |
| azuread_custom_directory_role.this | resource |
| azuread_directory_role.this | resource |
| azuread_directory_role_assignment.this | resource |
| azuread_application_published_app_ids.well_known | data source |
| azuread_client_config.current | data source |
| azuread_service_principal.msgraph | data source |
| Name | Description | Type | Default | Required |
|---|---|---|---|---|
| activated_directory_roles | Built-in Entra (Azure AD) directory roles to activate in the tenant, keyed by a stable logical name. Built-in roles exist from templates but are dormant until activated; activating one exports its object id so assignments can be made against it. Reference an entry from role_assignments with directory_role_key. Provide exactly one of display_name or template_id per entry. |
map(object({ |
{} |
no |
| custom_directory_roles | Custom Entra directory roles to create, keyed by a stable logical name. Each carries one or more permissions blocks listing allowed_resource_actions (see the Microsoft permissions reference). Reference an entry from role_assignments with custom_role_key. |
map(object({ |
{} |
no |
| graph_app_role_grants | Microsoft Graph APPLICATION permission grants (admin consent) to EXISTING principals, keyed by a logical label you choose. This is the managed-identity shape the rest of the family cannot reach: a Logic App, Function App, automation, or VM identity that needs app-only Graph has no app registration of its own, so the service-principal module's in-call grants cannot target it, and directory roles are the wrong tool. role_names take Graph permission names(ServiceMessage.Read.All) and resolve against the tenant's Microsoft Graph service principal, so configuration reads like the permission reference rather than GUID soup; role_ids take explicitapp role GUIDs for anything unusual. Each grant IS tenant-wide admin consent, and creating one needs AppRoleAssignment.ReadWrite.All (or Global Administrator) on the applier. |
map(object({ |
{} |
no |
| privileged_graph_app_role_ids | Graph application permissions treated as privileged by the warning check (name => app role GUID on the Microsoft Graph service principal): each one is escalation-capable, able to grant or rewrite its way to broader tenant control. Extend this to treat more permissions as privileged. |
map(string) |
{ |
no |
| role_assignments | Directory role assignments to create, keyed by a stable logical name. Each assigns one role to one principal (a user, group or service principal object id), optionally scoped to a single directory object (directory_scope_id) or an application-specific scope (app_scope_id). Reference the role in exactly one of three ways: - directory_role_key: a key from activated_directory_roles (assigns the built-in by template id) - custom_role_key: a key from custom_directory_roles (assigns the custom role by object id) - role_id: a raw template id (built-in) or object id (custom), for roles managed elsewhere |
map(object({ |
{} |
no |
| Name | Description |
|---|---|
| activated_directory_role_object_ids | Map of activated built-in directory role key to its object id. |
| activated_directory_role_template_ids | Map of activated built-in directory role key to its template id (the value used when assigning a built-in role). |
| custom_directory_role_object_ids | Map of custom directory role key to its object id (the value used when assigning a custom role). |
| custom_directory_roles | Map of custom directory role key to its useful attributes. |
| graph_app_role_grant_ids | Map of grant instance key (label|permission) to the app role assignment id. |
| role_assignment_ids | Map of role assignment key to the directory role assignment id. |