> ## Documentation Index
> Fetch the complete documentation index at: https://notes.kodekloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Demo Admission Webhooks in Action

> Demo of Kubernetes admission controllers showing how mutating LimitRanger injects resource defaults and validating ResourceQuota enforces quotas during pod and deployment creation.

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:

```bash theme={null}
kubectl exec -n kube-system kube-apiserver-controlplane \
  -- kube-apiserver -h 2>&1 | grep enable-admission | head -5
```

Typical relevant excerpt:

```text theme={null}
--enable-admission-plugins strings    admission plugins that should be enabled in addition to default enabled ones (..., LimitRanger, MutatingAdmissionWebhook, ValidatingAdmissionWebhook, ResourceQuota)
```

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:

```bash theme={null}
kubectl describe limitrange default-limits -n admission-lab
```

Example summarized output as a table for clarity:

| Type | Resource | Default Request | Default Limit |
| - | - | - | - |
| Container | cpu | 100m | 500m |
| Container | memory | 128Mi | 512Mi |

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):

```yaml theme={null}
# pod-no-resources.yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - name: app
    image: nginx
```

Apply the pod into the `admission-lab` namespace:

```bash theme={null}
kubectl apply -f pod-no-resources.yaml -n admission-lab
# pod/test-pod created
```

Describe the created pod to see what was admitted:

```bash theme={null}
kubectl describe pod test-pod -n admission-lab
```

Relevant snippet showing injected resources:

```text theme={null}
Containers:
  app:
    Image:         nginx
    State:         Running
    Ready:         True
    Limits:
      cpu:     500m
      memory:  512Mi
    Requests:
      cpu:     100m
      memory:  128Mi
...
Events:
  Normal  Scheduled  <time>  default-scheduler  Successfully assigned admission-lab/test-pod to controlplane
  Normal  Pulling    <time>  kubelet            spec.containers{app}: Pulling image "nginx"
  Normal  Pulled     <time>  kubelet            spec.containers{app}: Successfully pulled image "nginx"
  Normal  Created    <time>  kubelet            spec.containers{app}: Container created
  Normal  Started    <time>  kubelet            spec.containers{app}: Container started
```

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:

```bash theme={null}
kubectl describe resourcequota pod-quota -n admission-lab
```

Example output summarized:

| Resource | Used | Hard |
| - | - | - |
| pods | 1 | 4 |

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:

```bash theme={null}
kubectl delete pod -n admission-lab test-pod
# pod "test-pod" deleted
```

## 5) Attempt to exceed the quota with a Deployment

Here is a Deployment that requests 5 replicas:

```yaml theme={null}
# quota-buster.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: quota-buster
spec:
  replicas: 5
  selector:
    matchLabels:
      app: quota-buster
  template:
    metadata:
      labels:
        app: quota-buster
    spec:
      containers:
      - name: app
        image: nginx
```

Apply it into the `admission-lab` namespace:

```bash theme={null}
kubectl apply -f quota-buster.yaml -n admission-lab
# deployment.apps/quota-buster created
```

Check the pods:

```bash theme={null}
kubectl get pods -n admission-lab
```

Example output (only four pods are created due to the quota):

```text theme={null}
NAME                                READY   STATUS    RESTARTS   AGE
quota-buster-5d7f649478-2694g       1/1     Running   0          7s
quota-buster-5d7f649478-47nmd       1/1     Running   0          7s
quota-buster-5d7f649478-btz8x       1/1     Running   0          7s
quota-buster-5d7f649478-m2dtq       1/1     Running   0          7s
```

Check the Deployment status:

```bash theme={null}
kubectl get deploy -n admission-lab quota-buster
```

Example output:

```text theme={null}
NAME           READY   UP-TO-DATE   AVAILABLE   AGE
quota-buster   4/5     4            4           23s
```

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.

## Links and references

* [Kubernetes: Admission Controllers](https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/)
* [Kubernetes: LimitRange](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#limitrange)
* [Kubernetes: ResourceQuota](https://kubernetes.io/docs/concepts/policy/resource-quotas/)

> **[Watch Video](https://learn.kodekloud.com/user/courses/prep-course-certified-cloud-native-platform-engineer-cnpe/module/35a7fadb-02d8-4557-a819-2e4dcfa970cc/lesson/d53940b9-5f20-45c2-8878-1e625bc1e193)**

> **[Practice Lab](https://learn.kodekloud.com/user/courses/prep-course-certified-cloud-native-platform-engineer-cnpe/module/35a7fadb-02d8-4557-a819-2e4dcfa970cc/lesson/b2db939b-d7a6-4431-9c87-3ba55a87f53d)**


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.