When Gatekeeper evaluates a violation rule, what is in input and what is not?
answer
- two branches, nothing else
- the request, plus the Constraint's knobs
- no siblings, no cluster state, no history
- input.review.object and input.parameters
- push facts in, never pull them
basics
~20 sTwo things only: input.review, holding the resource under decision as input.review.object (and its previous version as oldObject on an update), and input.parameters, holding the matched Constraint's parameters. No other object, no cluster state, no history.
solid answer
~50 sGatekeeper hands the rule a single document with two branches. `input.review` is the admission request being decided, whose `object` is the resource the client is trying to write and whose `oldObject` is its prior state on an update. `input.parameters` is the `spec.parameters` of the Constraint that matched — the thresholds and allow-lists that make one template reusable. That is the entire world the rule can see. It cannot look up the Pod's Namespace, count how many Services already exist, check what was deployed yesterday, or call anything. Every rule you can write is therefore a predicate over one object plus configuration. When a rule genuinely needs a second object, the fact has to be pushed in — as a parameter, or by having Gatekeeper replicate those objects into its own cache — rather than fetched during evaluation.
go deeper
Remember the two names: input.review.object is the resource being written, input.parameters is the configuration from the Constraint that matched. Nothing else is handed to the rule.
Explain why the shape is narrow and what it forbids: no second object, no counts across the cluster, no history. Show that parameters are what make one template reusable.
Given a policy that needs a second object, pick a route and defend it: replicate the objects, push the fact in as a parameter, or move the check off the admission path and verify a stamped field instead.
Decide the house rule for your template library: which facts are allowed to become policy inputs at all, who keeps them current, and where a check belongs when admission is the wrong place for it.
## The whole input, and it is small When Gatekeeper evaluates a `violation` rule, `input` has exactly two branches: - **`input.review`** — the admission request under decision. `input.review.object` is the resource the client is trying to create or update. On an update, `input.review.oldObject` is the version already stored. Everything under `review` comes from that one request. - **`input.parameters`** — the `spec.parameters` of the Constraint that matched this request, shaped by the parameter schema the template declares. There is no third branch. This is the single most important fact about writing Gatekeeper rules, and it is the one candidates most often get wrong, because a rule *reads* like a program that could go and look something up. ## What that rules out Each of these is a natural-sounding policy that the input shape simply cannot express on its own: | the policy someone asks for | why the review alone cannot answer it | | --- | --- | | "only allow hostPath in namespaces labelled `infra`" | the Namespace is a *different object*; the review carries the Pod | | "no two workloads may claim the same node port" | requires the other workloads, which are not in the request | | "reject if this image was not scanned in the last week" | requires history and an external record | | "at most ten Pods per team" | requires a count over existing objects | A rule is a predicate over **one object plus configuration**. If a question needs a second object, the input shape has already answered it: not here, not like this. ## Why parameters exist `input.parameters` is what stops a template library from becoming one template per value. The template declares a schema — say a list of allowed volume types, or a boolean for whether a readinessProbe is required — and each Constraint fills it in. The rule reads `input.parameters.allowedTypes` rather than hard-coding a list, which means: - one template, many Constraints, each scoped to different namespaces with different strictness; - changing the allowed list is a small edit to a Constraint, reviewed like any other manifest, not a re-release of policy source; - the values are visible in the cluster as data, which matters when someone asks *why* a rule blocked them. A rule that hard-codes the values it should have taken as parameters is the most common review comment on a first template. ## The push-not-pull consequence Because the rule cannot pull, facts have to be pushed to it, and there are only a few doors: 1. **Into `input.parameters`.** Best when the fact is small, slow-moving and human-reviewable — an approved registry list, a set of allowed labels. Something outside Gatekeeper keeps the Constraint current. 2. **Into Gatekeeper's own replicated copy of chosen Kubernetes objects,** so a rule can see siblings such as Namespaces from `data` rather than from `input`. This works only for cluster objects and buys you staleness in exchange. 3. **Out of admission entirely.** Do the lookup in CI or a controller, have it stamp the result onto the object as a label or annotation, and let the rule check that field. The check becomes a predicate over one object again — which is exactly the shape admission supports. ## The same rule, a second caller One more thing follows from the input shape. Gatekeeper does not only evaluate rules on the admission path; it also sweeps objects that already exist and re-runs the same rules over them, putting the live object where `input.review.object` sits. That is only possible *because* the input is this narrow: a rule that depends on nothing but the object in front of it can be replayed against any object, at any time, in any order. A rule that reached out to the network mid-evaluation could not be replayed meaningfully at all. ## Interview-grade pitfalls - **"I'll just query the API server."** There is no client in the rule's world, and no credentials either. - **Confusing `input.parameters` with the template's parameter schema.** The schema is the declaration in the ConstraintTemplate; `input.parameters` is one Constraint's values for it, at evaluation time. - **Assuming `input.review.object` is what is stored.** It is what the client is proposing, before it exists. Defaults filled in later by other controllers are not necessarily there yet. - **Expecting the rest of the cluster to be visible by default.** Nothing beyond the request and the parameters is present unless you explicitly arranged for it.
- A rule must reject a Pod unless its Namespace carries an owner label. Why does reading input.review.object not work?Because the Namespace is a separate object and the review carries only the Pod being written. Your options are to have Gatekeeper replicate Namespaces so the rule can read them as data, to pass the acceptable owners in as parameters and require the label on the workload itself, or to move the check to a controller that reconciles Namespaces.
- Where do the values in input.parameters come from?From `spec.parameters` on the Constraint that matched the request, validated against the parameter schema the ConstraintTemplate declares. One template can back many Constraints, each with different values and different scope, which is why a rule should read parameters rather than hard-code the list it enforces.
- How does the narrow input shape help when the same rule is replayed over objects that already exist?A rule that only reads the object in front of it plus its parameters is deterministic and order-independent, so the same policy can be re-evaluated against a live object by putting that object where the reviewed one sits. A rule that depended on outside state at evaluation time could not be replayed and its past results could not be reproduced.
saying these in an interview costs you the question
- Thinks a rule can query the API server for another object
- Assumes the whole cluster is visible under input
- Confuses input.parameters with the template's parameter schema
- Hard-codes thresholds the Constraint should supply
- Believes the rule sees history or previously deployed versions