Exceptions with expiry
Break-glass that closes itself.
In short. A policy program without exceptions will grow shadow forks: teams copy clusters, disable webhooks, or invent wild labels that mean "leave us alone." A policy program with eternal exceptions is just…
A policy program without exceptions will grow shadow forks: teams copy clusters, disable webhooks, or invent wild labels that mean "leave us alone." A policy program with eternal exceptions is just documentation for holes. The workable middle is explicit, reviewed, time-boxed exceptions with owners and expiry dates.
Implement exceptions as data — Constraint exceptions, Kyverno PolicyExceptions, or Rego data files — not as commented-out rules in Slack. Every exception should answer: why, who, until when, what compensating control.
Time-boxed break-glass
# example PolicyException sketch applied brieflykubectl apply -f exception-batch-job.yamlkubectl get policyexceptions -A# calendar reminder / CI check fails if expires-on annotation < today
NAMESPACE NAME AGEbatch allow-privileged 1d
metadata:annotations:owner: payments-teamexpires-on: "2026-08-01"ticket: SEC-1234reason: vendor-installer needs privileged once
* namespaces recreates the hole. Scope to the smallest object identity that works.Going deeper
Automate expiry: a controller or CI job lists exceptions, opens tickets seven days before expiry, and fails a compliance check when expired objects remain. Humans will not calendar this forever.
Publicly track exception debt on a scorecard. Leadership should see "14 temporary holes" as a risk metric next to CVE counts. Invisible exceptions never get budget to remediate.
Compensating controls must be real: extra monitoring, network isolation, or manual approval gates. An exception whose compensation is "we will be careful" is not a control.
Store exceptions beside policies in Git when the engine allows declarative exceptions as code. Ticket-only exceptions in a spreadsheet diverge from reality within a month.
On expiry, prefer auto-removal with a monitoring alarm over silent renewal. Renewal should cost a human decision each time.
Reject exceptions that request "all policies in namespace X." Force requesters to name the rule IDs. Precision keeps the hole small and the review honest.
Publish a monthly exceptions report to engineering leadership. Sunlight shrinks debt faster than private nagging.
Tie exception tickets to the original policy PR that caused pain when appropriate — sometimes the fix is clarifying the rule message, not punching a forever hole.
Teach requesters to propose an expiry under thirty days by default. Longer windows require a director-level approval in mature programs.
Default-deny exception creation to a small approver group in your ticketing workflow so any engineer cannot self-issue holes without review.
Try this
Add an expires-on annotation to a lab exception and write a one-liner CI check that fails if date < today.
EXP=2026-01-01python - <<'PY'from datetime import dateimport osprint('expired' if date.today().isoformat() > os.environ['EXP'] else 'ok')PY
expired
Takeaway
Exceptions must be explicit, owned, narrow, and dated. Anything else is either denial theater or an untracked vulnerability.
Next: enforcement points — CI, admission, and audit working as one system.