Azure Policy Overview: Governance Rules for Azure Resources

Azure Policy is a governance service that lets you define and enforce rules about what Azure resources can look like, where they can be created, and what properties they must have. Unlike Azure RBAC — which controls who can act — Azure Policy controls what those actions are allowed to produce.

What Azure Policy does

Every time a resource is created or updated in Azure, Azure Policy evaluates the request against any policies assigned at the relevant scope. Depending on the policy’s effect, the result may be:

  • The request is denied before the resource is created.
  • The request is allowed but a non-compliance record is written for auditing.
  • A related resource is automatically deployed alongside the main resource.
  • A property on the resource is automatically modified to meet the requirement.

Azure Policy also continuously evaluates existing resources. A resource created before a policy was assigned can still appear as non-compliant. This is important for compliance reporting — you can see not just whether new resources comply, but whether your entire existing estate meets your standards.

Common use cases for Azure Policy include:

  • Restricting which Azure regions resources can be created in (data residency for GDPR, HIPAA, etc.).
  • Requiring specific tags on all resources (for cost allocation and ownership tracking).
  • Blocking creation of resources without encryption enabled.
  • Enforcing that all storage accounts use HTTPS-only access.
  • Ensuring diagnostic settings are enabled on all Key Vaults.
  • Limiting which virtual machine SKUs can be deployed (to control costs).

Policy vs RBAC: a clear distinction

Azure RBAC answers: “Can this user create a virtual machine in this subscription?” (permission check).

Azure Policy answers: “Is this virtual machine being created in an approved region with the required tags?” (compliance check).

They work independently. A user with the Contributor RBAC role has permission to create resources, but Azure Policy can still deny the specific resource if it does not meet policy requirements. A deny policy can block an action even from a subscription owner, because policy evaluation happens at the Azure Resource Manager layer before the action is executed.

The exception: users with the Owner role can modify policy assignments — if they have been granted the appropriate Policy Contributor role or are an Owner at that scope. But they cannot bypass a policy that has already been evaluated.

Policy effect types

The effect field in a policy definition determines what happens when a resource does not comply. There are several effect types, and choosing the right one matters.

Deny

Blocks the resource creation or update request. The user receives a 403 error with a message indicating which policy blocked the request. This is the strongest effect — use it when a non-compliant resource must never exist.

Audit

Allows the resource to be created but records a non-compliance event in the policy compliance dashboard. Nothing is blocked. Use this when you want to measure compliance before enforcing it, or when you cannot block certain actions without breaking existing workflows.

AuditIfNotExists

Evaluates a related resource. For example: “Audit if a storage account does not have a private endpoint.” The audit record is created on the main resource (the storage account) if the related resource (the private endpoint) does not exist. This cannot block — it only audits.

DeployIfNotExists

When a resource is created and a related resource does not exist, automatically deploys the related resource. For example, when a VM is created without diagnostic settings, deploy the diagnostic settings automatically. This effect requires a managed identity assigned to the policy assignment, because it needs permission to create the related resource.

Modify

Adds or changes tags or properties on a resource during creation or update. For example, automatically add a created-by-policy: true tag to all resources, or set the httpsOnly property on all storage accounts to true. Like DeployIfNotExists, this also requires a managed identity on the assignment.

Disabled

Turns off the policy evaluation entirely. Useful for temporarily disabling a policy without deleting the assignment.

Effect precedence when multiple policies apply to the same resource: Disabled → Append → Deny → Audit → AuditIfNotExists → DeployIfNotExists → Modify. If one policy says Deny and another says Audit, the deny takes effect.

A real policy definition: deny resources outside allowed regions

Azure has a built-in policy for this, but examining a custom definition shows every field and its purpose. The following policy denies creation of any resource outside of eastus and westus.

{
  "mode": "All",
  "displayName": "Allowed resource locations - East US and West US only",
  "description": "Denies creation of resources in any location other than East US or West US.",
  "parameters": {
    "allowedLocations": {
      "type": "Array",
      "metadata": {
        "displayName": "Allowed locations",
        "description": "The list of locations that resources can be created in."
      },
      "defaultValue": ["eastus", "westus"]
    }
  },
  "policyRule": {
    "if": {
      "not": {
        "field": "location",
        "in": "[parameters('allowedLocations')]"
      }
    },
    "then": {
      "effect": "deny"
    }
  }
}

Breaking down each field:

  • mode: “All” means the policy applies to all resource types. Use “Indexed” if you only want it to apply to resource types that support location and tags.
  • parameters: Makes the policy reusable. Instead of hard-coding the allowed locations, they are passed in at assignment time. The defaultValue is used if no value is provided during assignment.
  • policyRule.if: The condition that triggers the effect. Here: if the resource’s location is NOT in the list of allowed locations.
  • policyRule.then.effect: What happens when the condition is true — in this case, deny the request.
  • field: “location”: Refers to the resource’s location property. The Policy language has dozens of built-in field aliases for common resource properties.

Assigning the policy to a subscription via the CLI

To use a custom policy definition, first create the definition, then assign it to a scope.

# Step 1: Save the policy JSON to a file
# (Assume the JSON above is saved as allowed-locations-policy.json)

# Step 2: Create the policy definition at subscription scope
az policy definition create \
  --name "allowed-locations-custom" \
  --display-name "Allowed resource locations" \
  --description "Denies resources outside East US and West US" \
  --rules @allowed-locations-policy.json \
  --mode All

# Step 3: Get the policy definition ID
POLICY_ID=$(az policy definition show \
  --name "allowed-locations-custom" \
  --query id \
  --output tsv)

