Hey, Azure Guy!

Azure Policy at Scale, Part 1: EPAC or native ALZ? Asking a better question

Written in a personal capacity. I work as a Microsoft Cloud Solution Architect, but this series is my own research and my own opinion. It is not an official Microsoft position.

This is Part 1 of a series called Azure Policy at Scale: Native ALZ Governance vs EPAC. I have wanted to write it for a long time. It is one of the few technical questions where I keep hearing confident answers that contradict each other, and where the people giving those answers are all competent and all acting in good faith.

The question sounds simple: if you are running Azure Landing Zones, should you manage Azure Policy with the native tooling, or with Enterprise Policy as Code (EPAC)?

I should say up front how this series started. I set out to argue that Microsoft had left customers without guidance on this decision, and partway through the research I found the guidance. It is published on Microsoft Learn and it is reasonably clear. That changed the article I was writing, and I have left the correction visible rather than quietly rewriting history.

The trigger

Two things pushed me into this.

The first is that there are genuinely different views on this, including inside Microsoft. I am not going to characterise anyone else’s position or quote internal material, because that would be both inappropriate and unverifiable for you as a reader. What I can say is that in my own conversations with colleagues, and in customer engagements, I have heard the native path and the EPAC path each described as the obvious choice, sometimes in the same week.

The second is more concrete, and you can check it yourself. Both approaches live in repositories under the same Azure/ GitHub organisation:

If you are a customer or a partner, that is a confusing signal: two well-maintained approaches to the same problem, in the same organisation, with no obvious signpost telling you which one is meant for you. It comes up in customer conversations regularly.

Why the usual framing fails

The debate is almost always held as a tooling comparison: which one deploys policy better?

I think that question is largely settled. Both approaches can do the basics. Both can manage policy definitions, initiatives (policy set definitions) and assignments. Both can handle exemptions as Azure resources. Both can run in a pipeline. Both are open source. Both are actively maintained.

The feature-checklist version of this argument therefore produces long tables that convince nobody, because whichever tool you already prefer will win on the criteria you chose to put in the table. I have read several of those comparisons, and I wrote a first draft of one myself before throwing it away.

A good deal of what gets compared is also simply out of date, which I come back to later in this post.

The reframe

I would rather ask:

When does native ALZ policy governance suffice, and when do additional governance and operational requirements justify introducing EPAC as a separate policy operating model?

The thesis this series builds toward:

EPAC is not “ALZ Policy, but for grown-ups”. It is a different category of thing.

EPAC is a policy lifecycle and operations engine. The native ALZ path is a landing zone implementation that includes policy. Comparing them directly is a category error, and I think a good deal of the confusion follows from it.

That leads to the question the rest of the series is really about:

The question is no longer whether native Azure Landing Zones can manage Azure Policy at scale. The real question is whether Azure Policy needs to become a separately operated governance product in your organisation.

That is an architecture question rather than a tooling preference, and the answer differs per organisation.

The thing almost nobody quotes

Microsoft publishes decision guidance for exactly this choice. I had planned to write that no such guidance existed, and I was wrong about that.

It sits in the Azure Architecture Center article Deploy Azure landing zones, in a section titled Enterprise policy as code for policy management. EPAC is described there as:

“Enterprise policy as code (EPAC) is an alternative method to deploy, manage, and operate Azure Policy across your organization’s Azure estate. You can use EPAC instead of the standard platform options to manage the policies in an Azure landing zone environment.”

The next paragraph is the one I think matters most in this entire discussion:

“Compare the life cycle and flexibility of the two approaches before you decide on what approach to use long term. Begin by evaluating the native policy management in the default implementation. If that implementation doesn’t meet your governance needs, then do a minimum viable product (MVP) or proof of concept by using EPAC. Compare options, validate your findings, and confirm your choice before you implement an approach because you can’t easily change policy governance methods after you establish them.”

That is a complete decision sequence:

  1. Evaluate the native policy management in the default implementation first.
  2. Move to EPAC only if that does not meet your governance needs.
  3. Prove it with an MVP or proof of concept before committing.
  4. Decide carefully, because you cannot easily change course later.

The same article also notes that “EPAC is best suited for more advanced development operations (DevOps) and IaC customers, but organizations of any scale can use EPAC after they assess it.” It is worth reading in full, because it does not restrict EPAC to large enterprises, but it does attach an assessment step.

Separately, the Cloud Adoption Framework article Enforce cloud governance policies recommends, under Use policy as code:

