Stage 3 · Build
Kubernetes Controllers in Go
Admission Webhooks
Mutating/validating webhooks, cert-manager, and CEL for policy enforcement.
Webhook Types
Admission webhooks intercept requests to the Kubernetes API server. They can modify resources (mutating) or validate them (validating). Webhooks run before objects are persisted, making them ideal for policy enforcement.
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: my-mutating-webhook
webhooks:
- name: mutate-pods.myorg.io
admissionReviewVersions: ["v1"]
sideEffects: None
clientConfig:
service:
name: webhook-server
namespace: system
path: /mutate-pods
rules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
failurePolicy: Fail
matchPolicy: EquivalentThe webhook configuration tells the API server which requests to send to your webhook. rules defines which resources and operations trigger the webhook. failurePolicy controls what happens when the webhook is unavailable.
Mutating Webhook
Mutating webhooks modify resources before they are stored. They can add labels, inject sidecars, set defaults, or transform requests.
Validating Webhook
Validating webhooks check resources against rules and reject invalid ones. They run after mutating webhooks and cannot modify the resource.
cert-manager Integration
Webhooks require TLS certificates. cert-manager automates certificate provisioning and rotation. It creates certificates, stores them as secrets, and rotates them before expiry.
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: selfsigned-issuer
namespace: system
spec:
selfSigned: {}
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: webhook-serving-cert
namespace: system
spec:
secretName: webhook-server-cert
duration: 2160h # 90 days
renewBefore: 360h # 15 days before expiry
isCA: false
usages:
- server auth
dnsNames:
- webhook-server.system.svc
- webhook-server.system.svc.cluster.local
issuerRef:
name: selfsigned-issuer
kind: Issuercert-manager creates and manages TLS certificates. The Certificate resource defines the certificate properties. cert-manager creates the secret and rotates the certificate before it expires. The webhook server reads the certificate from the secret.
CEL Validation
CEL (Common Expression Language) provides declarative validation without writing a webhook. CEL rules run at the API server level, are faster than webhooks, and require no infrastructure.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: webapps.myorg.io
spec:
versions:
- name: v1
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
image:
type: string
x-kubernetes-validations:
- rule: "self.matches('^[a-z0-9]+(/[a-z0-9-]+)*:[a-z0-9.-]+$')"
message: "must be a valid container image reference"
replicas:
type: integer
x-kubernetes-validations:
- rule: "self >= 1 && self <= 100"
message: "must be between 1 and 100"
env:
type: array
items:
type: object
properties:
name:
type: string
value:
type: string
x-kubernetes-validations:
- rule: "self.all(e, e.name != 'SECRET_KEY')"
message: "SECRET_KEY environment variable is not allowed"CEL rules validate fields without writing Go code. They run at the API server level with zero latency overhead. CEL expressions have access to the resource fields and can reference other fields. This is the preferred approach for simple validation rules.
Failure Policies
Failure policies control what happens when a webhook is unreachable. Fail rejects the request. Ignore allows the request through. Choose based on whether your webhook is critical or advisory.
# Critical webhook — reject if unavailable
webhooks:
- name: security-check.myorg.io
failurePolicy: Fail
# If the webhook is down, no one can create pods
# Advisory webhook — allow if unavailable
webhooks:
- name: optional-lint.myorg.io
failurePolicy: Ignore
# If the webhook is down, allow the request
# Timeout configuration
webhooks:
- name: strict-check.myorg.io
failurePolicy: Fail
timeoutSeconds: 5
# If the webhook doesn't respond in 5 seconds, rejectFail is safer for security webhooks — it fails closed. Ignore is better for advisory checks — it fails open. timeoutSeconds prevents slow webhooks from blocking the API server. Always set a timeout.
Always test what happens when your webhook is down. If failurePolicy is Fail and your webhook pod is OOMKilled, no one can create resources in the cluster. Test by killing the webhook pod and verifying the failure mode.
Mark this lesson complete to store local progress and unlock a cleaner resume path the next time you visit.