skip to content

Controller-Created Objects

A rule written against Pods never sees the Deployment a developer applied, and the requester it does see is a controller. Interviewers use it to test whether you have written a real cluster rule.

on this pageshow

questions

4

When you kubectl apply a Deployment, which admission requests does the API server actually see?

level: juniorimportance: must knowfreq 72%

answer

  1. your apply is not the whole story
  2. count the hops down to the Pod
  3. each hop is its own CREATE
  4. requester is a kube-system service account
  5. kubectl already printed success

basics

~20 s

Three separate ones, not one: your Deployment, then the ReplicaSet the deployment controller creates, then one request per Pod from the ReplicaSet controller. Each is admitted on its own, under the controller's identity rather than yours.

solid answer

~40 s

One `kubectl apply` of a Deployment produces a chain of independent admission requests spread over time. The API server first admits the Deployment itself, with the requester recorded as you. The deployment controller then creates a ReplicaSet — a second CREATE, made as `system:serviceaccount:kube-system:deployment-controller`. The ReplicaSet controller then creates each Pod — one CREATE per replica, made as `system:serviceaccount:kube-system:replicaset-controller`. A CronJob works the same way: the cronjob controller creates a Job, the job controller creates the Pods. The consequence matters more than the trivia: a rule written against Pods does not run while your apply is in flight. It runs seconds later, against an object no human submitted, on a connection your terminal is not holding — so a denial there can never come back as an error from `kubectl apply`.

go deeper

for a junior

Be ready to count the hops out loud: Deployment, then ReplicaSet, then one Pod per replica, each a separate admission request. Know that the last two are made by control-plane controllers, not by you.

for a middle

Explain the mechanics: admission is per-API-request, the requester identity differs at each hop, and the same field lives at a different path on a Pod, a pod template and a CronJob's jobTemplate.

for a senior

Show that you design for the feedback path, not just the enforcement point. Say where a Pod-level denial surfaces, who will never see it, and what you add so the failure is noticed within minutes rather than days.

for a principal

Own the platform consequence: a guardrail that enforces correctly but reports into a controller's event stream generates support load and erodes trust in the whole gate. Decide up front where developers are told no.