# Step 4: Get the current subscription ID
SUBSCRIPTION_ID=$(az account show --query id --output tsv)

# Step 5: Assign the policy to the subscription
az policy assignment create \
  --name "enforce-allowed-locations" \
  --display-name "Enforce allowed resource locations" \
  --policy "$POLICY_ID" \
  --scope "/subscriptions/$SUBSCRIPTION_ID" \
  --params '{"allowedLocations": {"value": ["eastus", "westus", "eastus2"]}}'

After assignment, any attempt to create a resource in a disallowed region returns a 403 error. The error message identifies the specific policy assignment that blocked the request.

Test with audit effect before switching to deny. This lets you see what would be blocked without disrupting existing workflows. Once you confirm the compliance report shows only the resources you intended to catch, update the effect to deny.

Policy initiatives: grouping policies for a compliance standard

A policy initiative (also called a policy set definition) is a collection of policy definitions assigned together. Instead of creating and managing dozens of individual policy assignments, you create one initiative and assign it once.

Azure includes built-in initiatives for common compliance frameworks:

  • Azure Security Benchmark: Microsoft’s best-practice recommendations, covering identity, networking, data protection, and more.
  • NIST SP 800-53: US federal security controls.
  • ISO 27001: International information security standard.
  • PCI DSS: Payment card industry data security standard.
  • CIS Microsoft Azure Foundations Benchmark: Center for Internet Security Azure hardening guide.
# List built-in policy initiatives
az policy set-definition list \
  --query "[?policyType=='BuiltIn'].{Name:displayName, ID:name}" \
  --output table

# Assign the Azure Security Benchmark initiative to a subscription
INITIATIVE_ID=$(az policy set-definition show \
  --name "1f3afdf9-d0c9-4c3d-847f-89da613e70a8" \
  --query id \
  --output tsv)

az policy assignment create \
  --name "azure-security-benchmark" \
  --display-name "Azure Security Benchmark" \
  --policy-set-definition "$INITIATIVE_ID" \
  --scope "/subscriptions/$SUBSCRIPTION_ID"

After assigning an initiative, the compliance dashboard groups all policy results under the initiative name, making it easy to see overall compliance percentage and which individual policies are failing.

Built-in vs custom policies

Azure ships with hundreds of built-in policy definitions maintained by Microsoft. They cover common scenarios: allowed locations, required tags, storage account HTTPS, VM disk encryption, Key Vault soft delete, and much more. Before writing a custom policy, always search the built-in library — the policy you need almost certainly exists.

# Search built-in policies by keyword
az policy definition list \
  --query "[?policyType=='BuiltIn' && contains(displayName, 'location')].{Name:displayName}" \
  --output table

Custom policies are needed when built-in policies do not cover your specific requirement — for example, enforcing a specific naming convention unique to your organization, or requiring a custom tag schema. Custom policies are defined in JSON using the Policy definition language and can be shared across subscriptions using management group scope.

For location restrictions specifically, see the dedicated restricting resource locations page for a step-by-step walkthrough including testing and remediation.

Common mistakes with Azure Policy

  1. Assigning deny policies to production without testing first. If you assign a deny policy and it is broader than you intended, it can block legitimate resource creation immediately. Always use the audit effect first, review the compliance report, and only switch to deny when you are confident the scope is correct.
  2. Not understanding that policies apply to existing resources too. A policy assigned today will flag resources created before the policy existed as non-compliant. This is not a bug — it is the audit function working correctly. Plan for a remediation window when assigning new policies to large environments.
  3. Confusing policy scope with RBAC scope. A policy assigned at the management group scope applies to all subscriptions under that management group. This is more powerful than subscription scope — be deliberate about where you assign policies.
  4. Forgetting to assign a managed identity for DeployIfNotExists and Modify effects. These effects require a managed identity on the policy assignment to perform write actions. If you forget this, the policy evaluates correctly but the remediation never runs, leaving you wondering why non-compliant resources are not being fixed.
  5. Using too many individual policy assignments instead of initiatives. If you assign 50 individual policies to the same scope, the compliance dashboard becomes hard to read. Group related policies into an initiative for cleaner reporting.

Frequently asked questions

Does Azure Policy replace Azure RBAC?

No. They serve different purposes. Azure RBAC controls what actions a user or application can perform (who can create resources, who can read data). Azure Policy controls what properties resources must or must not have (which regions are allowed, which SKUs are permitted, whether tags are required). A user with the Contributor RBAC role can still be blocked by a policy that denies creation of resources in unapproved regions. Both systems are complementary and work independently.

Can I apply a policy that fixes existing non-compliant resources automatically?

Yes, using the deployIfNotExists and modify effects. These effects can create remediation tasks that apply corrections to existing resources. The deployIfNotExists effect can deploy a related resource (for example, enabling diagnostic settings on all storage accounts). The modify effect can add or change properties on existing resources. You trigger remediation manually or set it to auto-remediate. Not all policies support remediation — audit and deny effects only check, they do not fix.

What is the difference between a policy and a policy initiative?

A policy definition is a single rule (for example, "require a tag named environment on all resources"). A policy initiative (also called a policy set definition) is a named collection of policy definitions grouped for a common compliance goal. For example, the built-in "Azure Security Benchmark" initiative contains over 200 individual policy definitions. Assigning the initiative assigns all of them at once. Initiatives make it easier to track compliance against a standard rather than managing hundreds of individual assignments.

Last verified: 19 March 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.