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).
match (effective permission)
where
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 — 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}).'