Lesson 04 — Azure Policy: Governance at Scale
What Azure Policy Is — and What It Is Not
Azure Policy enforces resource configurations. RBAC controls who can perform actions. These are orthogonal systems that must both be satisfied for an operation to succeed — but they operate independently, and conflating them is a source of real architectural mistakes.
| Dimension | Azure RBAC | Azure Policy |
|---|---|---|
| Question it answers | Can this identity perform this action? | Is this resource configuration allowed in this environment? |
| Grants permissions? | Yes — explicitly grants actions to principals | No — never grants permissions; only restricts or audits what permitted users deploy |
| Can block an Owner? | Only via Deny Assignments (not direct RBAC) | Yes — a Policy Deny blocks a resource deployment even if the deployer is an Owner |
| Operates at | Identity plane — the principal making the request | Resource plane — the resource being created or modified |
Policy Definitions: Structure
A policy definition is a JSON document that specifies a condition (if) and an effect (then). When a resource matches the if condition, the effect is applied.
{
"mode": "Indexed",
"policyRule": {
"if": {
"allOf": [
{ "field": "type", "equals": "Microsoft.Storage/storageAccounts" },
{ "field": "Microsoft.Storage/storageAccounts/supportsHttpsTrafficOnly",
"notEquals": true }
]
},
"then": {
"effect": "Deny"
}
},
"parameters": {
"allowedEffect": {
"type": "String",
"defaultValue": "Deny",
"allowedValues": ["Audit", "Deny", "Disabled"]
}
}
}
The mode field
| Mode | What it evaluates | When to use |
|---|---|---|
| All | Every resource type, including resource groups and subscriptions themselves | Policies that apply to resource group properties, or subscription-level configurations |
| Indexed | Only resource types that support tags and location metadata | Tag and location policies — the default for most compliance policies. Avoids false positives on resource types that don't have tags (e.g. extensions, providers). |
Policy Effects — Memorise All Seven
The effect determines what Azure does when a resource matches the policy's if condition. This is the most heavily tested aspect of Azure Policy. Know all effects, their purpose, and their sequencing.
| Effect | What it does | Example use case |
|---|---|---|
| Disabled | The policy is present but does nothing. Useful for testing or temporarily suspending a policy without deleting the assignment. | Disabling a Deny policy before a planned change window; testing a new policy definition before activating it. |
| Append | Adds fields or tags to a resource during create or update. Does not modify existing fields — only appends. Does not remediate existing resources. | Appending a CreatedBy tag using the request context; appending a default NSG rule that must always be present. |
| Modify | Adds, replaces, or removes properties during create or update. More powerful than Append — can change existing values. Requires a managed identity on the assignment for remediation of existing resources. | Inheriting a CostCenter tag from the resource group; enforcing a specific tag value; converting HTTP storage accounts to HTTPS on update. |
| Deny | Blocks the resource operation at the ARM layer. The deployment fails before the resource is written. Evaluates at create and update time. | Blocking storage accounts without HTTPS; blocking resources in non-allowed regions; blocking VM SKUs not in an approved list. |
| Audit | Allows the resource to be created/updated regardless, but marks it as Non-compliant in the compliance dashboard and creates a compliance event. | Auditing storage accounts without a specific tag; auditing VMs without Entra ID login extension — situations where you want visibility without blocking. |
| AuditIfNotExists | Audits a parent resource when a specified related/child resource does not exist. The parent resource is allowed to deploy; the audit marks it non-compliant if the related resource is absent. | Audit VMs without the Azure Monitor Agent extension; audit storage accounts without Defender for Storage enabled; audit App Services without diagnostic settings. |
| DeployIfNotExists (DINE) | Deploys a related resource if it doesn't exist. Actively remediates the gap — does not just audit it. Requires a managed identity on the assignment with sufficient permissions to deploy the related resource. | Automatically deploy diagnostic settings on new storage accounts; deploy Log Analytics agent to new VMs; enable Defender for Storage on new storage accounts. |
Policy Evaluation Logic
Understanding when policies are evaluated is as important as understanding effects.
New and updated resources
When a resource is created or updated (via portal, CLI, ARM template, Terraform, or any other mechanism), Azure evaluates all applicable policies at the ARM layer before writing the resource. Deny effects fire here and return a 403 to the caller. This happens synchronously during the deployment.
Existing resources
Policies do not retroactively block existing non-compliant resources. Existing resources are evaluated during compliance scan cycles. These run:
- Automatically approximately every 24 hours on a schedule Azure controls
- On-demand via
az policy state trigger-scanor the portal's "Trigger evaluation" button - Immediately after a new policy assignment is made (on the resources within that scope)
Policy Initiatives (Policy Sets)
An initiative is a collection of policy definitions grouped together to achieve a common governance goal. Instead of assigning 50 individual policies, you assign one initiative. Compliance is reported at both the initiative level and the individual policy level within it.
Built-in initiatives for compliance frameworks
| Initiative | Purpose | Typical assignment scope |
|---|---|---|
| Azure Security Benchmark | Microsoft's baseline security recommendations for Azure. Good starting point for any environment. | Root Management Group or per-environment subscription |
| CIS Microsoft Azure Foundations Benchmark | Center for Internet Security hardening guidelines mapped to Azure policies. | Production subscriptions requiring CIS compliance |
| NIST SP 800-53 Rev. 5 | US federal controls framework. Required for FedRAMP and many US government workloads. | Government or regulated environment subscriptions |
| PCI DSS v4.0 | Payment card industry data security standard. Required for cardholder data environments. | Subscriptions containing CDE (cardholder data environment) workloads |
| ISO 27001:2013 | International information security management standard. | Enterprise-wide or per-certification-scope subscriptions |
Policy Assignments
A policy assignment is the binding of a policy (or initiative) definition to a scope. The same definition can be assigned at multiple scopes with different parameters and different enforcement modes.
Assignment components
| Component | Description |
|---|---|
| Scope | Management Group, Subscription, or Resource Group. Lower scope = narrower application. RBAC applies: you need write permissions on the scope to create an assignment. |
| Parameters | Override the policy definition's default parameter values for this specific assignment. E.g. set allowedLocations to ["eastus", "westus2"] for this subscription while a different subscription uses ["northeurope"]. |
| Non-compliance message | A custom message shown to deployers when their resource is blocked by this policy. Should clearly explain what the user must do differently. |
| Enforcement mode | Enabled: policy is fully enforced (Deny fires, DINE deploys). Disabled: policy evaluates for compliance reporting only, but Deny does not block and DINE does not deploy — useful for pre-testing a policy in production. |
| Managed identity | Required for Modify and DeployIfNotExists effects. Azure creates a system-assigned managed identity for the assignment; you must grant it the necessary RBAC role. |
Policy Exclusions vs. Exemptions — A Critical Distinction
Both mechanisms allow resources to be excluded from a policy assignment, but they behave very differently:
| Property | Exclusion (notScope) | Exemption |
|---|---|---|
| How configured | A scope listed in notScope on the assignment — set at assignment creation time | A separate Exemption resource created on a specific resource or scope |
| Granularity | Entire scope (subscription, resource group) — cannot target individual resources | Can target a specific resource, resource group, or subscription |
| Compliance dashboard | Excluded resources are invisible — they do not appear in compliance reports at all | Exempt resources appear in the compliance dashboard with state Exempt and the documented reason |
| Time limit | Permanent — no expiry | Time-bounded — has an optional expiry date (after which the resource becomes non-compliant again) |
| Documented reason | No — no audit trail or reason required | Yes — requires a category (Waiver or Mitigated) and a description |
| Audit trail | No dedicated audit trail — it is just a scope in the assignment definition | Appears in Activity Log; shows in compliance report as Exempt |
notScope to exclude a resource makes it invisible to compliance reports — your auditors will have no way to see the exception was made. Exemptions with documented reasons appear in reports as Exempt with justification, satisfying audit requirements. Use notScope only for entire development environments or sandboxes that should never contribute to production compliance metrics.
Remediation Tasks
Policies with Modify or DeployIfNotExists effects can automatically fix non-compliant existing resources through remediation tasks. New resources are handled at deployment time; existing resources require an explicit remediation task.
How remediation works
- A policy with DINE or Modify effect is assigned, or resources already exist that are non-compliant with such a policy.
- The compliance scan identifies non-compliant resources.
- An administrator triggers a Remediation Task from the Policy compliance blade (or it can be configured to auto-remediate on assignment).
- Azure iterates through all non-compliant resources in scope and applies the effect — deploying the missing resource (DINE) or modifying the existing resource (Modify).
- The remediation task runs using the managed identity attached to the policy assignment. If the managed identity lacks permissions, individual resources will fail to remediate and you'll see per-resource errors in the task log.
Compliance States
The Azure Policy compliance dashboard reports four possible states per resource per assignment:
| State | Meaning | Action required |
|---|---|---|
| Compliant | Resource satisfies the policy condition | None |
| Non-compliant | Resource does not satisfy the policy condition. For Audit/AuditIfNotExists policies, the resource is deployed but flagged. For Deny policies, this state indicates an existing resource that pre-dates the policy assignment. | Remediate the resource (for Modify/DINE policies), or manually bring it into compliance |
| Exempt | Resource has an active Exemption applied | Review exemption justification and expiry — ensure it is still valid |
| Conflict | Two or more policy assignments produce contradictory evaluations for the same resource (e.g. one policy requires tag value "A" and another requires tag value "B" for the same tag) | Resolve by making one policy more specific, adding an exemption, or consolidating the conflicting assignments |
Common Real-World Policies (Production Reference)
These are the policies you will encounter most frequently in real Azure environments. Know their names, effects, and how they are typically configured:
| Policy | Effect | Notes |
|---|---|---|
| Allowed locations | Deny | Restricts resource creation to specific Azure regions. Assign at Management Group scope to cover all subscriptions. Use parameters to customise per-environment allowed locations. |
| Require a tag and its value | Deny | Blocks resources that are missing a specific tag or have an incorrect value. Commonly used for CostCenter, Environment, Owner. |
| Inherit a tag from resource group | Modify | Copies a tag value from the resource group to child resources at create/update time. Requires a managed identity on the assignment with Tag Contributor or Contributor role. |
| Allowed virtual machine SKUs | Deny | Restricts VM creation to an approved list of SKUs. Prevents engineers from accidentally deploying oversized or expensive SKUs in dev/test environments. |
| Secure transfer to storage accounts should be enabled | Deny | Blocks creation of storage accounts with HTTPS-only disabled. One of the most important baseline security policies — no exceptions. |
| Deploy Log Analytics agent to Windows/Linux VMs | DeployIfNotExists | Automatically deploys the Log Analytics (or Azure Monitor) agent extension to new VMs. Requires managed identity with VM Contributor + Log Analytics Contributor roles. |
| Audit VMs without backup configured | AuditIfNotExists | Audits VMs that do not have an active Azure Backup protection item. Uses AuditIfNotExists to check for the absence of the backup-related child resource. |
| Storage accounts should use customer-managed keys | Audit | Flags storage accounts not encrypted with CMK. Commonly used in regulated industries to enforce CMK over Microsoft-managed keys. |
Azure Blueprints vs. Deployment Stacks
Azure Blueprints was Microsoft's original mechanism for packaging ARM templates, RBAC assignments, and Policy assignments together for repeatable environment deployment. Blueprints are deprecated — Microsoft stopped developing them and recommends migration to the replacement: Azure Deployment Stacks.
| Feature | Azure Blueprints (deprecated) | Azure Deployment Stacks |
|---|---|---|
| Status | Deprecated — will be retired | GA — active development |
| Template support | ARM templates only | ARM templates and Bicep files |
| Deny assignments | Yes — could lock down blueprint-managed resources | Yes — DenySettings control what operations are allowed on stack-managed resources |
| Scope | Subscription and management group | Resource group, subscription, and management group |
| CI/CD integration | Limited | Native Azure CLI / PowerShell / Bicep support — integrates naturally with pipelines |
Hands-On: Assign and Evaluate a Policy
- Assign the Azure Security Benchmark initiative: Navigate to Policy → Definitions. Filter by Category = Security Center. Find the Azure Security Benchmark initiative. Click Assign. Set scope to a development subscription. Set enforcement mode to DoNotEnforce (Disabled) — this evaluates for compliance without blocking anything. Submit the assignment.
- Trigger a compliance scan: Go to Policy → Compliance. Find your initiative assignment. Click the "…" menu → Trigger evaluation. Wait 5–10 minutes for initial results to appear. Examine which policies show Non-compliant resources.
-
Create a custom Deny policy: Go to Policy → Definitions → + Policy definition. Set the scope to your subscription. Create a policy that denies storage account creation when
supportsHttpsTrafficOnlyis nottrue. Use the JSON example from earlier in this lesson. Assign it with enforcement mode Enabled. - Test the Deny policy: Attempt to create a storage account with Secure transfer required set to Disabled. The deployment should fail with a policy violation message. Examine the error — it will reference the policy definition name and assignment. Then create the same storage account with HTTPS enabled — it should succeed.
- Create an exemption: For one non-compliant resource in the compliance dashboard, create an Exemption. Set category to Waiver, add a justification note, and set an expiry date 30 days in the future. Observe how the compliance state changes to Exempt and the exemption appears in the compliance report.
Check Your Understanding
Click any option to see immediate feedback. These questions reflect real exam reasoning and production decision-making.
1. You assign a policy with Deny effect to a Management Group. An Owner of a subscription inside that MG deploys a resource that violates the policy. What happens?
2. You want to automatically add a missing CostCenter tag to resources deployed without it, inheriting the value from their resource group. Which policy effect should you use?
resourceGroup().tags['CostCenter'] expression and write it to the resource. Append can add a field but cannot read from a parent scope to inherit a value, and cannot replace an existing incorrect value. Deny (B) would block deployments but not automatically fix them — creating friction for engineers rather than a seamless governance control. AuditIfNotExists (D) only audits and makes no changes.3. A policy with DeployIfNotExists effect needs to automatically deploy a diagnostic setting on every new storage account. What does the policy assignment require beyond the definition itself?
4. What is the difference between a policy exclusion (notScope) and a policy exemption?
5. You assign an initiative containing 50 policy definitions to a subscription. Three policies in the initiative overlap with a separate Deny policy assigned at the Management Group. What compliance state will a resource show when it satisfies the initiative but violates the standalone MG-level Deny policy?
6. You need to audit whether all VMs have the Azure Monitor Agent extension installed, without blocking deployments of VMs that don't have it. Which policy effect is correct?
Also read: Understand Azure Policy effects (the canonical reference for all effect semantics and evaluation order) and Azure Policy exemption structure. The effects article is required reading before the exam.
This lesson covered the full Azure Policy model. There is significant depth to explore — ask your teacher to go deeper on any of these:
- Walk me through authoring a complete DeployIfNotExists policy definition in JSON that deploys diagnostic settings to a storage account, including the managed identity configuration.
- How does the policy evaluation order interact with ARM template deployments that create multiple resources — does each resource get evaluated independently?
- When should I use Azure Policy's Modify effect vs. a DeployIfNotExists effect for tag inheritance — what are the operational trade-offs?
- How do I migrate an existing Azure Blueprint assignment to Deployment Stacks without disrupting production environments?