
Kyverno is a Kubernetes policy engine that can validate, mutate, generate resources and verify image signatures, at the moment they are submitted to the API server. A CNCF Graduated project since March 2026, it is written in YAML and in CEL, the Kubernetes expression language. This guide is for a DevOps engineer who wants richer guardrails than the Pod Security Standards. Everything has been replayed on Kyverno 1.19.1 and Kubernetes 1.37: installation in 40 seconds, rejection of an unsigned image, and a cluster that rejects every write when the Kyverno webhook becomes unreachable.
A point of timeline to know before writing your first policy, because it
decides which syntax to learn. The CEL policy types arrived in two steps:
ValidatingPolicy and ImageValidatingPolicy in v1.14, then
MutatingPolicy, GeneratingPolicy and DeletingPolicy in v1.15. They
moved to beta in 1.16, then to the stable policies.kyverno.io/v1 API in
v1.17, the release that also declared the historical ClusterPolicy and
CleanupPolicy CRDs deprecated. v1.19 makes this deprecation visible:
the kyverno.io CRDs, Policy included, carry deprecated: true and the API
returns a warning on every apply. Their removal is announced for v1.20.
The practical consequence: if you start today, write your policies in CEL. The historical YAML DSL remains in this guide because most production clusters still use it and you need to be able to read it, not because you should write new ones.
You do not even have to remember it: the API tells you on every
apply.
Warning: kyverno.io/v1 ClusterPolicy is deprecated and will be removed in afuture release; migrate to ValidatingPolicy, MutatingPolicy, GeneratingPolicyor ImageValidatingPolicy (policies.kyverno.io), seehttps://kyverno.io/docs/guides/migration-to-cel/The resource is created anyway and works normally: it is a warning,
not a rejection. The policies.kyverno.io/v1 group also offers more types
than the five listed here, each with a namespace-scoped variant:
NamespacedValidatingPolicy, NamespacedMutatingPolicy and so on. Useful
when a team must set its own rules without touching the whole
cluster.
A word on the positioning relative to the CKS: the certification curriculum does not list Kyverno as a required skill. It mentions Pod Security Standards, permitted registries, signing and validating artifacts and static analysis. Kyverno is a practical tool to implement these requirements on a real cluster, but it is not an exam topic in itself.
What you will learn
- When to use Kyverno (and when not to)
- Install Kyverno and understand its operational complexity, webhook failure included
- Create security-oriented validation policies
- Verify image signatures (Supply Chain Security)
- Test a policy outside the cluster with the Kyverno CLI
- Diagnose violations with PolicyReports
Compatibility and versions
Kyverno follows a release cycle aligned with Kubernetes. Each major release supports several Kubernetes versions, but the available features vary from one combination to another: it is the Kyverno and Kubernetes pair that you need to check, not either one in isolation.
| Kyverno | Helm chart | Notes |
|---|---|---|
| 1.19.x | 3.9.x | Current branch, the one in this guide; deprecation warnings on the kyverno.io API |
| 1.18.x | 3.8.x | Previous branch |
| 1.17.x | 3.7.x | End of support |
Community support lasts about three months per minor branch: the release of version n+1 ends the fixes for version n. The project states that it tests 1.19 on Kubernetes 1.33 to 1.35. Versions outside this range, including the 1.36 and 1.37 of this course, may work, but they are not tested by the project: the examples below were replayed here, which is not a guarantee of support.
The examples in this guide were replayed on Kyverno v1.19.1, installed by chart 3.9.1, on a Kubernetes 1.37 cluster. The installation takes about forty seconds and deploys four controllers: admission, background, cleanup and reports. It is therefore not a minor add-on, which is one more reason to measure its impact before switching it to blocking mode.
When to use Kyverno
Each tool has its area of excellence. This table helps you choose according to your real need, not the popularity of the tool.
| Need | Recommended tool | Why |
|---|---|---|
| Simple validation, no dependency | VAP | Native, GA since K8s 1.30 |
| Standard security profiles (runAsNonRoot...) | Pod Security Admission | 3 ready-made profiles |
| Simple mutation (defaults) | MutatingAdmissionPolicy | Native and enabled since K8s 1.36 |
Advanced mutation (sidecars, foreach, context) | Kyverno | Richer than CEL alone |
| Automatic generation (NetworkPolicies) | Kyverno | Unique feature |
| Image signature verification | Kyverno | Cosign/Sigstore integration |
| Existing OPA/Rego culture | Gatekeeper | Rego ecosystem |
Simple decision rule: if you need generation, signature
verification or a mutation that CEL cannot express, Kyverno is probably
the right choice. Otherwise, start with the native solutions: PSA,
ValidatingAdmissionPolicy, and MutatingAdmissionPolicy since 1.36.
What Kyverno does better
This split has shifted along the way, and your cluster version decides.
Up to Kubernetes 1.35, the API server could reject a resource with a
ValidatingAdmissionPolicy, but not modify it. Since 1.36,
MutatingAdmissionPolicy is GA and enabled by default: simple CEL
mutation has become native, and Kyverno 1.19 supports it too.
That leaves three capabilities with no native equivalent: generating a
resource in response to another, querying a registry to verify a
signature, and producing PolicyReports. Add to that a mutation richer than
CEL, with patchStrategicMerge, context and foreach. This is what still
justifies adding a dependency to the control plane.
- Rich mutation: inject sidecars, apply a rule to every container with
foreach, rely on external context. Simple defaults, on the other hand, now belong toMutatingAdmissionPolicy - Generation: automatically create NetworkPolicies, Secrets, ResourceQuotas
- Image verification: Cosign, Sigstore, SLSA attestations
- PolicyReports: native compliance audit
When NOT to use Kyverno
What these situations have in common is the benefit versus operational debt ratio. Every webhook added to the cluster is a component to maintain, to update at the pace of Kubernetes and to monitor. If the need can be covered by a mechanism already present in the API server, adding Kyverno costs more than it brings.
- Simple validation without mutation → prefer VAP (native, no dependency)
- Simple defaults to set → prefer MutatingAdmissionPolicy, native since 1.36
- Standard security profiles → prefer Pod Security Admission (simpler)
- Cluster without HA → Kyverno is an admission webhook, a sensitive component
- Team already trained in Rego (in French) → prefer Gatekeeper
Operational complexity
Installing Kyverno means inserting a component between the API server and every resource write in the cluster. This position explains most of its operational constraints: its availability governs that of deployments, its TLS certificates have a limited lifetime, and its RBAC rights cover a large part of the cluster. Before writing a single policy, decide how the cluster behaves when Kyverno is unavailable.
The diagram shows the path of a write. The API server calls the Kyverno webhook, which mutates then validates the resource before it is stored in etcd. The bottom exit is the one people forget: if the webhook does not answer, the API server rejects the write.
This is not theoretical. The chart's resource webhooks carry
failurePolicy: Fail. Measured by making the Kyverno service unreachable:
even a compliant pod is rejected.
Error from server (InternalError): Internal error occurred: failed calling webhook"mutate.kyverno.svc-fail": failed to call webhook: Post"https://kyverno-svc.kyverno.svc:443/mutate/fail?timeout=10s": dial tcp10.96.174.50:443: connect: connection refusedIn production, deploy with HA:
helm install kyverno kyverno/kyverno --version 3.9.1 \ --set admissionController.replicas=3 \ --set backgroundController.replicas=2 \ -n kyverno --create-namespaceIf Kyverno blocks the cluster, deleting its webhooks is not enough as long
as its admission controller is running: measured, it recreates
kyverno-resource-validating-webhook-cfg in under 20 seconds. You must
stop it first. A clean shutdown removes the resource webhooks by itself;
manual deletion remains the safety net if a crashed controller left them in
place.
# 1. Stop the admission controllerkubectl -n kyverno scale deployment kyverno-admission-controller --replicas=0
# 2. Delete the webhooks that would remain in placekubectl delete validatingwebhookconfiguration kyverno-resource-validating-webhook-cfgkubectl delete mutatingwebhookconfiguration kyverno-resource-mutating-webhook-cfgInstallation
Two methods coexist, and the choice is not cosmetic. The Helm chart
exposes the production settings, number of replicas per controller,
resources, namespace exclusions, and allows a controlled upgrade. The
install.yaml manifest deploys a fixed configuration, handy for a
throwaway cluster but hard to customise afterwards. In both cases, Kyverno
must live in a dedicated namespace: the project explicitly forbids
co-locating it with other applications, kube-system included.
# Add the Helm repositoryhelm repo add kyverno https://kyverno.github.io/kyverno/helm repo update
# Install Kyverno with HA, pinned chart (Kyverno 1.19.1)helm install kyverno kyverno/kyverno --version 3.9.1 \ -n kyverno --create-namespace \ --set admissionController.replicas=2 \ --wait --timeout 5mkubectl create -f https://github.com/kyverno/kyverno/releases/download/v1.19.1/install.yamlCheck the installation:
kubectl get pods -n kyvernoNAME READY STATUS RESTARTS AGEkyverno-admission-controller-769b8f7647-pqjbn 1/1 Running 0 37skyverno-admission-controller-769b8f7647-xfbbk 1/1 Running 0 37skyverno-background-controller-86d8df7447-wvdxj 1/1 Running 0 37skyverno-cleanup-controller-86c886ffff-nlnkk 1/1 Running 0 37skyverno-reports-controller-57c7978d69-z2d5z 1/1 Running 0 37sExample 1: Requiring runAsNonRoot (CKS-ready)
This example maps directly to the CKS objective "Use appropriate pod
security standards". Both tabs produce the same rejection, through very
different paths: the CEL version evaluates a boolean expression on
the submitted object, whereas the historical version compares the resource
with a YAML pattern applied recursively. The CEL version wins on the
readability of complex conditions, in particular the exclusion of system
namespaces, which fits here in a single matchConditions line.
apiVersion: policies.kyverno.io/v1kind: ValidatingPolicymetadata: name: require-run-as-non-rootspec: validationActions: [Deny] matchConstraints: resourceRules: - apiGroups: [""] apiVersions: ["v1"] operations: ["CREATE", "UPDATE"] resources: ["pods"] matchConditions: - name: exclude-system-ns expression: >- !(['kube-system','kyverno'].exists(ns, object.metadata.namespace == ns)) validations: - expression: >- object.spec.containers.all(c, has(c.securityContext) && has(c.securityContext.runAsNonRoot) && c.securityContext.runAsNonRoot == true ) message: "Tous les conteneurs doivent avoir runAsNonRoot: true."apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: require-run-as-non-rootspec: # DEPRECATED: use spec.rules[*].validate.failureAction validationFailureAction: Enforce background: true rules: - name: run-as-non-root match: any: - resources: kinds: - Pod validate: message: "Tous les conteneurs doivent avoir runAsNonRoot: true" pattern: spec: containers: - securityContext: runAsNonRoot: trueReplayed on Kubernetes 1.37, the CEL version shows READY true in
kubectl get validatingpolicy within a few seconds, then rejects an nginx
pod without a securityContext with the policy message:
Error from server: admission webhook "vpol.validate.kyverno.svc-fail-finegrained-require-run-as-non-root"denied the request: Policy require-run-as-non-root failed: Tous les conteneurs doivent avoir runAsNonRoot: true.Example 2: Rejecting hostPath and hostNetwork
These three rules close the doors that give the container direct access to
the node: a hostPath volume mounts a host directory into the pod,
hostNetwork puts the pod in the node's network namespace, hostPID and
hostIPC give it visibility of the host's processes and shared
memory. Each rule is independent and fails separately, which makes the
diagnosis readable: Kyverno reports the exact path that triggered the
rejection.
Note the =(volumes) anchor: it makes the check conditional. A pod
without any volume passes the rule instead of failing on a missing field.
Measured: a pod that mounts the host's /etc is rejected with
rule deny-hostpath failed at path /spec/volumes/0/hostPath/, a pod with
hostNetwork: true with rule deny-host-network failed at path /spec/hostNetwork/.
apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: deny-host-accessspec: background: true rules: - name: deny-hostpath match: any: - resources: kinds: - Pod validate: failureAction: Enforce message: "Les volumes hostPath sont interdits" pattern: spec: =(volumes): - X(hostPath): "null" - name: deny-host-network match: any: - resources: kinds: - Pod validate: failureAction: Enforce message: "hostNetwork n'est pas autorisé" pattern: spec: =(hostNetwork): false - name: deny-host-pid-ipc match: any: - resources: kinds: - Pod validate: failureAction: Enforce message: "hostPID et hostIPC sont interdits" pattern: spec: =(hostPID): false =(hostIPC): falseExample 3: Restricting the allowed registries
This control links Kyverno to the Supply Chain Security domain of the
CKS. The foreach loop goes through every container of the pod, which
avoids the classic blind spot of a rule that would only check the first
one. Watch out for the trap of the image without an explicit registry: a
manifest that asks for busybox:1.37 matches none of the allowed patterns
and is rejected, even though the image does come from Docker Hub.
Measured: the same image written docker.io/library/busybox:1.37 passes the
rule. This is the intended effect, provided you explain it in the error
message.
apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: restrict-image-registriesspec: background: true rules: - name: validate-registries match: any: - resources: kinds: - Pod validate: failureAction: Enforce message: "Images autorisées uniquement depuis gcr.io ou docker.io/library" foreach: - list: "request.object.spec.containers" deny: conditions: all: - key: "{{ element.image }}" operator: AnyNotIn value: - "gcr.io/*" - "docker.io/library/*"Image signature verification (Supply Chain)
Verifying a signature at admission moves the control to the last useful moment: whatever happened in the build chain, an image not signed with the expected key does not enter the cluster. Kyverno resolves the image reference with the registry, fetches the associated Cosign signature and validates it against the public key declared in the policy. A consequence to anticipate: the admission controller needs outbound network access to the registry, and a private registry requires giving it read credentials.
With the new CEL policy types (1.17+)
ImageValidatingPolicy separates two concerns that the historical
syntax mixed up. The attestors block declares who is allowed to sign;
the validations block describes what is required of the image once the
signature is verified. That is where you would add a condition on an SLSA
attestation or on the content of an SBOM.
Two details cost an hour of debugging if you ignore them, both measured on
Kyverno 1.19.1. The public key does not live in a Secret: the key field
accepts data, plain-text PEM, kms or expression, never secretRef, and
the API rejects the policy with
unknown field "spec.attestors[0].cosign.key.secretRef". And the name of an
attestor must not contain a dash, because it is referenced from a CEL
expression: my-cosign-key reads as a subtraction there and returns
undeclared reference to 'key'.
The policy below was replayed with the test image that the Kyverno project
publishes, ghcr.io/kyverno/test-verify-image, whose signed variant carries
a Cosign signature and whose unsigned variant carries none. This
signature was not recorded in Sigstore's public transparency log (Rekor),
hence the ctlog block that exempts it from that check; an image signed by
cosign sign with a key, which records the signature in Rekor by default,
does without it.
apiVersion: policies.kyverno.io/v1kind: ImageValidatingPolicymetadata: name: verify-image-signaturespec: validationActions: [Deny] matchConstraints: resourceRules: - apiGroups: [""] apiVersions: ["v1"] operations: ["CREATE", "UPDATE"] resources: ["pods"] matchImageReferences: - glob: "ghcr.io/kyverno/test-verify-image*" attestors: - name: mycosignkey cosign: key: data: | -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE8nXRh950IZbRj8Ra/N9sbqOPZrfM 5/KAQN0/KjHcorm/J5yctVd7iEcnessRQjU917hmKO6JWVGHpDguIyakZA== -----END PUBLIC KEY----- ctlog: insecureIgnoreTlog: true validations: - expression: >- images.containers.map(image, verifyImageSignatures(image, [attestors.mycosignkey])).all(e, e > 0) message: "Image must be signed with our Cosign key."The result, measured on Kubernetes 1.37: the signed variant is
admitted, the unsigned variant is rejected with the policy message, and an
image outside the matchImageReferences pattern, such as busybox, is not
affected.
$ kubectl run signed --image=ghcr.io/kyverno/test-verify-image:signed@sha256:b31bfb4d0213f254d361e0079deaaebefa4f82ba7aa76ef82e90b4935ad5b105pod/signed created$ kubectl run unsigned --image=ghcr.io/kyverno/test-verify-image:unsigned@sha256:74a98f0e4d750c9052f092a7f7a72de7b20f94f176a490088f7a744c76c53ea5Error from server: admission webhook "ivpol.validate.kyverno.svc-fail" denied the request:Policy verify-image-signature failed: Image must be signed with our Cosign key.The call to verifyImageSignatures is not decorative: it is what
triggers the verification. Measured by replacing it with the expression
"true": the attestors are then evaluated by nobody, and every image
matching the pattern is rejected, the signed variant included, with
image ... is not verified: no policy performed a signature or attestation check on it.
A validation must therefore always call verifyImageSignatures, or
verifyAttestationSignatures for an attestation.
With the historical ClusterPolicy
The verifyImages rule writes the public key in clear in the policy, which
remains acceptable, a public key not being a secret, but it
complicates rotation: changing it means editing every policy
involved. The background: false is not a detail: verifying signatures
requires network calls to the registry, an operation too costly to be
replayed as a background task on every existing resource. This example was
not replayed: it is there to help you recognise this syntax in an existing
cluster, the CEL version above being the one to write.
apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: verify-image-cosignspec: background: false rules: - name: verify-signature match: any: - resources: kinds: - Pod verifyImages: - imageReferences: - "gcr.io/my-project/*" failureAction: Enforce attestors: - entries: - keys: publicKeys: | -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE... -----END PUBLIC KEY-----Mutation: adding defaults
Mutation lets Kyverno automatically modify a resource before it is stored. It is a mature Kyverno feature, and the policy below adds three security settings to every container that does not declare them.
apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: add-security-defaultsspec: background: false # Mutation = no background rules: - name: add-security-context match: any: - resources: kinds: - Pod mutate: patchStrategicMerge: spec: containers: - (name): "*" securityContext: +(runAsNonRoot): true +(allowPrivilegeEscalation): false +(readOnlyRootFilesystem): trueMutation operators
The Kyverno mutation syntax uses special operators to control its behaviour. Understanding these operators is essential to write effective mutations.
| Operator | Effect | Use |
|---|---|---|
(key) | Conditional anchor | Target specific containers |
+(key) | Add if absent | Non-intrusive defaults |
<(key) | Global anchor | Condition on another part of the resource |
Concrete example: if you want to add runAsNonRoot: true only to pods that do not already have that value, use +(runAsNonRoot): true. This avoids overriding an explicit configuration set by the developer.
A security mutation can break what it protects. Measured on Kubernetes
1.37: a busybox pod does receive the three fields, then stays in
CreateContainerConfigError, because its image starts as root and
runAsNonRoot: true now forbids it. Before generalising such a mutation,
check that your images run as non-root and support a read-only file
system.
Mutation only knows these three anchors. There is no removal anchor: to
remove a field, you go through patchesJson6902 and its remove operation.
The =() equality, ^() existence and X() negation anchors belong to
validation, not to mutation, and that is where you meet them earlier in
this guide.
Generation: automatic NetworkPolicies
Generation answers a recurring problem: a security resource must exist
in every namespace, and nobody thinks of creating it. Here, creating a
namespace triggers the creation of a NetworkPolicy that blocks all
incoming and outgoing traffic by default. The synchronize: true field
changes the contract: Kyverno does not merely create the resource, it
restores it if someone modifies or deletes it. This is what sets
generation apart from a simple initialisation script.
apiVersion: kyverno.io/v1kind: ClusterPolicymetadata: name: generate-default-denyspec: rules: - name: create-network-policy match: any: - resources: kinds: - Namespace exclude: any: - resources: namespaces: - kube-system - kyverno generate: apiVersion: networking.k8s.io/v1 kind: NetworkPolicy name: default-deny namespace: "{{request.object.metadata.name}}" synchronize: true data: spec: podSelector: {} policyTypes: - Ingress - EgressEffect: measured, every new namespace receives a default-deny
NetworkPolicy within a few seconds. Namespaces that existed before the
policy do not receive it: for that you need to enable generateExisting: true
in the rule.
failureAction and gradual rollout
Deploying a policy straight in blocking mode (Enforce) is risky. Kyverno allows a gradual rollout, with two modes and per-namespace overrides. Measured with the policy below: a pod without an app label is rejected in production and created in another namespace, where the violation goes to a PolicyReport.
| Value | Effect | Phase |
|---|---|---|
Enforce | Blocks the request | Production |
Audit | Logs into PolicyReports | Discovery |
Recommended strategy:
- Start with
Audit: violations are recorded in the PolicyReports. Look at them to understand the impact. - Add overrides: switch to
Enforceon the critical namespaces, production, while staying inAuditelsewhere. - Generalise
Enforce: once all workloads are compliant, switch to blocking mode globally.
Gradual strategy, with an override for production:
spec: rules: - name: require-labels match: any: - resources: kinds: - Pod validate: failureAction: Audit # Permissive by default failureActionOverrides: - action: Enforce namespaces: - production # Strict in production message: "Le label 'app' est obligatoire" pattern: metadata: labels: app: "?*"Kyverno CLI (shift-left)
The CLI lets you test policies locally before deployment, without a
cluster, which makes it usable in a pipeline job. Two commands cover the
essentials: kyverno apply evaluates a policy against one or more
manifests and shows the pass / fail / warn / error / skip count, while
kyverno test runs a suite of cases described in a kyverno-test.yaml
file. The apply command also serves as a syntax check: a malformed
policy comes up as error before it even reaches the cluster.
# Install through Krew (the plugin follows version 1.19.1)kubectl krew install kyverno
# Test a policy against a manifestkyverno apply ./policy.yaml --resource ./pod.yaml
# Run the test suite described in ./policy-tests/kyverno-test.yamlkyverno test ./policy-tests/Here is the actual output of kyverno apply, measured with CLI
1.19.1 on a pod that violates the policy of example 1. The command exits
with code 1, which is enough to fail a CI job:
Applying 1 policy rule(s) to 1 resource(s)...policy require-run-as-non-root -> resource equipe-web/Pod/nginx-sans-securite failed:1 - Tous les conteneurs doivent avoir runAsNonRoot: true.
pass: 0, fail: 1, warn: 0, error: 0, skip: 0A test suite describes the expected result for each resource. The
kyverno create test command generates a skeleton, but the 1.19.1 one
carries a namespace field that kyverno test then rejects
(unknown field "namespace"). The accepted format, measured, names the
resource as namespace/name:
apiVersion: cli.kyverno.io/v1alpha1kind: Testmetadata: name: require-run-as-non-rootpolicies: - policy.yamlresources: - pod.yamlresults: - policy: require-run-as-non-root resources: - equipe-web/nginx-sans-securite kind: Pod result: failkyverno test ./policy-tests/ then returns Test Summary: 1 tests passed and 0 tests failed: the
test succeeds because the policy fails on this pod, as expected.
A frequent reflex is to look for a kyverno validate command to check the
syntax: it does not exist. CLI 1.19.1 exposes apply, completion,
create, docs, jp, migrate, test and version; fix and oci only
appear with the KYVERNO_EXPERIMENTAL=true variable. To detect an invalid
policy, go through kyverno apply.
The Kyverno CLI is part of the syllabus of the Kyverno Certified Associate certification, delivered by the Linux Foundation. For the CKS, it is not required but remains an asset: it lets you test a policy before deploying it, precisely the reflex the exam rewards.
Diagnosing policies
When a Kyverno policy "does not work", the symptom never says which of the two problems you have. Either the policy is rejected or inactive, and nothing is evaluated; or it works but does not select the resources you thought you were targeting, and its silence looks like a failure.
This distinction structures the whole diagnosis that follows, and it is
settled in one command: an accepted rule shows Ready: True in its
status. If so, look at the match and the enforcement mode,
never at the installation.
Essential commands
The diagnosis follows two distinct tracks that must not be confused. The first
concerns the policy itself: is it accepted by Kyverno? The answer is in
kubectl describe, in the status.conditions field. The second concerns the
evaluated resources: which violations were found? They live in the
PolicyReports, with one report per evaluated object, fed only if the
policy is in Audit mode or if background: true is active.
# List CEL policies (READY column) and historical oneskubectl get validatingpolicies,imagevalidatingpolicieskubectl get clusterpolicies,policies -A
# Details of a policy (errors, conditions)kubectl describe clusterpolicy <name>
# PolicyReports (one report per evaluated object)kubectl get policyreport -A
# Violation detailskubectl describe policyreport -n <namespace>
# Quick summarykubectl get policyreport -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.summary}{"\n"}{end}'Common errors
Here are the most frequent problems and how to solve them quickly, from symptom to fix.
| Symptom | Likely cause | Solution |
|---|---|---|
| Policy "Ready: False" | Syntax error | kubectl describe clusterpolicy |
| No violation in Audit | background: false | Add background: true |
| Mutation not applied | Pod already existing | Recreate the pod |
| Webhook timeout | Kyverno overloaded | Increase replicas |
Tip: the status.conditions field of a ClusterPolicy holds the detailed error messages. Look at it first.
Key points
ClusterPolicyandCleanupPolicyare deprecated since 1.17, 1.19 shows a warning on everyapply, and their removal is announced for v1.20validationFailureActionis deprecated: usevalidate.failureActionat rule level- Sensitive component: an unreachable webhook rejects every write; deploy in HA, and stop the controller before deleting its webhooks
- Best CKS bridge: image verification (Supply Chain Security)
- For simple validation → prefer VAP (native, no dependency)
- Unique features: generation and mature mutation
kyverno validatedoes not exist: the CLI is checked withkyverno applyandkyverno test- An
ImageValidatingPolicymust callverifyImageSignatures: with"true", every image is rejected, signed ones included
Knowledge check
These questions cover this guide only: the positioning of Kyverno
against native solutions, the syntax of validation and mutation rules,
and reading PolicyReports.
Knowledge check
Check what you have learned with this interactive quiz
How it works
- The timer starts when you click Start
- Multiple choice, true/false and short answer questions
- You can move between questions
- Detailed results are shown at the end
Starts the quiz and the timer
Review
(0/0)Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.
Weak areas
No topic below the pass mark.
Recommended next
Hints before you try again?
Continue the course: Kubernetes supply chain security: securing the delivery chain
A new full quiz with random questions
Work again only on the questions you missed