☁️ Azure

Azure Governance & Landing Zones

📅 July 21, 202611 min readITVedas

How management groups, Azure Policy, and landing zones combine to govern multi-subscription Azure estates at enterprise scale.

ADVANCED
⏱ 11 min read
Prerequisites:
Key Facts
  • A tenant supports up to six levels of management groups beneath the root, and up to 10,000 management groups per directory
  • Policy assignments and RBAC role assignments both inherit down the management group hierarchy by default and cannot be blocked, only overridden with exclusions
  • Azure Blueprints is deprecated, with Microsoft's retirement notice setting 11 July 2026 as the end-of-support date for blueprint artifacts
  • The Deny effect blocks a non-compliant resource at write time, while DeployIfNotExists and Modify actively remediate resources after evaluation using a managed identity

Why subscriptions are not enough

A subscription is a billing and scale boundary, not a governance boundary. RBAC role assignments and resource locks scoped to individual subscriptions work fine when an estate has a handful of them, but enterprises running landing zones for dozens or hundreds of workload teams end up with the same policy, the same custom RBAC roles, and the same network baseline copy-pasted into every subscription. Configuration drifts the moment someone forgets a step, and there is no single place to prove, for an auditor, that every subscription in the tenant enforces the same controls.

Microsoft.Management/managementGroups resources sit above subscriptions in the hierarchy and solve exactly this problem: they are containers you can nest, up to six levels deep beneath the implicit root management group, with a tenant-wide limit of 10,000 management groups. Every subscription must ultimately roll up to the root. Anything you assign at a management group — an Azure Policy assignment, an RBAC role assignment, a cost budget — is inherited by every management group, subscription, and resource beneath it. Inheritance is not optional and cannot be blocked lower in the hierarchy; you can only add policy exclusions or additional role assignments further down, you cannot revoke what was assigned above.

The practical design pattern is to mirror the hierarchy to how the organization actually wants to govern, not to its org chart. A typical enterprise hierarchy has a root, then a Platform branch (with Identity, Management, and Connectivity management groups) and a Landing Zones branch (typically split into Corp and Online to reflect different network connectivity patterns), plus a Sandbox branch for unrestricted experimentation and a Decommissioned branch for subscriptions awaiting deletion. Policy gets progressively stricter as you move from Sandbox toward Corp.

Azure Policy: definitions and initiatives

A policy definition is a JSON document with a policyRule: an if condition evaluated against resource properties, and a then block specifying an effect. A minimal built-in example is the policy that requires a tag on resource groups — the condition checks whether a specified tag key is absent, and the effect denies the request if so. Definitions are stored as Microsoft.Authorization/policyDefinitions and can be scoped to a management group or subscription, or left in the free built-in catalog Microsoft maintains (well over a thousand built-ins covering naming, encryption, allowed SKUs, and regulatory baselines like NIST 800-53 or PCI DSS).

In practice you rarely assign single definitions. An initiative — the API resource is still called policySetDefinition even though the portal renamed it years ago — bundles related definitions into one assignable unit. Microsoft's own Microsoft cloud security benchmark initiative bundles hundreds of definitions; a landing zone team typically builds a smaller custom initiative per management group tier, e.g. one initiative for "Corp connectivity requirements" and another for "mandatory tagging and cost controls." Grouping into initiatives matters operationally: compliance reporting, exemptions, and versioning all happen at the initiative level, so a single assignment gives you one compliance percentage instead of forcing you to reconcile dozens of individual policy states.

Parameters are what make a definition reusable instead of hard-coded. A definition like "allowed locations" takes a listOfAllowedLocations array parameter; the same definition gets assigned to the Corp management group with ["eastus","westeurope"] and to a regional subsidiary's management group with a different list, without duplicating the rule itself.

Effects, scope, and remediation

