azure-mg-roleassignment-write
Ability to assign RBAC at a management group scope (Owner / User Access Administrator) is a boundary-scoped self-grant over the whole subtree.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?mg) ==
ManagementGroup
?principal effectively holds Microsoft.Authorization/roleAssignments/write at ?mg scope (Owner or User Access Administrator, or a custom role granting it)
emit
| source type | Identity |
|---|---|
| target type | Identity |
| source | ?principal |
| target | ?principal |
| permissions | Microsoft.Authorization/roleAssignments/write |
| conditions | iam_permission deny_assignment |
| state logic | ACTIVE when roleAssignments/write is unconditionally held at ?mg; CONDITIONAL(iam_permission) when PIM-eligible-not-active or condition-gated; BLOCKED when a deny assignment on Microsoft.Authorization/roleAssignments/write applies at the scope (until guardrail-removal-upgrades-blocked lifts it). This self-grant CanGrantPermission scoped at ?mg feeds can-control.yaml control-boundary-via-iam-admin (scope_of -> boundary -> Controls(?mg)) and hierarchy-chains.yaml grant-at-boundary-controls-descendants -> whole subtree; the descendant CanEnterSubscription roll-ups are produced there, NOT here. |
Narrative
{principal.name} can assign roles at management group {mg.name} (Microsoft.Authorization/roleAssignments/write via Owner / User Access Administrator) and can therefore grant itself Owner of {mg.name} and everything nested beneath it.
Raw rule rules/derived/azure/mgmtgroups.yaml
id: azure-mg-roleassignment-write
emits: CanGrantPermission
description: Ability to assign RBAC at a management group scope (Owner / User Access Administrator) is
a boundary-scoped self-grant over the whole subtree.
match:
- - principal: null
- HasPermission
- mg: null
where:
- node_type(?mg) == ManagementGroup
- ?principal effectively holds Microsoft.Authorization/roleAssignments/write at ?mg scope (Owner or User
Access Administrator, or a custom role granting it)
emit:
source_type: Identity
target_type: Identity
source: ?principal
target: ?principal
scope: ?mg
permissions:
- Microsoft.Authorization/roleAssignments/write
conditions:
- iam_permission
- deny_assignment
state_logic: ACTIVE when roleAssignments/write is unconditionally held at ?mg; CONDITIONAL(iam_permission)
when PIM-eligible-not-active or condition-gated; BLOCKED when a deny assignment on Microsoft.Authorization/roleAssignments/write
applies at the scope (until guardrail-removal-upgrades-blocked lifts it). This self-grant CanGrantPermission
scoped at ?mg feeds can-control.yaml control-boundary-via-iam-admin (scope_of -> boundary -> Controls(?mg))
and hierarchy-chains.yaml grant-at-boundary-controls-descendants -> whole subtree; the descendant
CanEnterSubscription roll-ups are produced there, NOT here.
confidence: min(contributing_confidences)
derived_from:
- <HasPermission principal->mg (roleAssignments/write @ MG) edge_id>
false_positive_note: "Microsoft.Authorization/roleAssignments/write is held ONLY by Owner and User Access\
\ Administrator (per the overview role table) \u2014 NOT by Contributor or Management Group Contributor.\
\ Do not fire on Contributor. Edge is a self-grant (source==target==principal) carrying scope=?mg;\
\ the boundary-scoped meaning lives in scope, and can-control.yaml control-boundary-via-iam-admin\
\ turns it into Controls(?mg) \u2014 never point CanGrantPermission at the MG boundary node (schema\
\ target=[Identity] only). A grant scoped to a single distinct principal/resource is the generic identity-escalation\
\ primitive (azure/identity-escalation.yaml azure-role-assignment-write); this rule is the MG-scope\
\ specialization \u2014 dedupe on (CanGrantPermission, principal, MG scope)."
narrative: '{principal.name} can assign roles at management group {mg.name} (Microsoft.Authorization/roleAssignments/write
via Owner / User Access Administrator) and can therefore grant itself Owner of {mg.name} and everything
nested beneath it.'