Governance · Runbook
Azure Policy baseline: audit first, then enforce safely
An Azure Policy baseline built on Microsoft Learn guidance: audit first, stage rollout, handle exemptions and remediation, then move to enforcement.
- Effort: 1-2 days
- Risk: Medium
- Rollback: Partial
Applies to: Azure Policy
A sound Azure Policy baseline starts with audit, not deny. Microsoft Learn recommends starting with audit or auditIfNotExists before any enforcement effect, then widening scope in stages. Use DoNotEnforce, resource selectors and overrides to roll out, use exclusions only for permanent broad bypasses, and keep exemptions time-bound and tracked.
Official Microsoft Learn sources (checked on 2026-10-17):
- Overview of Azure Policy
- Policy assignment structure
- Evaluate the impact of a new policy definition
- Safe deployment of policy assignments
- Get policy compliance data
- Remediate non-compliant resources
- Policy exemption structure
- Understand scope in Azure Policy
- Effect basics and deny effect
- Policy as code workflows
- Policy enrollment structure
- Request disallowed by policy error
Confirm before acting:
- Enroll mode: Learn describes it, but the page does not label it generally available or preview, and its sample uses apiVersion
2025-02-01-preview. Treat it as preview or unconfirmed until you have seen a status from Microsoft. - Portal labels: the portal wording for creating a remediation task is documented for subscription-scope assignments. Check the exact labels in your portal before you write them into a procedure.
- Starting policies: choose your first built-in policies or initiatives from Microsoft’s built-in policy lists, and confirm the definition IDs in your own tenant before you assign anything.
- Limits: the numbers below are Learn’s figures at the time of checking. Re-read the overview page before you design around them.
What good looks like
A baseline here is a rollout method, not a list of policies. The Learn pages agree on the shape:
- Policy resources live in source control and deploy through one central mechanism (GitHub workflows or Azure Pipelines). Learn says write permissions to policy resources can be restricted to the deployment identity.
- Definitions sit at a management group or subscription. Learn suggests a management group near the root, shared by all target resources. Assignments go on child scopes.
- Learn recommends assigning initiatives even when you start with a single policy.
- New policies start in audit, or in DoNotEnforce, and move to enforcement in stages.
- Exceptions are tracked, time-bound and reviewed.
If you are building the wider platform around this, the Azure Landing Zones secure-by-default guide covers the foundation these guardrails sit on.
Who is affected
- Platform teams who own definitions, initiatives and assignments.
- Workload teams whose deployments get blocked, or whose resources show as non-compliant.
- Security and compliance teams. Learn’s guidance on evaluating a new policy says scope changes should be validated and communicated to them.
Roles matter here. Learn lists these:
- Resource Policy Contributor includes most Policy operations.
- Owner has full rights.
- Contributor and Reader get read operations. Contributor can trigger remediation but cannot create or update definitions and assignments.
- User Access Administrator is needed to grant the managed identity its permissions on
deployIfNotExistsandmodifyassignments. - Creating an exemption needs
Microsoft.Authorization/policyExemptions/writeplus theexempt/Actionverb on the target assignment. Learn says Resource Policy Contributor and Security Admin have read and write on exemptions.
For the wider role model, see the identity baseline for landing zones.
Why it matters
- Deny blocks work. In Resource Manager mode, Learn says deny stops the create or update request before it reaches the resource provider and returns
403 (Forbidden). Learn also warns that enforcement can hinder existing automation such as autoscale scripts. - Azure Policy is an explicit deny system. Learn says that if any assignment denies a resource, the only way to allow it is to modify the denying assignment, for example by excluding scopes.
- Overlapping assignments stack. They are evaluated independently, and Learn describes the net result as cumulative most restrictive. A deny at any scope blocks the resource.
- Definition edits hit every assignment. Learn says that if an assigned definition changes, all existing assignments use the updated logic when evaluating. Treat a definition edit as a change to every assignment of it.
- Feedback is slow. Learn gives about five minutes for a new assignment to apply to its scope before the evaluation cycle begins, with no predefined completion time for large scopes. Resource create or update results appear in the portal and SDKs around 15 minutes later. The standard cycle runs every 24 hours. Don’t judge a rollout on the first ten minutes of data.
Decisions to make
Effect order
Learn gives the evaluation order as disabled, then append and modify, then deny, then audit, then manual, then auditIfNotExists, with denyAction last. Deny is evaluated before audit, which prevents double logging of an undesired resource. Existing resources that match a deny definition are marked non-compliant, not deleted.
Exclusion or exemption
| Need | Use | What Learn says |
|---|---|---|
| Permanently bypass a broad scope, such as a test environment | Exclusion (notScopes) | Resources are not evaluated or counted in compliance. Set on the assignment, so it means modifying the assignment. |
| Time-bound or specific case that should stay tracked | Exemption | The resource is shown as exempt for tracking, and creating an exemption doesn’t require modifying the assignment. |
Exemption categories are Mitigated (intent met another way) and Waiver (non-compliance temporarily accepted). An exemption can target specific policies in an initiative through policyDefinitionReferenceId. It is a child object of the exempted scope or resource, so it is removed if the parent is removed.
Learn says expiresOn stops an exemption being honoured but does not delete the object. Expired exemptions need housekeeping.
Which rollout lever
| Lever | Use it for | Limit from Learn |
|---|---|---|
enforcementMode DoNotEnforce | Evaluate before enforcing. No effect, no Activity log entry. | Changing it on an existing assignment is an assignment update. |
| Overrides | Change the effect of policies in an initiative without editing the definition, for example audit now and deny later. | Up to 50 policyDefinitionReferenceId per override, up to 10 overrides per assignment. |
| Resource selectors | Gradual rollout by resource location or type. | Up to 10 resourceSelectors per assignment. |
| Enroll mode (unconfirmed status) | Staged enforcement through child enrollment objects. | See the warning above. |
Learn also lists object limits worth knowing: 200 assignments per scope, 1000 exemptions per scope, 400 notScopes per assignment, 500 policy definitions per scope, 200 initiative definitions per scope, and 50,000 resources per remediation task.
Runbook
-
Put policy in source control
Keep definitions, initiatives, assignments and exemptions in GitHub or Azure DevOps. Deploy them through a central pipeline. Restrict write permissions on policy resources to the deployment identity, as Learn suggests.
-
Choose where definitions live
Create definitions at a management group (near the root if they are shared) or subscription. Learn says a definition at a management group can be assigned to child management groups and subscriptions. Wrap even a single policy in an initiative, as Learn recommends.
-
Test the definition properly
Learn says to define tightly, test on a subset, audit new and updated resources, deploy to a subset, then widen, with continuous monitoring. For the test, assign in a Dev environment with enforcement mode Disabled (
doNotEnforce) so the effect does not trigger. Learn also says enforcement mode is no substitute for testing withPUTandPATCHcalls, compliant and non-compliant resources, and edge cases such as a missing property. -
Assign in audit or DoNotEnforce
For a
denyorappendpolicy, Learn’s safe deployment pattern is to assign at the highest scope, narrow with aresourceLocationresource selector to the least critical tier, and set the effect to Audit with an assignment override.For
modifyanddeployIfNotExistspolicies, set enforcementMode toDoNotEnforcewith the same location selectors.Add a
nonComplianceMessagesentry so engineers see a clear reason if the policy later denies. Learn says this is supported only for Resource Manager mode definitions. -
Sort out the managed identity before remediation
Learn says remediation uses the assignment’s managed identity, which needs the minimum required RBAC role. In the portal the roles are granted automatically. With SDK, CLI, PowerShell or IaC, Learn says you must grant the roles manually or the remediation deployment fails.
An assignment with a system-assigned identity needs a location. Learn says it cannot be
globaland cannot be changed. IfroleDefinitionIdsare edited in the definition later, the new permissions must be granted manually, even in the portal. -
Wait, then read the compliance data
Allow for the timings above. Review results under Policy > Compliance in the portal. Learn also says audit and deny results from new and updated resources can be queried in the
AzureActivitytable with Kusto queries, which is a route to alerting.To trigger an on-demand scan of a resource group, Learn gives this Azure CLI command (asynchronous, covers a subscription or resource group):
BASHaz policy state trigger-scan --resource-group "resourceGroupName"and the PowerShell equivalent:
POWERSHELLStart-AzPolicyComplianceScan -ResourceGroupName 'resourceGroupName' -
Widen tier by tier, with checks
Learn’s safe deployment page recommends automated compliance checks in the CI/CD pipeline at each rollout stage, with the pipeline failing and debugging starting when results are not as expected. Expand the location selector tier by tier, checking compliance and application health at each step.
-
Remediate existing resources
Remediation applies only to
deployIfNotExistsandmodifypolicies and acts on existing resources. Learn says you can start remediation tasks even when the assignment is onDoNotEnforce. Use Policy > Remediation (the policies to remediate tab), or Policy > Compliance, open the non-compliant assignment and create a remediation task. Confirm the labels in your portal.A task remediates one policy at a time. Learn also names
Start-AzPolicyRemediationandaz policy remediation createfor scripted use. Defaults per Learn:ResourceCount500 (maximum 50,000),ParallelDeploymentCount10 (range 1 to 30),FailureThreshold100%. Check the command reference for exact parameters before you script it. -
Switch to enforcement
For deny or append, Learn’s pattern is: once all tiers are audited, change the override effect to
denyand reset the selectors to Tier 0, then repeat the expansion. FormodifyanddeployIfNotExists, trigger remediation to confirm existing resources become compliant, then change enforcementMode toDefaultand reset the selector to Tier 0. Make this change first in an environment far from production. -
Stage definition version upgrades
For built-in definition upgrades, Learn describes an assignment override of kind
definitionVersionwith aresourceLocationselector. Resources outside the selector keep using the top-leveldefinitionVersion. When all locations are covered, remove the override and updatedefinitionVersion. -
Run exemptions as a register
Use exemptions for tracked, time-bound cases. Set
expiresOn, pick Mitigated or Waiver honestly, and review regularly. Learn says to remove those that don’t qualify. Creating, updating or deleting an exemption triggers evaluation of the corresponding assignment.
About enrollments
Learn describes a policy enrollment (Microsoft.Authorization/policyEnrollments) as a child object that adds resource hierarchies or resources to the enforcement path of an assignment set to Enroll mode. Enrolled resources have the effect enforced. Other in-scope resources still get compliance records but are not enforced.
Learn says the referenced assignment must already exist with Enroll enforcement mode. Enrollments are managed through Azure CLI, ARM, Bicep or Terraform AzAPI. Only assignmentScopeValidation and resourceSelectors can be updated by PATCH, with up to 10 resourceSelectors per enrollment. Given the unconfirmed status described above, don’t build your baseline on it until you have checked the availability in your tenant.
Checks
-
Every new assignment started in audit, auditIfNotExists or DoNotEnforce, and the result was reviewed before enforcement.
-
Compliance data was read after the five-minute apply window and the evaluation cycle, not before.
-
Each deployIfNotExists or modify assignment has a managed identity with the required roles, granted manually where you used IaC, CLI or PowerShell.
-
A test remediation task completed on a small scope before any wide run.
-
Every exclusion has a recorded reason. Every exemption has a category and an expiresOn date.
-
Expired exemptions are listed and deleted on a schedule.
-
Deny assignments carry a non-compliance message (Resource Manager mode).
-
Policy writes are limited to the deployment identity, and the pipeline fails when compliance results are not as expected.
-
Definition edits are reviewed as changes to every existing assignment of that definition.
When a deployment is denied, Azure CLI, PowerShell and the portal Activity log show RequestDisallowedByPolicy with the policy assignment and definition identifiers. Learn says the name is the last segment of each ID. Use az policy definition show and az policy assignment show to inspect them, and check the command reference for parameters.
Rollback
Rollback is partial. The bullets below cover the assignment, definition and enrollment side. Plan remediation separately (last bullet).
- Deny causing damage: set enforcementMode to
DoNotEnforce. Learn says changing the value on an existing assignment is an assignment update, and it lists an updated assignment as an evaluation trigger, so allow for the timings above. If you rolled out with an override, Learn’s safe deployment pattern uses an assignment override to set the effect to Audit, so setting it back is the matching step. Confirm how your pipeline applies that change. - Deny on a specific resource: Learn says the only route is to modify the denying assignment. Use an exemption for a tracked, time-bound case or
notScopesfor a permanent broad bypass. - Bad definition edit: all existing assignments use the updated logic when evaluating, so revert the definition from source control.
- Enrollment: Learn says deleting an enrollment does not delete the underlying assignment, so enforcement is withdrawn for that scope.
- Remediation: Learn says tasks act on existing resources, so pilot on a small scope first. Before you run a wide remediation, decide how you would undo it, and check the remediate-resources page for current guidance.
Common pitfalls
- Going straight to deny. Microsoft recommends audit first because enforcement can break existing automation.
- Forgetting the identity roles. Outside the portal, remediation fails without manually granted roles. Editing
roleDefinitionIdslater does not update the identity. - Reading compliance too early. There is a delay of about five minutes to apply, then evaluation, and around 15 minutes for a resource change to show.
- Confusing exclusion and exemption. Learn says resources in an exclusion aren’t evaluated or included in the compliance count. An exemption is the tracked, time-bound option and shows the resource as exempt.
- Letting exemptions rot. Expiry stops the exemption working but leaves the object behind.
- Editing a definition casually. Every assignment picks up the change.
- Assuming DoNotEnforce blocks remediation. Learn says remediation tasks can still be started for
deployIfNotExistspolicies in that mode. - Skipping real test cases. Enforcement mode is not a replacement for testing create, update and edge cases.
- Hitting limits late. 200 assignments per scope and 1000 exemptions per scope are easier to plan for than to untangle.