skip to content

In Kyverno, what does a validate.deny conditions block do that validate.pattern cannot?

level: juniorimportance: must knowfreq 62%

answer

  1. shape versus boolean test
  2. one describes required, one forbidden
  3. operators, sets, cross-field
  4. key, operator, value under any or all
  5. conditions true means blocked

basics

~20 s

A deny block evaluates boolean conditions with operators over the admission request and blocks when they are true. A pattern only asserts the shape a resource must match, so it cannot use operators, compare two fields, or read request metadata.

solid answer

~50 s

`validate.pattern` is declarative: you write a fragment of the desired resource and the incoming object must satisfy it, so it reads like the manifest a developer would write. `validate.deny.conditions` is a boolean test instead: a list of `key` / `operator` / `value` conditions grouped under `any` or `all`, where the key is normally a JMESPath expression in `{{ }}` substituted from the admission request. If the conditions come out true, the request is denied with the rule's message — so a deny block describes the forbidden state, while a pattern describes the required one. Only the deny form gives you operators such as `AnyNotIn` or `GreaterThan`, comparison between two fields, and access to things outside the object like `request.operation` or `request.userInfo.groups`. When the rule is simply "this field must be present and look like this", the pattern reads better.

go deeper

for a junior

Be ready to state the polarity out loud: a pattern says what the resource must look like, a deny block says what is forbidden and blocks when its conditions are true. Know that a condition is a key, an operator and a value.

for a middle

Expect to explain why the key is a JMESPath expression in braces and what that buys you — operators, set membership, and fields of the admission request such as the operation, that a pattern cannot reach at all.

for a senior

Show judgment about which form a given rule should use, and defend it on reviewability rather than expressiveness: a wildcard pattern that the governed team can read beats a correct deny block nobody dares patch.

for a principal

Own the house style. Decide which form is the default for policies your organisation ships, what a rule must look like before it is allowed to use the more powerful form, and how a bad patch to each form fails.

## Two ways to say no inside one Kyverno validate rule A Kyverno policy object holds rules; each rule selects resources with a `match` block and then decides. A `validate` rule expresses that decision in one of two main shapes: `validate.pattern` or `validate.deny`. Knowing which one a rule should use is the first thing an interviewer probes, because most real policies never leave this shape. ### validate.pattern — a shape the resource must satisfy A pattern is a fragment of a resource. Kyverno overlays it on the incoming object and the object must satisfy every part of it. It reads like the YAML the developer already writes: - `storageClassName: "encrypted-*"` — the field must exist and its value must match the wildcard. - A key with no wildcard means an exact literal. - Anchor syntax exists for conditional, existence and negation checks (a topic of its own). The pattern's virtue is reviewability. Someone who has never read a policy language can look at it and see the manifest they are expected to produce, and the diff of a change to it is small and obvious. ### validate.deny — boolean conditions that block when true `validate.deny.conditions` is a different thing entirely. It is a list of conditions, each `{ key, operator, value }`, grouped under `any` (at least one true) or `all` (every one true). The key is normally a JMESPath expression wrapped in `{{ }}`, substituted against the admission request before the operator runs. If the block evaluates to **true**, the request is **blocked** and `validate.message` is returned to the user. That polarity is the single most common source of confusion. A deny block enumerates the state you refuse to admit, not the state you want. A rule written as "storage class is in the encrypted set" under a deny block blocks exactly the compliant resources and admits everything else. ### What a pattern genuinely cannot do 1. **Operators.** A pattern has wildcards and anchors, not a general comparison vocabulary. "The value must be one of these four names" is `AnyIn` in a deny condition; there is no clean pattern equivalent when the names share no common prefix. 2. **Cross-field comparison.** Comparing one field of the resource against another is not expressible as a shape — a pattern is matched positionally against the object, so it has nothing to hold the other field's value in. 3. **Anything outside the resource.** A pattern is applied to the object. A deny condition's key is a JMESPath expression over the whole admission request, so it can read `request.operation` to apply only on CREATE, `request.userInfo.groups` to exempt a break-glass group, or `request.namespace`. None of that is part of the object being submitted. 4. **Combining a looked-up value with an operator.** A rule that must compare the object against a value fetched into the rule's context needs a condition to do the comparing. ### Worked example — restricting storage to encrypted classes Suppose PersistentVolumeClaims may only name a StorageClass from an approved encrypted set. If those classes all share a prefix, the pattern is genuinely the better rule: ``` pattern: spec: storageClassName: "encrypted-*" ``` One line, self-explanatory to the team it governs. But if the approved set is an arbitrary list of names, or the rule must apply only on CREATE and exempt the platform team's own service account, the pattern cannot express it and you move to a deny block with `AnyNotIn` over the list plus a condition on `request.operation`. The same contrast shows up with a Service of type LoadBalancer that must carry an internal-only annotation. As a shape, that is "if the type is LoadBalancer, then this annotation must be set" — expressible with a conditional anchor, but it reads awkwardly. As a deny block it is two plain conditions under `all`: type equals LoadBalancer, and the annotation is not the value we require. Most reviewers find the second version easier to argue about. ### How to choose Ask what the rule is really saying. "The resource must look like this" is a pattern. "This combination of facts is forbidden" — especially when the facts involve operators, sets, several fields, or the requester — is a deny block. A single Kyverno policy can hold rules of both kinds, and mixing them by fit rather than by habit produces policies people can actually read.

  • When would you still reach for validate.pattern over a deny block?
    When the rule is a shape: a required field, a literal value, or a wildcard match such as `storageClassName: "encrypted-*"`. The pattern looks like the manifest the developer writes, so it survives review by people who do not author policy, and a patch to it is easy to read. Reach for deny only when you need operators, set membership, several fields compared together, or request metadata.
  • Can a deny condition look at something that is not part of the submitted resource?
    Yes — that is one of its main advantages. The key is a JMESPath expression over the admission request, so it can read `request.operation` to scope the rule to CREATE, or `request.userInfo.groups` to let a named break-glass group through. A pattern is only ever matched against the object itself and has no access to any of that.
  • What happens when a deny block's conditions evaluate to false?
    Nothing visible: the rule does not deny, the request continues through the rest of admission, and the validate message is never shown. A deny rule is silent unless it fires, which is why an inverted condition list is so easy to ship — the policy looks installed and healthy while admitting exactly what it was meant to stop.

A pattern is a stencil you lay over the resource to see whether it fits. A deny block is a checklist of yes/no questions, and a checklist that comes back yes stops the change.

saying these in an interview costs you the question

  • Thinks a deny block describes the allowed resource
  • Believes a pattern can compare two fields to each other
  • Assumes conditions evaluating true means the request passes
  • Claims a pattern can read request.operation or the requesting user
  • Uses a deny block for a rule that is just a required literal

context