Glossary/Cloud Forensics/Kubernetes with Admission Controllers

What Is a Kubernetes Admission Controller?

A Kubernetes admission controller is code in the API server that intercepts requests after authentication and authorization but before persistence, to mutate or validate the object, making it the layer where most cluster security policy is enforced.

A developer runs kubectl apply on a Pod manifest that requests privileged: true, mounts the host filesystem, and pulls an unscanned image from a public registry. Authentication passes: the user has valid credentials. Authorization passes: their RBAC role allows creating Pods in that namespace. By every rule you have configured so far, that Pod is allowed. The thing that stops it before it ever reaches etcd is an admission controller.

An admission controller is the last gate in the Kubernetes API request path. It runs after the request is authenticated and authorized, but before the object is persisted to the cluster's datastore. At that point it can do one of three things: change the object, reject the object, or let it through. That single hook is where most cluster security policy actually lives, because it is the only place that sees every create, update, and delete with enough context to say no.

This guide defines what an admission controller is against the Kubernetes documentation, walks the request flow it sits in, separates mutating from validating controllers, covers the webhook and policy extension points that let you write your own, and gives the security use cases that make it the control plane's enforcement point.

What is a Kubernetes admission controller?

A Kubernetes admission controller is code that intercepts requests to the API server after authentication and authorization, but before the requested object is persisted to etcd. It can validate the request, mutate it, or both. It governs requests that create, modify, or delete objects. It does not touch read operations: get, list, and watch are never sent through admission control.

The reason this layer exists is that authentication and authorization answer narrow questions. Authentication answers "who is this." Authorization answers "is this identity allowed to perform this verb on this resource." Neither one looks at the contents of the object. An RBAC rule that permits creating Pods does not care whether the Pod runs as root, mounts the Docker socket, or pulls latest from an untrusted registry. Admission control is the layer that reads the object itself and enforces what it is allowed to contain.

Kubernetes ships with admission control as a built-in feature of the API server, not an add-on. A long list of controllers is compiled into the binary, and a default set is enabled out of the box. On a current cluster the default enabled plugins include NamespaceLifecycle, LimitRanger, ServiceAccount, PodSecurity, ResourceQuota, MutatingAdmissionWebhook, and ValidatingAdmissionWebhook, among others. Several core Kubernetes behaviors only work because an admission controller implements them: default storage classes get assigned, service account tokens get injected, and resource quotas get enforced at admission time. Turn the wrong ones off and the cluster stops behaving the way operators expect.

Controllers are toggled with two API server flags. --enable-admission-plugins turns specific plugins on, and --disable-admission-plugins turns them off, overriding the defaults. Because they live in the API server's startup configuration, the built-in set is a control-plane concern: changing it means changing how every node's kubelet ends up running workloads, since the API server is the single point every request passes through.

How admission control fits in the API request flow

Kubernetes admission controller
The API request path
Every write runs the same gauntlet. Admission control is the last gate, and the only stage that reads the object itself and can rewrite it before it reaches etcd.
1. Authentication
Who is this? Cert or token. Reject if unknown.
2. Authorization
May this identity do this verb? RBAC. Reject if not.
3a. Mutating admission
Runs first. Rewrites the object: inject defaults, sidecars, security context.
3b. Validating admission
Runs second. Accept or reject the final object. Cannot change it.
4. Persist
Object is written to etcd. Only survivors get here.
Why it matters Authn and authz never read the object's contents. Admission control does. Mutating always precedes validating so validation checks the object as it will be stored. If any controller denies, the whole write stops. There is no partial admission.

Every write to the Kubernetes API server runs the same gauntlet, in a fixed order. Understanding that order is the whole point, because admission control only makes sense as the stage that comes last.

  1. Authentication. The API server establishes who is making the request, from a client certificate, a bearer token, or another configured method. A request that cannot be authenticated is rejected here.
  2. Authorization. The server checks whether that identity is allowed to perform the requested verb (create, update, delete) on the requested resource, usually via RBAC. A request the identity is not permitted to make is rejected here.
  3. Admission control. The authenticated, authorized request now passes through the admission controllers. They inspect the actual object, mutate it if configured to, and validate it. Only a request that survives all of them is written to etcd.

