CONCEPT Cited by 1 source
Validating admission webhook¶
Definition¶
A validating admission webhook is a Kubernetes extension
point (admissionregistration.k8s.io/v1 →
ValidatingWebhookConfiguration) that lets a cluster operator
plug custom allow/deny logic into the API server's write
path. For every matching CREATE / UPDATE / DELETE
operation on configured resources, the API server sends an
AdmissionReview JSON payload to the webhook over HTTPS; the
webhook returns allow or deny (optionally with a
message); only allowed objects are persisted to etcd. It runs
after mutating webhooks and after built-in object
validation, so by the time it sees an object, the object is
already syntactically valid Kubernetes.
See the Kubernetes admission-controllers documentation for the full admission pipeline.
Where it sits in the API server¶
client
↓ kubectl apply
API server
1. Authentication
2. Authorization
3. Mutating admission webhooks
4. Built-in object validation (OpenAPI schema)
5. Validating admission webhooks ← this concept
6. Write to etcd
Because validating webhooks are the last gate before etcd, they are the last opportunity to reject an object without ever having it propagate to any controller, informer, or data-plane consumer.
What they are good at¶
- Enforcing rules that built-in Kubernetes validation
cannot express. Built-in validation checks the OpenAPI
schema of the resource — "is
spec.replicasan integer". It cannot check "does the predicate referenced inside this annotation exist in the Skipper runtime," because the annotation is just an opaque string to the API server. - Keeping enforcement at the write path. Once etcd has the object, every controller in the cluster that watches this resource will try to act on it. Catching a bad object at admission means one rejection message to one user, rather than N reconcile-loop error logs fanned out across N watchers.
- Symmetric validation between admission and runtime. If the webhook calls the same validator the data-plane controller uses at reconcile time, the two answers cannot drift. This is the architectural move Zalando makes in the Skipper case — see patterns/reuse-runtime-logic-on-admission-path.
What they are bad at¶
- Blast radius is on the write path, not on traffic. A bad
validating webhook does not drop customer requests
(
failurePolicy: Faildenies new writes; existing objects keep working). But it blocks CI/CD,kubectl apply, and operator writes fleet-wide if the validator is wrong — and that has its own blast radius (concepts/control-plane-change-blast-radius). failurePolicyis a real trade-off.Fail(default in practice for strict validators) means webhook-unavailability blocks writes — a webhook outage freezes the control plane.Ignoremeans webhook-unavailability permits writes — invalid objects leak through. Neither is free.- Latency added to every matching write. The webhook is in
the synchronous write path; its P99 latency and timeout
budget (default 10 s in Kubernetes) are now part of
kubectl applylatency. - Cannot validate state across the cluster. A webhook sees one object at a time; cross-object invariants (quota aggregation, leader uniqueness) require separate machinery because the webhook has no guarantee that two concurrent requests serialize past it in any particular order.
Seen in¶
- sources/2026-04-08-zalando-rejecting-invalid-ingress-routes-at-apply-time
— canonical wiki instance. Zalando deploys a validating
admission webhook (
ingress-admitter.teapot.zalan.do) that calls Skipper's own runtime filter registry, predicate specs, route validator, and backend parsers on theAdmissionReviewforIngressandRouteGroupresources. AnIngresswith a non-existent predicate likeNonExistingPredicate()is rejected atkubectl applywith a Skipper-specific error — "invalid 'zalando.org/skipper-predicate' annotation: unknown_predicate: predicate 'NonExistingPredicate' not found" — instead of being accepted, written to etcd, propagated to 300 Skipper replicas per cluster, and only surfacing as a broken route when a real request hits it. Shipped behind an-enable-advanced-validationSkipper flag (concepts/feature-flag-rollback-for-validator) so a false-positive rejection is a flag-off away from reverting, rolled out tier-by-tier across 250+ clusters, guided byskipper_route_invalid{route_id, reason}(concepts/invalid-route-observability-metric). Zalando's canonical architectural move: treat the production validator as a library and call it from the admission path so the two answers cannot drift. Available in open-source Skipper v0.24.18+.
Related¶
- systems/kubernetes · systems/skipper-proxy
- concepts/shift-left-validation · concepts/control-plane-change-blast-radius · concepts/feature-flag-rollback-for-validator · concepts/control-plane-data-plane-separation
- patterns/reuse-runtime-logic-on-admission-path · patterns/invisible-rollout-via-default-on-validation