Can a ValidatingAdmissionPolicy enforce an allowlist that only an external inventory service knows?
answer
- the fact is outside the input surface
- no client of any kind, by design
- mirror it, split it, or relocate it
- a copy in params has a staleness window
- the rule cannot detect its own staleness
basics
~20 sNot directly — CEL in an admission policy cannot call anything. Either mirror the inventory into a parameter resource and enforce against the copy, split the rule and keep only the self-contained half in-tree, or move the check to an engine that can do the lookup.
solid answer
~60 sNo. The expression is a pure function of the object, the old object, the request, the namespace object and any bound `params`; there is no client of any kind, so a fact that lives in a service at decision time is unreachable. You have three honest moves. **Mirror it**: run a small controller that writes the inventory's current answer into the parameter resource, and enforce against that copy — the decision is now made on data that is as fresh as your sync, and the controller must fail the mirror closed (empty or remove it, with `parameterNotFoundAction: Deny`) rather than let a stale allowlist keep approving. **Split it**: keep the structural half in CEL — the field is set, the value is well-formed, the shape is right — and enforce the lookup half where the lookup is cheap, typically before the manifest ever reaches the cluster. **Relocate it**: move the whole rule to an external policy engine that can perform the lookup, accepting that you have now put a live dependency in front of every matching write. Choosing between them is the real answer; "you cannot do it" is only the first sentence.
go deeper
Recall that admission CEL has no way to call a service, so any allowed set it compares against has to already be inside the cluster as an object.
Explain the mirroring pattern end to end: a controller writes the external answer into the parameter resource, the expression compares against that copy, and the copy is stale by however long the sync takes.
Demonstrate the split — which half of the requirement is self-contained enough to stay as an in-cluster backstop, which half moves earlier — and state explicitly what a broken mirror should do.
Own the trade you are making on the organisation's behalf: a fail-closed mirror couples deployments to an inventory's uptime, and pushing checks earlier trades enforcement coverage for developer speed. Say which you chose and who agreed to it.
## Why the answer is no, and why that is not the interesting part The input surface of an admission CEL expression is fixed: the incoming object, the previous object, the request attributes, the request's namespace object, and the parameter resource the binding selected. There is no HTTP client, no API client, no cache. This is deliberate — the expression runs inline on the API server's write path, so a lookup there would make every matching write depend on a third party's availability. So a requirement phrased as "only node classes the platform inventory currently marks as available" cannot be evaluated in-tree. The interview does not stop there. What an interviewer is testing is whether you can convert an unmeetable requirement into a met one by changing where or how it is enforced. ## Option one: mirror the fact into params Run a controller that reads the inventory on a schedule and writes the current allowed set into the parameter resource the policy is bound to. The expression stays trivial — a membership test against `params` — and the rule enforces continuously with no dependency in the request path. What you have accepted is a staleness window. Between the inventory changing and the mirror catching up, admission is enforcing yesterday's answer. Whether that matters depends on the direction of the change: a class being *added* late is a minor annoyance, a class being *withdrawn* late means you kept admitting workloads onto something that was retired. The subtlety candidates miss is that **the rule cannot detect its own staleness**. The expression has no way to reach outside its input to check whether the mirror is current, so freshness has to be enforced by the controller, not by the rule. The pattern that works is: the controller narrows or clears the parameter resource when it cannot confirm the inventory, and the binding sets `parameterNotFoundAction: Deny`, so a mirror that stops working degrades into refusal rather than into silent permissiveness. That is a decision you make deliberately — a fail-closed mirror can turn an inventory outage into a cluster-wide deployment freeze, and someone has to agree that is the trade you want. ## Option two: split the rule Most requirements that look like they need a lookup are actually two requirements welded together. Take them apart: - **Self-contained half** — the workload declares a node class at all; the value matches the naming convention; the tolerations are consistent with the selector; nothing carries a blanket toleration. All of this is in the submitted object, all of it is cheap, and all of it belongs in the in-tree policy as a permanent backstop that cannot be bypassed by any path into the cluster. - **Lookup half** — is *this* class currently approved for *this* workload. Enforce that where the lookup is natural and cheap: in the pipeline that renders the manifest, or in the reconciler that syncs it, where a network call costs nothing and the failure is a red build rather than a rejected write. The result is a coarse, always-on guardrail in the cluster and a precise check earlier. That is usually a better control than either half alone, because the in-cluster half survives someone bypassing the pipeline and the earlier half gives the developer a fast, specific failure. ## Option three: relocate the whole rule Move it to an external policy engine — a webhook-based engine such as Gatekeeper, Kyverno or Kubewarden — that can reach the fact, or supply it from data the engine replicates itself. Be honest about what changes: you now operate a component in the admission path, and the requirement's availability is coupled to it. That is a legitimate choice when the lookup is genuinely central to the control; it is a poor one when you have reached for it to avoid the mirroring work. ## How to answer this in an interview Lead with the constraint and the reason for it, then present the three moves and pick one for the case at hand, naming the trade you are accepting. If the fact changes rarely and matters a lot, mirror it and fail closed. If the fact is really a business decision about what a team may request, push it left into the pipeline and keep a structural backstop in-cluster. If the fact must be consulted at the moment of the write and nothing else will do, run an engine and own the dependency. The wrong answer is any of the three offered as *the* answer, and the very wrong answer is claiming CEL can be made to fetch it.
- You mirror the inventory into a parameter resource and the sync stops. What should happen?Decide it in advance, because the rule cannot tell. The workable pattern is a controller that clears or removes the parameter resource when it cannot confirm the source, with `parameterNotFoundAction: Deny` on the binding, so a broken mirror becomes refusal rather than silent permissiveness. Get agreement first: that turns an inventory outage into a deployment freeze.
- If you split the rule, which half stays in the cluster and why?The self-contained half — the field is set, the value is well-formed, the selector and tolerations are consistent. It stays because it needs nothing external, costs almost nothing, and is the part that must survive someone deploying around the pipeline. The lookup half goes where the lookup is cheap and the failure is a red build.
- Why not just move every rule to an external engine and be done with it?Because each rule you move puts a component you operate in front of the writes it matches, and the in-tree policy needs no such component. Rules that fit the input surface should stay where they cost nothing to run; relocation is for the ones that genuinely cannot be expressed, not a default.
It is like a doorman working from a printed guest list. He can enforce the list perfectly, but he cannot phone the office to ask who was added this morning — so either someone reprints the list often, or the checking moves to whoever can make the call.
saying these in an interview costs you the question
- Claims a CEL expression can be made to call an endpoint
- Mirrors the data but never decides what a stale mirror does
- Moves the whole rule out when only half needed the lookup
- Treats an external engine as making the lookup free
- Says only 'you cannot do that' and stops there