Skip to content

Test a policy change

A policy change is a Terraform change on one unit, live/_foundation/landing-zones/. You test it the same way you test any change in the platform: plan on a branch, read the diff, then apply. The difference is that the diff shows Azure Policy assignments, definitions, and sets rather than infrastructure.

Local plan

Run against the management subscription, from the unit folder. mise pins the Terraform and Terragrunt versions for the repo.

cd live/_foundation/landing-zones
terragrunt plan

The alz provider downloads the library into .alzlib and reads the live management group hierarchy through a data source at plan time. Keep .alzlib in .gitignore.

Read the plan before applying:

  • A parameter or effect change shows as an update to a azurerm_management_group_policy_assignment (or the azapi equivalent), with the parameter value changing in place.
  • creation_enabled = false shows the assignment being destroyed.
  • A new library definition or set shows as a create.

Through a pull request

The normal path is a pull request, so the change runs through the platform and posts its plan on the PR. Open a PR that touches landing-zones/, let discovery plan it, and review the plan in the run comment. The policy, security, and cost gates run on the plan as usual. Comment /apply once the plan is approved. See Plan and apply for the command flow.

Rollout discipline

Land the change advisory first, confirm compliance data, then enforce. Keep one control per pull request so the plan stays readable and reversible. A parameter or effect change reverts by restoring the previous value and applying again.

Worked example

A parameter change is the reliable end-to-end test: it always shows in the plan. On a branch, flip one tag effect from Audit to Deny on the tag-governance assignment in landing-zones/main.tf:

Enforce-Tag-Gov = {
  parameters = {
    environmentEffect = jsonencode({ value = "Deny" })
  }
}

The plan is a single in-place update to the assignment on the intermediate root. Nothing else changes: no management group, definition, or set is touched.

  # module.management_groups...azapi_resource.policy_assignments["Enforce-Tag-Gov"] will be updated in-place
  ~ resource "azapi_resource" "policy_assignments" {
      ~ body = {
          ~ properties = {
              ~ parameters = {
                  ~ environmentEffect = { value = "Audit" -> "Deny" }
                }
            }
        }
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Review the plan, comment /apply, then check the assignment in the Azure Policy compliance view. Revert by restoring Audit and applying again. Roll a real control out advisory-first: land it on Audit, confirm compliance, then move to Deny.

Not every attribute round-trips

Some assignment attributes do not produce a plan diff on an already-applied assignment in the current provider version. A non-compliance message change, for example, can plan as no change even though the input is valid. Always confirm your specific edit shows in the plan before you rely on it. Parameter and effect changes are the reliable signal.