“Consider using Enterprise Azure Policy as Code (EPAC) to manage policies aligned with recommended Azure landing zone policies.”

So EPAC is documented and acknowledged in Microsoft’s own architecture and governance guidance.

I formed my own position before I found any of this, and it turned out to match the published sequence closely. I mention that as evidence that the reasoning holds up independently, not as vindication. If the guidance had contradicted me I would have had to say so, and Part 5 does contain a couple of findings that went against my position.

The guidance is not missing, then, but it is easy to miss, which is a different and more interesting problem. It lives in an Architecture Center article about landing zone deployment, in a subsection under Variants and specializations, alongside things like sovereign landing zones and partner implementations. A practitioner comparing two policy tools is unlikely to start there.

The positioning tells you something in itself. EPAC is documented as a variant rather than as one of the standard deployment options, which is a verifiable statement about how it is meant to be picked up.

What each thing actually is

Some plain definitions before going further, with no judgement attached.

EPAC is a PowerShell module (EnterprisePolicyAsCode) that implements true desired-state management for Azure Policy. Its source of truth is a Definitions/ folder in your repository, and its core flow is three stages:

Build-DeploymentPlans  →  Deploy-PolicyPlan  →  Deploy-RolesPlan

Plan first, then apply policy resources, then apply the role assignments that DeployIfNotExists and Modify policies need. If you have used Terraform, the shape will feel familiar.

The native path is harder to define, because it is not one thing. I spent a while writing “AVM/ALZ” as if it were a single product, and it is not. The distinction matters more than I first assumed, particularly for Part 2.

ALZ and AVM are different layers, with different owners:

Layer What it does Where it lives
Guidance Conceptual architecture, design areas, policy documentation Azure/Azure-Landing-Zones, described as “Azure Landing Zones documentation”
Data The policy assets: definitions, set definitions, assignments, archetypes Azure/Azure-Landing-Zones-Library, described as “Library of assets to deploy Azure Landing Zones architectures”
Engine The modules that actually create the resources AVM: avm/ptn/alz/empty on Bicep, terraform-azurerm-avm-ptn-alz on Terraform
Composition Wires the Library data into the AVM modules, exposes the customisation surface Azure/alz-bicep-accelerator, described as “Azure Verified Modules for Platform Landing Zones - Bicep”
Bootstrap Repository setup, pipelines, deployment Azure/accelerator-bootstrap-modules

The engine row is the one that changed how I write about this. You follow ALZ guidance, and the ALZ documentation describes the policy story well, but in the current AVM based ALZ implementation, the component that actually creates your policy definitions and assignments is an AVM module. On the Bicep path that module is avm/ptn/alz/empty, whose README lists what it deploys: management groups, policyDefinitions, policySetDefinitions, policyAssignments, roleDefinitions and roleAssignments.

Stated precisely, “native ALZ policy management” means ALZ Library data, composed by the ALZ starter module, deployed by AVM pattern modules, driven by the accelerator pipeline. That is a mouthful, which is why people compress it, and the compression is where a lot of the confusion starts.

The layering also clarifies what EPAC is being compared against. EPAC replaces the data, engine and composition layers for policy specifically. It does not replace the guidance layer, and it does not replace AVM for anything else in your landing zone. You do not stop using Azure Verified Modules because you adopted EPAC.

All of which brings me back to the category point. A lot of the disagreement starts because EPAC and ALZ are being compared as if they were the same type of solution.

A critical distinction: there is no single “ALZ”

“ALZ” splits along two axes, and most comparisons flatten both of them.

Axis one: Bicep and Terraform are not interchangeable for this discussion. They solve policy lifecycle through fundamentally different mechanisms:

ALZ Bicep + AVM ALZ Terraform + AVM
Lifecycle mechanism Azure Deployment Stacks Terraform state
Removal of dropped resources ActionOnUnmanage semantics plan / apply / destroy
Where the “desired state” lives In Azure, on the stack In the state file

Treating them as one thing is, in my experience, the most common error in this comparison, and I made it myself in the first draft of my research notes. Part 3 goes into the mechanics properly, including one widely repeated claim about Deployment Stacks that turns out to be wrong.

Axis two: ALZ and AVM are not the same layer, as the table above showed. That one caught me out as well. It matters because when you ask whether something is supported, the answer depends on which layer you are asking about. The guidance, the data, the engine and the pipeline are maintained by different teams, in different repositories, under different statements.

Part 2 is entirely about that, and it produced the finding that surprised me most.

