Skip to main content

Implementing Azure Policy for Compliance at Scale

Learn how Azure Policy automatically enforces and audits resource rules across a subscription, and how it differs from RBAC.

Overview and What You Will Learn

In this lab, you will assign a built-in Azure Policy that requires a specific tag on every resource, run it in audit mode first, and see exactly how Policy differs from RBAC in what problem it actually solves.

Why This Matters in Production

At an organization the size of Swiggy, asking fifty engineers to "please remember to tag every resource with a cost center" reliably fails within weeks - some people forget, some tag inconsistently, and finance ends up unable to allocate cloud spend accurately. Azure Policy turns that request from a matter of individual discipline into an automatically enforced rule.

Core Principles

RBAC and Azure Policy solve two genuinely different problems, and confusing them is one of the most common governance mistakes.

◈ DIAGRAM
+------------------------------------------+ +------------------------------------------+
| RBAC | | Azure Policy |
| Controls WHO can do something | -------> | Controls WHAT a resource is allowed |
| (identity + permission) | | to look like (configuration + compliance)|
+------------------------------------------+ +------------------------------------------+

A single Policy defines one rule - "require this tag," for example. An Initiative groups several related policies into one package, useful for enforcing an entire standard (tagging, encryption, allowed regions) as a single assignable unit rather than several separate assignments.

◈ DIAGRAM
+------------------------------------------+
| Policy assigned at a scope |
+------------------------------------------+
|
v
+------------------------------------------+
| Evaluates every existing + new resource |
+------------------------------------------+
|
v
+------------------------------------------+
| Audit mode: reports non-compliant items |
| Deny mode: blocks non-compliant creation |
+------------------------------------------+

Detailed Step-by-Step Practical Lab

  1. Create a Resource Group to scope the policy assignment to:
Bash
az group create --name rg-policy-lab-mumbai --location centralindia
  1. Find the definition ID for a built-in tagging policy:
Bash
az policy definition list \
--query "[?contains(displayName, 'Require a tag')]" \
--output table
  1. Create a small parameters file for the policy assignment, rather than passing JSON inline on the command line:
Bash
cat > policy-params.json << 'PARAMSEOF'
tagName:
value: CostCenter
PARAMSEOF
Note

Passing parameters via a separate file instead of an inline JSON string keeps the command itself simple to read and avoids escaping quotes inside quotes - a pattern worth using anywhere a CLI command would otherwise need an embedded JSON object.

  1. Assign the policy in Audit mode first, so it reports without blocking anything:
Bash
az policy assignment create \
--name "require-costcenter-tag-audit" \
--scope "/subscriptions/<sub-id>/resourceGroups/rg-policy-lab-mumbai" \
--policy "<policy-definition-id-from-step-2>" \
--params policy-params.json
Note

Starting in Audit mode is deliberate. It lets you see which existing resources would fail the policy before you risk blocking a legitimate deployment with Deny mode.

  1. Create a resource without the required tag to see it get flagged as non-compliant:
Bash
az storage account create \
--name stpolicylabrahul \
--resource-group rg-policy-lab-mumbai \
--location centralindia \
--sku Standard_LRS
  1. Check the compliance state - it may take a few minutes for the evaluation to run:
Bash
az policy state list \
--resource-group rg-policy-lab-mumbai \
--output table
  1. Fix the compliance issue by applying the missing tag:
Bash
az resource tag \
--tags CostCenter=CC-4021 \
--resource-group rg-policy-lab-mumbai \
--name stpolicylabrahul \
--resource-type "Microsoft.Storage/storageAccounts"
  1. Once you trust the policy's behavior, this is the point where a real deployment would switch the assignment from Audit to Deny mode to actively block non-compliant resources going forward.

  2. Clean up:

Bash
az policy assignment delete --name "require-costcenter-tag-audit"
az group delete --name rg-policy-lab-mumbai --yes --no-wait

Production Best Practices & Common Pitfalls

Common Mistake

Assigning a new Azure Policy directly in Deny mode without testing it in Audit mode first. A policy with a small logic error can block an entire team's legitimate deployments the moment it goes live, with no warning beforehand.

Tip

Group related policies into an Initiative when you're enforcing a broader standard - like "every resource must be tagged, encrypted, and deployed only to approved regions" - rather than managing three separate policy assignments that could drift out of sync with each other.

  • Policy does not replace RBAC. A user can have full Contributor access (RBAC) and still be blocked from creating a non-compliant resource (Policy) - the two systems work together, not as substitutes for each other.
  • Compliance evaluation is not instant. Newly created resources may take several minutes to appear in a compliance report - do not assume a policy failed to apply just because a resource doesn't show up as evaluated immediately.

Quick Reference & Troubleshooting Commands

Command Description
az policy definition list List available built-in and custom policy definitions
az policy assignment create Assign a policy at a given scope
az policy state list Check compliance state for resources
az policy assignment delete Remove a policy assignment

Explore More in Azure Fundamentals and Governance

All 6 Topics

Frequently Asked Questions

Is Implementing Azure Policy for Compliance at Scale free to learn on DevOps Network?

Yes - this topic, like everything on DevOps Network, is 100% free with no paywall or sign-up gate.

What does the Implementing Azure Policy for Compliance at Scale topic cover?

Learn how Azure Policy automatically enforces and audits resource rules across a subscription, and how it differs from RBAC.