Kyverno Certified Associate common mistakes
Kyverno Certified Associate · Understand the traps and how to avoid them.
Treating Kyverno validation rules as if they were admission webhook 'deny-if-any' checks, so a validate rule with a failing pattern is assumed to block the request outright, and the candidate cannot predict whether a resource is admitted when the rule is in Audit versus Enforce mode.
Kyverno decouples the rule's match/validate logic from the failure action. The same rule produces a PolicyReport entry in Audit mode and an admission denial in Enforce mode. Candidates who learned admission control from generic webhook material expect the rule itself to encode the deny behaviour.
What to do instead
Before answering, identify three things separately: the rule type (validate, mutate, generate, verifyImages), the failureAction (or validationFailureAction for legacy ClusterPolicy), and whether the rule actually matches the resource (match/exclude plus preconditions). Practise writing one validate rule and toggling failureAction between Audit and Enforce to see the admission result change while the rule body stays identical.
Assuming every Kyverno policy kind is cluster-scoped and that a namespaced Policy applies cluster-wide, then mis-predicting which resources a policy governs and which namespaces its reports appear in.
Kyverno has both ClusterPolicy (cluster-scoped) and Policy (namespaced). A namespaced Policy only applies to resources in its own namespace, and its PolicyReport/ClusterPolicyReport placement differs. Candidates who only studied ClusterPolicy examples assume all policies are global.
What to do instead
Memorise the pairing: ClusterPolicy produces ClusterPolicyReport entries; namespaced Policy produces namespaced PolicyReport entries. When a question mentions a namespaced Policy, immediately restrict the affected resources to that namespace. Note that match kinds and namespaces inside a namespaced Policy cannot widen its scope beyond its namespace.
Writing match blocks that omit apiGroups and apiVersions, or using exclude where a precondition was needed, so the rule matches far more resources than intended (or fails to match the target at all).
Kyverno match/exclude entries require kinds and apiGroups, and the apiVersion handling differs between resource kinds. Candidates also confuse exclude (resource-level filtering) with preconditions (request-level conditions on the incoming object or the user), which changes whether the rule fires.
What to do instead
Use the canonical match shape with any/all blocks, always include apiGroups and kinds, and add apiVersions when the kind exists in multiple groups. Use exclude for filtering out resources by kind/name/namespace/labels and preconditions for conditions on request data such as request.userInfo, request.operation, or values inside the object. Test each rule with the CLI before assuming the match is right.
Confusing mutate rules with generate rules, for example expecting a mutate rule to create a missing ConfigMap or expecting a generate rule to patch the triggering resource's own fields.
Both rule types change cluster state, so candidates conflate them. Mutate patches the incoming resource (or existing resources via mutateExisting); generate creates or updates a separate downstream resource and requires a data or clone source plus synchronize behaviour. The exam tests whether you can pick the right rule type for a stated goal.
What to do instead
Use a decision rule: if the desired outcome modifies the submitted object, it is mutate (patchStrategicMerge, patchesJson6902, or foreach). If the desired outcome creates another object such as a ConfigMap, Secret, or NetworkPolicy, it is generate, and you must specify the resource data or clone source and whether synchronize is enabled to keep the generated resource in sync.
Misusing JMESPath expressions and Kyverno variables: writing {{ request.object.metadata.labels.app }} when the label may be absent, or using a variable in a place where Kyverno requires a plain string, leading to rule errors rather than clean pass/fail results.
Kyverno variables are JMESPath expressions wrapped in double braces. Missing fields yield null, and null interpolated into a patch or condition can produce a rule error instead of a denial. Candidates also forget that some fields (such as certain match values or annotation keys) do not support variable substitution.
What to do instead
Guard optional fields with a precondition or a JMESPath fallback such as {{ request.object.metadata.labels.app || 'default' }}, and remember the backtick-quoted literal syntax for string comparisons in JMESPath. Use the CLI to render variables and inspect the resulting policy before applying it, and keep variables out of fields that require literal values.
Running `kyverno apply` and reading only the exit code or the error line, ignoring the per-rule results and PolicyReport-style output, so the candidate concludes a policy passed when the resource was actually reported as a failure in Audit mode.
The CLI reports rule results (pass, fail, error, skip) and can emit a report; in Audit semantics a failing validate rule still appears as a failure result without an admission denial. Candidates accustomed to CI tools that fail only on non-zero exit misread the output.
What to do instead
Read the full result table: check which rules were applied, which were skipped due to match/exclude or preconditions, and which returned fail or error. Use the flag that sets the policy failure action to Enforce when you want the CLI to exit non-zero on violations, and compare the report output to what the cluster would record.
Using `kyverno test` with a test manifest whose policy path, resource path, or expected results do not line up, then blaming Kyverno for a failure that was actually a path or expectation error.
The test manifest references policies and resources by relative path and lists expected rule results per resource. Relative paths resolve from the manifest location, and expected results must match rule names exactly. Candidates edit the policy but forget to update the expectations or the paths.
What to do instead
Keep the test manifest, policies, and resources in a known directory layout, reference paths relative to the manifest, and name expected results exactly as the rules are named. Run the test, then reconcile each unexpected result against the actual rule output from kyverno apply before changing the expectation.
Installing Kyverno with a Helm chart but leaving the admission controller's failurePolicy or webhook configuration at defaults without understanding the consequence, then being unable to explain what happens to requests when Kyverno is unavailable.
Kyverno registers validating and mutating webhooks. The failurePolicy (Fail or Ignore) on those webhooks determines whether API requests are blocked when the controller cannot respond. Candidates focus on policy YAML and skip the installation-time webhook behaviour that the exam can probe.
What to do instead
Know that the default failurePolicy is Fail for the resource webhooks, meaning requests can be blocked if Kyverno is down, and that Ignore lets requests through. When a question asks about availability impact, answer from the webhook failurePolicy and the controller's replica count, not from the policy's validationFailureAction.
Planning an upgrade or configuration change without accounting for CRD updates and the order of operations, for example upgrading the controller image before applying the new CRDs, or assuming a Helm upgrade alone migrates existing policy objects.
Kyverno ships CRDs that must be current for new policy fields to be accepted, and some releases change defaults or require migration steps. Candidates treat Kyverno like a stateless Deployment and skip the CRD and release-notes steps.
What to do instead
For any upgrade question, state the sequence: read the release notes for breaking changes and migrations, update CRDs first (or use the chart's CRD handling), then upgrade the controller, then verify policies still validate and reports are produced. Mention checking the installed version with the CLI or the deployment image tag before and after.
Assuming a policy that exists in the cluster is automatically active, without checking whether it is in Audit mode, whether background scanning is enabled, or whether a mutating policy's changes are visible only on new admissions.
Kyverno distinguishes admission-time enforcement from background scanning, and mutation applies at admission time (plus mutateExisting for existing resources). A policy can be present, matching, and still not block anything or not affect already-running workloads.
What to do instead
When asked whether a policy takes effect, check failureAction/validationFailureAction, background mode, and whether the change requires re-admission of existing resources. For mutation of existing objects, look for mutateExisting or a generate rule with synchronize. Confirm behaviour by checking PolicyReports and by re-applying or recreating the resource.