Skip to main content

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
{
  "label": {
    "type": "string"
  }
}
spec.targets Defines which admission control targets this template applies to
[
  {
    "target": "admission.k8s.io",
    "rego": "package example\n\nviolation[{'msg': msg}] {\n  input.review.object.metadata.labels[label] = \"value\"\n}"
  }
]

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

  1. Deploy webhook server with TLS certificate
  2. Configure ValidatingWebhookConfiguration or MutatingWebhookConfiguration
  3. Send test request using curl or Kubernetes API client
  4. Validate response format and logic
  5. Check logs for errors or unexpected behavior

11. Troubleshooting Admission Failures

Example: Checking Admission Controller Logs

kubectl logs -n kube-system <admission-controller-pod>
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.

Workflow: Debugging Admission Controller Issues

  1. Check the admission controller logs for errors
  2. Review the resource YAML for validation issues
  3. Verify webhook endpoints are accessible
  4. Confirm network policies allow communication

Was this article helpful?