Skip to content

Azure Policy

The landing zone governs itself with Azure Policy. One module, the ALZ pattern module, builds the whole management group hierarchy and assigns the policy that governs every subscription placed into it. This section explains how that policy is put together and the two layers where you customize it.

This is Azure Policy, the platform's preventive and detective governance. It is a different thing from the policy, security, and cost gates, which run conftest, checkov, and infracost against a Terraform plan in a pull request. The gates check code before it applies. Azure Policy governs resources once they exist.

How policy reaches a management group

All of it flows through a single unit in the landing-zone repository, _foundation/landing-zones/, which sources Azure/avm-ptn-alz/azurerm. The module reads a library through the alz provider, builds the management groups from an architecture, and assigns policy to each group from the archetypes attached to it.

flowchart LR
  L[ALZ library<br/>definitions, sets,<br/>assignments, archetypes,<br/>architecture] -->|alz provider<br/>library_references| P[avm-ptn-alz]
  P --> H[Management group<br/>hierarchy]
  P --> A[Policy assignments<br/>on each MG]
  M[policy_assignments_to_modify<br/>policy_default_values] -.tune.-> A

The library is layered. The provider reads the stock Azure Landing Zones library first, then your own library on top. The reference implementation vendors its library into the landing-zones unit at lib/ and points the provider at it with get_terragrunt_dir(), so there is no external dependency to resolve at plan time:

provider "alz" {
  library_overwrite_enabled = true
  library_references = [
    { path = "platform/alz", ref = "2026.04.2" },
    { custom_url = "${get_terragrunt_dir()}/lib" },
  ]
}

A git reference to a shared catalog is the alternative when you want one library across many repos: { custom_url = "git::https://github.com/<org>/<catalog>.git//library/<path>?ref=<tag>" }.

References are read in order, so your library comes last and wins. library_overwrite_enabled lets one of your assets replace a stock asset of the same name. Everything in the combined library must be uniquely named otherwise.

What lives where

Piece Location Owns
Module consumption and live tuning the landing-zone repo, _foundation/landing-zones/main.tf Which assignments to modify, and the default values fed to them.
Provider and library pin the same unit's terragrunt.hcl The stock library ref and the local lib/ path (or a git catalog ref).
Your custom library vendored in the unit at landing-zones/lib/ (or a shared catalog repo) Your architecture, archetypes, and your own definitions, sets, and assignments.

The two customization layers

There are two places to change policy, and the right one depends on what you are changing.

Layer Where Use it to
In-repo tuning policy_assignments_to_modify and policy_default_values in landing-zones/main.tf Change parameters, effects, enforcement mode, non-compliance messages, scope exclusions, or disable a single assignment. Fast, no library release.
In-library authoring the vendored lib/ (or your shared catalog, then bump its ref) Add or replace a policy definition, an initiative, an assignment, an archetype, or reshape the management group hierarchy.

Reach for in-repo tuning first. It needs no library release and it is the module's designed seam for per-tenant differences. Author in the library when the change is structural or you want it to ship to every client that consumes the library.

The recipes for both are in Customizing policies.

The reference baseline

Out of the box the stock archetypes assign the Microsoft cloud security benchmark and the ALZ policy set to the intermediate root, and the corp, online, and platform archetypes layer their own assignments below.

The starter library ships one worked example on top of that: a tag-governance archetype attached to the intermediate root, which assigns a baseline tagging strategy (mandatory tags on resource groups with allowed values, and tag inheritance from subscription and resource group). Its tag keys follow the Microsoft Cloud Adoption Framework tag examples (app, env, opsteam, costcenter, businessunit, criticality, confidentiality). Treat it as the template for your own controls: adapt the tags, values, and scope per client.

The example effects start in Audit and move to Deny once the estate is clean. That advisory-first rollout is a deliberate governance pattern, and it maps to the CAF Govern methodology (policy-driven guardrails introduced without blocking existing workloads) and the WAF Operational Excellence pillar (change landed safely). Moving to Deny then serves WAF Security and Cost Optimization, since untagged and misclassified resources are prevented rather than reported.

Next: Customizing policies.