An admission controller is a piece of code that intercepts requests to the Kubernetes API server after they've been authenticated and authorized, but before the object is written to the cluster's storage. It gets a look at every pod, deployment, service, or config map someone tries to create, and it can approve the request, reject it outright, or quietly change it before it goes any further. Kubernetes ships with a set of built-in admission controllers, and clusters can add their own through webhooks that call out to custom logic. Think of it as the last checkpoint between "someone asked for this" and "this now exists in the cluster."
The reason admission controller exists is that authentication and authorization only answer part of the question. Role-based access control can confirm that a user or service account is allowed to create pods, but it has no opinion on whether that particular pod requests unlimited memory, runs as root, pulls an image from an unapproved registry, or skips a label the platform team needs for cost tracking. Without a stage that inspects the actual content of the request, a cluster has no way to enforce those rules, and every team ends up relying on trust, code review, or hope. Admission control gives platform teams a programmatic place to say no, or to fix the request automatically, before it ever becomes a running workload.
The mechanism splits into two categories that run in a fixed order. Mutating admission controllers go first and can modify the object, injecting a sidecar container, adding a default resource limit, or stamping on a label. Validating admission controllers run after mutation and get a final, unmodified view of the object to accept or reject. Kubernetes has built-in controllers for things like namespace lifecycle and resource quota, and it also supports two generic webhook types, MutatingAdmissionWebhook and ValidatingAdmissionWebhook, which let a cluster operator point at any HTTP service and have it participate in this decision. Policy engines such as OPA Gatekeeper and Kyverno are built on top of these webhooks, giving teams a declarative way to write rules instead of writing webhook servers from scratch.
By 2026, admission control has become the default place where organizations enforce security and compliance policy in Kubernetes, largely because the alternative, catching problems after deployment, is slower and more expensive. Pod Security Admission replaced the older, less flexible PodSecurityPolicy as the built-in way to enforce baseline, restricted, or privileged pod standards, and most platform teams pair it with Gatekeeper or Kyverno for anything more specific to their business. Regulated industries in particular lean on admission control to prove, with an audit trail, that no workload reached production without passing checks for things like image provenance, network policy, or resource limits.
This page covers how admission controllers fit into the request lifecycle, the difference between mutating and validating behavior, where policy engines fit on top of the raw webhook mechanism, and the tradeoffs teams run into once they start relying on it for anything more than a handful of rules. The durable idea underneath all of this is simple: a Kubernetes cluster is only as disciplined as the checks it enforces automatically, and admission control is the layer that turns written policy into something the API server actually checks on every single request. Once a team understands that, they can stop treating security and compliance as something reviewed after the fact and start treating it as something the cluster itself refuses to violate.
Every write request to a Kubernetes cluster, whether it comes from kubectl, a CI pipeline, or a controller reconciling a resource, moves through the same pipeline. First the API server authenticates the caller, confirming who is making the request. Then it checks authorization, usually through RBAC, confirming that caller is allowed to perform that verb on that resource type. Only after both of those pass does the request reach admission control, and only after admission control approves does the object actually get written to etcd. This ordering isn't an implementation detail, it's the reason admission control is useful at all: by the time an object reaches this stage, the cluster already knows who is asking and that they're allowed to ask, so the only question left is whether the specific thing being requested is acceptable. If any admission controller in the chain rejects the request, the API server returns an error and nothing is written, no partial state, no orphaned object sitting half-created in etcd.
That ordering matters because it means admission controllers see something RBAC never does: the full content of the object being created or updated. RBAC can say "this service account may create deployments in the payments namespace." It cannot say "but not if the deployment requests more than 4 CPU cores" or "but only if it references an image from our internal registry." Those are content-level rules, and content-level rules are exactly what admission controllers exist to check. This is also why bypassing admission control by editing objects directly in etcd, something teams occasionally try during an outage, is dangerous: it skips every one of these checks entirely, not just the visible ones.
The two-phase split inside admission control, mutating first and then validating, is deliberate. If a mutating webhook injects a default resource limit onto a pod that didn't specify one, the validating stage then evaluates the pod as it will actually run, limits included, rather than rejecting it for a gap that's about to be filled in anyway. This lets platform teams set sane defaults invisibly while still enforcing hard rules on the final result. Within each phase, multiple webhooks can be registered and Kubernetes calls them in the order they're configured, which means the specific sequence of mutations can itself affect the final object, something teams occasionally get wrong when two mutating webhooks both try to set the same field.
It's worth being precise that admission control only applies to writes, not reads. A `kubectl get` or `kubectl describe` never touches this pipeline. That keeps the performance overhead contained to the operations where it actually matters, object creation and modification, rather than adding latency to every interaction with the cluster. It also means admission control has nothing to say about objects that already exist and simply sit there unchanged; a policy added today only applies going forward, which is why teams auditing for compliance need a separate process to check what's already running.
Kubernetes ships with a set of admission controllers compiled directly into the API server binary, and cluster operators enable or disable them through a flag at startup. Common ones include NamespaceLifecycle, which stops objects from being created in a namespace that's being deleted, ResourceQuota, which enforces namespace-level limits on CPU, memory, and object counts, and LimitRanger, which applies default resource requests and limits. These run fast because they're native code, not a network call to an external service, and because they ship with the API server, there's no separate deployment to manage, no certificate to rotate, and no extra pod that can crash. That reliability is exactly why the built-in set is kept deliberately narrow and generic, covering only concerns that apply to essentially every cluster rather than anything organization-specific.
Webhooks are the extension point for everything the built-in set doesn't cover. A ValidatingAdmissionWebhook or MutatingAdmissionWebhook configuration tells the API server to call out over HTTPS to a service, hand it the object being created, and wait for a response saying allow, deny, or (for mutating webhooks) here's a patch to apply. This is how organizations implement rules that are specific to their environment, like requiring every image to come from a signed, scanned registry, or requiring every namespace to carry a cost-center label. The webhook configuration also includes a `rules` field that scopes exactly which API groups, versions, and operations trigger the call, so a well-designed webhook only intercepts the narrow slice of traffic it actually needs to evaluate rather than every request in the cluster.
The tradeoff is latency and availability. A built-in controller adds effectively no round-trip cost. A webhook adds a network call, and if that webhook service is slow, overloaded, or down, the cluster has to decide what to do: fail open (allow the request anyway) or fail closed (block it). Most security-sensitive policies are configured to fail closed, which is correct for safety but means a broken webhook service can quietly halt every deployment in the cluster. This is the single most common operational incident tied to admission control, and it's why webhook services need their own uptime discipline, not just correct policy logic. Teams that run admission webhooks in production typically run multiple replicas behind their own service, set a tight but reasonable timeout (often one to a few seconds), and alert on webhook error rates the same way they'd alert on any other critical path service.
Policy engines like OPA Gatekeeper and Kyverno exist precisely to reduce how often teams have to hand-write webhook servers. Instead of writing and deploying a custom HTTP service for every rule, teams write policy as data (Rego for Gatekeeper, YAML-based rules for Kyverno) and the engine's own webhook, already running and already hardened, evaluates that policy against incoming objects. This shifts the operational burden from "maintain N custom services" to "maintain one policy engine and N policy definitions," which is a meaningfully smaller surface to keep reliable. It also changes who can write policy: instead of needing a developer to build and ship a webhook service for every new rule, a platform or security engineer can add a policy definition as a YAML or Rego file, which lowers the bar enough that policy tends to get written and maintained by the people who actually understand the compliance or security requirement.
The webhook mechanism is plumbing. The value an organization gets from admission control comes from the policies it enforces, and those policies tend to cluster around a few recurring concerns. Security policy blocks privileged containers, containers running as root, or containers with writable root filesystems, closing off common paths to container breakout. Supply chain policy restricts image sources to internal or verified registries and can require that images carry a signature or an attached SBOM before they're allowed to run, which matters because a cluster with no such check will pull and run whatever image a manifest happens to reference, including one an attacker swapped in at a public registry.
Resource governance policy enforces that every container specifies CPU and memory requests and limits, which protects cluster stability by preventing a single misconfigured workload from starving its neighbors. Labeling and metadata policy requires consistent tags for cost allocation, ownership, and environment, which sounds administrative but is often the difference between a finance team being able to attribute cloud spend accurately and not being able to at all. It's also frequently the difference between an incident responder finding the right owner in two minutes versus spending an hour paging through Slack trying to figure out who's responsible for the workload that's paging on-call at 3 a.m.
Compliance-driven policy is its own category, especially in healthcare, finance, and other regulated sectors. Here the rules often map directly to a control in a framework like SOC 2 or HIPAA, and the admission controller becomes the technical enforcement mechanism that lets an auditor see, in logs, that every workload passed a specific check before it ran. This turns a policy document into something enforced by software rather than something enforced by hoping engineers read the wiki page. For an auditor, a rejected admission request in the logs is a far stronger piece of evidence than a written policy that says engineers are supposed to follow a checklist, because the log proves the rule was actually applied rather than merely written down somewhere.
What ties these together is that none of them are things Kubernetes itself has an opinion on by default. A vanilla cluster will happily run a privileged, unlabeled, unlimited container pulled from any registry on the internet. Admission control is the layer where an organization's specific judgment about risk gets encoded into something the cluster actually checks, which is a very different thing from writing that judgment into a document nobody consults at deploy time. The gap between a written standard and an enforced one is exactly the gap admission control is built to close, and it's usually a wider gap than teams expect until they run their first policy in audit mode and see how many existing workloads would already fail it.
Admission control is the right tool for anything that can be evaluated by looking at a single object at the moment it's submitted: does this pod have resource limits, does this image come from an approved registry, does this namespace have the required labels, is this container requesting host network access it shouldn't have. These are point-in-time, self-contained checks, and that's exactly the shape of question admission control answers well. It's also a good fit for enforcing consistency across teams at scale, since a rule encoded once in a policy applies to every namespace and every team automatically, without anyone having to remember to check it manually.
It's the wrong tool, or at least an incomplete one, for anything that requires context beyond the object itself. Detecting that a workload is behaving anomalously after it's running, noticing that a container is making unexpected network calls, or catching a credential being exfiltrated at runtime, none of that is admission control's job. That's runtime security tooling, and conflating the two leads teams to assume they're protected against threats that only show up after a pod is already scheduled and executing. A cluster can have a strict admission policy and still be compromised through a vulnerability that only manifests once code is executing, which is exactly why mature security programs treat admission control as one layer among several rather than a complete answer.
It's also not a substitute for image scanning as a separate discipline. Admission control can check that an image passed a scan and carries an attestation to that effect, but running the actual vulnerability scan is a different pipeline stage, typically in CI or in a registry-integrated scanner, that happens before the image is ever referenced in a manifest. Admission control enforces that the scan happened and passed; it doesn't do the scanning itself, and a cluster that tries to run scans synchronously inside an admission webhook usually finds the added latency unacceptable for anything beyond a trivially fast check.
And it's not a good place to put every rule an organization can think of. Each additional validating webhook adds latency to every single create and update operation in the cluster, and each one is another dependency that can fail. Teams that treat admission control as a dumping ground for every possible check tend to end up with slow deployments and a debugging nightmare when three different webhooks disagree about what's wrong with an object. The discipline is to reserve admission control for rules that are genuinely non-negotiable and cheap to evaluate, and to solve everything else somewhere else in the pipeline, whether that's a CI gate, a code review requirement, or a separate runtime monitoring system built for exactly that job.
Start in audit or dry-run mode before enforcing anything. Both Gatekeeper and Kyverno support a mode where a policy logs what it would have blocked without actually blocking it. This gives a platform team real data on how many existing workloads would fail a new rule, which is almost always more than expected, before that rule starts rejecting deployments and generating angry tickets. It's worth setting a deadline for how long a policy stays in audit mode, too, since audit mode with no follow-up plan tends to quietly become the permanent state, which defeats the purpose of adopting the rule in the first place.
Roll policies out gradually, by namespace or by team, rather than cluster-wide on day one. A common pattern is to enforce baseline security policies (no privileged containers, no root) everywhere immediately since almost nothing legitimate needs those permissions, while phasing in stricter rules, like mandatory resource limits or registry restrictions, team by team as each one has time to adjust its manifests. Pairing this rollout with a clear exception process, some documented way for a team to request a scoped, time-boxed waiver, keeps the rollout from stalling entirely the first time a legitimate workload needs to break a new rule temporarily.
Build observability into the webhook services themselves, not just into the policies. Track webhook latency, error rate, and timeout rate as first-class metrics, because a policy engine that's healthy in terms of "correctly enforcing rules" but unhealthy in terms of "responding within its timeout window" will start failing closed and blocking legitimate deployments. This is an operational service like any other, and it deserves the same on-call attention as the API server it's sitting in front of, including a runbook for what to do if the webhook itself needs to be temporarily disabled during an incident.
Finally, keep policy definitions in version control and reviewed the same way application code is. A validating webhook that blocks root containers is, functionally, security-critical infrastructure, and a change to it deserves the same pull request scrutiny as a change to authentication logic. Teams that treat policy YAML as an afterthought tend to discover, usually during an incident, that someone loosened a rule six months ago without anyone noticing, often because the change looked small and was approved without anyone tracing through what it actually permitted.
An admission controller is a stage in the Kubernetes API request pipeline that runs after authentication and authorization but before an object is saved, and it can approve, reject, or modify that object based on policy.
A mutating admission controller can change the object, such as adding a default resource limit or a label, while a validating admission controller only accepts or rejects the object as it currently stands, and mutation always runs before validation in the chain.
For a couple of simple rules, a hand-written webhook is fine, but once an organization has more than a handful of policies, a policy engine reduces the number of services that need to be built, secured, and kept available, since the engine's webhook is already hardened and only the policy definitions change.
The cluster follows the failurePolicy set on that webhook, either failing open (allowing the request through) or failing closed (blocking it), and a webhook configured to fail closed that goes down can block every create or update operation that it's registered to intercept.
Yes, each webhook adds a network round trip to every matching request, so a cluster with many chained webhooks will see higher latency on deployments and updates, which is why teams should keep the policy set focused rather than exhaustive.
Pod Security Admission is a specific built-in admission controller that enforces one of three predefined pod security standards (privileged, baseline, restricted), and it replaced the older PodSecurityPolicy mechanism; it's one example within the broader admission control system, not a synonym for it.
No, admission control only evaluates objects at the moment of creation or update; anomalous behavior in an already-running container is the job of runtime security tooling, not admission control.
RBAC decides whether a specific user or service account is allowed to perform an action on a resource type at all, while admission control looks at the actual content of the request and can reject or modify it based on what's inside, regardless of who submitted it.
Start with a policy engine in audit mode on baseline security rules, like blocking privileged containers, review what it would have flagged across existing workloads, and only switch to enforcing mode once the false-positive rate is low enough that teams won't be blindsided. It also helps to pick a small, easy first win, like requiring a cost-center label, so the platform team and the rest of the organization build confidence in the rollout process before tackling rules that touch security or resource limits directly.