The effect is the part of a policy that actually does something, and picking the wrong one is the most common landing zone governance mistake. Deny blocks the ARM/Bicep write request outright — the resource is never created, and the caller sees a policy violation error at deployment time. Audit lets the resource deploy but marks it non-compliant in the policy compliance dashboard, which is the right default for a new policy you haven't validated against real workload traffic yet. Append and Modify alter the request before or after evaluation — Modify can add or replace a tag, or attach a resource to a specific NSG, and unlike Append it can also remove a field. DeployIfNotExists (DINE) and AuditIfNotExists evaluate a related resource rather than the one being created — the canonical example is a policy that checks whether a VM has the Microsoft Defender for Endpoint extension installed and, if not, deploys it.

DINE and Modify effects both require a managed identity attached to the policy assignment, with RBAC roles granted on that identity scoped to whatever it needs to create or change. This identity is a common audit failure point: teams assign a DINE policy, it shows as non-compliant forever, and the root cause is that the assignment's system-assigned identity was never granted the Contributor or resource-specific role it needs to remediate. Existing non-compliant resources are not retroactively fixed when a DINE policy is assigned — you have to trigger a remediation task (Microsoft.PolicyInsights/remediations) explicitly, which walks existing resources and applies the deployment.

Scope determines where an assignment applies and where it can be excluded. Assignments made at a management group cascade to every child scope, but each assignment can carry an excludedScopes list — used sparingly, typically for a subscription under active migration that can't yet meet a new baseline. Broad exclusions are a governance smell; if half the subscriptions under a management group are excluded from its policy, the policy is assigned at the wrong level. For genuine one-off exceptions with an expiry date, use a policy exemption (Microsoft.PolicyInsights/policyExemptions) instead of an exclusion — exemptions are time-bound and show up in compliance reporting as "exempt" rather than silently disappearing from evaluation.

Why Azure Blueprints is not the answer anymore

Azure Blueprints packaged a set of artifacts — ARM templates, RBAC assignments, policy assignments, resource groups — into a single versioned, assignable object, with the promise of tracking which subscriptions had which blueprint version applied. It looked like the natural tool for landing zone deployment, and a lot of early landing zone guidance was written around it. Microsoft has since deprecated the service: the retirement notice sets 11 July 2026 as the date blueprint artifacts stop being supported, and the documented migration path is explicit — Blueprints does not get a direct successor, it gets replaced by a combination of separate tools that each do one job.

The replacement pattern splits Blueprints' responsibilities back into their natural layers. Repeatable resource deployment moves to Microsoft.Resources/templateSpecs (a versioned, RBAC-controlled container for an ARM or Bicep template, callable from a pipeline or the portal) or to deployment stacks (Microsoft.Resources/deploymentStacks), which add lifecycle management — a stack can deny deletion of the resources it manages, and cleans up resources removed from the template on the next apply, something plain ARM/Bicep deployments never did. Guardrails move entirely to Azure Policy, assigned at management group scope as described above. And the versioning, approval, and rollout process that Blueprints tried to own internally moves to a normal CI/CD pipeline against a git repository, using whatever gating your organization already uses for other infrastructure code.

The practical implication for new work: don't build a landing zone pipeline around Microsoft.Blueprint/blueprintAssignments. If you inherited an existing estate that used Blueprints, plan a migration — export the underlying artifacts, convert the ARM template into a template spec or Bicep module, recreate the policy and RBAC assignments as native management-group-scoped assignments, and retire the blueprint assignment once the replacement is validated. Existing blueprint assignments continue to function until the retirement date but will not receive new features.

What a landing zone actually is

"Landing zone" gets used loosely to mean "a subscription with some stuff pre-configured," but in the Cloud Adoption Framework it has a specific meaning: a landing zone is the set of subscriptions, network topology, identity configuration, and policy that a workload lands into, scaled and governed consistently, before any workload-specific resource is deployed into it. The CAF's Azure landing zone conceptual architecture is a reference design, not a product — it's published as a set of principles plus reference implementations (Bicep modules in the Azure/ALZ-Bicep repo, and Terraform modules in the Azure/terraform-azurerm-alz provider) that map directly onto the management group hierarchy described earlier.

The design separates two concerns that were conflated in earlier "enterprise scaffold" guidance: platform-level capabilities that are shared and centrally owned, and workload-level resources that are owned by individual application teams. That separation is what "platform landing zone" versus "application landing zone" refers to, and it's the single most important structural idea in the whole framework — get it right and governance scales linearly with the number of application teams instead of the number of subscriptions.

