Connect an Image Scanner Through an Admission Webhook
Given an incomplete configuration located at /etc/kubernetes/bouncer and a functional container image scanner with an HTTPS endpoint at https://smooth-yak.local/review, perform the following tasks to…
Live lab access
This task description is public. Live practice requires full access unless this is the selected free weekly task. AI Lab Coach is available in single-task labs, including the free weekly task. See this week's free task.
Create an account to continue →
On a phone? Read the task and create your account here, then sign in on a desktop or laptop for the terminal lab. Nothing starts until you choose Start.
The task
Context
You must fully integrate a container image scanner into the kubeadm provisioned cluster.
Task
Given an incomplete configuration located at /etc/kubernetes/bouncer and a functional container image scanner with an HTTPS endpoint at https://smooth-yak.local/review, perform the following tasks to implement a validating admission controller.
First, re-configure the API server to enable all admission plugin(s) to support the provided AdmissionConfiguration.
Next, re-configure the ImagePolicyWebhook configuration to deny images on backend failure.
Next, complete the backend configuration to point to the container image scanner's endpoint at https://smooth-yak.local/review.
Finally, to test the configuration, deploy the test resource defined in /home/candidate/vulnerable.yaml which is using an image that should be denied.
> You may delete and re-create the resource as often as needed.
> The container image scanner's log file is located at /var/log/nginx/access_log.
Original Prepium guide · Written for Kubernetes v1.35 and checked against the official documentation on 6 October 2026. Use a disposable practice cluster. This edits the API server's static Pod on a control plane node: use a throwaway kubeadm VM and keep a copy of the original manifest outside /etc/kubernetes/manifests.
How ImagePolicyWebhook asks an external scanner before a Pod is admitted
ImagePolicyWebhook is a validating admission plugin built into kube-apiserver. For each Pod it POSTs an ImageReview listing the container images to an HTTPS backend, and the backend answers allowed or not. It is disabled by default and relies on three pieces of configuration that point at each other, so one broken link breaks the whole chain.
kube-apiserver --enable-admission-plugins=...,ImagePolicyWebhook
└─ --admission-control-config-file ──→ AdmissionConfiguration
└─ imagePolicy.kubeConfigFile ──→ kubeconfig (server: https://..., CA, client cert)
└─ ImageReview (imagepolicy.k8s.io/v1alpha1) ──→ scanner: allowed true/false
1. Link 1: the AdmissionConfiguration
This example keeps everything under one directory of its own, /etc/kubernetes/prepium-admission/:
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: ImagePolicyWebhook
configuration:
imagePolicy:
kubeConfigFile: /etc/kubernetes/prepium-admission/review.kubeconfig
allowTTL: 30 # seconds an approval is cached
denyTTL: 30 # seconds a denial is cached
retryBackoff: 500 # milliseconds between retries
defaultAllow: true # what happens when the backend cannot answer
The plugin's settings can be embedded like this or kept in a separate file referenced with path:. defaultAllow is the security switch: true means "fail open" (admit Pods when the scanner is down or unreachable), false means "fail closed" (reject them). A hardened setup fails closed.
2. Link 2: the webhook kubeconfig
clusters:
- name: image-review
cluster:
certificate-authority: /etc/kubernetes/prepium-admission/review-ca.crt
server: https://image-review.prepium.test/check
users:
- name: kube-apiserver
user:
client-certificate: /etc/kubernetes/prepium-admission/apiserver-client.crt
client-key: /etc/kubernetes/prepium-admission/apiserver-client.key
In this file clusters describes the remote scanner and users describes the API server's own credentials towards it. The server URL must use HTTPS and must be the full path of the review endpoint, not just the host.
3. Link 3: flags and mounts on kube-apiserver
Append ImagePolicyWebhook to the existing comma-separated --enable-admission-plugins list (do not replace the list), and add --admission-control-config-file pointing at the AdmissionConfiguration. The API server runs in a container, so the directory must also appear as a hostPath volume with a matching volumeMount; otherwise the paths inside your files do not exist from the server's point of view. Save the manifest and wait for the kubelet to recreate the static Pod (crictl ps -a | grep kube-apiserver).
4. Test both answers and the failure path
kubectl create namespace prepium-tutorial
kubectl -n prepium-tutorial run review-me --image=nginx:1.27-alpine
kubectl -n prepium-tutorial get pods
A denial comes straight back from kubectl run as an admission error, and no Pod object is stored. Check the scanner's own access log to prove the API server actually called it. To test the failure path, make the backend unreachable on purpose: with defaultAllow: true the Pod is admitted, with false it is rejected. Cached decisions (the TTLs) can hide a change for a few seconds.
Common mistakes
- Setting
--admission-control-config-filebut not enabling the plugin: the config is never used and every image is admitted. - Overwriting
--enable-admission-pluginswith only the new name, silently dropping plugins such as NodeRestriction. - Paths that exist on the host but are not mounted into the API server container: the server cannot read its own configuration and does not come back healthy.
- A
serverURL that is not the exact review endpoint, or that useshttp://: the docs require HTTPS, and when the backend cannot give a valid answer the result falls back todefaultAllow.
| Example check | Evidence |
|---|---|
| Plugin enabled | ImagePolicyWebhook in the running server's --enable-admission-plugins |
| Config wired | --admission-control-config-file set and its directory mounted |
| Fail-closed behaviour | defaultAllow: false; Pods rejected while the backend is down |
| Backend consulted | New request lines in the scanner log for each Pod create |
Cleanup: kubectl delete namespace prepium-tutorial, then restore the saved manifest. References: ImagePolicyWebhook, imagepolicy.k8s.io/v1alpha1, kubeconfig files. Next, try API server authentication or image SBOMs.
What this tests
Scan images for vulnerabilities, harden Dockerfiles, generate SBOMs, and enforce image policy. On the CKS exam, Supply Chain Security tasks are graded purely on what you build in the cluster - not multiple choice - so the only way to get faster is to do them on a real cluster against a clock.
Practice it for real
The public description lets you study the task before signing up. Full access includes this live lab; the selected Task of the Week is free with an account. You solve the task in a real terminal, hit validate, and a programmatic checker scores exactly what you got right and wrong (with partial credit). You can open the solution while practising, then retry and use the failed checks to improve your score.