Azure Policy Management Done Right


Managing Azure Policy at scale is one of those challenges that seems simple until you actually try to do it. Sure, you can click around the portal and manually create policies and assignments, but what happens when you have dozens of subscriptions, hundreds of policies, and multiple teams all trying to manage governance? You end up with a mess.

Enter the Enterprise Policy As Code (EPAC) framework - a PowerShell-based solution that promises to bring order to the chaos of Azure Policy management.

EPAC (Enterprise Policy As Code) is an open-source framework built by Microsoft Employees (but isn’t an official Microsoft Product or solution) that uses PowerShell to manage Azure Policy deployments at scale. Think of it as Infrastructure as Code, but specifically designed for Azure Policy with all the complexities that come with managing policies, assignments, exemptions, and role assignments.

The framework provides a true desired state deployment approach - you define what you want in code, and EPAC figures out what changes need to be made to get Azure to match that desired state. It’s like having a smart deployment engine that understands the dependencies between policy definitions, assignments, and the RBAC permissions required for policies with modify or deployIfNotExists effects.

At its core, EPAC uses a structured folder approach where you define:

  • Policy Definitions
  • Policy Set Definitions (initiatives) for grouping related policies
  • Policy Assignments that specify where policies should be applied
  • Policy Exemptions for managing exceptions in an auditable way
  • Global Settings that define your Azure environments and deployment strategy

And everything is maintained in JSON files which are easy to manage and maintain.

The magic happens when you run the PowerShell scripts:

  1. Build-DeploymentPlans analyzes your current Azure environment and compares it to your desired state defined in code
  2. Deploy-PolicyPlan and Deploy-RolesPlan execute the changes needed to bring Azure into compliance with your definitions

This approach gives you a “plan before deploy” capability - you can see exactly what will change before making any modifications to your environment.

EPAC in a nutshell

Here’s where things get interesting, and honestly, where I think EPAC shows both its strengths and current limitations.

EPAC works beautifully in “greenfield” environments - new Azure deployments where you’re starting fresh and can design your management group structure according to best practices. It also shines in mature enterprise environments where teams already have a solid understanding of their current policy landscape and governance requirements.

The framework assumes you’re working in environments that follow Azure Landing Zone patterns with well-defined management group hierarchies and clear separation between development and production scopes. If you’re in that position, EPAC is fantastic.

But here’s the reality: most organizations aren’t starting fresh. They have existing Azure environments with policies that were created manually, subscriptions scattered across different management groups, and governance that evolved organically rather than being designed upfront.

In these brownfield scenarios, EPAC’s default full strategy can be quite aggressive - it wants to own and manage ALL policies within its defined scope, which means it will remove any policies that aren’t defined in your EPAC repository. For many organizations, this is terrifying.

As an MSP (Managed Service Provider), this presents unique challenges. We’re often working with clients who have existing Azure environments with policies we didn’t create, governance structures we didn’t design, and business processes we can’t immediately change.

This is where EPAC’s OwnedOnly strategy becomes crucial. Instead of managing everything within a scope, OwnedOnly tells EPAC to only manage the policies it explicitly knows about - the ones defined in your repository. It won’t touch existing policies that aren’t under EPAC management.

For MSPs, this is a much safer starting point. You can begin managing specific policies through EPAC while leaving existing governance structures intact. It’s a way to gradually introduce policy-as-code practices without disrupting current operations.

While EPAC provides a solid foundation, I’m finding that most real-world implementations require some customization.
Because the EPAC framework is built using a PowerShell module EnterprisePolicyAsCode, you can easily create your own PowerShell scripts and functions which interact with the core EPAC module to handle specific use cases.

Some examples I’ve already started building and implementing are for example:

  • Create a custom GlobalSettings file without a development environment
  • Create the default folder structure (the HydrationKit depends heavily on the ‘default’ GlobalSettings file)
  • Create a new baseline from your Live Azure environment to be used as your starting point in your Infrastructure as Code journey (or override your current baseline)
  • Check the differences between the Live Azure environment and baseline

The beauty of EPAC being PowerShell-based is that it integrates naturally with other automation you might already have in place.

EPAC represents a significant step forward in Azure Policy management. The combination of desired state deployment, policy-as-code practices, and PowerShell-based automation provides excellent control over complex governance scenarios.

While the current implementation leans toward more mature or greenfield environments, the framework’s flexibility means it can be adapted for various scenarios. The OwnedOnly strategy provides a safe migration path for brownfield environments, and the PowerShell foundation makes customization straightforward.

I don’t have my complete solution exactly where I want it yet, but EPAC provides a solid stepping stone toward enterprise-grade policy management. The key is understanding that it’s a framework to build upon, not necessarily a complete out-of-the-box solution for every scenario.

In a few months, I expect to have developed the additional tooling needed to make EPAC work seamlessly in our MSP environment. The foundation is definitely there - it’s just a matter of building the right customizations on top of it.

Happy scripting! 😀