Policy Baseline
A long policy catalogue looks impressive and helps almost no one. What matters is the small set of guardrails enforced before workloads spread everywhere, while the environment is still small enough to shape. This page defines that baseline and the lifecycle that operates it.
Purpose
This page defines Azure Policy as the central governance engine for the platform — used to enforce standards, evaluate compliance, deploy supporting configuration, and remediate drift.
Design Reasoning
A good policy baseline is not a pile of individual assignments. It is packaged into initiatives, parameterized, assigned at appropriate scopes, and operated with a lifecycle.
Azure Policy effects fall into a few categories you will actually use:
- Deny — block non-compliant create/update requests (allowed locations, public access, resource types).
- Audit / AuditIfNotExists — report non-compliance without blocking; the safe way to measure impact first.
- Modify / Append — adjust requests, typically to add or inherit tags.
- DeployIfNotExists — deploy supporting configuration (diagnostic settings, agents) when it is missing.
Manual, DenyAction, and Disabled also exist; the four above cover most of a landing zone baseline. Crucially, only Modify and DeployIfNotExists support remediation — and both require a managed identity with the right permissions.
Audit before you deny
Start guardrails that could break in-flight workloads in Audit, measure the real impact, communicate required changes, and only then tighten to Deny, Modify, or DeployIfNotExists. Breaking teams is how governance loses trust permanently.
Policy exemptions must be treated as managed exceptions — each with a reason, an owner, and an expiration date — not as a quiet way to make a warning disappear.
Architecture Decision Record
| Decision | Choice | Rationale |
|---|---|---|
| Policy packaging | Group related policies into initiatives | Initiatives simplify assignment, parameterization, review, and lifecycle management. |
| Rollout model | Audit, then enforce | A staged lifecycle surfaces impact before enforcement, avoiding broken deployments and lost trust. |
Tradeoff: Initiatives add a layer of indirection over individual policies. For anything beyond a handful of assignments, that indirection is what keeps the baseline reviewable.
Recommended Configuration
The guardrails worth enabling first, with the effect to start from:
| Area | Approach | Effect |
|---|---|---|
| Allowed locations | Initiative parameter for permitted regions | Deny |
| Required tags | Built-in required-tag policies and tag inheritance | Deny or Modify |
| Public IP restrictions | Built-in or custom policies by resource type | Deny |
| Storage public access | Built-in storage policies | Deny |
| Storage secure transfer | Built-in storage policies | Deny |
| Diagnostic settings | Initiative using category groups | DeployIfNotExists |
| Resource type restrictions | Built-in “not allowed resource types” policy | Deny |
| Private endpoints for sensitive services | Built-in where available, custom where not | Audit, then Deny or DeployIfNotExists |
In a landing zone, DeployIfNotExists and Modify should deploy or adjust supporting resources and configuration — diagnostic settings, tags, agents — not full application workloads.
Example Implementation
A management-group-scoped assignment of a DeployIfNotExists initiative, with the system-assigned identity that remediation requires:
targetScope = 'managementGroup'
@description('Resource ID of the diagnostic-settings initiative to assign.')param policyDefinitionId string
@description('Name of the policy assignment.')param assignmentName string = 'diag-settings-baseline'
@description('Resource ID of the central Log Analytics workspace.')param logAnalyticsId string
resource assignment 'Microsoft.Authorization/policyAssignments@2025-03-01' = { name: assignmentName location: 'switzerlandnorth' identity: { type: 'SystemAssigned' } properties: { displayName: 'Deploy diagnostic settings baseline' policyDefinitionId: policyDefinitionId enforcementMode: 'Default' parameters: { logAnalytics: { value: logAnalyticsId } } }}The managed identity still needs a role assignment (for example, Contributor or a least-privilege custom role) at the remediation scope so it can deploy the missing configuration.
Validation Steps
# Assignments at the intermediate root scopeaz policy assignment list \ --scope /providers/Microsoft.Management/managementGroups/contoso
# Exemptions for a subscription — every one should have an owner and expiryaz policy exemption list --scope /subscriptions/<subscription-id>
# Remediation tasks (policyinsights extension)az policy remediation list --management-group contosoOperate the baseline as a lifecycle:
- Start with
AuditorAuditIfNotExists. - Measure impact across the estate.
- Communicate the required changes.
- Move to
Deny,Modify, orDeployIfNotExists. - Create remediation tasks where needed.
- Review exemptions regularly.
Common Mistakes
- Exemptions without expiration dates, which become permanent, undocumented exceptions.
- Many individual assignments instead of initiatives, which makes the baseline unreviewable.
- Using
DeployIfNotExiststo deploy workloads rather than supporting configuration. - Assigning policies too broadly at the tenant root.
- Missing managed identity permissions for remediation, so remediation silently fails.
- Leaving policies in
Auditforever, which provides visibility but never a guardrail.