What does a Kubernetes AdmissionReview request actually carry, and what is simply absent from it?
answer
- one object, one instant
- oldObject only on update or delete
- userInfo and dryRun are in there
- no other object, no cluster state, no history
- the image is a string, not its contents
basics
~20 sIt carries the single object being submitted, the previous version on an update or delete, the requesting user and groups, and a dryRun flag. It carries no other object, no cluster state, no history, and no artifact contents.
solid answer
~50 sAn AdmissionReview is a snapshot of one request at one instant. The request holds the submitted `object`, `oldObject` (the stored version, present on updates and deletes but empty on a create), `userInfo` with the requester's username and groups, the `operation`, the resource and namespace, and `dryRun`, which tells the policy the result will not be persisted. What it does not hold matters more: no other object in the cluster, no count of anything, no history of what was deployed before, and none of the contents of artifacts the object merely references. A container spec carries an image reference string, not the image's packages, licences or layers. So a rule can only decide from what is inside that one payload; every other fact has to be brought to the decision from somewhere else, or the rule has to live somewhere else.
code
yaml · 15 linesrequest:
uid: 5f2b...
operation: CREATE
userInfo:
username: system:serviceaccount:build:deployer
groups: [system:serviceaccounts, system:authenticated]
dryRun: false
object:
kind: Pod
spec:
containers:
- name: api
image: registry.internal/api:2026.08.1 # a string, not the image
# oldObject: absent on CREATE
# no other objects, no cluster state, no historygo deeper
Be ready to list the request's contents from memory: the submitted object, the old object on updates and deletes, the requester's identity, the operation, and dryRun. Then say plainly what is not there.
Explain why the absences are structural. Widening the input means stale replicated state or per-request I/O in the write path, so they are not fields somebody forgot to add.
Show that you triage a proposed rule by its inputs first. Name which required fact is missing and where that fact really lives before discussing how to express the rule.
Own the consequence for the estate: rules that need facts outside the request should be placed elsewhere on purpose, and the coverage map should say so rather than implying admission covers them.
### What the request is When a client asks the Kubernetes API server to create, update or delete an object, the API server can hand the request to a policy for a decision before the object is persisted. The payload the policy sees is an `AdmissionReview`, and its `request` field is a snapshot of exactly one API request, at one instant, for one object. That framing is the whole leaf. Almost every rule that fails to work at admission fails because its author assumed the payload contained something it never contains. ### What the request carries - `object` — the object as submitted, after any earlier mutating step has already changed it. - `oldObject` — the currently stored version of the object. It is populated on an update and on a delete; on a create there is no prior state, so it is empty. This is what lets a rule compare before and after — for example, allowing a field to exist but not to change. - `userInfo` — the username, UID, groups and extra attributes of whoever made the request. This is a real, server-authenticated fact, and it is one of the few pieces of provenance the payload genuinely has. - `operation` — CREATE, UPDATE, DELETE or CONNECT. - The resource, subresource, namespace, object name, the kind, and a request `uid` that correlates the response back to the request. - `dryRun` — true when the API server will not persist the result. A check that writes somewhere outside the cluster must not do so when this is set, or a harmless preview turns into a side effect. - `options` — the API options attached to the operation, such as delete options. ### What the request does not carry - **Any other object.** Not the other Pods in the namespace, not the Namespace's own labels, not the referenced Secret or ConfigMap, not the owning controller. - **Any cluster state.** No counts, no totals, no quota usage, no view of what else is running. - **Any history.** Not what this object looked like last quarter, not who changed it before, not whether it has ever been through this rule. - **The contents of anything the object references.** A container spec carries a string such as `registry.internal/api:2026.08.1`. It does not carry the image's layers, its installed packages, its dependency list, or the licences those dependencies use. It does not even pin which bytes will be pulled — the reference is resolved later, on the node. - **Anything about behaviour.** What the process does after it starts is not in a create request, because that has not happened yet. ### Why the gaps are structural, not incidental The request is scoped to one write because that is what admission is: a decision that has to be made synchronously, in the API server's critical path, for every write. Widening its input means either replicating cluster state somewhere the policy can read (which is then stale) or making the policy do I/O per request (which puts a network dependency in front of every write). Neither of those is a field you can simply ask for; both change the failure model of the cluster. ### What this means when you write a rule Before writing anything, ask what facts the rule needs and where each one comes from. If every fact is inside the submitted object, the request body, or the requester's identity, admission can decide it — for example, requiring a label, rejecting a field value, or refusing a change made by an identity that should not be making it. If any required fact is outside the payload, admission is the wrong choke point for that rule, and the honest answer is to place the control where the fact exists rather than to approximate it. ### Where the missing facts do live Each class of missing fact has a natural home. Facts about an artifact's composition — what is inside it, including dependency licences — are established when the artifact is built, and live in the inventory produced then. Facts about behaviour — a process that fetches and executes something an hour after start — are only observable to a runtime sensor watching the workload as it runs. Facts about the whole estate — how many workloads exist, what was admitted before the rule was written — belong to a periodic scan of live state, not to a single write. Recognising which of these you are being asked for is the skill this question tests. A candidate who reaches for the request payload for all three has not yet noticed that admission sees one object, once.
- Does the request tell you which image bytes will actually run?No. The container spec carries a reference string, and what that reference resolves to is decided later, when the node pulls it. So any rule reasoning about what is inside the image is reasoning about something the request does not pin down, and the answer can differ between the moment of admission and the moment of pull.
- Why is oldObject empty on a create?Because there is no stored version yet. It is populated on updates and deletes, which is what makes before-and-after rules possible: you can allow a field to be set at creation but refuse later changes to it, or refuse a delete of an object in a particular state. On a create you have only what was submitted.
- What is dryRun in the request for?It tells the policy the API server will not persist the outcome — the caller is previewing. The decision itself should be identical, but any external effect a check performs, such as recording a finding or calling out to another system, must be suppressed, otherwise a preview leaves real traces behind.
It is a border check on one traveller's passport: identity and documents are right there, but nothing about who else is in the country, or what this person will do next week.
saying these in an interview costs you the question
- Thinks a rule can query other objects in the cluster
- Assumes the request includes the image's packages or licences
- Believes the payload contains the object's deploy history
- Treats the image tag as pinning the bytes that will run
- Expects oldObject to be populated on a create