Restricting Azure Resource Locations with Azure Policy

Restricting which Azure regions resources can be created in is one of the most common compliance requirements — required by GDPR, data sovereignty laws, and internal governance policies alike. Azure Policy makes this enforceable with a single built-in policy definition, and the CLI walkthrough below covers assignment, testing, and understanding what happens with existing resources.

Why location restrictions matter

When engineers create Azure resources manually or through automation, there is nothing in the default experience that prevents them from selecting West Europe when the organization requires all data to stay in the United States. Location restrictions exist because:

  • Data residency requirements: Regulations like GDPR (EU), the Health Insurance Portability and Accountability Act (HIPAA, US), and industry-specific frameworks specify where data must be stored and processed. Accidentally creating a database in a non-compliant region is a compliance violation.
  • Internal governance: Organizations with centralized IT may restrict regions to those where they have support agreements, committed use discounts, or established network infrastructure.
  • Cost control: Azure pricing varies by region. Restricting to specific regions prevents engineers from creating resources in regions with higher base pricing.
  • Audit and certification: Compliance audits require evidence that controls are enforced, not just documented. A policy with a deny effect provides a technical control that satisfies auditor requirements better than a policy document alone.

The built-in Allowed locations policy

Azure ships with a built-in policy definition named “Allowed locations”. Its policy definition ID is e56962a6-4747-49cd-b67b-bf8b01975c4c. It accepts an array of allowed location names and applies a deny effect to any resource whose location is not in the list.

There is also a second built-in policy, “Allowed locations for resource groups” (ID: e765b5de-1225-4ba3-bd56-1ac6695af988), which restricts where resource groups themselves can be created. Both policies are independent — you typically assign both if you want full coverage.

# Confirm the built-in policy exists and view its details
az policy definition show \
  --name "e56962a6-4747-49cd-b67b-bf8b01975c4c" \
  --query '{displayName:displayName, description:description, effect:policyRule.then.effect}' \
  --output json

Step-by-step: assign the policy to a subscription

Step 1: Identify your subscription ID and target regions

# Get your active subscription ID
SUBSCRIPTION_ID=$(az account show --query id --output tsv)
echo "Subscription: $SUBSCRIPTION_ID"

# List available Azure regions (to confirm the exact location name strings)
az account list-locations \
  --query "[].{DisplayName:displayName, Name:name}" \
  --output table | grep -i "us"

Location names in Azure Policy are the programmatic names, not the display names. eastus not “East US”. Use the name column from the above output.

Step 2: Assign the Allowed locations policy

POLICY_DEFINITION_ID="/providers/Microsoft.Authorization/policyDefinitions/e56962a6-4747-49cd-b67b-bf8b01975c4c"

az policy assignment create \
  --name "allowed-locations-us-only" \
  --display-name "Restrict resources to US regions" \
  --description "Denies creation of resources outside approved US regions" \
  --policy "$POLICY_DEFINITION_ID" \
  --scope "/subscriptions/$SUBSCRIPTION_ID" \
  --params '{
    "listOfAllowedLocations": {
      "value": ["eastus", "eastus2", "westus", "westus2", "centralus", "global"]
    }
  }'

Note the “global” value in the allowed list. Some Azure resources (DNS zones, certain global services) use global as their location. Without it, those resource types would appear non-compliant even though they have no geographic data placement.

Step 3: Assign the matching resource group location policy

RG_POLICY_ID="/providers/Microsoft.Authorization/policyDefinitions/e765b5de-1225-4ba3-bd56-1ac6695af988"

az policy assignment create \
  --name "allowed-locations-rg-us-only" \
  --display-name "Restrict resource groups to US regions" \
  --policy "$RG_POLICY_ID" \
  --scope "/subscriptions/$SUBSCRIPTION_ID" \
  --params '{
    "listOfAllowedLocations": {
      "value": ["eastus", "eastus2", "westus", "westus2", "centralus"]
    }
  }'

Policy assignments can take up to 30 minutes to propagate and become fully enforced. In practice, enforcement is usually active within a few minutes, but allow time before testing in automated pipelines.

Testing the policy by attempting a blocked deployment

After assigning the policy, try to create a resource in a blocked region. This confirms the policy is working as expected.

# Attempt to create a resource group in North Europe (blocked)
az group create \
  --name test-blocked-rg \
  --location "northeurope"

The command returns a 403 error with output similar to this:

{
  "error": {
    "code": "RequestDisallowedByPolicy",
    "target": "test-blocked-rg",
    "message": "Resource 'test-blocked-rg' was disallowed by policy.
                Policy identifiers: '[{\"policyAssignment\":{
                  \"name\":\"allowed-locations-rg-us-only\",
                  \"id\":\"/subscriptions/.../providers/Microsoft.Authorization/policyAssignments/allowed-locations-rg-us-only\"
                },\"policyDefinition\":{...}}]'.",
    "additionalInfo": [
      {
        "type": "PolicyViolation",
        "info": {
          "policyDefinitionDisplayName": "Allowed locations for resource groups",
          "evaluationDetails": {
            "evaluatedExpressions": [
              {
                "result": "True",
                "expressionKind": "field",
                "expression": "location",
                "path": "location",
                "expressionValue": "northeurope",
                "targetValue": ["eastus","eastus2","westus","westus2","centralus"],
                "operator": "notIn"
              }
            ]
          },
          "policyAssignmentName": "allowed-locations-rg-us-only"
        }
      }
    ]
  }
}

