Trigger policy remediation only on assignment change¶
Context and Problem Statement¶
Every terraform apply destroys and recreates all policy remediation resources (~1000+) because a null_resource with timestamp() feeds into replace_triggered_by. This dominates plan and apply output, slows down runs, and obscures meaningful changes.
Decision Drivers¶
- Apply output is dominated by remediation destroy/create cycles, hiding real infrastructure changes.
- Hundreds of unnecessary Azure API calls per apply increase run time and risk throttling.
- Policy remediations are one-shot tasks; re-creating them when nothing changed adds no value.
- Azure Policy evaluates compliance on its own cycle and can trigger remediation independently.
Considered Options¶
- Remove
replace_triggered_byentirely and rely on Terraformfor_eachdiff plus Azure Policy evaluation. - Replace
timestamp()trigger withreplace_triggered_byreferencing the policy assignment resource. - Create a single remediation per assignment without
policy_definition_reference_id. - Move remediation to a separate Terraform configuration or CI step.
Decision Outcome¶
Chosen option: "Replace timestamp() trigger with replace_triggered_by referencing the policy assignment resource", because it eliminates unnecessary churn while re-triggering remediations whenever the assignment is updated or replaced.
Per the Terraform replace_triggered_by documentation, a reference to a single resource instance triggers replacement when that instance is planned for update or replace -- not only on replacement. This means in-place changes to parameters, enforce, not_scopes, etc. also re-trigger all remediations for that assignment.
Consequences¶
- Good, because it eliminates ~1000+ destroy/create cycles on every apply.
- Good, because remediations are re-triggered when the assignment changes, including in-place updates (parameters, enforcement, scopes).
- Good, because new policy definitions added to a set are handled by Terraform's
for_eachdiff without needing the trigger. - Neutral, because Azure Policy's own evaluation cycle continues to handle ongoing compliance independently.
- Bad, because new non-compliant resources appearing without a config change do not receive an immediate Terraform-triggered remediation.
Validation¶
- Terraform plan on an unchanged environment shows zero remediation changes.
- Terraform plan after modifying a policy assignment (e.g.
parametersorenforce) shows remediation replacements for that assignment only. - Azure Portal confirms remediation tasks are created when assignments change.
Pros and Cons of the Options¶
Remove replace_triggered_by entirely¶
- Good, because it is the simplest change.
- Good, because Terraform
for_eachdiff still handles added or removed policy definitions in the set. - Bad, because modifying assignment parameters (enforcement, scopes) would not re-trigger existing remediations.
Replace timestamp() trigger with replace_triggered_by referencing the policy assignment resource¶
- Good, because it ties remediation lifecycle directly to the assignment that owns it.
- Good, because it covers both in-place updates and replacements of the assignment.
- Good, because blast radius is limited to the changed assignment.
- Neutral, because it still replaces all remediations for a changed assignment, even if only one parameter changed.
Create a single remediation per assignment without policy_definition_reference_id¶
- Good, because it would reduce resource count from N-per-set to 1-per-assignment.
- Bad, because Azure requires
policy_definition_reference_idfor policy set definition remediations; omitting it is not supported.
Move remediation to a separate Terraform configuration or CI step¶
- Good, because it decouples remediation lifecycle from infrastructure apply.
- Bad, because it adds operational complexity and a second state file to manage.
- Bad, because it breaks the co-location of assignment and remediation logic.