The order matters for security reasoning. By the time a request reaches admission control, you already know it came from a real identity that is allowed to make this kind of change. What you do not yet know is whether the change is safe. Admission control is the only stage that reads the object's spec and decides on its contents. It is also the only stage that can rewrite the request: authentication and authorization can say yes or no, but they cannot edit what you submitted.

Admission control itself runs in two passes, and the split is what makes the next section necessary. The mutating pass runs first and can alter the object. The validating pass runs second and can only accept or reject. The reason mutating comes first is mechanical: a mutating controller might inject a sidecar or set a default, and the validating controllers need to check the object as it will actually be stored, not as it was submitted.

Mutating vs validating admission controllers

Admission controllers come in two functional kinds, and a single controller can be one or both. The distinction is not cosmetic. It determines what the controller is allowed to do to your request and when it runs.

DimensionMutating admission controllerValidating admission controller
What it doesModifies the object before it is storedAccepts or rejects the object as-is
Can change the objectYesNo
Can reject the requestYesYes
PhaseRuns firstRuns second
Typical jobInject defaults, sidecars, labels, security contextEnforce policy, block non-compliant objects
Built-in exampleServiceAccount, DefaultStorageClass, PriorityPodSecurity, ResourceQuota, NamespaceLifecycle
Webhook extensionMutatingAdmissionWebhookValidatingAdmissionWebhook

Mutating controllers run first and can rewrite the request. They are how Kubernetes applies sensible defaults and how service meshes inject sidecars. The built-in ServiceAccount controller adds a default service account and mounts its token into a Pod that did not specify one. DefaultStorageClass assigns a storage class to a PersistentVolumeClaim that omits one. A mutating webhook from a service mesh injects the proxy container. The object that gets stored is not always the object you submitted, and mutating controllers are the reason.

Validating controllers run second and can only say no. Once mutation is done, the object is in its final form, and validating controllers check it against policy. PodSecurity rejects a Pod that violates the namespace's Pod Security Standard. ResourceQuota rejects a request that would push a namespace over its limit. NamespaceLifecycle rejects creation of objects in a namespace that is being deleted. A validating controller cannot fix a bad object. It can only block it and return an error.

The ordering is a hard rule, not a convention. Mutating always precedes validating, so that validation runs against the object as it will be persisted. If a mutating webhook injects a privileged sidecar, the validating PodSecurity controller will see and reject that sidecar, because it runs afterward. If any controller in either pass denies the request, the whole operation stops and the user gets the error. There is no partial admission.

Dynamic admission control: webhooks and policies

The built-in controllers are fixed in the API server binary. The real power, and where cluster-specific security policy lives, is dynamic admission control: extension points that let you plug in your own logic without recompiling Kubernetes. There are two ways to do it.

Admission webhooks are the original mechanism. You run an HTTP server, register it with the cluster through a MutatingWebhookConfiguration or ValidatingWebhookConfiguration, and the API server calls out to it on matching requests. The server receives an AdmissionReview object describing the request, and returns one that allows, denies, or patches it. The two built-in controllers MutatingAdmissionWebhook and ValidatingAdmissionWebhook are what actually dispatch these calls. This is how external policy engines like OPA Gatekeeper and Kyverno hook in, and how image-scanning gates block unscanned or vulnerable images at deploy time. The cost is operational: you are running, securing, and scaling a webhook server that sits in the critical path of every matching request.

