The Microsoft Tech Community "Azure Policy Recommended Practices" post, published on the Core Infrastructure and Security Blog, opens with a distinction that sounds simple but is violated in almost every enterprise Azure environment we encounter: use Azure Policy to prohibit anybody and any service from doing something; use RBAC to prohibit specific users and service principals from doing something. These are different tools for different purposes, and conflating them is the root cause of most Azure governance dysfunction.
The structural mistake that follows from misunderstanding this distinction is assigning policies at the subscription or resource group level. Microsoft's guidance is explicit: assign policies at the highest management group scope possible, deploy custom policy definitions at the top management group (the single management group directly beneath the Tenant Root Group), and do not assign policies to subscriptions or resource groups. The reason is inheritance and debuggability. A policy assigned at a subscription creates an exception to management group policy that has to be tracked, documented, and managed separately. Multiply that by hundreds of subscriptions and you have a governance state that no one can reason about completely.
The recommended management group hierarchy comes from the Azure Cloud Adoption Framework's Enterprise-Scale Landing Zone design: Tenant Root Group at the top, then a Platform management group for shared services, then a Landing Zones management group branching into Corp, Online, Sandbox, and Decommissioned children. The CAF explicitly recommends keeping this hierarchy to no more than three or four levels deep. Deeper hierarchies make policy inheritance harder to trace and debug.
For initiative assignments (policy sets) the guidance is to rely on initiatives rather than individual policy assignments wherever possible, and to limit the total number of initiatives at any given scope to five. The baseline initiative should be the Microsoft Cloud Security Benchmark, which covers the most common security and operational controls. For regulatory compliance, extend built-in initiatives like NIST SP 800-53, ISO 27001, or PCI DSS with organisation-specific custom definitions rather than building from scratch.
The policy effects matter as much as the policy definitions. The recommended pattern for rolling out new governance is audit first, enforce later. You achieve this by parameterising the effect in your custom policy definitions: include an allowedValues list of effect options and set a defaultValue of Audit. This lets you see the compliance impact of a policy before it has any operational consequences. When you are confident in the policy definition and have resolved the violations it surfaces, you change the assignment parameter to Deny.
Auto-remediation via DeployIfNotExists and Modify effects is where Azure Policy provides the most leverage at scale. Enabling Microsoft Defender for Cloud on new subscriptions, applying default diagnostic settings to new resources, attaching network security groups to new subnets. These are tasks that a governance team cannot do manually at any meaningful scale. DeployIfNotExists policies do them automatically, with a system-assigned managed identity scoped to the minimum permissions required for the remediation task. Microsoft's recommended practices explicitly prefer system-assigned over user-assigned managed identities for these policies because system-assigned identities are scoped to a single assignment, reducing the attack surface.
For organisations managing Azure Policy as code, the recommended infrastructure is the Azure/terraform-azurerm-caf-enterprise-scale Terraform module on GitHub, which deploys the complete Enterprise-Scale management group hierarchy with out-of-the-box policy assignments, RBAC roles, and initiative assignments. The Policy-as-Code requirements Microsoft documents are worth reading in full: the deployment must be idempotent, desired-state (reverting drift), DRY (no repeated JSON definitions), CI/CD integrated, and round-trip capable (able to extract and re-ingest existing configurations).
The governance architecture that actually works at scale is not a compliance team reviewing tickets. It is a management group hierarchy enforced by code, a policy initiative library aligned to the Microsoft Cloud Security Benchmark and your regulatory requirements, and infrastructure templates that encode compliance requirements so that teams cannot provision non-compliant resources even if they try.
Sources: Microsoft Tech Community, "Azure Policy Recommended Practices," Core Infrastructure and Security Blog (techcommunity.microsoft.com, post #3798024); Azure Cloud Adoption Framework, Management groups design (learn.microsoft.com); Azure/terraform-azurerm-caf-enterprise-scale on GitHub.