Platform landing zones vs. application landing zones

A platform landing zone is not one subscription — it's usually three, each with a distinct purpose and distinct ownership by the central platform team. The Identity subscription hosts domain controllers or Microsoft Entra Domain Services if needed. The Management subscription hosts the Log Analytics workspace, Azure Monitor and Sentinel configuration, and Automation account that every other subscription in the tenant sends telemetry to. The Connectivity subscription hosts the hub in a hub-and-spoke topology (or the Virtual WAN hub in a Virtual WAN topology) — ExpressRoute or VPN gateways, Azure Firewall, DNS resolution, and the private DNS zones that spokes link into. These three exist once, are deployed first, and change infrequently once stable.

An application landing zone is a subscription (or small group of subscriptions) provisioned per workload team, spoke-peered into the connectivity hub, pre-populated with the policy and RBAC inherited from its management group, and handed to the workload team to deploy their actual application resources into. The CAF distinguishes Corp application landing zones, which require private connectivity back through the hub (no direct internet ingress), from Online application landing zones, which are internet-facing by design and don't route through the same hub-based egress. A team building an internal line-of-business API lands in Corp; a team building a public marketing site lands in Online — and the management group each subscription sits under is what makes that distinction enforceable rather than just documented.

The point of the split is ownership and blast radius. Platform teams change firewall rules and DNS zones without needing sign-off from every application team, because those changes live in subscriptions application teams don't have write access to. Application teams deploy and redeploy their own resources constantly without needing platform-team approval for every change, because the guardrails constraining what they can do are enforced by policy inherited from above, not by a human review gate on every deployment.

Subscription vending as a self-service pattern

The operational bottleneck in a landing zone model that stops here is subscription creation itself: if provisioning a new application landing zone requires the platform team to manually create a subscription, move it under the right management group, peer its VNet to the hub, and assign the right RBAC, that team becomes a queue, and the whole benefit of "self-service governed by policy" is undercut by a manual step at the front.

Subscription vending addresses this by turning landing zone creation into a parameterized, pipeline-driven request instead of a manual task. A workload team submits a small set of inputs — an intended management group (which encodes Corp vs. Online), an address space request for the spoke VNet, a cost center for billing, an environment tag — through a form, a pull request against a config repository, or an internal developer portal. A pipeline consumes that request and runs an infrastructure-as-code module (typically Terraform against the Microsoft.Subscription resource provider, or an equivalent Bicep/ARM deployment using Microsoft.Subscription/aliases) that creates the subscription, places it under the correct management group so policy inheritance takes effect immediately, provisions the spoke VNet and peers it to the hub, and applies budget alerts. No platform engineer touches a single request; the platform team's effort goes into building and maintaining the vending module once, not into repeating the same manual steps for every new team.

What makes this pattern distinctly a governance mechanism rather than just automation convenience is the ordering guarantee it gives you: because management group placement happens as part of subscription creation, a vended subscription is compliant with baseline policy from the moment it exists, before any workload resource has been deployed into it. There is no window where a new subscription sits ungoverned waiting for someone to remember to assign policy to it — which is precisely the failure mode management groups and initiatives were introduced to close in the first place.

Key Takeaways

  • Management groups exist to apply policy and RBAC once, above the subscription boundary, instead of re-applying controls to every subscription individually
  • Azure Policy definitions describe a single rule; initiatives (policySetDefinitions) group related definitions so they can be assigned, versioned, and reported on as one unit
  • Choosing a policy effect is an architectural decision — Deny prevents drift but blocks legitimate deployments if scoped wrong, DeployIfNotExists corrects drift but needs remediation tasks and a permissioned identity
  • Azure Blueprints should not be adopted for new work; the supported pattern is Template Specs or Deployment Stacks for repeatable IaC plus Azure Policy for guardrails, versioned in a normal CI/CD pipeline
  • A landing zone is not a single deployment but an operating model — a platform landing zone run by a central platform team, and application landing zones provisioned repeatably underneath it, ideally through a self-service subscription vending process