skip to content

What does matchPolicy Equivalent do in a Kubernetes admission policy that Exact does not?

level: seniorimportance: nice to knowfreq 31%

answer

  1. resources are served at more than one version
  2. listing one version is not listing the resource
  3. conversion before the engine sees it
  4. no match leaves no trace at all
  5. the v1 API already defaults the safer way

basics

~20 s

Equivalent makes a rule fire even when a request arrives under an API version the rule did not list, converting the object first. Exact intercepts only the listed group, version and resource, so other served versions pass unevaluated.

solid answer

~50 s

Resource rules match on group, version and resource. Under `matchPolicy: Exact`, only a request whose group/version/resource appears verbatim in the rules is intercepted. Under `Equivalent` — the default in the v1 admission registration API — a request for a *different* served version of a resource that is listed under some version is converted to a version the rule did list and intercepted as that version, so the engine still reads the field paths it knows. This matters wherever a resource is served at more than one version: a custom resource offered at `v1beta1` and `v1`, or a built-in during a deprecation window. With `Exact` and only one version listed, creating the object through the other version is a silent bypass — not an error, not a denial, simply no evaluation. That is the failure mode to name in an interview: a rule that produced no verdict looks exactly like a rule that passed.

go deeper

for a junior

Know that admission rules list specific API groups, versions and resources, and that a request outside that list is simply never evaluated rather than allowed by the rule.

for a middle

Explain the two settings and the default in the v1 API, and give the case that motivates Equivalent: one resource served at two versions with clients still using the old one.

for a senior

Focus on diagnosis. Say how a silently unmatched rule looks identical to a healthy one, and what you measure — evaluations per rule against objects created — to tell them apart.

for a principal

Argue for coverage as first-class evidence: a control that cannot show which requests it saw cannot support any claim that it was in force, however many green runs sit behind it.

## The field and what it controls An admission registration's resource rules enumerate API groups, API versions and resources. `matchPolicy` decides how strictly that enumeration is read: - **`Exact`** — intercept only requests whose group, version and resource appear in the rules as written. - **`Equivalent`** — intercept requests for any *served version* of a resource that the rules list under some version. The API server converts the object to a version the rule did list and presents it that way. In the `admissionregistration.k8s.io/v1` API, `matchPolicy` defaults to `Equivalent`, and the same field with the same default exists on the match constraints of the built-in policy resource. So the dangerous configuration is one someone set deliberately, usually by copying an older example. ## Why more than one version exists at all Kubernetes resources are versioned, and the same underlying object can be served at several versions simultaneously. A custom resource definition may serve `v1beta1` and `v1` at once while its consumers migrate, with a conversion strategy declared for moving between them. Built-in resources go through the same pattern during a deprecation window, when the old group/version is still served alongside the new one. Clients pick a version: an older Helm chart, a controller compiled against a previous release, a `kubectl` plugin, or a CI job pinned to an old manifest may all reach the same object through the version you did not think about. ## The failure this produces Your rule lists one version. `matchPolicy` is `Exact`. Someone creates the object through the other served version. The API server compares group/version/resource against the rules, finds no match, and proceeds — no interception, no engine call, no record that a policy declined to look. The object is admitted with none of your constraints applied. What makes this a senior question rather than a trivia one is the diagnosis. Every dashboard you own says the rule is healthy, because *not matched* and *matched and allowed* are indistinguishable at every place you would normally look. The rule body is correct, the tests pass, the review approved it. The only signal is negative: the count of evaluations for that rule does not move even though objects of that kind are created daily. So the operational habit worth stating is to watch **evaluation counts per rule**, not only denial counts, and to treat a rule with zero evaluations over a window in which matching objects were definitely created as broken rather than as a quiet success. ## Which to choose For a security guardrail, prefer `Equivalent`, which is also the default. It errs toward evaluating more requests rather than missing them, and conversion means the engine keeps reading the field paths it was written against instead of needing a branch per version. `Exact` has a narrow, honest use: a rule about something that exists only in one version — a field introduced in the newer schema, or a legacy shape you want to reject specifically — where matching the other version would evaluate an object where your expression makes no sense. Two boundaries to keep straight. First, `Equivalent` extends a match **across versions of a resource you already listed**; it never adds a resource you did not list. A rule about Pods does not become a rule about Deployments, and the API server derives no relationship between them for you. Second, conversion has to be possible: for a custom resource served at multiple versions, a conversion strategy must be in place for the API server to present the object in the version your rule asked for. ## The general lesson Every scoping mechanism in admission shares this property: the failure of a match block is silent by construction. A denial is loud and lands on a developer's terminal; a non-match produces nothing anywhere. That asymmetry is why the match block deserves as much review attention as the rule body, and why coverage — *did this rule see the objects it was supposed to see* — belongs in your evidence alongside *what did it decide*.

  • How would you detect that a rule was never firing rather than passing cleanly?
    Instrument coverage, not just verdicts. Record how many requests each rule evaluated, and compare that against how many objects of the matched kinds were created in the same window. A rule with zero evaluations over a week in which dozens of matching Deployments were created has not been quietly successful, it has been unwired. Denial counts alone can never distinguish the two.
  • If a custom resource is served at v1beta1 and v1, what does Equivalent hand the engine?
    The object converted to the version the rule listed. If the rule lists `v1` and the request came in at `v1beta1`, the engine receives the `v1` representation and its field paths keep working, so you write and test one rule instead of one per served version. That conversion has to be possible — a custom resource serving multiple versions needs a conversion strategy declared for it.
  • Does Equivalent mean you can be sloppy about which resources you list?
    No. It only widens a match across versions of a resource already listed; it never adds a resource. If you list Deployments, requests that create Pods directly are still outside your scope, and the API server will not infer the relationship for you. Getting the resource list right is a separate exercise from getting the version handling right.

saying these in an interview costs you the question

  • Says Exact and Equivalent only change error messages
  • Treats no match as equivalent to a clean pass
  • Assumes listing one version covers every served version
  • Thinks Equivalent widens the match to other resource kinds
  • Judges rule health from denial counts alone

context