imagine
- The simplest ImagePolicyWebhook
webhook 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
imagine
using Helm, this deploys the latest released version ofimagine
:
make deploy
- Generate the needed certificate to be used with
imagine
, this will be used byimagine
as 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.yaml
shall be copied to /etc/kubernetes/imagine
, make sure you've created it first.
- Now change the
kube-apiserver
static Pod manifest (in/etc/kubernetes/manifests
), you'll need to add the following configuration:
ImagePolicyWebhook
to the--enable-admission-plugins
flag--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: imagine
Wait 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 created
vs
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: nope
And 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: nope
Congratulations, 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-tools
Generate 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-certs
You can now start the webhook HTTP server:
make run
Send 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