Skip to main content
Authentication tells Kubernetes who you are.
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 the enable-admission-plugins flag to see which plugins are enabled:
Typical relevant excerpt:
From the list, this demo focuses on:
  • 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 the admission-lab namespace:
Example summarized output as a table for clarity: This LimitRange means:
  • Containers created without resource requests will receive defaults: cpu: 100m and memory: 128Mi.
  • Containers created without limits will receive defaults: cpu: 500m and memory: 512Mi.
LimitRanger is implemented as a mutating admission controller that injects these defaults at admission time — the injected fields are persisted on the stored object.

3) Create a pod with no resource fields

Catalog the pod manifest we’ll create (no resources.requests or resources.limits specified):
Apply the pod into the admission-lab namespace:
Describe the created pod to see what was admitted:
Relevant snippet showing injected resources:
Explanation:
  • Although the manifest contained no requests or limits, 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:
Example output summarized: 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:
Apply it into the admission-lab namespace:
Check the pods:
Example output (only four pods are created due to the quota):
Check the Deployment status:
Example output:
Explanation:
  • 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).
This short demo illustrates how mutating (LimitRanger) and validating (ResourceQuota) admission controllers can work together to implement platform defaults and enforce quotas. Try these steps in your Kubernetes lab or cluster to observe admission ordering and enforcement firsthand.

Watch Video

Practice Lab