Skip to main content
Course/Security & Scale/Admission Controllers β€” Request Validation & Mutation
8/855 min
Security & Scale

Admission Controllers β€” Request Validation & Mutation

Understand how admission controllers intercept API requests to enforce policies and inject configuration before resources are persisted.

advanced55 minRead β†’ Lab β†’ Quiz β†’ Practice
🧠 Brain Warm-Up
🧠 Brain Warm-Up: You apply a Pod manifest with no CPU/memory limits in a namespace with a ResourceQuota. The request is rejected. What component rejects it β€” and at what point in the API request lifecycle? Think before reading.

API Request Lifecycle

Every kubectl apply goes through this pipeline before the object is stored in etcd:

kubectl apply
     β”‚
     β–Ό
kube-apiserver
     β”‚
     β”œβ”€ 1. Authentication (AuthN)  β€” who are you?
     β”‚
     β”œβ”€ 2. Authorization (AuthZ / RBAC) β€” are you allowed?
     β”‚
     β”œβ”€ 3. Mutating Admission  ◄── can MODIFY the request
     β”‚        (built-in + webhooks run in parallel)
     β”‚
     β”œβ”€ 4. Schema validation  β€” is the object valid?
     β”‚
     β”œβ”€ 5. Validating Admission  ◄── can only APPROVE or REJECT
     β”‚        (built-in + webhooks run in parallel)
     β”‚
     └─ 6. Persist to etcd βœ“

Mutating runs before Validating so that mutations are visible to validators.

Built-in Admission Controllers

ControllerWhat it does
LimitRangerApplies default CPU/memory requests/limits from LimitRange objects
ResourceQuotaRejects requests that would exceed namespace quotas
PodSecurityEnforces Pod Security Standards (privileged/baseline/restricted)
NamespaceLifecyclePrevents object creation in terminating namespaces
DefaultStorageClassAdds the default StorageClass to PVCs that don't specify one
ServiceAccountAuto-injects the default ServiceAccount token into Pods

PodSecurity Admission (PSA)

PSA replaced PodSecurityPolicy (deprecated in 1.21, removed in 1.25). It is enforced via namespace labels:

# Enforce the restricted standard (rejects violating Pods)
kubectl label ns production pod-security.kubernetes.io/enforce=restricted

# Warn but allow (useful during migration)
kubectl label ns staging pod-security.kubernetes.io/warn=baseline

# Also audit to the API audit log
kubectl label ns staging pod-security.kubernetes.io/audit=restricted

Pod Security Standards

StandardWhat is blocked
privilegedNothing β€” all capabilities allowed
baselineBlocks hostPID, hostIPC, hostNetwork, privileged containers, unsafe sysctls
restrictedAll of baseline + requires non-root, no privilege escalation, drops all capabilities

Webhook Admission Controllers

The MutatingAdmissionWebhook and ValidatingAdmissionWebhook built-in controllers enable external admission logic. The apiserver calls your HTTPS service with an AdmissionReview request:

kubectl apply
     β”‚
     β–Ό
kube-apiserver ──HTTPS──► your-webhook-service
                          (receives AdmissionReview JSON)
                          (returns allowed: true/false + optional patches)

Webhook Configuration

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
  name: my-validator
webhooks:
  - name: validate.example.com
    rules:
      - apiGroups: ["apps"]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["deployments"]
    clientConfig:
      service:
        name: my-webhook-svc
        namespace: default
        path: /validate
      caBundle: <base64-encoded-CA>
    failurePolicy: Fail    # Reject if webhook is unreachable
    admissionReviewVersions: ["v1"]
    sideEffects: None

failurePolicy

  • Fail (default): request rejected if webhook is unreachable β€” safer for security policies
  • Ignore: request allowed if webhook is unreachable β€” safer for non-critical checks
⚠️ A webhook with failurePolicy: Fail that crashes takes down all object creation for its matched resources. Always deploy webhooks with redundancy and test failover.

Real Example: Istio Sidecar Injection

Istio's automatic sidecar injection is implemented as a MutatingAdmissionWebhook:

  1. You label a namespace: kubectl label ns myapp istio-injection=enabled
  2. When a Pod is created in that namespace, apiserver calls the Istio webhook
  3. The webhook patches the Pod spec to add the istio-proxy sidecar container and istio-init init container
  4. The mutated Pod spec is stored in etcd β€” kubectl get pod shows both containers