Azure Policy — effects, timing and RequestDisallowedByPolicy
What Azure Policy does to an agent's request and how to read its refusals — the effects (deny, denyAction, modify, append, audit, auditIfNotExists, deployIfNotExists, disabled) and their evaluation order, RequestDisallowedByPolicy and how to find the blocking assignment and definition, enforcement mode, exemptions, timing of new assignments and compliance scans, and the remediation identity for modify and deployIfNotExists.
markdownreferencev159K7-48G9stage: operatetrust: officialservice: policyinterface: any--acquire-policy-token--change-referenceacquirePolicyTokenx-ms-policy-external-evaluationsexternalEvaluationEnforcementSettingsmissingTokenActionFailed to acquire policy tokenAzure PolicyRequestDisallowedByPolicywas disallowed by policyPolicy identifierspolicyAssignment policyDefinitiondeny effect 403denyAction deletemodify effectappendauditauditIfNotExistsdeployIfNotExistsremediation managed identity roleDefinitionIdsenforcementMode DoNotEnforcepolicy exemption waiver mitigatedaz policy assignment showaz policy definition showaz policy state listcompliance scan 24 hourspolicy evaluation order
Azure Policy is not a permission. It runs after RBAC has allowed the call, so Owner can still be refused. A refusal names the assignment and the definition that blocked it, and the fix is almost always to change the request so it complies (a SKU, a region, a tag, publicNetworkAccess: Disabled), not to fight the policy.
Reading RequestDisallowedByPolicy
"statusMessage": {"error":{"code":"RequestDisallowedByPolicy","target":"examplenic1207",
"message":"Resource `examplenic1207` was disallowed by policy. Policy identifiers:
"policyAssignment":{"name":"Network interfaces should not have public IPs",
"id":"/subscriptions/{sub}/providers/Microsoft.Authorization/policyAssignments/1111aa2222bb3333cc4444dd"} …
"policyDefinition":{"name":…, "id":"…/policyDefinitions/<definition-name>"} …
(Microsoft's example, shortened.) The name shown is the display name; the real name, which the CLI needs, is the last segment of each id.
Then read the rule:
az policy definition show --name <definition-name>
az policy assignment show --name <assignment-name> --scope <scope-from-the-id>
The definition's policyRule.if says which property values are refused; the assignment's parameters fill in the allowed values (allowed locations, SKUs). If the message was lost, the Activity log of the target scope holds the same identifiers. A built-in definition lives at tenant scope (/providers/Microsoft.Authorization/policyDefinitions/…); a custom one at a management group or subscription (--management-group <mg> on definition show).
Effects, in evaluation order
| Effect | What it does to your request |
|---|---|
disabled | Nothing (checked first) |
append, modify | Change the request before it reaches the provider: add tags, set properties, set identity.type on VMs. Your deployed resource may differ from your template |
deny | Refuses create or update with 403, before the resource provider sees it |
audit | Allows, logs non-compliance |
manual | Allows; compliance is attested |
auditIfNotExists | Allows; after success, logs if a related resource is missing |
denyAction | Refuses the named action, today only DELETE, with 403. Policy assignments, deny assignments, locks, deployment stacks and subscriptions are exempt |
deployIfNotExists | After success, deploys a related resource (diagnostic settings, an agent: reference/monitor/diagnostic-settings-and-data-collection.md) using the assignment's managed identity |
modify and deployIfNotExists act through the assignment's identity, which needs the roles in the definition's roleDefinitionIds at the target scope. If remediation never happens, check that identity's role assignments. Existing resources are only fixed by a remediation task; a new assignment alone marks them non-compliant.
Timing
| Event | Takes effect |
|---|---|
| New assignment | About 5 minutes |
| New or updated resource appears in compliance | About 15 minutes |
| Full compliance scan | Every 24 hours (or start an on-demand scan) |
Tag-only PATCH | Only policies that inspect tags are evaluated |
When a policy you expect doesn't act
| Symptom | Cause | Check |
|---|---|---|
| Resource created despite a deny policy, no Activity log entry | Assignment enforcementMode is DoNotEnforce | az policy assignment show … --query enforcementMode |
| Tag or location policy ignores the resource | Definition mode should be indexed for tags and location, all for everything else | az policy definition show … --query mode |
| Resource ignored | Its scope is in the assignment's notScopes, or an exemption (waiver or mitigated, possibly with expiresOn) covers it | az policy assignment show … --query notScopes; az policy exemption list --scope <scope> |
| Compliance shows old results | Evaluation hasn't run yet (timings above) | az policy state list --resource <id> --top 5 |
Exemptions
An exemption takes a resource or scope out of one assignment (or some definitions in an initiative) for a reason category, optionally until expiresOn: az policy exemption create --name … --policy-assignment <assignment-id> --exemption-category waiver --scope <scope>. Creating one needs policy-exemption write permission at that scope; agents should propose an exemption to their human, not create one to get past a deny.
Policies that need an external evaluation (--acquire-policy-token)
In the policy API (stable 2025-03-01 and later, by its examples), a policy definition can carry externalEvaluationEnforcementSettings: before a write is allowed, an external endpoint (a change-approval system, for example) must have evaluated that exact operation. Its missingTokenAction (Audit or Deny) says what happens to a write that arrives without a policy token.
- The caller gets the token from
POST /subscriptions/{id}/providers/Microsoft.Authorization/acquirePolicyTokenwith the operation's URI, method and body (and an optionalchangeReference), then sends the write with the token in thex-ms-policy-external-evaluationsheader. The token is bound to the request: its URI, API version and a hash of the payload. - Azure CLI 2.91 does this for you: every write command accepts
--acquire-policy-tokenand--change-reference <id>. The CLI callsacquirePolicyToken(API 2025-11-01) with the same correlation ID, and fails withFailed to acquire policy token, exception: …orNo token returned. Response: …when the endpoint refuses. - A token response has a
result(Succeeded,Failed), per-endpointresultswith apolicyActionandmessage, aretryAfterfor retryable failures, and anexpiration.
When a write is denied by such a policy and you didn't pass a token, retry with --acquire-policy-token (and the change reference your human gives you). If the token request itself fails, the external system's message is the reason: don't work around it.
Next
Other refusal layers: guides/identity/fix-access-denied.md.