Governing the Provinces
Fix a misconfigured Kyverno policy estate and use Policy Reporter to restore proper governance across the Republic's provinces.
Mission Objective
- Empire-wide laws enforce across every province: no privileged containers, every workload carries a valid
republic.rome/gensandrepublic.rome/provincematching its namespace, scoped by namespace label rather than hardcoded names - Aegyptus's scribe law applies only within Aegyptus, admitting
republic.rome/role: scribeworkloads exclusively - The legacy exception is scoped to Aegyptus's grandfathered workload and cannot be claimed by any other province
- The Tabularium's ledger is on file: policy reports exported in OpenReports format as
estate-audit.yaml
Key Learnings
- How to scope policies using ValidatingPolicy (opens in new tab) (cluster-wide) and NamespacedValidatingPolicy (opens in new tab) (per-namespace), and when to use each
- How CEL expressions (opens in new tab) in
ValidatingPolicyandPolicyExceptionexpress fine-grained admission conditions - How to write and scope a PolicyException (opens in new tab) correctly so only the intended workloads are exempt
- How to use Policy Reporter (opens in new tab) and the OpenReports (opens in new tab) format to audit and debug a policy estate across multiple namespaces
Best Suited For
Platform engineers and SREs who have some familiarity with Kyverno, ideally after completing the Beginner level. You should be comfortable reading Kubernetes YAML and basic kubectl commands.
The Story
The Republic has grown. What once was a single city is now a sprawling empire of provinces, each governed by different magistrates with different needs. The legal scholars decided to catalogue every law in a central archive (the Tabularium) so that each province's statutes could be tracked and audited in one place.
But cataloguing the laws introduced new chaos. Policies meant for one province are bleeding into another. Exceptions that were meant to be narrow have been written too broadly. And somewhere in the estate, a workload is slipping through that shouldn't be.
The Tabularium's auditors have handed you a report: Policy Reporter shows violations where there should be none, and silence where there should be enforcement. Your mission: investigate the policy estate, fix the scoping issues, and restore order before the provinces descend into chaos.
Architecture
Five namespaces span the estate: four provinces (gallia, hispania, britannia, aegyptus) with republic.rome/realm: province, and castra, the infra namespace, with republic.rome/realm: infra. These labels drive policy scoping; use kubectl get ns --show-labels to inspect them.
Two empire-wide policies cover all provinces: no-privileged-containers and require-census (every workload must declare a valid republic.rome/gens and a matching republic.rome/province). Aegyptus adds aegyptus-require-scribe-role for its local scribe requirement, and a PolicyException covers its single legacy workload.
The broken policies live in manifests/policies/ and manifests/exceptions/. After each change, run make apply to redeploy the workloads, then make verify to check your progress.
Ready to start?
Launch in a preconfigured devcontainer
Free GitHub account required
Walkthrough
Open in GitHub Codespaces. The devcontainer is pre-configured and starts automatically. When you push from Codespaces, GitHub forks the repository to your account automatically.
Prefer working locally? Clone the repo and open it in any editor that supports the Dev Containers specification (VS Code, JetBrains IDEs, and others). The devcontainer config will be detected automatically.
When your Codespace is ready, the policy estate is already deployed, but something is wrong. Open Policy Reporter at port 30110 (find it in the Ports tab) to get an overview of the estate:
- Which namespaces have violations?
- Which policies are generating results, and which are silent when they shouldn't be?
Then dig into the cluster:
# Inspect the namespace topology — the labels here drive policy scoping kubectl get ns --show-labels # List all policies — note which are cluster-wide and which are namespaced kubectl get validatingpolicies kubectl get namespacedvalidatingpolicies -A # Inspect any policy or exception in full kubectl get validatingpolicy <name> -o yaml kubectl get policyexceptions -A -o yaml # See the raw OpenReports data behind Policy Reporter kubectl get policyreports -AYou can also launch k9s for a terminal UI view:
k9sReview the Objective and investigate what is wrong in
manifests/policies/andmanifests/exceptions/.Think about what each policy is supposed to cover, and compare that against what it is actually matching. The namespace labels you saw with
kubectl get ns --show-labelsare a key part of the picture.Test locally with the Kyverno CLI before applying:
kyverno apply manifests/policies/require-census.yaml --resource manifests/workloads/citizens.yaml kyverno apply manifests/policies/aegyptus-require-scribe-role.yaml --resource manifests/workloads/aegyptus-legacy-scribe.yamlApply your changes to the cluster:
make applyPolicies only act at admission, so
make applyredeploys the workloads to re-evaluate the estate against your changes. Then check Policy Reporter again. The picture should improve as you fix each issue.Once the estate is in order, the Senate expects the Tabularium's ledger on file. Export the cluster's policy reports, the OpenReports data behind Policy Reporter, as the audit of record.
kubectl get policyreports -A -o yaml > estate-audit.yaml
Complete Your Challenge
- When you push from Codespaces, GitHub forks the repository to your account automatically. If you are working locally, fork the repository on GitHub before pushing.
- Verify your solution:
If it passes, it generates a Certificate of Completion you can paste into the discussion../verify.sh - Share your solutions in the challenge thread (opens in new tab) on community.offon.dev.
Completed the challenge? Share your achievement on LinkedIn (opens in new tab)
Toolbox
- kubectl (opens in new tab) - Apply and inspect cluster resources, check namespace labels and policy status
- kyverno CLI (opens in new tab) - Test and lint policies locally before applying to the cluster
- k9s (opens in new tab) - Explore cluster resources and policy reports in a terminal UI