Working with Admission Controllers
1. Understanding Admission Controllers
| Aspect | Description | Notes |
|---|---|---|
| Purpose | Validate and mutate requests to the Kubernetes API server | Enforce policies and configurations before objects are persisted |
| Type | Dynamic, pluggable validation and mutation | Can be implemented as webhook or built-in |
| Trigger Events | Creation, update, deletion of resources | Can intercept all API calls to the Kubernetes API server |
| Configuration | Defined in AdmissionReview objects |
Uses ValidatingWebhookConfiguration or MutatingWebhookConfiguration |
Example: Admission Controller Configuration
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: example-admission-controller
webhooks:
- name: example.example.com
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
clientConfig:
service:
name: example-service
namespace: example-namespace
path: /validate
admissionReviewVersions: ["v1"]
Note: Admission controllers run in the order specified in the configuration. Ensure proper ordering to avoid conflicts.
2. Enabling Admission Plugins
| Plugin Name | Description | Enabled by Default | Configuration |
|---|---|---|---|
| NamespaceLifecycle | Prevents creation of resources in a namespace that is being terminated | YES | Enabled by default in all clusters |
| LimitRanger | Enforces resource limits and requests for pods in a namespace | YES | Enabled by default in all clusters |
| ResourceQuota | Enforces resource quotas per namespace | YES | Enabled by default in all clusters |
| PodSecurityPolicy | Enforces security policies for pods (deprecated in favor of Pod Security Admission) | NO | Must be explicitly enabled via admission controller configuration |
| MutatingAdmissionWebhook | Allows custom logic to mutate incoming requests before they are persisted | NO | Enabled via webhook configuration |
| ValidatingAdmissionWebhook | Allows custom logic to validate incoming requests before they are persisted | NO | Enabled via webhook configuration |
Example: Enabling a Custom Admission Plugin via Webhook
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: example-webhook-config
webhooks:
- name: example.example.com
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
clientConfig:
url: https://example.com/webhook
caBundle: <ca-cert-data>
admissionReviewVersions: ["v1"]
Note: Admission plugins are evaluated in the order specified in the API server configuration. The order can impact how resources are processed and validated.
3. Using ValidatingWebhookConfiguration
| Field | Description | Example Value |
|---|---|---|
| apiVersion | API version of the resource | admissionregistration.k8s.io/v1 |
| kind | Kind of the resource | ValidatingWebhookConfiguration |
| metadata.name | Name of the configuration | my-validating-webhook |
| webhooks[].name | Name of the webhook | my-webhook |
| webhooks[].clientConfig.url | URL of the webhook service | https://my-webhook-service.example.com/validate |
| webhooks[].rules | Rules to match resources | [{ "apiGroups": [""], "apiVersions": ["v1"], "operations": ["CREATE", "UPDATE"], "resources": ["pods"] }] |
| webhooks[].failurePolicy | How to handle errors in the webhook | Fail or Ignore |
| webhooks[].timeoutSeconds | Timeout for the webhook call | 10 |
Example: ValidatingWebhookConfiguration YAML
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: my-validating-webhook
webhooks:
- name: my-webhook
clientConfig:
url: https://my-webhook-service.example.com/validate
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
failurePolicy: Fail
timeoutSeconds: 10
Note: The webhook must be accessible from the Kubernetes API server. Ensure TLS is configured correctly if using HTTPS.
4. Using MutatingWebhookConfiguration
| Field | Description | Example Value |
|---|---|---|
| webhooks.name | Name of the webhook | mutating-webhook |
| webhooks.clientConfig.url | URL of the webhook service | https://mutating-service.default.svc:443/mutate |
| webhooks.clientConfig.caBundle | Base64 encoded CA bundle to verify the webhook server's certificate | LS0tLS1CRUdJTiBDRVJ...== |
| webhooks.rules | Rules that define when to call the webhook | [{"apiGroups": [""], "apiVersions": ["v1"], "operations": ["CREATE"], "resources": ["pods"]}] |
| webhooks.namespaceSelector | Selector to filter namespaces | {"matchLabels": {"env": "dev"}} |
Example: MutatingWebhookConfiguration YAML
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: example-mutating-webhook
webhooks:
- name: example-mutating-webhook.example.com
clientConfig:
url: https://mutating-service.default.svc:443/mutate
caBundle: LS0tLS1CRUdJTiBDRVJ...
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE"]
resources: ["pods"]
namespaceSelector:
matchLabels:
env: dev
Note: The webhook must be accessible over HTTPS and the CA bundle must be valid to ensure secure communication.
5. Implementing OPA Gatekeeper
Example: Basic OPA Gatekeeper Policy
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: pod-must-have-owner
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
labels:
- owner
| Field | Description | Values |
|---|---|---|
| apiVersion | API version of the constraint | constraints.gatekeeper.sh/v1beta1 |
| kind | Type of constraint | K8sRequiredLabels |
| metadata.name | Unique name for the constraint | String |
| spec.match.kinds | Resource types to enforce constraint on | List of apiGroups and kinds |
| spec.parameters.labels | Required labels for resources | List of label names |
Note: OPA Gatekeeper uses Rego policies to define constraints. The
K8sRequiredLabels constraint ensures that all pods must have an owner label.Example: Constraint Template
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
targets:
- target: admission.k8s.io
rego: |
package k8srequiredlabels
violation[{"msg": msg, "details": {}}] {
input.review.object.metadata.labels[_] == ""
msg := sprintf("label %v is required", [input.review.object.metadata.labels[_]])
}
Key Concepts
- Constraint Templates: Define reusable policy structures using Rego.
- Constraints: Instances of constraint templates applied to specific resources.
- Rego: Policy language used to define validation logic.
- Admission Control: Enforces policies at resource creation/update time.
6. Creating Constraint Templates
| Field | Description | Example |
|---|---|---|
| kind | Must be "ConstraintTemplate" | ConstraintTemplate |
| metadata.name | Unique name for the template | requirelabel |
| spec.crd.spec.versions[0].schema.openAPIV3Schema.properties | Defines the schema for constraints using this template | |
| spec.targets | Defines which admission control targets this template applies to | |
Example: Basic Constraint Template
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: requirelabel
spec:
crd:
spec:
names:
kind: RequireLabel
validation:
openAPIV3Schema:
properties:
label:
type: string
targets:
- target: admission.k8s.io
rego: |
package requirelabel
violation[{"msg": msg}] {
input.review.object.metadata.labels[label] = "value"
}
Note: The
rego field contains the Rego policy that defines how constraints are enforced.
7. Creating Constraints
Example: Constraint Template
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
properties:
labels:
type: array
items:
type: string
targets:
- target: admission.k8s.io
rego: |
package k8srequiredlabels
violation[{"msg": msg}] {
input.review.object.metadata.labels[_] == ""
msg := sprintf("label %v is required", [input.review.object.metadata.labels[_]])
}
| Field | Description | Values |
|---|---|---|
| apiVersion | API version of the constraint template | constraints.gatekeeper.sh/v1beta1 |
| kind | Kind of the constraint template | ConstraintTemplate |
| metadata.name | Name of the constraint template | String |
| spec.crd.spec.names.kind | Kind of the constraint CRD | String |
| spec.targets.target | Admission control target | admission.k8s.io |
| spec.targets.rego | Rego policy logic | String (Regula code) |
Note: The Rego policy must be written in the
gatekeeper namespace and must define a violation rule that returns messages when constraints are violated.Example: Constraint Instance
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: require-app-label
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
labels:
- app
| Field | Description | Values |
|---|---|---|
| apiVersion | API version of the constraint | constraints.gatekeeper.sh/v1beta1 |
| kind | Kind of the constraint | K8sRequiredLabels |
| metadata.name | Name of the constraint instance | String |
| spec.match.kinds | Resource kinds to apply the constraint to | Array of apiGroups and kinds |
| spec.parameters.labels | Labels that must be present | Array of label names |
8. Implementing Image Policy
| Property | Value | Description |
|---|---|---|
| policy | imagePolicy |
Enables image policy enforcement |
| imagePullSecrets | [{name: "my-secret"}] |
Secrets for pulling images from private registries |
| allowedRegistries | ["gcr.io", "docker.io"] |
Whitelisted image registries |
| blockedRegistries | ["registry.example.com"] |
Blacklisted image registries |
Example: Image Policy Configuration
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: image-policy-webhook
webhooks:
- name: image-policy-validator
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
clientConfig:
service:
name: image-policy-service
namespace: default
path: /validate
admissionReviewVersions: ["v1"]
Example: Image Policy Enforcement
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
containers:
- name: app-container
image: gcr.io/my-project/app:v1.0
Note: Ensure the image registry is in
allowedRegistries or not blocked by blockedRegistries.
Warning: Misconfiguring image policies can block legitimate deployments.
9. Using LimitRanger
| Property | Value | Description |
|---|---|---|
| limitType | Pod |
Defines the type of resource limits to enforce |
| max.cpu | 2 |
Maximum CPU limit per Pod |
| min.cpu | 100m |
Minimum CPU request per Pod |
| max.memory | 1Gi |
Maximum memory limit per Pod |
| min.memory | 128Mi |
Minimum memory request per Pod |
Example: LimitRanger Configuration
apiVersion: v1
kind: List
items:
- apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
name: limit-range-webhook
webhooks:
- name: limit-range-webhook
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
clientConfig:
service:
name: limit-range-service
namespace: kube-system
path: /validate
admissionReviewVersions: ["v1"]
Example: Pod with LimitRanger Enforced Limits
apiVersion: v1
kind: Pod
metadata:
name: example-pod
spec:
containers:
- name: example-container
image: nginx:latest
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "512Mi"
cpu: "500m"
Note: LimitRanger enforces resource limits at Pod creation time and will reject any Pod that does not comply with the defined constraints.
10. Testing Admission Webhooks
Example: Testing Admission Webhook with curl
curl -X POST \
http://admission-webhook-service:8080/validate \
-H 'Content-Type: application/json' \
-d '{"request":{"uid":"1234567890","object":{"apiVersion":"v1","kind":"Pod","metadata":{"name":"test-pod"},"spec":{"containers":[{"name":"test-container","image":"nginx"}]}}}}'
| Field | Description | Example Value |
|---|---|---|
| request.uid | Unique identifier for the request | 1234567890 |
| request.object | The Kubernetes object being admitted | {"apiVersion":"v1","kind":"Pod",...} |
| request.operation | Operation type (CREATE, UPDATE, DELETE) | CREATE |
Note: The webhook must respond with a JSON object containing
allowed and optionally status.
Example: Validating Admission Response
{
"response": {
"allowed": true,
"status": {
"message": "Pod created successfully"
}
}
}
Testing Workflow
- Deploy webhook server with TLS certificate
- Configure
ValidatingWebhookConfigurationorMutatingWebhookConfiguration - Send test request using
curlor Kubernetes API client - Validate response format and logic
- Check logs for errors or unexpected behavior
11. Troubleshooting Admission Failures
| Issue | Cause | Solution |
|---|---|---|
| Admission denied | Validation rules violated | Review request payload and validate against schema |
| Timeout during admission | Slow or unresponsive webhook | Optimize webhook performance or increase timeout |
| Webhook not reachable | Network or DNS issues | Verify network policies and DNS resolution |
Note: Use
kubectl describe on the resource to see admission review details.