azure-sub-contributor-administers

Contributor at a subscription/RG can create, modify, and delete resources under it, but cannot assign RBAC.

derived azure emits CanAdminister

match

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

{'principal': None} HasPermission {'scope': None}

where

node_class(?scope) == AdministrativeBoundary and node_type(?scope) in [Subscription, ResourceGroup] ?principal has EFFECTIVE actions '*' at ?scope MINUS Microsoft.Authorization/*/write and .../elevateAccess/action (Contributor b24988ac-6180-42a0-ab88-20f7382dd24c) ?principal does NOT hold Microsoft.Authorization/roleAssignments/write at ?scope

emit

source typeIdentity
target type*
source?principal
target?scope
permissions*
conditionsdeny_assignment condition_expression
state logicACTIVE when the Contributor assignment is unconditional and active; CONDITIONAL(condition_expression) with an ABAC condition or CONDITIONAL(pim_activation) for an eligible PIM assignment; BLOCKED where a deny assignment / deny Azure Policy covers the write actions at/above ?scope (honoring excludePrincipals / doNotApplyToChildScopes). Upgrade of a BLOCKED edge is deferred to hierarchy-chains guardrail-removal-upgrades-blocked.

Narrative

{principal.name} holds Contributor at {scope.name} and can create, modify, and delete resources under it (but cannot assign RBAC, so cannot self-grant Owner).

Raw rule rules/derived/azure/subscriptions.yaml

id: azure-sub-contributor-administers
emits: CanAdminister
description: Contributor at a subscription/RG can create, modify, and delete resources under it, but cannot
  assign RBAC.
match:
- - principal: null
  - HasPermission
  - scope: null
where:
- node_class(?scope) == AdministrativeBoundary and node_type(?scope) in [Subscription, ResourceGroup]
- ?principal has EFFECTIVE actions '*' at ?scope MINUS Microsoft.Authorization/*/write and .../elevateAccess/action
  (Contributor b24988ac-6180-42a0-ab88-20f7382dd24c)
- ?principal does NOT hold Microsoft.Authorization/roleAssignments/write at ?scope
emit:
  source_type: Identity
  target_type: '*'
  source: ?principal
  target: ?scope
  permissions:
  - '*'
  conditions:
  - deny_assignment
  - condition_expression
  state_logic: ACTIVE when the Contributor assignment is unconditional and active; CONDITIONAL(condition_expression)
    with an ABAC condition or CONDITIONAL(pim_activation) for an eligible PIM assignment; BLOCKED where
    a deny assignment / deny Azure Policy covers the write actions at/above ?scope (honoring excludePrincipals
    / doNotApplyToChildScopes). Upgrade of a BLOCKED edge is deferred to hierarchy-chains guardrail-removal-upgrades-blocked.
  confidence: '0.9'
  derived_from:
  - <HasPermission edge_id (Contributor / '*' minus Authorization/*/write @scope)>
  false_positive_note: "CRITICAL: Contributor CANNOT assign RBAC \u2014 never emit CanGrantPermission\
    \ or Controls for it. It yields management-plane control over resources (create/ modify/delete/deploy)\
    \ that inherits down the tree, but it cannot self-escalate to Owner via role assignment. Its only\
    \ escalation is Phase-4 deploy-with-MI (see vm.yaml/functions.yaml), NOT modelled here. Do not fire\
    \ if the principal also holds roleAssignments/write (that is Owner/UAA -> the grant rules)."
  narrative: '{principal.name} holds Contributor at {scope.name} and can create, modify, and delete resources
    under it (but cannot assign RBAC, so cannot self-grant Owner).'
move · open · esc close