imagine - The simplest ImagePolicyWebhook example you'll ever find!
In the Kubernetes API request journey, imagine plays a role in the validating admission phase, where the red dot in the diagram marks our position. This project showcases how simple it can be to integrate a custom webhook into Kubernetes and validate container images effectively.
I'm kind of assuming that you've deployed a small cluster using kubeadm. I've done that on-top of KVM during development of this project, see this repository on how that was done.
- Deploy
imagineusing Helm, this deploys the latest released version ofimagine:
make deploy- Generate the needed certificate to be used with
imagine, this will be used byimagineas the server-side certificate of the webhook:
make k8s-gen-cert- Copy the following files to a specific directory on all control-plane nodes:
files/admissionconfig.yaml
files/config.yamlshall be copied to /etc/kubernetes/imagine, make sure you've created it first.
- Now change the
kube-apiserverstatic Pod manifest (in/etc/kubernetes/manifests), you'll need to add the following configuration:
ImagePolicyWebhookto the--enable-admission-pluginsflag--admission-control-config-file=/etc/kubernetes/imagine/admissionconfig.yaml
and:
...
spec:
containers:
- volumeMounts:
- mountPath: /etc/kubernetes/imagine
name: imagine
readOnly: true
...
volumes:
- hostPath:
path: /etc/kubernetes/imagine
type: DirectoryOrCreate
name: imagineWait for a while to let the kube-apiserver start up again, check the status with e.g. crictl.
You can now run the simplest of tests:
kubectl run --image nginx nginx-1
pod/nginx-1 createdvs
kubectl run --image nope nginx-2
Error from server (Forbidden): pods "nginx-2" is forbidden: image policy webhook backend denied one or more images: image name contains disallowed string: nopeAnd from the perspective of imagine these requests looks something like this:
imagine-67d4f474cf-4hf8m 2024/11/25 20:22:40 Received request: POST /
imagine-67d4f474cf-4hf8m 2024/11/25 20:22:40 Raw JSON request body: {"kind":"ImageReview","apiVersion":"imagepolicy.k8s.io/v1alpha1","metadata":{"creationTimestamp":null},"s
pec":{"containers":[{"image":"nginx"}],"namespace":"default"},"status":{"allowed":false}}
imagine-67d4f474cf-4hf8m 2024/11/25 20:22:40 Image: nginx, Allowed: true, Reason: Image name is allowed
imagine-67d4f474cf-4hf8m 2024/11/25 20:22:53 Received request: POST /
imagine-67d4f474cf-4hf8m 2024/11/25 20:22:53 Raw JSON request body: {"kind":"ImageReview","apiVersion":"imagepolicy.k8s.io/v1alpha1","metadata":{"creationTimestamp":null},"s
pec":{"containers":[{"image":"nope"}],"namespace":"default"},"status":{"allowed":false}}
imagine-67d4f474cf-4hf8m 2024/11/25 20:22:53 Image: nope, Allowed: false, Reason: image name contains disallowed string: nopeCongratulations, you're now done! 🎉
- Check the logs of
imagine, it logs incoming requests verbatim, and also the status and reason of the validating admission control request. - Check the logs of the
kube-apiserver.
Check that you have all necessary tools installed:
make check-toolsGenerate certificates:
- Generates the CA private key
- Generates the CA certificate
- Generates the private key to be used by the webhook HTTP server
- Generates the webhook HTTP server CSR
- Signs the CSR with the CA's key and certificate to issue the webhook HTTP server certificate
make gen-certsYou can now start the webhook HTTP server:
make runSend two requests that includes two admission requests with Pod container images named: nope:latest and nginx:latest. We'll not allow container images containing nope to be started basically:
make send