README
¶
glua-webhook: Lua-Powered Kubernetes Mutating Webhook
A Kubernetes mutating admission webhook that uses Lua scripts to dynamically modify pod specifications. This example demonstrates how to build a production-ready webhook using the glua library.
Features
- Lua-based mutation logic: Write custom mutation rules in Lua instead of Go
- Dynamic pod modification: Add annotations, labels, or modify any pod specification
- Production-ready: Includes proper TLS certificate management via cert-manager
- Helm chart: Easy deployment to any Kubernetes cluster
- Label-based targeting: Only mutates pods with
thomas.maurice/mutate=truelabel
What This Example Does
This webhook adds two annotations to any pod that has the label thomas.maurice/mutate=true:
coucou.lil: hello- A custom annotation demonstrating the mutation capabilityglua.mutated-at: <timestamp>- Records when the mutation occurred
Architecture
┌─────────────────┐
│ Kubernetes API │
│ Server │
└────────┬────────┘
│ Pod CREATE/UPDATE
▼
┌─────────────────────┐
│ MutatingWebhook │
│ Configuration │
└────────┬────────────┘
│ HTTPS Request
▼
┌─────────────────────┐
│ glua-webhook │
│ (Go Server) │
│ ┌───────────────┐ │
│ │ Lua Runtime │ │
│ │ mutate.lua │ │
│ └───────────────┘ │
└────────┬────────────┘
│ JSON Patches
▼
┌─────────────────┐
│ Modified Pod │
└─────────────────┘
Prerequisites
- Kubernetes cluster (local or remote)
kubectlconfigured to access the clusterhelm(v3+) installeddockerfor building the imagekindfor local testing (optional)
Quick Start
1. Create a Kind Cluster (Local Testing)
make kind
This creates a local Kubernetes cluster named glua-webhook-test.
2. Install cert-manager
The webhook requires TLS certificates managed by cert-manager:
make cert-manager
This installs cert-manager and waits for it to be ready.
3. Build and Deploy the Webhook
make install
This will:
- Build the Docker image
- Load it into the Kind cluster
- Deploy the webhook using Helm
- Configure the mutating webhook
4. Test the Mutation
make test
This creates a test pod with the mutation label and displays the annotations that were added.
Expected output:
{
"coucou.lil": "hello",
"glua.mutated-at": "2025-10-07T00:00:00Z"
}
Manual Testing
Create a pod with the mutation label:
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: my-test-pod
labels:
thomas.maurice/mutate: "true"
spec:
containers:
- name: nginx
image: nginx:alpine
EOF
Verify the annotations were added:
kubectl get pod my-test-pod -o jsonpath='{.metadata.annotations}' | jq .
Customizing the Mutation Logic
The mutation logic is defined in Lua and stored in a ConfigMap. To customize:
-
Edit
scripts/mutate.luaor the ConfigMap incharts/glua-webhook/templates/configmap.yaml -
Upgrade the Helm release:
helm upgrade glua-webhook ./charts/glua-webhook --namespace glua-webhook
Lua Script API
The Lua script has access to:
pod: The Kubernetes Pod object as a Lua tablepatches: An empty table to populate with JSON patch operations
Example patch operation:
table.insert(patches, {
op = "add",
path = "/metadata/annotations/my-key",
value = "my-value"
})
Supported operations: add, remove, replace, move, copy, test
Configuration
Helm Values
Key configuration options in charts/glua-webhook/values.yaml:
# Image configuration
image:
repository: glua-webhook
tag: latest
pullPolicy: IfNotPresent
# Webhook behavior
webhook:
failurePolicy: Fail # Fail or Ignore
timeoutSeconds: 10
objectSelector:
matchLabels:
thomas.maurice/mutate: "true"
# Resources
resources:
limits:
cpu: 200m
memory: 128Mi
requests:
cpu: 100m
memory: 64Mi
Webhook Scope
The webhook is configured to only mutate pods with the label thomas.maurice/mutate=true. To change this:
- Edit
webhook.objectSelectorinvalues.yaml - Upgrade the Helm release
To mutate all pods in specific namespaces:
webhook:
namespaceSelector:
matchLabels:
glua-mutate: "enabled"
objectSelector: {}
Makefile Targets
make help # Show available targets
make build # Build the webhook binary
make docker # Build Docker image
make kind # Create Kind cluster
make cert-manager # Install cert-manager
make install # Deploy webhook to cluster
make uninstall # Remove webhook from cluster
make test # Run mutation test
make logs # Show webhook logs
make clean # Clean build artifacts
make all # Create cluster, install, and test
Development
Building Locally
make build
./bin/webhook --help
Running Locally (Outside Kubernetes)
# Generate self-signed certificates
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
# Run the webhook
./bin/webhook \
--address=:8443 \
--cert=cert.pem \
--key=key.pem \
--script=scripts/mutate.lua
Viewing Logs
make logs
Or directly:
kubectl logs -n glua-webhook -l app=glua-webhook -f
Troubleshooting
Webhook Not Mutating Pods
- Check webhook logs:
make logs - Verify the pod has the correct label:
thomas.maurice/mutate=true - Check webhook configuration:
kubectl get mutatingwebhookconfigurations glua-webhook -o yaml
Certificate Issues
If you see TLS errors:
# Check certificate status
kubectl get certificate -n glua-webhook
# Check cert-manager logs
kubectl logs -n cert-manager -l app=cert-manager
Pod Creation Failures
If pods fail to create:
- Check webhook failure policy (set to
Ignorefor debugging):
helm upgrade glua-webhook ./charts/glua-webhook \
--namespace glua-webhook \
--set webhook.failurePolicy=Ignore
- Check webhook is reachable:
kubectl get svc -n glua-webhook
kubectl get endpoints -n glua-webhook
Cleanup
# Uninstall webhook
make uninstall
# Delete Kind cluster
make kind-delete
Project Structure
example/webhook/
├── main.go # Webhook server implementation
├── Dockerfile # Container image definition
├── Makefile # Build and deployment automation
├── README.md # This file
├── scripts/
│ └── mutate.lua # Lua mutation script
└── charts/glua-webhook/ # Helm chart
├── Chart.yaml # Chart metadata
├── values.yaml # Default configuration
└── templates/
├── _helpers.tpl # Template helpers
├── serviceaccount.yaml # Service account
├── service.yaml # Kubernetes service
├── deployment.yaml # Webhook deployment
├── configmap.yaml # Lua script ConfigMap
├── certificate.yaml # TLS certificate
└── mutatingwebhook.yaml # Webhook configuration
Security Considerations
- The webhook runs as a non-root user (UID 65532)
- Read-only root filesystem
- Dropped capabilities
- TLS encryption for all webhook traffic
- Certificate rotation via cert-manager
Learn More
Documentation
¶
There is no documentation for this package.