Admission policies are the newer, in-process alternative. ValidatingAdmissionPolicy became stable in Kubernetes 1.30 and lets you write validation rules in CEL, the Common Expression Language, declared as Kubernetes resources. The rules run inside the API server, with no external HTTP callout, no webhook server to operate, and no extra network hop to fail. For a rule like "replica count must be 5 or fewer" or "this label is required," a policy is simpler and more reliable than a webhook. A MutatingAdmissionPolicy exists as the mutating counterpart and is newer in the policy line, so confirm its stability against your cluster version before relying on it. The webhook path stays necessary when your logic needs to reach outside the cluster, for example to call a registry scanner or an external service.

The practical guidance is to reach for a policy first and a webhook when the policy model cannot express what you need. Both are how you turn cluster security requirements into enforced, automatic gates rather than documentation nobody follows.

Security use cases for admission controllers

Admission control is where a large share of container security policy is actually enforced, because it is the chokepoint every workload definition passes through before it runs. The concrete jobs:

  • Block insecure Pod specs. The built-in PodSecurity controller enforces the Pod Security Standards (privileged, baseline, restricted) per namespace, rejecting Pods that run privileged, mount the host path, escalate privileges, or otherwise breach the level the namespace is labeled for. This is the supported replacement for the removed PodSecurityPolicy.
  • Gate images at deploy time. A validating webhook that calls an image scanner can reject any Pod whose image is unscanned, fails policy, or carries known-critical vulnerabilities, stopping a bad image before it is ever scheduled.
  • Enforce required configuration. Policies can require that every Pod sets resource limits, carries owner labels, pulls from approved registries only, or runs as a non-root user, turning standards into hard gates.
  • Inject security defaults. Mutating controllers can add default security contexts, drop Linux capabilities, set imagePullPolicy: Always, or attach a sidecar, so the secure setting is applied even when the author forgot it.
  • Contain blast radius. ResourceQuota and LimitRanger cap what a single namespace or Pod can consume, limiting the damage a compromised or runaway workload can do to the rest of the cluster.

The strategic value is that admission control moves policy enforcement to the left of runtime. A scanner that finds a vulnerable container already running is incident response. An admission webhook that refuses to admit that container is prevention. That shift, from detecting bad workloads to refusing to create them, is why admission control is central to a cloud native security program rather than a niche API server setting.

The same chokepoint is also a target. The webhook configurations, the policies, and the API server flags that define admission are themselves objects an attacker with enough access will try to weaken or delete. Treat the admission configuration as control-plane security: restrict who can edit webhook and policy resources, monitor for changes to them, and watch the API server's admission decisions in the audit log for rejection patterns and sudden shifts in request volume.

Frequently Asked Questions

What is a Kubernetes admission controller?

A Kubernetes admission controller is code in the API server that intercepts requests after authentication and authorization but before the object is written to etcd. It can mutate the object, validate it, or both, and it governs only requests that create, modify, or delete objects, not reads. It is the layer that inspects the object's actual contents and enforces what a workload is allowed to be.

What is the difference between a mutating and a validating admission controller?

A mutating admission controller can change the object before it is stored, for example by injecting a default service account, a sidecar, or a security context. A validating admission controller cannot change anything; it can only accept or reject the object as submitted. Mutating controllers always run first so that validation checks the object in its final, stored form.

When do admission controllers run in the Kubernetes API request flow?

They run third, after authentication and authorization. Authentication establishes who is making the request and authorization establishes whether that identity may perform the verb, then admission control inspects the object itself. Within admission control, the mutating pass runs before the validating pass, and only a request that survives both is persisted.

What is the difference between an admission webhook and ValidatingAdmissionPolicy?

An admission webhook is an external HTTP server the API server calls out to on matching requests, used by engines like OPA Gatekeeper and Kyverno and for tasks that must reach outside the cluster. ValidatingAdmissionPolicy, stable since Kubernetes 1.30, runs validation rules written in CEL inside the API server with no external callout, so it is simpler and more reliable for rules the policy model can express. Use a policy first and a webhook when you need logic the policy cannot reach.

