Implementing Admission Controllers: Enforcing Organizational Policies in Kubernetes

Introduction

In a Kubernetes environment, ensuring compliance with security and operational policies is critical. Admission controllers provide a mechanism to enforce organizational policies at the API level before resources are created, modified, or deleted.

In this post, we will build a simple admission controller in Minikube. Instead of using a custom image, we will leverage a lightweight existing image (busybox) to demonstrate the webhook concept.

Why Use Admission Controllers?

Admission controllers help organizations enforce policies such as:
✅ Blocking privileged containers
✅ Enforcing resource limits
✅ Validating labels and annotations
✅ Restricting image sources

By implementing an admission webhook, we can inspect and validate incoming requests before they are persisted in the Kubernetes cluster.

Step 1: Create the Webhook Deployment

We will use busybox as the container image instead of a custom-built admission webhook image.

Create webhook-deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: admission-webhook
spec:
  replicas: 1
  selector:
    matchLabels:
      app: admission-webhook
  template:
    metadata:
      labels:
        app: admission-webhook
    spec:
      containers:
      - name: webhook
        image: busybox
        command: ["/bin/sh", "-c", "echo Webhook Running; sleep 3600"]
        ports:
        - containerPort: 443
        volumeMounts:
        - name: certs
          mountPath: "/certs"
          readOnly: true
      volumes:
      - name: certs
        secret:
          secretName: admission-webhook-secret
Click Here to Copy YAML

Key Changes:

  • Using busybox instead of a custom image
  • The container prints “Webhook Running” and sleeps for 1 hour
  • Mounting a secret to hold TLS certificates

Step 2: Generate TLS Certificates

Kubernetes requires admission webhooks to communicate securely. We need to generate TLS certificates for our webhook server.

Run the following commands in Minikube:

openssl req -x509 -newkey rsa:4096 -keyout tls.key -out tls.crt -days 365 -nodes -subj "/CN=admission-webhook.default.svc"
kubectl create secret tls admission-webhook-secret --cert=tls.crt --key=tls.key

This creates a self-signed certificate and stores it in a Kubernetes Secret.

Step 3: Define the MutatingWebhookConfiguration

Now, let’s create a Kubernetes webhook configuration that tells the API server when to invoke our webhook.

Create webhook-configuration.yaml:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: admission-webhook
webhooks:
  - name: webhook.default.svc
    clientConfig:
      service:
        name: admission-webhook
        namespace: default
        path: "/mutate"
      caBundle: ""
    rules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE"]
        resources: ["pods"]
    admissionReviewVersions: ["v1"]
    sideEffects: None
Click Here to Copy YAML

Key Details:

  • The webhook applies to all Pods created in the cluster
  • The webhook will be called whenever a Pod is created
  • The caBundle field will be populated later

Apply the webhook configuration:

kubectl apply -f webhook-configuration.yaml

Step 4: Test the Webhook

Let’s check if the webhook is being triggered when a new Pod is created.

Create a test Pod:

apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - name: test
    image: busybox
    command: ["sleep", "3600"]
Click Here to Copy YAML

Apply the Pod:

kubectl apply -f test-pod.yaml

If the webhook is working correctly, the admission controller should intercept the request and either allow or reject it based on the configured policies.

Step 5: Debugging and Logs

To check the logs of the webhook, run:

kubectl logs -l app=admission-webhook

If the webhook is not working as expected, ensure:

  • The webhook deployment is running (kubectl get pods)
  • The secret exists (kubectl get secret admission-webhook-secret)
  • The webhook configuration is applied (kubectl get mutatingwebhookconfigurations)

Conclusion

We successfully set up a custom Kubernetes admission controller. Instead of a custom-built webhook image, we used a minimal container (busybox) to simulate webhook functionality.

Key Takeaways:

  • Admission controllers enforce security policies before resources are created
  • Webhooks provide dynamic validation and policy enforcement
  • Minikube can be used to test webhooks without pushing images to remote registries

What’s your experience with admission controllers? Let’s discuss!👇

Leave a comment