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.

derived azure emits CanGrantPermission

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'principal': None} HasPermission {'mg': None}

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 typeIdentity
target typeIdentity
source?principal
target?principal
permissionsMicrosoft.Authorization/roleAssignments/write
conditionsiam_permission deny_assignment
state logicACTIVE 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.'
move · open · esc close