azure-mi-role-assignment

explicit azure emits HasRole

match (record)

{ "condition": "principalType == \u0027ServicePrincipal\u0027 and principalId matches a MI principalId", "field": "principalId", "resource_type": "Microsoft.Authorization/roleAssignments" }

emit

source typeManagedIdentity
target typeRole
source<managed identity (resolved from principalId)>
target<role definition at the assigned scope>

Narrative

Managed identity {mi.name} holds {role.name} at scope {scope} - any bearer token for {mi.name} carries these ARM RBAC permissions.

Raw rule rules/explicit/azure-managedidentity.yaml

id: azure-mi-role-assignment
emits: HasRole
applies_to:
- azure
match_record:
  resource_type: Microsoft.Authorization/roleAssignments
  field: principalId
  condition: principalType == 'ServicePrincipal' and principalId matches a MI principalId
emit:
  source_type: ManagedIdentity
  target_type: Role
  source: <managed identity (resolved from principalId)>
  target: <role definition at the assigned scope>
  api_source: az role assignment list --assignee <mi-objectId> --all-namespaces
  evidence_field: principalId, roleDefinitionId, scope
  note: Resolve principalId -> MI node via the Entra SP object (principalType == 'ServicePrincipal', servicePrincipalType
    == 'ManagedIdentity'). The scope on the role assignment determines whether this is same-subscription
    or cross-subscription (cross-subscription feeds azure-mi-cross-subscription-rbac in managedidentity.yaml).
    PIM-eligible assignments (not-active) should be emitted as CONDITIONAL(iam_permission).
  narrative: "Managed identity {mi.name} holds {role.name} at scope {scope} \u2014 any bearer token for\
    \ {mi.name} carries these ARM RBAC permissions."
move · open · esc close