TT Lab
Get started
Learn Learning paths Courses

KCA — Kyverno Certified Associate

Watch a Policy Actually Block

Continue in TT Lab

This lab runs on real Kyverno

k3s + Kyverno is actually running inside the VM. The admission webhooks are registered, so when you attach a policy, things really get rejected, values really get injected, and other objects really get created.

The early policy-writing labs run on a fake cluster with only the CRDs loaded. There, no matter how well you write a policy, nothing happens — yet kubectl apply succeeds, so it looks normal on the screen.

It takes 4–5 minutes to come up the first time. It installs Kyverno and waits for the webhooks to be registered.

The expected study time is 70 minutes. The session starts at 60 minutes, so check the remaining time and extend it before it expires. This lab is pinned to k3s 1.35.8 and Kyverno 1.19.1. It uses ClusterPolicy to practice reading existing policies, but this API was deprecated in Kyverno 1.19, and the official documentation says it will be removed in 1.20. Do not copy it as is into a new project; check the supported versions and the new policy API.

Goal

Check for yourself when and how each of the policy's three actions (validate, mutate, and generate) happens, and see the difference between Enforce and Audit, and what happens when you leave out an exception.

Why it matters

The most dangerous state in a policy engine is not "the policy is wrong" but "the policy is applied nowhere." The latter is dangerous because it is quiet.

And the three actions happen at different times.

Action When What
mutate Admission, before validate Modifies the object
validate Admission Rejects or lets it pass
generate After admission, by a separate controller Creates other objects

If you do not know this order, the policies neutralize each other. If mutate puts in a label and validate requires that label, it passes thanks to the order. Conversely, generate happens outside admission, so it needs separate permissions.

Steps

Create the Pods in the kca namespace.

  1. Check how Kyverno is called and put it in /root/kca/install.txt. The webhook configuration must be registered.
  2. With the require-team ClusterPolicy (Enforce), require the team label, and put in /root/kca/validate.txt that a Pod without the label is rejected and that ok-pod, which has it, comes up.
  3. With the add-defaults policy, inject the owner label into Pods, and put in /root/kca/mutate.txt what actually went into the mutated Pod. Also write down the order of mutate and validate.
  4. With the gen-baseline policy, have it create a baseline ConfigMap in a new namespace, create tenant-x to check, and put it in /root/kca/generate.txt.
  5. Apply the warn-only policy as Audit, and put in /root/kca/audit.txt that the violating violator Pod gets created and that it is recorded in the PolicyReport.
  6. Add an exception to require-team to exclude the system namespaces, and put in /root/kca/exclude.txt why it has to be so.
  7. Create /root/kca/test-pod.yaml, test it with the kyverno CLI before putting it on the cluster, and put the result in /root/kca/cli.txt.
  8. In /root/kca/report.md, write the three lines enforce_blocks=yes, audit_blocks=no, and policies= along with an explanation.

Notes

How the policy gets called

Check how Kyverno is called and put it in /root/kca/install.txt. The webhook configuration must be registered.

The API server asks Kyverno only when a ValidatingWebhookConfiguration is registered.

Reject

With the require-team ClusterPolicy (Enforce), require the team label, and put in /root/kca/validate.txt that a Pod without the label is rejected and that ok-pod, which has it, comes up.

It blocks only if it is Enforce. Test both a Pod without the label and a Pod that has it.

Modify — and there is an order

With the add-defaults policy, inject the owner label into Pods, and put in /root/kca/mutate.txt what actually went into the mutated Pod. Also write down the order of mutate and validate.

mutate runs before validate. That is why validate can require a value that mutate inserted.

Create something else

With the gen-baseline policy, have it create a baseline ConfigMap in a new namespace, create tenant-x to check, and put it in /root/kca/generate.txt.

generate is done by the background controller. So that controller must have permissions, and the resource is not created immediately.

Only record, without blocking

Apply the warn-only policy as Audit, and put in /root/kca/audit.txt that the violating violator Pod gets created and that it is recorded in the PolicyReport.

An Audit policy creates the object even if it is violated. The results accumulate in the PolicyReport.

When you widen the policy scope, check the exceptions and recovery

Add an exception to require-team to exclude the system namespaces, and put in /root/kca/exclude.txt why it has to be so.

The earlier steps targeted only kca. This time you widen the target but exclude the system namespaces. Do not judge that webhook calls are also excluded just because of a policy exception.

Test before putting it up

Create /root/kca/test-pod.yaml, test it with the kyverno CLI before putting it on the cluster, and put the result in /root/kca/cli.txt.

kyverno apply <정책> --resource <매니페스트> tests a policy without a cluster (the placeholders are the policy and the manifest). It is used in CI.

What did you learn

In /root/kca/report.md, write the three lines enforce_blocks=yes, audit_blocks=no, and policies= along with an explanation.

Along with the three lines enforce_blocks=, audit_blocks=, and policies=, write about the timing of the three actions and the exception story.