Authorization tells Kubernetes what you are allowed to do. There is a third gate after authentication and authorization: admission control. Even if a request is authenticated and authorized, it still must pass through admission controllers. This is where platform governance typically lives: injecting defaults, enforcing quotas, validating configurations, and other policy enforcement. In this walkthrough we:
- Inspect which admission plugins are active on the cluster.
- Demonstrate how a mutating admission controller (LimitRanger) injects defaults.
- Show how a validating admission controller (ResourceQuota) enforces limits based on those injected values.
Mutating admission plugins run first and may change the object. Validating admission plugins run afterward and can accept or reject the request but cannot mutate it. This sequence allows validating controllers (like ResourceQuota) to see the final values injected by mutating controllers (like LimitRanger).
1) Check enabled admission plugins
Run the kube-apiserver help and filter for theenable-admission-plugins flag to see which plugins are enabled:
- LimitRanger — a mutating admission controller that injects defaults (LimitRange).
- ResourceQuota — a validating admission controller that enforces resource and object count limits.
2) LimitRange defaults (LimitRanger)
Describe the LimitRange that provides defaults in theadmission-lab namespace:
This LimitRange means:
- Containers created without resource
requestswill receive defaults:cpu: 100mandmemory: 128Mi. - Containers created without
limitswill receive defaults:cpu: 500mandmemory: 512Mi.
3) Create a pod with no resource fields
Catalog the pod manifest we’ll create (noresources.requests or resources.limits specified):
admission-lab namespace:
- Although the manifest contained no
requestsorlimits, the LimitRanger (mutating admission controller) injected defaults during admission. Those defaults are stored on the Pod object in the API server.
4) ResourceQuota (validating controller)
A ResourceQuota is a validating controller: it can accept or reject requests but does not mutate them. If a Pod arrives with no requests, ResourceQuota would have no numeric usage to account for — but because LimitRange ran first and injected defaults, ResourceQuota can evaluate resource usage correctly. Describe the ResourceQuota in the same namespace:
This shows the namespace hard-limits pods to 4; currently 1 pod is used (the test pod we created).
Delete the test pod to return to an empty namespace:
5) Attempt to exceed the quota with a Deployment
Here is a Deployment that requests 5 replicas:admission-lab namespace:
- The ReplicaSet attempted to create the fifth Pod, but creating that additional Pod would have violated the ResourceQuota. The validating admission controller rejected the creation of the fifth Pod. The Deployment therefore reports 4/5 ready.
LimitRange defaults are applied only at admission time. Updating a LimitRange does not retroactively change existing Pods — only Pods created after the change will receive the new defaults. Be cautious when relying on defaults for long-running workloads.
6) Important behavior to keep in mind
- Order matters: Mutating admission controllers run first and may change the object; validating admission controllers run next and can accept or reject the mutated object.
- Limits injected by LimitRanger are persisted on the object stored in etcd; ResourceQuota evaluates usage based on those persisted values.
- Updating a LimitRange does not update already-running Pods — only newly created Pods (or recreated Pods) pick up changes.
- Deployments and ReplicaSets will continue to reconcile until replicas equal the desired count; validating admission failures can leave a Deployment partially scaled (e.g., 4/5).