azure-policy-assignment-write-deploy-effect

Write a policy assignment with deployIfNotExists or modify effect, specifying a managed identity (system- or user-assigned) that the remediation engine uses to deploy ARM templates or modify resources. This is modeled as CanModifyConfiguration on the remediation task (BuildWorker): writing the assignment modifies the identity binding and ARM template that the remediation task will execute. Downstream, can-execute-as execute-as-via-config-identity-swap combines this with CanPassIdentity(MI) to derive CanExecuteAs(MI).

derived azure emits CanModifyConfiguration

match (effective permission)

{ "action": "Microsoft.Authorization/policyAssignments/write", "scope_type": "resource|resourceGroup|subscription|managementGroup" }

where

principal effectively holds Microsoft.Authorization/policyAssignments/write at the scope the targeted or new assignment references a policyDefinition or policySetDefinition with at least one deployIfNotExists or modify effect rule the assignment includes a non-empty identity block (system-assigned or user-assigned MI)

emit

source typeIdentity
target typeBuildWorker
source<principal>
target<remediation task (BuildWorker) for the policy assignment>
permissionsMicrosoft.Authorization/policyAssignments/write
conditionsrole_compatibility iam_permission
state logicACTIVE when the principal holds policyAssignments/write at the target scope AND the assignment is confirmed to reference a deployIfNotExists or modify effect definition. For system-assigned MI: no assign/action gate — ACTIVE when policyAssignments/write is confirmed (the system MI is auto-created by ARM). For user-assigned MI: requires Microsoft.ManagedIdentity/userAssignedIdentities/assign/action on the target MI (CanPassIdentity gate); CONDITIONAL(iam_permission) if assign/action is absent or unconfirmed. CONDITIONAL(role_compatibility) if the effect type is not confirmed (could be Deny/Audit only). BLOCKED if a deny assignment covers policyAssignments/write at the scope. Management-group scope affects all descendant subscriptions — higher blast radius, same state logic. Escalation to CanExecuteAs(MI) is derived by can-execute-as execute-as-via-config-identity-swap when CanPassIdentity(principal -> MI) is present; cite that rule, do NOT re-derive here.

Narrative

{principal.name} can write a policy assignment (Microsoft.Authorization/policyAssignments/write) with a deployIfNotExists or modify effect definition and a managed identity attached. The Azure Policy remediation engine deploys ARM templates or modifies resources AS that managed identity; combined with CanPassIdentity on the MI, can-execute-as execute-as-via-config-identity-swap derives CanExecuteAs({principal.name} -> {mi.name}).

Raw rule rules/derived/azure/policy.yaml

id: azure-policy-assignment-write-deploy-effect
emits: CanModifyConfiguration
description: 'Write a policy assignment with deployIfNotExists or modify effect, specifying a managed
  identity (system- or user-assigned) that the remediation engine uses to deploy ARM templates or modify
  resources. This is modeled as CanModifyConfiguration on the remediation task (BuildWorker): writing
  the assignment modifies the identity binding and ARM template that the remediation task will execute.
  Downstream, can-execute-as execute-as-via-config-identity-swap combines this with CanPassIdentity(MI)
  to derive CanExecuteAs(MI).'
match_effective_permission:
  action: Microsoft.Authorization/policyAssignments/write
  scope_type: resource|resourceGroup|subscription|managementGroup
where:
- principal effectively holds Microsoft.Authorization/policyAssignments/write at the scope
- the targeted or new assignment references a policyDefinition or policySetDefinition with at least one
  deployIfNotExists or modify effect rule
- the assignment includes a non-empty identity block (system-assigned or user-assigned MI)
emit:
  source_type: Identity
  target_type: BuildWorker
  source: <principal>
  target: <remediation task (BuildWorker) for the policy assignment>
  permissions:
  - Microsoft.Authorization/policyAssignments/write
  conditions:
  - role_compatibility
  - iam_permission
  state_logic: "ACTIVE when the principal holds policyAssignments/write at the target scope AND the assignment\
    \ is confirmed to reference a deployIfNotExists or modify effect definition. For system-assigned MI:\
    \ no assign/action gate \u2014 ACTIVE when policyAssignments/write is confirmed (the system MI is\
    \ auto-created by ARM). For user-assigned MI: requires Microsoft.ManagedIdentity/userAssignedIdentities/assign/action\
    \ on the target MI (CanPassIdentity gate); CONDITIONAL(iam_permission) if assign/action is absent\
    \ or unconfirmed. CONDITIONAL(role_compatibility) if the effect type is not confirmed (could be Deny/Audit\
    \ only). BLOCKED if a deny assignment covers policyAssignments/write at the scope. Management-group\
    \ scope affects all descendant subscriptions \u2014 higher blast radius, same state logic. Escalation\
    \ to CanExecuteAs(MI) is derived by can-execute-as execute-as-via-config-identity-swap when CanPassIdentity(principal\
    \ -> MI) is present; cite that rule, do NOT re-derive here."
  confidence: 0.9
  derived_from:
  - 'effective permission: Microsoft.Authorization/policyAssignments/write'
  - 'can-execute-as.yaml: execute-as-via-config-identity-swap (CanModifyConfiguration + CanPassIdentity
    => CanExecuteAs)'
  - 'cicd-chains.yaml: cicd-modify-buildspec-executes-as (remediation task is analogous to a build runner)'
  false_positive_note: "ONLY emit when the policy assignment references a deployIfNotExists or modify\
    \ effect definition \u2014 Deny, Audit, and AuditIfNotExists effects do NOT produce execution paths\
    \ (no remediation MI execution occurs). Verify the effect type from the policyDefinition properties.policyRule.then.effect\
    \ field. A CanPassIdentity(principal -> MI) edge is required for can-execute-as to derive CanExecuteAs;\
    \ without it, this edge is a governance-write capability, not a confirmed escalation. The remediation\
    \ MI must also hold RBAC (via roleDefinitionIds granted at assignment scope) to perform meaningful\
    \ actions as that MI \u2014 an MI with no granted role yields execution but no elevated capability.\
    \ Do NOT emit for built-in definitions that use deployIfNotExists but that an attacker cannot modify\
    \ (e.g., Microsoft Defender-provisioned assignments the attacker did not create). Only emit when policyAssignments/write\
    \ is the attacker's actual capability. policyAssignments/write at resource-group scope only creates\
    \ assignments for that RG; scope the edge accordingly."
  narrative: '{principal.name} can write a policy assignment (Microsoft.Authorization/policyAssignments/write)
    with a deployIfNotExists or modify effect definition and a managed identity attached. The Azure Policy
    remediation engine deploys ARM templates or modifies resources AS that managed identity; combined
    with CanPassIdentity on the MI, can-execute-as execute-as-via-config-identity-swap derives CanExecuteAs({principal.name}
    -> {mi.name}).'
move · open · esc close