Kubernetes Admission Controllers, Explained
Admission controllers intercept requests to the Kubernetes API server after authentication, validating or mutating objects before they're persisted.
Admission controllers are plugins that intercept requests to the Kubernetes API server after they’ve been authenticated and authorized, but before the object is persisted to etcd. They get the last word on whether a request goes through as written, gets modified first, or gets rejected outright — which makes them the layer where cluster-wide policy actually gets enforced.
Where admission control sits in the request lifecycle
Every request to the Kubernetes API — creating a pod, updating a deployment, deleting a namespace — passes through a pipeline before it takes effect:
- Authentication — who is making this request?
- Authorization — RBAC checks whether that identity is allowed to perform this action on this resource.
- Admission control — a chain of admission controllers gets to inspect, modify, or reject the request.
- Persistence — if nothing rejected it, the object is written to etcd.
RBAC answers “is this user allowed to create pods at all?” Admission control answers a different question: “given that they’re allowed, does this specific pod meet our rules?” A user might have full permission to create pods, but an admission controller can still reject a pod that requests no resource limits, references an unapproved image registry, or omits required labels.
Validating vs mutating webhooks
Kubernetes ships with several built-in admission controllers, but the extensible mechanism most teams actually build on is the dynamic admission webhook, which comes in two flavors:
| Mutating admission webhook | Validating admission webhook | |
|---|---|---|
| Can it change the request? | Yes — returns a JSON patch | No — accept or reject only |
| Runs when | Before validating webhooks | After all mutations are applied |
| Typical use | Inject sidecars, set defaults, add labels | Enforce policy, block non-compliant objects |
| Failure mode | Can silently alter behavior if misconfigured | Fails loudly — request is rejected |
Mutating webhooks run first, in a defined order, so that by the time validating webhooks run, they’re checking the final, fully-mutated version of the object. This ordering matters: a validating webhook that runs before a mutating one that adds required labels would reject objects that were always going to end up compliant.
A classic real-world example of a mutating webhook is automatic sidecar injection — a service mesh’s control plane watches for new pods and injects a proxy container into the pod spec before it’s scheduled, without every developer having to add that container manually. Validating webhooks are more often used for policy enforcement: rejecting pods that run as root, that don’t specify resource requests, or that pull images from an unapproved registry.
Built-in admission controllers
Beyond dynamic webhooks, the API server ships with a set of built-in admission controllers that are compiled in and enabled or disabled via a flag on kube-apiserver. Common ones include controllers that set default storage classes, enforce namespace existence before creating objects in it, and apply resource quotas. Most managed Kubernetes offerings enable a sensible default set and don’t expose fine-grained control over which built-ins run — the customization surface for cluster operators is almost entirely in dynamic webhooks and, in newer clusters, declarative policy engines that themselves run as validating or mutating webhooks under the hood.
Why teams reach for admission control
Admission controllers are how platform teams turn “please follow these conventions” from a wiki page into something the cluster actually enforces. Typical policies enforced this way:
- Requiring every pod to declare CPU and memory limits, so a single misconfigured deployment can’t starve a shared cluster.
- Blocking images from registries outside an approved allowlist, as part of a broader software supply chain security posture.
- Rejecting containers configured to run as root or with privileged security contexts.
- Enforcing required labels or annotations for cost attribution and ownership tracking.
- Auto-injecting configuration — TLS certificates, proxy sidecars, environment variables — so individual teams don’t have to remember to do it themselves.
This is a core piece of the tooling that lets platform teams build a self-service internal developer platform: policy that’s enforced automatically rather than reviewed manually in every pull request. See what platform engineering is for how admission control fits into that broader picture, and what GitOps is for how these policies are typically version-controlled and rolled out alongside everything else in the cluster.
Writing your own webhook
A custom admission webhook is just an HTTP server the API server calls with an AdmissionReview request, and expects an AdmissionReview response back containing an allow/deny decision (and, for mutating webhooks, a JSON patch). You register it with the cluster via a ValidatingWebhookConfiguration or MutatingWebhookConfiguration object, which tells the API server which resources and operations should trigger a call to your webhook.
Because the webhook sits directly in the request path, it needs to be fast and highly available — a slow or unreachable webhook can block every matching API request cluster-wide, unless it’s configured with a failurePolicy of Ignore rather than Fail. That tradeoff is itself a policy decision: Ignore keeps the cluster available if the webhook goes down, but means the policy it enforces silently stops applying during an outage.
Most teams don’t hand-write webhooks for common policies anymore — general-purpose policy engines that run as a validating (and sometimes mutating) webhook, with rules expressed in a policy language rather than custom server code, have become the standard way to get this behavior without maintaining bespoke webhook servers.
The takeaway
Admission controllers are where Kubernetes enforces “allowed, but only if it looks like this” — running after authentication and RBAC authorization, with the power to mutate a request before it’s stored or reject it outright. Mutating webhooks run first and can inject defaults or sidecars; validating webhooks run last and can only accept or reject. For most teams, the real decision isn’t whether to use admission control — it’s whether to write custom webhooks or adopt a policy engine that expresses the same rules more declaratively.
Tagged
Keep reading
Chisato · · 4 min read Kubernetes Network Policies Explained
Kubernetes NetworkPolicies control which pods can talk to which, at the network layer. Here's how they work and why pods are open by default.
Chisato · · 4 min read Kubernetes RBAC Explained
Kubernetes RBAC controls who can do what in a cluster using Roles, ClusterRoles, and bindings. How the pieces fit together, with a worked example.
Chisato · · 5 min read What Are Reproducible Builds? Verifiable Software, Explained
Reproducible builds produce bit-for-bit identical output from the same source, so anyone can verify a binary. Why they matter and how to achieve them.