Skip to main content
Authentication tells Kubernetes who you are.
Authorization tells Kubernetes what you are allowed to do.
There is a third gate before a request is accepted: admission control. Even after successful authentication and authorization, requests must pass through admission controllers. This is where much platform governance lives — injecting defaults, enforcing quotas, validating configuration, mutating objects, and denying non-compliant requests.
Admission controllers run after authentication and authorization but before objects are persisted to etcd. Some admission controllers mutate objects (mutating admission controllers), while others only allow or deny requests (validating admission controllers).

Which admission plugins are active?

On many clusters the kube-apiserver runs as a pod. Inspect the kube-apiserver help output to see admission-related flags and which plugins are enabled. For example:
You may see both the deprecated --admission-control help text and the newer --enable-admission-plugins output. The important point for this demo: LimitRanger (a mutating admission controller) and ResourceQuota (a validating admission controller) are enabled on the cluster. Note: --admission-control is deprecated in favor of --enable-admission-plugins / --disable-admission-plugins. See the Kubernetes API server docs for details:

LimitRanger (mutating) — injecting defaults

LimitRanger is a mutating admission controller enabled by default on many clusters. It can inject default resource requests and limits for containers based on a LimitRange object in the namespace. Inspect the LimitRange in the demo namespace:
Example output (abridged):
This LimitRange indicates:
  • If a container is created without resource requests, it will get a default cpu: 100m and memory: 128Mi.
  • If a container is created without resource limits, it will get a default cpu: 500m and memory: 512Mi.
Create a Pod manifest that has no resource requests or limits (file: pod-no-resources.yaml):
Apply the Pod:
Describe the created Pod to see the injected defaults:
Excerpt of the container section (abridged):
Even though these values were not present in the manifest, LimitRanger (a mutating admission controller) injected the defaults before the Pod object was persisted.

ResourceQuota (validating) — enforcing namespace resource usage

ResourceQuota is a validating admission controller: it denies requests that would exceed the hard limits set for a namespace. It does not mutate objects; it only accepts or rejects them. Inspect the ResourceQuota in the namespace:
Example output:
This quota restricts the namespace to at most 4 Pods. ResourceQuota must be able to account for concrete resource values; when a Pod has no explicit requests/limits, LimitRanger provides those defaults so ResourceQuota can count the resources and decide whether to admit the request.

How LimitRange and ResourceQuota work together

  • LimitRange (mutating): injects default resource requests/limits at admission time when an object is created or recreated.
  • ResourceQuota (validating): counts the (possibly mutated) resources and rejects requests that would exceed the hard limits.
Table summary:

Demo: quota-buster deployment (5 replicas in namespace with pod quota 4)

Create a Deployment manifest quota-buster.yaml that requests 5 replicas:
Apply the Deployment:
Check pods and the Deployment status:
Because the namespace admission-lab has a hard pod quota of 4, only four Pods can be admitted. The ReplicaSet/Deployment controller will attempt to create the fifth Pod, but ResourceQuota (validating) will cause that Pod creation to be rejected. The Deployment will end up in a state such as “4/5 ready” (4 available, 5 desired), illustrating the interaction between mutating defaults and validating quotas.

Important behavior note

  • LimitRange defaults are applied only at admission time when an object is created or recreated. Updating a LimitRange later does not retroactively change resource requests/limits of already running Pods. Only new Pods or Pods that are deleted and recreated will pick up the new defaults.
Admission controllers run at admission time. Mutating controllers change the object before it’s stored; validating controllers accept or reject the request. Changes to defaults (e.g., a LimitRange) do not mutate already existing objects.
That was a concise overview of mutating vs validating admission controllers and how they interact (LimitRanger + ResourceQuota). Try these steps in a test cluster to observe the behavior firsthand.

Watch Video

Practice Lab