Undoubtedly, Kubernetes has become the standard for container orchestration, making it necessary to work with extensions that add a layer of security and modularity.

So, what exactly are these extensions? According to the Kubernetes documentation, “An admission controller is a piece of code that intercepts requests to the Kubernetes API server prior to persistence of the object, but after the request is authenticated and authorized.”

In essence, these extensions help us define and govern operations for our Kubernetes cluster. They act as a security checkpoint before object data from API requests is executed or stored into etcd.

In this blog, I will show you how to install and configure these admission controllers. For your information, you can find the list of all functions of the admission controller for version 1.26 of Kubernetes in the official documentation.

Deploy status

In this blog, I suggest testing two admission controllers, which are the ImagePolicyWebhook and the NodeRestriction, which will check and validate if a pod can be deployed or not. First, let’s test the deployment of an nginx pod with version 1.42.

kubectl run nginx --image=nginx:1.14.2
kubectl get pod --watch
nabil@dbi-master01:~$ kubectl run nginx --image=nginx:1.14.2
pod/nginx created
nabil@dbi-master01:~$ kubectl get pod --watch
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          13s

The pod is running, so we can delete it.

kubectl delete pod nginx

Check the configuration

Check the Kubernetes setup currently being used. This should show the admissionregistration.k8s.io/vi API.:

kubectl api-versions | grep admissionregistration
nabil@dbi-master01:~$ kubectl api-versions | grep admissionregistration
admissionregistration.k8s.io/v1

Dump the k8s cluster configuration to display the references to mutating webhooks and validating webhooks, but without image policy webhooks:

kubectl cluster-info dump | grep -i imagepolicyWebhook
nabil@dbi-master01:~$ kubectl cluster-info dump | grep -i imagepolicyWebhook
nabil@dbi-master01:~$

Normally, the command should return nothing as you can see above.

Enable Controller

We will now activate the admission controller. Simply edit the kubernetes apiserver manfiest file , look for the --enable-admission-plugins flag in the configuration section of the kube-apiserver and add the ImagePolicyWebhook plugin at the end of the line to enable the webhook.

With a high user privilege, edit the /etc/kubernetes/manifests/kube-apiserver.yaml file

nabil@dbi-master01:~$ sudo su -
[sudo] password for nabil:
root@dbi-master01:~# vi /etc/kubernetes/manifests/kube-apiserver.yaml

Navigate down to the spec code block to find the --enable-admission-plugins line (here, the 6th flag in the kube-apiserver spec).

spec:
  containers:
  - command:
    - kube-apiserver
    - --admission-control-config-file=/etc/kubernetes/admission-control/admission-control.conf
    - --advertise-address=*.*.*.*
    - --allow-privileged=true
    - --authorization-mode=Node,RBAC
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    - --enable-admission-plugins=NodeRestriction
    - --enable-bootstrap-token-auth=true
    - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
    - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
    - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
    - --etcd-servers=https://127.0.0.1:2379
    - --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
    - --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key
    - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
    - --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
    - --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
    - --requestheader-allowed-names=front-proxy-client
    - --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
    - --requestheader-extra-headers-prefix=X-Remote-Extra-
    - --requestheader-group-headers=X-Remote-Group
    - --requestheader-username-headers=X-Remote-User
    - --secure-port=6443
    - --service-account-issuer=https://kubernetes.default.svc.cluster.local
    - --service-account-key-file=/etc/kubernetes/pki/sa.pub
    - --service-account-signing-key-file=/etc/kubernetes/pki/sa.key
    - --service-cluster-ip-range=10.*.*.*/12
    - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
    - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key

Add ImagePolicyWebhook at the end of the line to enable the webhook:

--enable-admission-plugins=NodeRestriction,ImagePolicyWebhook

Save and exit. Then, check the status of the server:

kubectl get nodes

The connection may be refused, as the cluster take few minutes to set up the configuration.

nabil@dbi-master01:~$ kubectl get nodes
The connection to the server 10.*.*.*:6443 was refused - did you specify the right host or port?

Keep cool! Wait and retry a couple of minutes later to the nodes UP and RUNNING (Ready state).

nabil@dbi-master01:~$ kubectl get nodes
NAME          STATUS   ROLES           AGE   VERSION
k8s-master01   Ready    control-plane   58m   v1.25.0
k8s-worker01   Ready    <none>          57m   v1.25.0

Test the setup

Search again to see if the image policy webhook is enabled:

kubectl cluster-info dump | grep ImagePolicyWebhook
nabil@dbi-master01:~$ kubectl cluster-info dump | grep ImagePolicyWebhook
                            "--enable-admission-plugins=NodeRestriction,ImagePolicyWebhook",
I0704 13:21:57.710001       1 plugins.go:161] Loaded 12 validating admission controller(s) successfully in the following order: LimitRanger,ServiceAccount,ImagePolicyWebhook,PodSecurity,Priority,PersistentVolumeClaimResize,RuntimeClass,CertificateApproval,CertificateSigning,CertificateSubjectRestriction,ValidatingAdmissionWebhook,ResourceQuota.
I0704 13:21:57.711659       1 plugins.go:161] Loaded 12 validating admission controller(s) successfully in the following order: LimitRanger,ServiceAccount,ImagePolicyWebhook,PodSecurity,Priority,PersistentVolumeClaimResize,RuntimeClass,CertificateApproval,CertificateSigning,CertificateSubjectRestriction,ValidatingAdmissionWebhook,ResourceQuota.
I0704 13:21:58.647369       1 plugins.go:161] Loaded 12 validating admission controller(s) successfully in the following order: LimitRanger,ServiceAccount,ImagePolicyWebhook,PodSecurity,Priority,PersistentVolumeClaimResize,RuntimeClass,CertificateApproval,CertificateSigning,CertificateSubjectRestriction,ValidatingAdmissionWebhook,ResourceQuota.
nabil@dbi-master01:~$

We can clearly see here that the command returns that the image policy webhook is enabled, unlike the previous paragraph where the command returned nothing

Now, we will try to deploy a nginx image which contain some known vulnerabilities:

kubectl run nginx --image=1.14.2
nabil@dbi-master01:~$ kubectl run nginx --image=1.14.2
Error from server (Forbidden): pods "nginx" is forbidden: image policy webhook backend denied one or more images: Image(s) contain serious vulnerabilities: [1.14.2]
nabil@dbi-master01:~$

This time, the deployment should be denied from being provisioned because of image vulnerabilities.
Now, try with a busybox image:

kubectl run busybox --image=busybox:1.36.1
nabil@dbi-master01:~$ kubectl run busybox --image=busybox:1.36.1
pod/busybox created

The pod is created successfully, meaning the webhook works as intended.

Good job, you have successfully activated and used an admission controller.