skip to content

How do you scope a Kyverno PolicyException to one vendor workload, not its whole namespace?

level: middleimportance: nice to knowfreq 36%

answer

  1. narrow on rules and on resources
  2. pod names are generated, not chosen
  3. a namespace match covers tomorrow too
  4. labels are set by whoever owns the workload
  5. prove it with a workload that still fails

basics

~20 s

Combine namespaces, kinds and a label selector in the exception's match block, and list the exact rule names. Avoid matching on pod names, which carry generated suffixes, and avoid a namespace-only match, which silently covers every future workload there.

solid answer

~40 s

Scope on three axes at once. In `spec.exceptions`, name the exact rule or rules rather than a wildcard, so only the control the appliance genuinely cannot meet is waived. In `spec.match`, pin `namespaces` to the one namespace, pin `kinds` to the kinds actually submitted for that workload, and add a `selector` on labels the appliance carries. Do not scope by `names` for pods: pods created through a Deployment get a generated suffix, so a literal name never matches and a name wildcard quietly catches anything later named similarly. Do not stop at the namespace either, because a namespace-only match exempts every future workload there too. And be honest about the residual weakness: if the workload team can set the selector label on anything, they can widen their own exemption without touching the exception object.

go deeper

for a junior

Know the fields available in an exception's match block: namespaces, kinds, names and a label selector, and that they narrow rather than widen what is exempted.

for a middle

Explain why pod names are unusable for matching and why a namespace-only match keeps growing, and produce a scoped match block on request.

for a senior

Bring up that whoever can set the selector label can move workloads into the exemption, and propose either a label outside their control or an explicit acceptance of the residual risk.

for a principal

Decide how narrow is worth the operational cost across many teams, and whether exemptions should be generated from a request rather than hand-scoped each time.

## Why scoping is the whole job An exemption is a hole in a control. Its cost is proportional to how much it covers and how long it lasts. The rule side and the resource side of a PolicyException each offer a lazy option that works immediately and grows on its own, and resisting both is most of the skill here. ## Axis one: the rules `spec.exceptions[].ruleNames` decides which controls are off. Name the specific rules. A wildcard covers every rule under that policy including rules added later, so an exception written today for a base-image problem silently waives next quarter's addition to the same policy. If a policy bundles several unrelated checks, the exemption is a good reason to notice that and split them, not a reason to waive the bundle. ## Axis two: the resources `spec.match` uses Kyverno's resource-selector shape: `any` or `all`, each with `resources` carrying `namespaces`, `kinds`, `names` and a label `selector`. Three practical rules: **Never scope pods by name.** Pods created through a Deployment carry a generated suffix, for example `vendor-appliance-7d9f8c4b6-x2k9p`. A literal name will not match anything you can predict, and the wildcard people write instead, `vendor-appliance-*`, matches anything a future engineer names with that prefix. Name-based matching is reasonable for a singleton object whose name is fixed and meaningful; it is the wrong tool for pods. **Never stop at the namespace.** `namespaces: [vendor-appliance]` alone is a statement that this rule does not apply in that namespace, for everything, forever. It is convenient on the day the appliance is installed and wrong three months later when the namespace has picked up a sidecar service and a debugging job. If the namespace genuinely contains only the appliance and is expected to stay that way, say so explicitly in the review; do not let it be an accident. **Pin the kinds you actually submit.** Include the kinds that are really applied for this workload, and no more. If the workload is delivered as a Deployment, the exception has to cover the controller object, because that is the object admission sees. Adding Job and CronJob because they might exist one day is exactly the kind of speculative width that makes an exemption inventory unreadable later. ## Axis three, the one people forget: who controls the selector input A label selector is the tightest available scope and it is not a security boundary on its own. If the exception matches `app: vendor-appliance`, then anyone who can set that label on a workload in that namespace can move their workload inside the exemption. Usually that is the same team that owns the namespace, which means the exemption is effectively self-service for them even though the exception object is under someone else's control. There is no perfect fix, only honest choices. You can select on a label the workload team does not set, such as one applied by the vendor's own manifests and unlikely to be copied. You can accept the residual risk and note it, on the reasoning that the team could already do worse things in their own namespace. Or you can scope by the controller object's name where that name is stable and vendor-supplied, which is the case where name-based matching earns its place. What you should not do is present a label-scoped exemption as if the label were tamper-proof. ## Putting it together For an appliance in its own namespace, the defensible shape is: the exact rule names plus their controller variants; `namespaces` limited to that one namespace; `kinds` limited to Pod and the controller kind actually applied; and a `selector` on the appliance's identifying label. Every field is a narrowing, and each one answers a question a reviewer will otherwise have to ask. ## How to check it Do not assume the scope from reading it. Apply a second, unrelated workload into the same namespace that would violate the rule, and confirm it is still denied. That single negative test is what proves the exemption is scoped rather than a namespace-wide switch, and it is the evidence worth keeping.

  • Why not just scope the exception by pod name?
    Pods created through a controller get a generated suffix, so no literal name matches reliably, and the prefix wildcard people reach for instead catches every future object named similarly. Name matching suits a singleton object with a fixed, meaningful name; for pods, a label selector plus kind and namespace is both tighter and stable.
  • How would you prove the exemption did not widen the hole beyond the appliance?
    Apply a second workload in the same namespace that violates the same rule and confirm it is still denied. A positive test only shows the appliance passes; the negative test is what demonstrates the exemption is scoped rather than a namespace-wide switch, and it is worth keeping as evidence.
  • A label selector is only as good as who can set the label. What do you do about that?
    Either select on a label the workload team does not control, such as one applied by vendor-supplied manifests, or scope on a stable vendor-supplied controller name, or accept and record the residual risk. The mistake is presenting a label-scoped exemption as if the label were tamper-proof.

saying these in an interview costs you the question

  • Scopes the exception to a namespace and stops there
  • Matches pods by literal or wildcarded name
  • Uses a wildcard over rule names for convenience
  • Treats a label selector as a tamper-proof boundary
  • Never tests that a different workload is still denied

context