Are admission controllers a security tool?

Yes, admission control is where much of a cluster's security policy is enforced. It blocks insecure Pod specs through the built-in PodSecurity controller, gates container images through scanning webhooks, requires safe configuration, and injects security defaults. Because it is the single point every write passes through before persistence, it shifts policy enforcement from detecting bad workloads at runtime to refusing to create them.

What replaced PodSecurityPolicy?

PodSecurityPolicy was removed in Kubernetes 1.25. Its supported replacement is Pod Security Admission, implemented by the built-in PodSecurity admission controller, which enforces the three Pod Security Standards (privileged, baseline, restricted) at the namespace level in enforce, audit, or warn mode. For policy beyond those standards, teams use ValidatingAdmissionPolicy or an external admission webhook engine.

The bottom line

An admission controller is the final gate in the Kubernetes API request path: it runs after authentication and authorization, before the object is stored, and it can mutate the request, validate it, or reject it. Mutating controllers run first and can rewrite the object; validating controllers run second and can only block it. That two-pass hook is where most cluster security policy is actually enforced.

Use the built-in controllers that ship enabled, enforce Pod Security Standards through the PodSecurity controller, and add cluster-specific rules with ValidatingAdmissionPolicy for in-process checks or admission webhooks when your logic must reach outside the cluster, such as image scanning. Then protect the admission configuration itself, because the gate that refuses bad workloads is only as strong as the access controls around it.

Frequently asked questions

What is a Kubernetes admission controller?

<p>A Kubernetes admission controller is code in the API server that intercepts requests after authentication and authorization but before the object is written to etcd. It can mutate the object, validate it, or both, and it governs only requests that create, modify, or delete objects, not reads. It is the layer that inspects the object's actual contents and enforces what a workload is allowed to be.</p>

What is the difference between a mutating and a validating admission controller?

<p>A mutating admission controller can change the object before it is stored, for example by injecting a default service account, a sidecar, or a security context. A validating admission controller cannot change anything; it can only accept or reject the object as submitted. Mutating controllers always run first so that validation checks the object in its final, stored form.</p>

When do admission controllers run in the Kubernetes API request flow?

<p>They run third, after authentication and authorization. Authentication establishes who is making the request and authorization establishes whether that identity may perform the verb, then admission control inspects the object itself. Within admission control, the mutating pass runs before the validating pass, and only a request that survives both is persisted.</p>

What is the difference between an admission webhook and ValidatingAdmissionPolicy?

<p>An admission webhook is an external HTTP server the API server calls out to on matching requests, used by engines like OPA Gatekeeper and Kyverno and for tasks that must reach outside the cluster. ValidatingAdmissionPolicy, stable since Kubernetes 1.30, runs validation rules written in CEL inside the API server with no external callout, so it is simpler and more reliable for rules the policy model can express. Use a policy first and a webhook when you need logic the policy cannot reach.</p>

Are admission controllers a security tool?

<p>Yes, admission control is where much of a cluster's security policy is enforced. It blocks insecure Pod specs through the built-in PodSecurity controller, gates container images through scanning webhooks, requires safe configuration, and injects security defaults. Because it is the single point every write passes through before persistence, it shifts policy enforcement from detecting bad workloads at runtime to refusing to create them.</p>

What replaced PodSecurityPolicy?

<p>PodSecurityPolicy was removed in Kubernetes 1.25. Its supported replacement is Pod Security Admission, implemented by the built-in PodSecurity admission controller, which enforces the three Pod Security Standards (privileged, baseline, restricted) at the namespace level in enforce, audit, or warn mode. For policy beyond those standards, teams use ValidatingAdmissionPolicy or an external admission webhook engine.</p>

Practice track
SOC Analyst Tier 1
Build your foundational skills to monitor, detect, and escalate security alerts. This track includes essential tools, basic log analysis, and introductory incident response labs.
Browse SOC Analyst Tier 1 Labs โ†’