Kubernetes Admission Controllers

Admission controllers are the enforcement gate at the end of the kube-apiserver request pipeline: after a request is authenticated and authorized, they validate or mutate the object before it is persisted to etcd. They are the mechanism behind Kubernetes governance — from built-in quota enforcement to dynamic policy engines like Kyverno. Source: Enforce Kubernetes Security with Kyverno Source: CKA Day 22

Position in the Request Pipeline

Every request to the API server flows through a strict pipeline (see Kubernetes Authentication & Authorization):

Client Request → TLS Termination → Authentication → Authorization → Admission Control → etcd

Admission control is the last gate before persistence. Authentication answered “who are you?”, authorization answered “may you do this?”, and admission control answers “does this object conform to policy?” A request can be fully authenticated and RBAC-authorized and still be rejected here — this is what makes admission control the natural home for organizational compliance rules.

Two Flavours: Validating and Mutating

TypeWhat It DoesOrdering
MutatingModifies the object before persistence (inject defaults, patch fields)Runs first
ValidatingAccepts or rejects the object as-isRuns after mutation, so it sees the final object

Mutating always precedes validating: validators must evaluate the object exactly as it will be stored.

Built-In Admission Controllers

Kubernetes ships with many compiled-in controllers, enabled via --enable-admission-plugins on the API server:

ControllerPurpose
ResourceQuotaRejects objects that would exceed the Namespace’s ResourceQuota
LimitRangerApplies default/ min/ max requests and limits from a LimitRange
PodSecurityEnforces Pod Security Standards (replaced PodSecurityPolicy in 1.25+) — see Container Security
ServiceAccountAuto-injects the default ServiceAccount and token into Pods
MutatingAdmissionWebhook / ValidatingAdmissionWebhookDelegate decisions to external HTTP webhooks — the extensibility point

Dynamic Admission Control: Webhooks

The two webhook controllers turn admission control into an extension mechanism. Instead of recompiling the API server, you register a ValidatingWebhookConfiguration or MutatingWebhookConfiguration pointing at an HTTPS endpoint; the API server then POSTs an AdmissionReview object to that endpoint for every matching request and honours its allow/deny/patch response.

This is how tools like Kyverno, OPA Gatekeeper, and service meshes (sidecar injection) work: the engine registers its own webhook configurations, and the API server defers policy decisions to it. Webhook endpoints require TLS — the API server validates the serving certificate, which is why admission webhooks consume kubernetes.io/tls Secrets (see TLS Fundamentals).

The Governance Scaling Problem

Writing custom admission webhooks by hand is the “classic” way to enforce organizational rules — but it scales poorly:

  1. Language barrier — webhook servers are typically written in Go; most DevOps engineers are not Go developers.
  2. One webhook per rule — a rule for resource requests/limits, another for image tags, another for labels… each needs its own service, TLS, and deployment.
  3. Constant churn — compliance rules change as the organization evolves; every change means code, review, and redeploy.

At the scale of hundreds of teams and thousands of applications, maintaining bespoke webhook controllers consumes disproportionate engineering time. This is precisely the gap that dynamic admission controllers fill: a single engine (Kyverno, OPA Gatekeeper) that reads declarative policies and generates webhook configurations automatically — the DevOps engineer writes YAML, not Go. Source: Enforce Kubernetes Security with Kyverno

What a Rejection Looks Like

When a validating webhook (or built-in controller) denies a request, the API server returns an error before anything touches etcd:

$ kubectl create deployment nginx --image=nginx
# error: failed to create deployment: admission webhook "validate.kyverno.svc" denied the request:
# resource requests and limits are required

Nothing is persisted, no Pods are scheduled — the policy violation is stopped at the front door. This is the deploy-time control tier of Shift Left Security: non-compliant manifests never become running workloads.

See Also


Tags: kubernetes admission-controller security governance api-server webhooks devops