In a Kyverno validate.pattern, what happens if a field in the pattern is missing from the resource?
answer
- the pattern is a shape, not a filter
- no required flag exists in a pattern
- a missing key is a failure, not a skip
- star also matches the empty string
- question-mark-star means at least one character
basics
~10 sAn unanchored field in a Kyverno validate.pattern is mandatory: if the resource does not have it, the pattern fails and the request is rejected. Give it the value ?* to demand any non-empty value.
solid answer
~50 sA `validate.pattern` is a shape that Kyverno overlays on the incoming object. Every key you write is required and every value you write must match, unless the key carries an anchor. So a pattern asking for `spec.containers[].resources.limits.memory` fails a container that has no `resources` block at all — absence is a violation, not a skip — and Kyverno reports the rule name plus the path it failed at, something like `/spec/containers/0/resources/limits/memory/`. Values are glob-matched, not exact: `*` means zero or more characters, so `"*"` also accepts an empty string and is a common way to accidentally assert nothing; `?` means exactly one character, which is why `"?*"` — one character then anything — is the idiom for "this field must be set to something". `!` negates a value match, and numeric or quantity comparisons like `">=128Mi"` are available for limits.
go deeper
Be ready to say plainly that a key written in a Kyverno pattern is required, and that a resource missing it is rejected. Know that ?* is how you demand a non-empty value.
Explain the glob semantics behind the values: why * accepts an empty string, why ?* does not, and how ! and the quantity comparisons let one pattern assert a ceiling rather than mere presence.
Show judgment about which keys stay unanchored. The assertion belongs unanchored; anchors are for selecting which resources or list elements the assertion covers, and mixing that up is how rules end up asserting nothing.
Own the authoring convention across the policy library: a documented default that every assertion is unanchored and every anchor is justified in a comment keeps a library of rules reviewable by people who did not write them.
## What a pattern is A Kyverno `validate` rule can decide in two ways. One is a `deny` block with explicit conditions; the other, which most policies use, is `validate.pattern` — a fragment of YAML shaped like the resource you are checking. Kyverno walks your pattern and the incoming object together and asks, at every position, "does the object satisfy what the pattern says here?" If every position is satisfied, the rule passes. If any position is not, the rule fails, and the admission request is rejected with the rule's `message` and the JSON path where the mismatch happened. The single most important consequence for a new policy author: **a key you write in a pattern is required.** There is no `required: true` marker, because writing the key *is* the requirement. A pattern of ```yaml pattern: spec: containers: - resources: limits: memory: "?*" ephemeral-storage: "?*" ``` says: every container must have a `resources` object, containing `limits`, containing both `memory` and `ephemeral-storage`, each set to a non-empty value. A container that omits `resources` entirely does not "fall through" the check — it fails it. That is the behaviour you want for a limits rule, and it is the opposite of what people expect coming from tools where a missing field simply means the check does not apply. ## Matching values, not just keys Pattern values are glob expressions, not literals: - `*` matches zero or more characters. Because zero is allowed, `memory: "*"` is satisfied by an empty string and, in practice, asserts almost nothing beyond "the key exists". - `?` matches exactly one character. So `"?*"` means one character followed by anything — at least one character. This is the canonical way to say "must be set". - `!` negates: `name: "!istio-proxy"` matches any name that is not `istio-proxy`. - `|` expresses alternatives: `"Gi|Mi"`-style value lists let one field accept several fixed values. - Numeric and quantity comparisons — `>`, `<`, `>=`, `<=` — let a limits rule assert a ceiling, for example `memory: "<=4Gi"`, rather than merely asserting presence. A field written as `"?*"` and a field written as `"<=4Gi"` are both assertions; the difference is only how strict the value check is. Both still require the key to exist. ## Making a field optional on purpose Because every plain key is mandatory, the anchors exist to say something weaker or something inverted: - `()` — conditional anchor. The anchored key/value is a *condition*: if it holds, the peer keys in the same block are evaluated; if it does not, that block is skipped without failing. - `=()` — equality anchor. If the key is present its value must match; if the key is absent, nothing is checked. This is the right anchor for an optional sub-object such as `initContainers` that must be correct when it exists. - `^()` — existence anchor, valid on arrays: at least one element must match, instead of all of them. - `X()` — negation anchor: the key must **not** be present. The value under it is not evaluated, so whatever you write there is a placeholder. `X(cpu)` under `resources.limits` asserts that no CPU limit is set. - `<()` — global anchor: if its condition is not met, Kyverno skips the entire rule rather than just that block. ## Why this trips people up Authors reach for an anchor when they mean "required" and end up with a rule that never fires. The reverse error is just as common: leaving an optional collection like `initContainers` unanchored, which then rejects every pod that happens not to have init containers. The rule of thumb is: write the thing you are asserting unanchored, and use an anchor only for the parts that select *which* resources or *which* list elements the assertion applies to. ## What the developer sees When the pattern fails and the policy is enforcing, the API request is rejected and the message Kyverno returns carries three useful things: your `message` text, the rule name, and the path at which the pattern failed — for example `rule require-memory-limit failed at path /spec/containers/1/resources/limits/memory/`. Quoting that path back at the person whose deploy just failed is usually the fastest way to end the conversation: it names the container index and the exact field they forgot.
- What is the difference between writing "*" and "?*" as a pattern value?`*` matches zero or more characters, so an empty value satisfies it and the check degenerates into "the key exists". `?` matches exactly one character, so `?*` means at least one character. When you want "this field must actually be set", `?*` is the value to write; `*` is a common way to ship a rule that asserts far less than you intended.
- Which anchor asserts that a field must be absent, and what does its value mean?The negation anchor, `X(key)`. It says the key cannot be present on the resource, and Kyverno does not evaluate whatever value you write under it, so that value is only a placeholder. A team that requires memory limits but forbids CPU limits, to avoid throttling, writes `memory: "?*"` alongside `X(cpu)` inside `resources.limits`.
- Where does the rejection message tell the developer what to fix?Kyverno returns the rule's `message` together with the rule name and the JSON path at which the pattern failed, for example `/spec/containers/0/resources/limits/memory/`. The path includes the list index, so it identifies the specific container. Write the `message` to say what to add, and let the path say where.
saying these in an interview costs you the question
- Thinks pattern fields are optional unless marked required
- Uses * to mean must be set, when it matches empty
- Believes a missing field skips the check silently
- Treats a pattern as a selector rather than an assertion
- Expects a separate required or presence keyword