Every Azure Policy Exemption Should Come With an Expiry Date
How to stop permanent waivers from turning into quiet governance drift
Every Azure Policy Exemption Should Come With an Expiry Date
How to stop permanent waivers from turning into quiet governance drift

No expiration. No exemption.
The real problem
Most teams do not get in trouble because they created one exemption. They get in trouble because the exemption never leaves. A waiver created for a migration weekend becomes a six-month exception. A workaround for a legacy appliance becomes a normal operating state. Then the policy dashboard still looks clean enough that nobody feels the pain until audit, outage, or incident review.
Azure Policy exemptions are useful because they preserve an explicit record instead of hiding the issue. Microsoft documents that exemptions count toward overall compliance, can be scoped to assignments or initiative members, and can be made time-bound with the expiresOn property. That is exactly why they need stronger operational discipline than a one-line approval in a ticket.
Treat exemptions like leases. Owner, reason, end date, and review cadence are non-negotiable.
What Azure Policy exemptions actually do
At the platform level, an exemption is a first-class object under Microsoft.Authorization/policyExemptions. The important parts are simple:
- It targets a policy assignment or initiative assignment through policyAssignmentId.
- If the target is an initiative, you can narrow the exemption to specific policyDefinitionReferenceId values instead of exempting the whole initiative.
- The exemptionCategory is either Waiver or Mitigated.
- expiresOn is optional in the platform, but once the date passes, the exemption is no longer honored, even though the object remains for record-keeping.
- You can use resourceSelectors to narrow the exemption to a subset of resources by location, type, and other supported selector kinds.
That last point matters. The platform lets you be precise. If your internal process still issues broad, permanent exemptions, the tool is not the bottleneck. Your operating model is.
Opinionated blueprint: the minimum standard
This is the floor, not the gold-plated version. If your process does less than this, expect exemption sprawl.
Core record fields

Control fields
These are the fields that stop a valid exemption from decaying into silent debt.

How long should an exemption live?
I would not let the answer default to forever. Make teams justify longer terms instead of letting them inherit them.

Simple policy — The burden of proof should increase with scope and duration. The wider the exemption, the shorter the default term and the stronger the approval path.
Practical operating workflow
1) Make the request concrete Capture the assignment, the exact resource scope, why the policy is being bypassed, and what will make the exemption removable.
2) Narrow the blast radius If the assignment is an initiative, exempt only the relevant policyDefinitionReferenceId values. If only one location or resource type needs relief, use resourceSelectors instead of broad scope.
3) Set expiresOn at creation Do not allow a second step later for adding the date. If the platform allows creation, your process should require expiry before approval.
4) Store operating metadata At minimum, keep requestedBy, approvedBy, approvedOn, ticketRef, owner, and reviewCadence in metadata. Microsoft explicitly supports custom metadata properties for this purpose.
5) Report weekly and review monthly Use Azure Resource Graph to catch expiring items, then force renewal decisions before the clock runs out.
6) Remove or renew with evidence If the issue is fixed, delete the exemption. If it is still needed, make the owner re-justify it and set a new date instead of carrying the old approval forever.
Query pack for aging exemptions
Microsoft publishes an Azure Resource Graph sample to find policy exemptions that expire within 90 days. Start there, then add your own watch lists for items with no expiry and items missing metadata.
Expiring within 90 days
PolicyResources
| where type == 'microsoft.authorization/policyexemptions'
| extend expiresOnC = todatetime(properties.expiresOn)
| where isnotnull(expiresOnC)
| where expiresOnC >= now() and expiresOnC < now(+90d)
| project name, properties.displayName, expiresOnC
Missing an expiry date
PolicyResources
| where type == 'microsoft.authorization/policyexemptions'
| extend expiresOn = todatetime(properties.expiresOn)
| where isnull(expiresOn)
| project name,
displayName = properties.displayName,
category = properties.exemptionCategory,
exemptionId = id
Missing basic metadata
PolicyResources
| where type == 'microsoft.authorization/policyexemptions'
| extend requestedBy = tostring(properties.metadata.requestedBy)
| extend approvedBy = tostring(properties.metadata.approvedBy)
| extend ticketRef = tostring(properties.metadata.ticketRef)
| where isempty(requestedBy) or isempty(approvedBy) or isempty(ticketRef)
| project name,
displayName = properties.displayName,
requestedBy,
approvedBy,
ticketRef
That third query is opinionated. Azure does not require those fields. Your process should.
A clean exemption payload shape
Use this as a pattern for metadata discipline. Adjust field names to your workflow, but keep the meaning intact.
{
"properties": {
"displayName": "Temporary waiver for legacy appliance",
"description": "Vendor remediation scheduled in Q3",
"metadata": {
"requestedBy": "platform-team",
"approvedBy": "cloud-governance-board",
"approvedOn": "2026-04-15T00:00:00Z",
"ticketRef": "CHG-10427",
"owner": "network-platform",
"reviewCadence": "30d"
},
"policyAssignmentId": "<assignment-id>",
"exemptionCategory": "Waiver",
"expiresOn": "2026-07-15T00:00:00Z"
}
}
Mistakes that create permanent drift
- Using management-group scope because it is convenient, not because it is necessary.
- Exempting the full initiative when only one definition reference really needs relief.
- Creating a waiver with no remediation path and calling it temporary.
- Letting the same approval live through multiple renewals without fresh evidence.
- Treating exempt as compliant in internal conversations even though the risk still exists.
- Giving teams write access to exemptions without making them accountable for review.
Microsoft also calls out an extra security control here; creating an exemption requires more than write permission on the exemption object. The creator also needs the exempt/Action verb on the target assignment. That is a good thing. Keep exemption creation tighter than normal policy read access.
메타데이터
- post_id
- 8e07a6bc7ec1
- slug
- every-azure-policy-exemption-should-come-with-an-expiry-date-8e07a6bc7ec1
- url
- https://systemweakness.com/every-azure-policy-exemption-should-come-with-an-expiry-date-8e07a6bc7ec1
- canonical_url
- https://systemweakness.com/every-azure-policy-exemption-should-come-with-an-expiry-date-8e07a6bc7ec1
- author_url
- https://medium.com/@mrkoozer
- status
- ok
- fetched_at
- 2026-06-23 06:34:20