## One command, several admission requests Admission control in Kubernetes is per-API-request, not per-intent. Every write that reaches the API server is admitted on its own, and the API server has no notion of "the thing the user was trying to do". So the mental model of "I applied a Deployment, therefore admission looked at my Deployment" is only one third true. Applying a Deployment produces this chain: 1. **CREATE (or UPDATE) Deployment** — submitted by you. The requester in the admission payload is your username and your groups. If a rule denies here, the API server returns the failure on your open connection and `kubectl` prints it and exits non-zero. 2. **CREATE ReplicaSet** — submitted moments later by the deployment controller, running inside the control plane as the service account `system:serviceaccount:kube-system:deployment-controller`. 3. **CREATE Pod, once per replica** — submitted by the ReplicaSet controller as `system:serviceaccount:kube-system:replicaset-controller`. The batch path is the same shape with different actors: a CronJob is admitted when you apply it; the cronjob controller creates a Job on each schedule tick; the job controller creates the Pods. Three kinds, three requests, three requesters. ## Why the chain matters to a policy author **The Pod is the object your rule usually cares about.** Container images, `securityContext`, resource limits, host mounts, host networking — these live on the pod spec. So the natural rule targets Pods. But the Pod is the object *furthest* from the human. Between the developer's editor and the Pod there are two machine-made requests, and by the time the Pod is created the developer's `kubectl apply` has already printed `deployment.apps/checkout configured` and returned zero. **A denial at the Pod hop has nowhere to go.** The requester is a controller. Controllers do not have terminals; they have work queues. When the create fails, the ReplicaSet controller records the failure against the ReplicaSet — an event, and a `ReplicaFailure` condition — and retries with backoff. Nothing about that is printed to anybody. The user sees a Deployment that reports zero ready replicas and no obvious reason. **Each request stands alone.** The admission payload for the Pod carries the Pod, the requester and the operation. It does not carry the Deployment, the ReplicaSet, or any other cluster state. A rule evaluating the Pod cannot ask "which Deployment is this from?" or "did the same team already have three of these?" — that data is simply not in the request, and the engine gets no free lookup. ## What the same field looks like at each hop The same setting exists at several levels with different paths. A memory limit is at `spec.containers[].resources.limits.memory` on a Pod, at `spec.template.spec.containers[].resources.limits.memory` on a Deployment, StatefulSet, DaemonSet, ReplicaSet or Job, and at `spec.jobTemplate.spec.template.spec.containers[].resources.limits.memory` on a CronJob. Choosing which of those to match is the central authoring decision on this material, and the chain above is why: matching Pods is complete but silent, matching the workload kinds is loud but partial. ## Bare Pods, for contrast Applying a Pod directly is the degenerate case: one request, requester is you, and a denial appears immediately in your terminal with the rule's message. That is why rules feel well-behaved in a demo and mysterious in production — the demo used a bare Pod and production uses Deployments. ## What to say in an interview Count the hops, name the requesters, then state the consequence: a Pod-level denial is real enforcement but invisible feedback, because the request that was rejected was never the one the human made.

  • If a rule targeting Pods denies one of those Pods, where does the rejection actually land?
    On the ReplicaSet. The controller records a create failure as an event on the ReplicaSet and sets a `ReplicaFailure` condition, then retries with backoff. The Deployment shows zero ready replicas. Nothing is written to the developer's terminal, and `kubectl get pods` shows no pod at all — because no Pod object was ever admitted.
  • Does applying a bare Pod directly follow the same path?
    No — that is a single request with you as the requester, so a denial comes straight back on your connection and `kubectl` exits non-zero with the rule's message. It is the same rule and the same evaluation; only the feedback path differs, which is why rules behave so differently in a demo than under a Deployment.
  • Can the rule evaluating the Pod look up the Deployment that ultimately caused it?
    Not from the request. The admission payload carries the object, its previous version on an update, the requester and a few request attributes — no other object and no cluster state. Any information you want the Pod-level rule to see has to be present on the Pod itself, for example a label the workload's pod template propagates.

You hand in a form at the counter and it is accepted. A clerk in the back office copies it onto a second form, and another clerk copies that onto a third. If the third form is rejected, the rejection sits on the back-office desk — the counter already told you you were fine.

saying these in an interview costs you the question

  • Thinks one kubectl apply produces one admission request
  • Expects a Pod-level denial to fail the kubectl apply
  • Believes the Pod request names the human who applied
  • Assumes the engine can read the parent Deployment while admitting the Pod
  • Confuses the Pod's own service account with the requester

context

open as a page

Should a memory-limit rule target Pods or the Deployment and CronJob templates that create them?

level: middleimportance: should knowfreq 58%

basics

~20 s

Target Pods for enforcement — every path ends in a Pod. Target the workload kinds too for feedback: only there does the denial reach the author's terminal. The two views can disagree, so decide which your intent means.

open as a page

A CronJob has produced nothing for two days and no kubectl command ever failed — what happened?

level: seniorimportance: should knowfreq 46%

basics

~20 s

Most likely a Pod-level admission rule is rejecting the job's Pods. The CronJob and its Jobs are admitted fine; only the Pod create is denied, by a controller, so the failure lands in a Job event and never in anyone's terminal.

open as a page

A Kubernetes admission rule exempts one username, yet still blocks that user's Deployment — why?

level: seniorimportance: nice to knowfreq 32%

basics

~20 s

Because the exemption is checked against the requester, and the request that gets blocked is the Pod create — made by the ReplicaSet controller's service account, not by the person. The human's name only ever appears on the Deployment request.

open as a page