skip to content

Your Kyverno PolicyException exempts a Pod but the Deployment is still blocked. Why?

level: middleimportance: should knowfreq 44%

answer

  1. pods are not how people deploy
  2. the engine generated extra rules
  3. look at the prefix on the reported name
  4. the exception must match the Deployment too
  5. autogen- plus the original rule name

basics

~10 s

Kyverno auto-generates pod-controller versions of a Pod rule under autogen- prefixed names. The Deployment is denied by autogen-check-base-image, a rule name the exception never listed, and by a kind its match block never included.

solid answer

~40 s

A rule written against Pods does not only run on Pods. Kyverno auto-generates equivalent rules for pod controllers, named by prefixing the original: `autogen-check-base-image` for Deployment, StatefulSet, DaemonSet and Job, and a CronJob variant. When someone applies a Deployment, the admission request is for the Deployment and the deny comes from the autogen rule, so an exception listing only `check-base-image` matches nothing. Two fixes are needed together: list the generated rule names in `ruleNames` (Kyverno accepts a wildcard such as `autogen-*` alongside the base name), and add the controller kinds to the exception's `match` block, since a match limited to `kind: Pod` will never match a Deployment. Watch the label selector too: for a Deployment it is evaluated against the Deployment's own labels, not the pod template's.

code

yaml · 18 lines
yaml
apiVersion: kyverno.io/v2   # served version varies by Kyverno release
kind: PolicyException
metadata:
  name: vendor-appliance-base-image
  namespace: kyverno-exceptions
spec:
  exceptions:
  - policyName: require-approved-base-image
    ruleNames:
    - check-base-image        # bare Pods only; autogen-check-base-image is missing
  match:
    any:
    - resources:
        namespaces: [vendor-appliance]
        kinds: [Pod]          # a Deployment never matches this
        selector:
          matchLabels:
            app: vendor-appliance

go deeper

for a junior

Know that Kyverno evaluates the object actually being applied, so a Deployment and a Pod are different admission requests even when the rule was written about pods.

for a middle

Explain the autogen naming and show both halves of the fix: the generated rule names in ruleNames, and the controller kinds in the exception's match block.

for a senior

Diagnose from the denial message outwards, and argue against the wildcard fix because it silently covers rules added to that policy later.

for a principal

Consider whether exemptions written by hand against generated rule names are sustainable at your fleet size, or whether the platform should generate the exception object from a request.

## The symptom Someone writes a policy rule against Pods, because pods are what actually run containers. A workload needs a carve-out, so a PolicyException is written naming that rule. Applying the appliance as a bare Pod works. Applying the same thing through its Deployment is still denied, with a message referencing a rule name the author does not recognise. ## Why it happens Kyverno solves a real usability problem: if rules only ran on Pods, every violation would surface at the ReplicaSet controller rather than at the moment a human applied a Deployment, and the feedback would be useless. So Kyverno auto-generates pod-controller variants of a Pod rule. The generated rules carry the original name with a prefix, `autogen-` for the standard controllers such as Deployment, StatefulSet, DaemonSet and Job, and a distinct CronJob variant. They are visible on the policy object once it is created; you are not meant to write them by hand. The consequence for exemptions is direct. Admission control acts on the object being submitted. When a user applies a Deployment, the request under evaluation is the Deployment, and the rule that produces the deny is the generated one, not the original. A PolicyException is matched on two things: the rule names it lists and the resource its own match block selects. Both are wrong in the naive exception. - **Rule name.** `ruleNames: [check-base-image]` does not cover `autogen-check-base-image`. These are different rule names as far as the engine is concerned. - **Kind.** `kinds: [Pod]` in the exception's match block does not match a Deployment. Even with the rule name fixed, the exception would not apply. The bare-Pod test passing is what makes this confusing: the author has evidence that the exception works, and the evidence is real, it just covers a path nobody actually deploys through. ## Fixing it List the generated names as well as the original, and widen the kinds: - `ruleNames: [check-base-image, autogen-check-base-image]`, or a wildcard such as `autogen-*` alongside the base name where you want all generated variants. - `kinds: [Pod, Deployment]`, adding Job or CronJob only if that workload actually uses them. Resist the temptation to write `ruleNames: ["*"]`. It fixes the symptom and quietly waives every other rule in that policy for the matched workload, including rules the author never looked at and rules added to that policy next quarter. An exemption should be as narrow as the problem, and a wildcard over rule names is a grant that grows on its own. ## The selector trap that comes next If the exception uses a label selector, remember what the selector is evaluated against. For a Pod request it is the Pod's labels. For a Deployment request it is the Deployment's own `metadata.labels`, not `spec.template.metadata.labels`. Teams frequently label the pod template carefully and leave the Deployment's own labels sparse, so the widened exception still misses. When it does, comparing what you selected on against `kubectl get deployment -o yaml` settles it in seconds. ## How to diagnose this class of problem generally Work backwards from the denial, not forwards from your intent: 1. Read the deny message and take the **rule name it actually reports**, verbatim. That name is the thing your exception must list. 2. Ask what **kind** the API server was admitting when it denied. That kind must appear in the exception's match block. 3. Check the labels and namespace on that exact object, not on the pod it will eventually create. 4. Only then check the plumbing: is exception processing enabled on the controller, and is this object's namespace one the controller honours. ## Why interviewers like this question It separates people who have configured Kyverno from people who have read about it. Nothing in the concept of an exemption predicts autogen; it is a specific behaviour of this engine, and the failure is silent in the worst way, since the object is valid, stored, and visibly present while doing nothing for the path anyone uses.

  • Why does Kyverno generate the controller rules at all instead of only checking Pods?
    So the denial surfaces on the object a human applied. If rules only ran on Pods, a bad Deployment would be accepted and fail later inside the ReplicaSet controller, where the error is buried in controller events instead of returned to the person running apply.
  • Is `ruleNames: ["*"]` a reasonable fix?
    It makes the symptom go away and quietly waives every rule in that policy for the matched workload, including rules added to the policy later. Prefer listing the original rule plus its generated variants, so the exemption cannot silently grow when the policy does.
  • You fixed the rule names and kinds, and the Deployment is still blocked. What now?
    Check the label selector against the Deployment's own metadata.labels rather than the pod template's, since that is what the selector is evaluated against for a Deployment request. If that matches, verify the controller is configured to process exceptions and that this object's namespace is honoured.

saying these in an interview costs you the question

  • Assumes a Pod rule only ever evaluates Pods
  • Reaches straight for a wildcard over all rule names
  • Never reads the rule name in the deny message
  • Selects on pod template labels for a Deployment request
  • Concludes exceptions are broken and drops the policy to audit

context