An Azure Policy exemption is usually born as a favor: a team needs to ship, a policy blocks them, and someone grants a waiver "just for now." Then two things go wrong in opposite directions. Exemptions created with an expiry date lapse silently, and the moment they do, the policy starts enforcing again, which can break deployments that relied on the waiver. Exemptions created with no expiry never lapse at all and quietly become permanent holes in the very guardrails the policy was supposed to provide. Either way, nobody gets told.
Why Azure cannot tell you this out of the box
- There is no notification when an exemption expires. The
expiresOndate is honored (the exemption simply stops applying), but nothing alerts the team that was depending on it. The first symptom is often a failed deployment or a compliance state that changed overnight. - There is no warning before expiry either. You cannot ask Azure to ping you 30, 14, or 7 days ahead so the exemption can be reviewed, renewed, or allowed to lapse on purpose.
- Nothing tracks exemptions across a subscription. Exemptions can live at management group, subscription, resource group, and resource scope, and the portal shows them in the context of each assignment. There is no single recurring report answering "what waivers exist right now, who do they cover, and which ones never expire?"
- No-expiry exemptions are invisible by design. An exemption without an
expiresOnis valid forever, so it never resurfaces on its own. The temporary waiver from two reorgs ago is still switching a control off today.
The DIY approach: enumerate exemptions on a schedule and classify them
The fix is an inventory job, not a policy change. Exemptions are ordinary ARM resources
(Microsoft.Authorization/policyExemptions), so a scheduled job with nothing more
than Reader access can do the whole thing:
- Run a scheduled job (a Function on a timer or an Automation runbook) that lists every policy exemption visible at subscription scope, including the ones inherited from management groups and the ones buried down at resource-group and resource scope.
- For each exemption, read
expiresOnand sort it into a bucket: expired (the policy is enforcing again), expiring soon (inside whatever warning window you choose), or no expiry set (a permanent waiver that deserves a periodic look). - Post the result somewhere humans already are, for example a Teams channel: exemption name, scope, category, days left. Expired and no-expiry items go at the top.
- Repeat daily. The value is the cadence: an exemption that shows up in a report every morning cannot expire silently or live forever unnoticed.
The catch is ownership: this is one more script to write, schedule, permission, and keep running, and the day it quietly stops is the day an exemption quietly lapses.
A ready-made option: Policy Exemption Tracker
Policy Exemption Tracker is that pattern packaged. Every day at 08:00 UTC it lists every Azure Policy exemption and reports the lifecycle to your Teams channel as an Adaptive Card: expired (the policy is now enforcing again, so recent deployments may fail), expiring soon (within thresholds you set, 30 / 14 / 7 / 1 days by default), and no expiry set (permanent exemptions, which are latent security gaps). It is read-only: the app runs under a system-assigned managed identity that needs only the Reader role at subscription scope, and alerts go only to a Teams webhook you configure.
Key facts
- Expiry behavior: when an exemption's
expiresOnpasses, the policy starts enforcing again, with no notification to anyone. - No-expiry exemptions: valid forever; they never resurface for review on their own.
- Native cross-scope inventory or expiry alerting: none; exemptions are viewed per assignment and scope.
- Durable fix: a daily job that enumerates exemptions and buckets them into expired / expiring soon / no expiry.
- Least privilege: the whole job is read-only and needs only Reader at subscription scope.
Related reading: set an Entra ID account to expire (temporary access that actually ends).
Written by the team at Katabarwa Labs. We build small, single-purpose Azure tools that run entirely inside your own tenant. Questions: abaho@llmgraph.ai.