Admission Controllers: The Final Gatekeepers
In the Kubernetes API request lifecycle, Admission Controllers sit between Authorization and Persistence. While RBAC determines "Who" can perform an action, Admission Controllers determine "What" that action contains and whether it complies with cluster-wide governance.
1. ARCHITECTURAL POSITIONING
An Admission Controller intercepts requests to the API server only after the request is Authenticated and Authorized.
1.1 The Request Pipeline
Admission Control is strictly for Write operations (CREATE, UPDATE, DELETE, CONNECT). It has no visibility into Read operations (GET, LIST, WATCH).
2. THE TWO-PHASE LIFECYCLE
Kubernetes executes admission controllers in a strict, two-phase serial sequence.
Phase 1: Mutating Admission
- Purpose: To "patch" or modify the object before it is validated.
- Examples: Injecting an Istio sidecar, adding default resource limits, or attaching node affinity rules.
- Internal Detail: If a mutating controller changes the object, Phase 1 may trigger Reinvocation, ensuring that all mutating controllers see the "final" intended state.
Phase 2: Validating Admission
- Purpose: To "Accept" or "Reject" the request based on hard policies.
- Examples: Ensuring no privileged containers are used, checking ResourceQuotas, or validating that labels exist.
- Constraint: Validating controllers cannot modify the object.
3. CRITICAL BUILT-IN CONTROLLERS
While there are over 30 built-in plugins, these are the architectural pillars:
| Plugin | Type | Role |
|---|---|---|
| NodeRestriction | Validating | Limits a Kubelet to only modify its own Node and Pods. Prevents cluster-wide lateral movement if a node is compromised. |
| PodSecurity | Validating | Implements Pod Security Standards (Privileged, Baseline, Restricted). Replaces the deprecated PSP. |
| ResourceQuota | Validating | Checks the incoming request against the Namespace's ResourceQuota budget. |
| LimitRanger | Dual | Injects default requests/limits (Mutation) and enforces min/max boundaries (Validation). |
| ServiceAccount | Mutating | Injects the default ServiceAccount if none is specified. |
4. DYNAMIC ADMISSION: WEBHOOKS
When built-in logic is insufficient, Kubernetes uses Admission Webhooks to call external services (e.g., OPA Gatekeeper, Kyverno).
4.1 How Webhooks Work
The API Server sends an AdmissionReview JSON object to the webhook service. The service responds with a uid and an allowed: true/false status.
4.2 JSON Patching (Mutation Mechanics)
Mutating webhooks use JSON Patch (RFC 6902). Instead of sending back the whole object, the webhook sends a list of operations.
Example Patch Response:
"patch": [
{"op": "add", "path": "/spec/containers/1", "value": {"name": "sidecar", "image": "log-agent:v1"}},
{"op": "replace", "path": "/metadata/labels/managed-by", "value": "policy-engine"}
]
5. BIBLE-GRADE YAML: WEBHOOK CONFIGURATION
This manifest defines how the API Server should interact with an external security service.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: security-policy-checker
webhooks:
- name: check-privileged-containers.company.com
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
scope: "Namespaced"
clientConfig:
service:
namespace: "security-system"
name: "policy-webhook-svc"
path: "/validate"
caBundle: <BASE64_CA_BUNDLE> # API Server needs this to verify Webhook Cert
# PRODUCTION SETTINGS:
admissionReviewVersions: ["v1"]
sideEffects: None
timeoutSeconds: 5
# FAILSAFE LOGIC:
# Fail: Reject request if Webhook is down (Secure)
# Ignore: Allow request if Webhook is down (Available)
failurePolicy: Fail
namespaceSelector:
matchExpressions:
- key: kubernetes.io/metadata.name
operator: NotIn
values: ["kube-system"] # Do not block critical system pods
6. PRODUCTION HAZARDS & BEST PRACTICES
6.1 The Circular Dependency (The "Deadlock")
Scenario: You have a ValidatingWebhook that checks all Pods. The Webhook itself runs as a Pod in the cluster.
- The Cluster reboots.
- The API Server tries to start the Webhook Pod.
- The API Server calls the Webhook to validate the Webhook Pod.
- The Webhook is not running yet.
- Result: The Cluster cannot start.
- Solution: Use
namespaceSelectorto exclude thekube-systemor the webhook's own namespace from the policy.
6.2 Latency Overhead
Every admission webhook adds an HTTP round-trip to every write request.
- Strategy: Keep webhooks lightweight. Use
matchExpressionsto only trigger webhooks for specific namespaces or labels to reduce API latency.
6.3 Idempotency
Mutating webhooks must be idempotent. If a request is retried, applying the same patch twice must not result in a corrupted object.
7. TROUBLESHOOTING & NINJA COMMANDS
7.1 Auditing Enabled Plugins
You can see which internal plugins are active by inspecting the API Server process.
kubectl get pods -n kube-system -l component=kube-apiserver -o yaml | grep -i admission-plugins
7.2 Debugging Webhook Failures
If kubectl apply hangs or returns a 500 Internal Server Error, the webhook is likely failing.
# 1. Check if the webhook service has endpoints
kubectl get endpoints -n security-system policy-webhook-svc
# 2. Check the logs of the policy engine
kubectl logs -n security-system -l app=policy-engine
# 3. Bypass a broken webhook (Emergency only - requires API Server access)
# Edit the ValidatingWebhookConfiguration and set failurePolicy: Ignore
7.3 Verifying OPA/Gatekeeper Constraints
If using Gatekeeper, you don't use standard YAML; you use ConstraintTemplates.
# Check for policy violations already in the cluster
kubectl get constraints
8. SUMMARY: AUTHORIZATION VS. ADMISSION
| Aspect | Authorization (RBAC) | Admission Control |
|---|---|---|
| Focus | Subject (Who is calling?) | Object (What is being created?) |
| Context | User/Group/Namespace. | Full YAML/JSON specification. |
| Modification | Cannot change the request. | Mutating can change the request. |
| Execution | Before Admission. | After Authorization. |