Throughout this series I name the layer and the IaC language. Where neither distinction matters for a sentence, I say “the native path”.

Why the old comparison is out of date

Most of the disagreement I run into has a fairly simple explanation.

EPAC was historically introduced to compensate for real gaps in classic ALZ Bicep implementations. Those gaps were not imaginary. If your reference point is an ALZ Bicep deployment from a few years ago, EPAC solved problems you actually had.

The native implementation has moved substantially since then, and I still encounter decisions that were made against a version of ALZ that no longer exists.

You can check this without relying on documentation. The Azure/accelerator-bootstrap-modules repository is public, and it currently ships two generations of deployment pipeline side by side:

  • bicep-classic uses plain incremental ARM deployments (New-AzManagementGroupDeployment and friends), with a separate helper to tear things down
  • bicep uses Azure Deployment Stacks (New-AzManagementGroupDeploymentStack), configured with ActionOnUnmanage = "DeleteAll"

Two eras of the operating model in one repository, readable in about five minutes. I find that better evidence than documentation, because it is the code that actually runs rather than a statement of intent.

For dating the shift: Microsoft announced that AVM for Platform Landing Zone using Bicep reached general availability in the Azure Tools Blog post of 20 January 2026, which also states that Bicep AVM is “the default starter module and the focus of all future development”.

If you evaluated this in 2023, the thing you evaluated is not the thing that exists now, which on its own is reason enough to revisit the decision.

My hypothesis, stated up front

Research papers state the hypothesis before the evidence, so that you can watch it succeed or fail. Mine is:

Default to native ALZ policy governance. Treat EPAC as a deliberate exception that requires a named, concrete requirement.

I have not yet personally encountered a customer case where that justification held up under questioning. I want to be careful about how much weight that carries: it is an observation from my own engagements, not proof, and my sample is not the world. If you have a case that breaks it, I would genuinely like to hear about it. Part 5 ends with an open invitation and a list of things that would change my mind.

I also want to be explicit that this is not a criticism of EPAC. It is a well-engineered project, actively maintained, shipping frequently, and built by people who understand this domain deeply. Part 4 is a deliberate attempt to prove myself wrong by hunting for the cases where EPAC is genuinely the right answer, and it finds several.

Method, credentials and scope

Since I am asking you to weigh evidence, you should know how it was gathered.

How the research was done. Four sources, deliberately combined:

  • Review of public primary-source documentation, conducted with AI assistance
  • My own deployments and hands-on testing
  • Experience from customer engagements
  • Conversations with colleagues

The sourcing rule I have held myself to. Every published claim in this series stands on a public primary source: Microsoft Learn, the ALZ documentation site, the ALZ Library repository, AVM documentation, the accelerator repositories, or EPAC’s own public documentation. Where something could not be sourced publicly, it is either cut or clearly restated as my own reasoning rather than presented as fact.

Two conventions follow from that, and I apply them consistently:

  • Absences are phrased as absences of documentation. I write “I found no documented X”, not “X does not exist”. The first is something I can stand behind; the second is a claim about the world that I am not in a position to make.
  • Factual claims are date-stamped. Everything in this series reflects what I could verify in August 2026. This area moves quickly (one relevant capability went generally available while I was writing), so please check current sources before making decisions on it.

What is out of scope. The quality of the policy content itself, RBAC, networking, and subscription vending. This series is about the policy operating model, not about whether a given initiative is a good one.

What is coming

The series runs to five parts:

  • Part 1: The question (this post). Why the usual framing fails, and the decision guidance that already exists.
  • Part 2: What “supported” actually means. The part that needs the most precision. I read the support statements word for word, and the result changed my view of the debate.
  • Part 3: One library, two engines. How both routes now consume the same ALZ Library, why Deployment Stacks are not a generic “AVM capability”, and a correction to a claim I see repeated constantly.
  • Part 4: Hunting for the EPAC-only case. A deliberate attempt at self-falsification. Where does native ALZ genuinely fall short?
  • Part 5: The verdict. A decision framework, my position labelled as opinion, and what would change my mind.

If you already have a strong view on this, I would particularly like to hear from you after Part 4. That is where I go looking for evidence against myself, and it is the part most likely to be incomplete.

One last thing, and it is why I think this decision deserves five posts rather than a tweet. Microsoft’s own guidance ends its recommendation with a warning:

“you can’t easily change policy governance methods after you establish them”

So whichever way you go, it is worth making the choice deliberately.

Revision log

Unchanged since publication on 20 Aug 2026. Anything I get wrong later lands here.