The error output tells you exactly which policy blocked the request (allowed-locations-rg-us-only), which field triggered it (location), and what the evaluated value was (northeurope). This makes it straightforward for engineers to understand why their deployment failed and what to change.

Now confirm that a compliant resource creation succeeds:

# This should succeed
az group create \
  --name test-compliant-rg \
  --location "eastus"

# Clean up
az group delete --name test-compliant-rg --yes --no-wait

Viewing compliance state for existing resources

After assignment, Azure Policy evaluates all existing resources against the new policy. Resources created before the policy was assigned may be non-compliant. View the compliance state with the CLI:

# Check compliance summary for the assignment
az policy state summarize \
  --policy-assignment "allowed-locations-us-only" \
  --query '{
    compliantResources:results.resourceDetails[?complianceState=='"'"'Compliant'"'"'] | length(@),
    nonCompliantResources:results.resourceDetails[?complianceState=='"'"'NonCompliant'"'"'] | length(@)
  }'

# List all non-compliant resources
az policy state list \
  --policy-assignment "allowed-locations-us-only" \
  --filter "complianceState eq 'NonCompliant'" \
  --query "[].{ResourceID:resourceId, Location:additionalInfo[0].info.expressionValue}" \
  --output table

Handling existing non-compliant resources

The Allowed Locations policy uses the deny effect, which only blocks new deployments — it does not and cannot move existing resources to different regions. For existing non-compliant resources, you have three options:

Option 1: Add an exclusion for legitimate exceptions

If a resource in a non-compliant region is there for a valid reason (a partner integration that requires a specific region, a legacy system being migrated), add a policy exclusion rather than leaving it as a persistent compliance failure:

# Update the assignment to exclude a specific resource group
az policy assignment update \
  --name "allowed-locations-us-only" \
  --not-scopes "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/legacy-eu-rg"

Option 2: Migrate the resource

Many Azure resource types support moving to a different region using Azure Resource Mover. For others, the process is to create a new instance in the allowed region, migrate data, update connection strings, and decommission the old instance. This is the correct long-term resolution for compliance.

Option 3: Accept the non-compliance with a tracked exception

If migration is planned but not immediate, track the exception in your compliance dashboard by adding an exemption to the policy assignment for that specific resource. Policy exemptions (available in Entra ID P1 or above) allow marking a resource as “waived” or “mitigated” with an expiry date, so it shows as exempt rather than non-compliant in the dashboard.

Applying the policy at management group level

For organizations with multiple subscriptions, assigning the location policy at management group scope means it applies to every subscription under that management group — new subscriptions added later are automatically covered.

# Get the management group ID
MGMT_GROUP_ID=$(az account management-group list \
  --query "[0].name" \
  --output tsv)

# Assign at management group scope
az policy assignment create \
  --name "allowed-locations-enterprise" \
  --display-name "Enterprise: Restrict to US regions" \
  --policy "$POLICY_DEFINITION_ID" \
  --scope "/providers/Microsoft.Management/managementGroups/$MGMT_GROUP_ID" \
  --params '{
    "listOfAllowedLocations": {
      "value": ["eastus", "eastus2", "westus", "westus2", "centralus", "global"]
    }
  }'

Management group assignments are appropriate for compliance standards that apply across the entire organization. Individual subscription-level assignments are better for exceptions or more restrictive sub-policies. For more on how management groups structure Azure environments, see Azure resource hierarchy.

For a broader understanding of what Azure Policy can enforce beyond location, see the Azure Policy overview page.

Common mistakes when restricting locations

  1. Forgetting to include “global” in the allowed list. Without “global”, resources like Azure DNS zones and some API Management features will appear non-compliant even though they store no data in a specific region. Always include “global” unless you have a specific reason not to.
  2. Assigning only the resource policy and forgetting resource groups. Resources and resource groups are evaluated separately. If you restrict resources to US regions but not resource groups, users can still create resource groups in Europe — the resources inside them will be blocked, but the resource group will exist, causing confusion.
  3. Using display names instead of programmatic names in the allowed list. The policy requires programmatic names like eastus, not display names like “East US”. Using display names causes the policy to evaluate all locations as non-compliant because no resource location matches the incorrectly formatted string.
  4. Not communicating the change to engineering teams before assigning. A deny policy assigned without notice will immediately block developers from deploying to their usual regions. Announce the change, document the approved regions list, and provide a grace period using audit effect before switching to deny.

Frequently asked questions

Does the Allowed Locations policy apply to Azure global services like Azure Active Directory or Azure DNS?

No. Resources that do not have a geographic location — such as Azure DNS zones, Microsoft Entra ID objects, and some global services — have a location value of "global". The Allowed Locations built-in policy skips resource types that return "global" as their location because they are not geographically bound. You can include "global" in your allowed locations list to explicitly permit these resource types without issue.

Can I exclude a specific resource group from a location policy assigned at the subscription level?

Yes. Policy assignments support exclusions. When creating or editing an assignment, you can specify resource groups, subscriptions, or management groups to exclude from the policy scope. Use this sparingly — too many exclusions undermine the compliance goal — but it is useful for pilot rollouts or for resource groups used by tools that require specific locations.

If a resource is already in a blocked region, will the policy delete it?

No. Azure Policy never deletes existing resources. A deny effect only blocks new creation and updates. An existing non-compliant resource will show up as non-compliant in the compliance dashboard, but it continues to operate. To remediate, you must move or recreate the resource in a compliant region, or add it to a policy exclusion if an exception is warranted.

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