Azure Policy
Compatible with the Microsoft.Authorization policy management plane used by the Azure CLI
(az policy ...), the azurerm Terraform provider (azurerm_policy_definition,
azurerm_policy_set_definition, azurerm_*_policy_assignment, azurerm_*_policy_exemption) and the
Azure SDKs (azure-resourcemanager-resources, armpolicy, azure-mgmt-resource). Covers policy
definitions, policy set definitions (initiatives), policy assignments and policy
exemptions at every scope the real service accepts.
HTTP-only, no Docker. All policy state is in-memory and ephemeral, like the rest of the ARM control plane.
Control plane only. Definitions are stored and validated structurally, but policy rules are never evaluated against resource requests: nothing is denied, audited or remediated, and there is no compliance state (
Microsoft.PolicyInsightsis not implemented). Use this to exercise the code that authors and deploys policies, not the code that reacts to their effects.
Features
- Policy definitions at subscription and management-group scope: CreateOrUpdate, Get, Delete, List
(
$filter=policyType eq 'Custom'andatExactScope()are honoured).policyTypeis alwaysCustom,modedefaults toIndexed,versiondefaults to1.0.0, andmetadatagains thecreatedBy/createdOn/updatedBy/updatedOnstamps Azure adds - Policy set definitions at subscription and management-group scope: CreateOrUpdate, Get, Delete,
List. Each reference gets a server-generated
policyDefinitionReferenceIdwhen none is supplied and adefinitionVersionof1.*.* - Policy assignments at management-group, subscription, resource-group and resource scope:
Create, Get, Update (PATCH of
identity,location,resourceSelectors,overrides), Delete (returns the deleted assignment), List for subscription / resource group / resource / management group withatScope(),atExactScope(),atScopeAndBelow()andpolicyDefinitionId eq '...'.scope,enforcementMode,definitionVersionandinstanceIdare populated server-side; aSystemAssignedidentity receives a stableprincipalId, andUserAssignedidentities resolve theirprincipalId/clientIdfrom Managed Identity when the identity exists - Policy exemptions at the same scopes: CreateOrUpdate, Get, Update (PATCH of
resourceSelectors,assignmentScopeValidation), Delete (returns the deleted exemption), List withatScope(),atExactScope(),excludeExpired()andpolicyAssignmentId eq '...'. Exemptions are deleted together with their assignment - Referential integrity: assignments and set definitions must reference definitions that exist
(
PolicyDefinitionNotFound/PolicySetDefinitionNotFound), exemptions must reference an existing assignment (PolicyAssignmentNotFound), and a definition or set definition that is still referenced cannot be deleted (InvalidDeletePolicyDefinitionRequest/InvalidDeletePolicySetDefinitionRequest) - Azure error shapes:
PolicyDefinitionNotFound,PolicySetDefinitionNotFound,PolicyAssignmentNotFound,PolicyExemptionNotFound,InvalidPolicyRule,InvalidCreatePolicySetDefinitionRequest,InvalidPolicyDefinitionReference,MissingSubscriptionfor tenant-level writes, and ARM'sInvalidRequestContentfor malformed JSON
Endpoints
{scope} is empty (tenant root), providers/Microsoft.Management/managementGroups/{mg},
subscriptions/{sub}, subscriptions/{sub}/resourceGroups/{rg} or a full resource id.
# Definitions and set definitions: subscription or management-group scope
PUT /{scope}/providers/Microsoft.Authorization/policyDefinitions/{name}
GET /{scope}/providers/Microsoft.Authorization/policyDefinitions/{name}
DELETE /{scope}/providers/Microsoft.Authorization/policyDefinitions/{name}
GET /{scope}/providers/Microsoft.Authorization/policyDefinitions[?$filter=...]
PUT /{scope}/providers/Microsoft.Authorization/policySetDefinitions/{name}
GET /{scope}/providers/Microsoft.Authorization/policySetDefinitions/{name}
DELETE /{scope}/providers/Microsoft.Authorization/policySetDefinitions/{name}
GET /{scope}/providers/Microsoft.Authorization/policySetDefinitions[?$filter=...]
# Built-in listings at the tenant root (always empty, see deviations)
GET /providers/Microsoft.Authorization/policyDefinitions
GET /providers/Microsoft.Authorization/policySetDefinitions
# Assignments and exemptions: management group, subscription, resource group or resource scope
PUT /{scope}/providers/Microsoft.Authorization/policyAssignments/{name}
PATCH /{scope}/providers/Microsoft.Authorization/policyAssignments/{name}
GET /{scope}/providers/Microsoft.Authorization/policyAssignments/{name}
DELETE /{scope}/providers/Microsoft.Authorization/policyAssignments/{name}
GET /{scope}/providers/Microsoft.Authorization/policyAssignments[?$filter=...]
PUT /{scope}/providers/Microsoft.Authorization/policyExemptions/{name}
PATCH /{scope}/providers/Microsoft.Authorization/policyExemptions/{name}
GET /{scope}/providers/Microsoft.Authorization/policyExemptions/{name}
DELETE /{scope}/providers/Microsoft.Authorization/policyExemptions/{name}
GET /{scope}/providers/Microsoft.Authorization/policyExemptions[?$filter=...]
Any api-version is accepted. Shapes follow the policy spec 2025-03-01 and the exemptions spec
2022-07-01-preview.
Quickstart
1. Create a definition and assign it to a resource group
BASE=http://localhost:4577
SUB=00000000-0000-0000-0000-000000000001
curl -s -X PUT "$BASE/subscriptions/$SUB/providers/Microsoft.Authorization/policyDefinitions/allowed-locations?api-version=2025-03-01" \
-H "Content-Type: application/json" \
-d '{"properties":{"displayName":"Allowed locations","mode":"All",
"policyRule":{"if":{"field":"location","notIn":["eastus"]},"then":{"effect":"deny"}}}}'
curl -s -X PUT "$BASE/subscriptions/$SUB/resourceGroups/my-rg/providers/Microsoft.Authorization/policyAssignments/enforce-locations?api-version=2025-03-01" \
-H "Content-Type: application/json" \
-d "{\"location\":\"eastus\",\"identity\":{\"type\":\"SystemAssigned\"},
\"properties\":{\"policyDefinitionId\":\"/subscriptions/$SUB/providers/Microsoft.Authorization/policyDefinitions/allowed-locations\"}}"
{
"identity": {"principalId": "4f0c…", "tenantId": "00000000-0000-0000-0000-000000000002", "type": "SystemAssigned"},
"properties": {
"policyDefinitionId": "/subscriptions/…/providers/Microsoft.Authorization/policyDefinitions/allowed-locations",
"definitionVersion": "1.*.*",
"scope": "/subscriptions/…/resourceGroups/my-rg",
"metadata": {"createdBy": "…", "createdOn": "2026-09-04T10:00:00Z"},
"enforcementMode": "Default",
"instanceId": "…"
},
"id": "/subscriptions/…/resourceGroups/my-rg/providers/Microsoft.Authorization/policyAssignments/enforce-locations",
"type": "Microsoft.Authorization/policyAssignments",
"name": "enforce-locations",
"location": "eastus"
}
2. Azure CLI
With the CLI pointed at the emulator (see the compat-azcli suite for the custom-cloud setup):
az policy definition create --name allowed-locations --mode All \
--rules '{"if":{"field":"location","notIn":["eastus"]},"then":{"effect":"deny"}}'
az policy assignment create --name enforce-locations --policy allowed-locations -g my-rg
az policy exemption create --name legacy -g my-rg --exemption-category Waiver \
--policy-assignment "$(az policy assignment show -n enforce-locations -g my-rg --query id -o tsv)"
az policy assignment list -g my-rg
3. Terraform
resource "azurerm_policy_definition" "allowed_locations" {
name = "allowed-locations"
policy_type = "Custom"
mode = "All"
display_name = "Allowed locations"
policy_rule = jsonencode({
if = { field = "location", notIn = ["eastus"] }
then = { effect = "deny" }
})
}
resource "azurerm_resource_group_policy_assignment" "enforce" {
name = "enforce-locations"
resource_group_id = azurerm_resource_group.example.id
policy_definition_id = azurerm_policy_definition.allowed_locations.id
}
Configuration
| Property | Env var | Default | Description |
|---|---|---|---|
enabled |
FLOCI_AZ_SERVICES_POLICY_ENABLED |
true |
Enables the Microsoft.Authorization policy resources. When disabled, their paths fall through to the generic ARM handler and answer 404 |
Intentional deviations
- No enforcement and no compliance data. Policy rules are stored, not evaluated. Resource
requests are never denied with
RequestDisallowedByPolicy,audit/modify/deployIfNotExistseffects do nothing, andMicrosoft.PolicyInsights(policy states, remediations, compliance summaries) is not implemented. - No built-in definitions. Azure ships thousands of built-in definitions and initiatives; none are
seeded. Tenant-rooted listings return an empty collection, tenant-rooted reads return
PolicyDefinitionNotFound/PolicySetDefinitionNotFound, and built-in ids (/providers/Microsoft.Authorization/policyDefinitions/{guid}) are accepted in assignments and set definitions without validation. - Management groups are scopes, not resources.
Microsoft.Management/managementGroups/{mg}is accepted as a scope for definitions, set definitions, assignments and exemptions, but management groups themselves are not modelled: any id is accepted, there is no hierarchy, and a management-group assignment does not appear in subscription-scoped listings. - Policy rules are validated structurally only. A rule must be an object with an
ifcondition and athenblock that names aneffect; aliases, functions, parameter references and effect details are not checked. Assignment parameters are not validated against the definition's parameter schema. - Exemption scope is not validated against the assignment's scope (
assignmentScopeValidationis stored and echoed only). - Definition versions are not implemented.
versionssub-resources answer404;versionanddefinitionVersionare stored and echoed as plain strings. systemDataandmetadataaudit fields name a fixed emulator identity rather than the caller, andmetadata.updatedBy/updatedOnappear only after the first update instead of being present asnullfrom creation.- Listings are unpaginated (
nextLinkis never returned) and$topis ignored. - Policy state is in-memory only, regardless of
storage.mode, like the rest of the ARM control plane.