Responsible Approach to Communicating With the API Server: Admission Controllers
Tags: devops, kubernetes, security, api
Published: 2022-09-02 12:25:12

##A bit of theory

_RBAC_ and _Network policies_ are two fundamental security elements of Kubernetes that you probably already know about if you work with it. These mechanisms are helpful for enforcing fundamental guidelines regarding what operations different users or services within your cluster are permitted to carry out.

However, there are situations when you require _more policy features_ or granularity than RBAC or network policies can provide. Alternatively, you might want to _run additional checks_ to verify a resource _before_ allowing it to join your cluster.

Admission Controllers (ACs) allow you to add _additional options_ to the work of Kubernetes to change or _validate objects_ when making requests to the Kubernetes API. 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kswoeuleimjfswqokxy2.png)

🖼️ Pic source: Giant Swarm

The image shows the various parts that make up the API component. The request initiates communication between the API and the admission controller. The authorization module determines whether the request issuer is permitted to carry out the operation after the request has been authenticated. The admittance magic kicks in once the request have been duly approved.

If the controller rejects the request, then the entire request to the API server is rejected and an error is returned to the end user.

To activate controllers discussed, you must specify the names of the controllers in the form of a list when creating or updating a cluster. After that, `kube-apiserver` will be started or restarted with the `--enable-admission-plugins` option and access controllers set.

Passing a controller that is not available for the current version of Kubernetes will return an appropriate error.

##What exactly can ACs be?

###🔬 In a scope of implementation

Admission controllers that are built into and made available by Kubernetes itself are known as **static** admission controllers. Not every one of them is turned on by default. The cloud companies also grab some of them or restrict some of them for their own usage. You can enable and utilize them if you are the owner of your Kubernetes deployment. Some examples:

`LimitRanger` _makes sure that any of the restrictions_ listed in the `LimitRange` object in a namespace _are not broken_ by incoming requests. Use this admission controller to impose those restrictions if you are utilizing `LimitRange` objects in your Kubernetes setup. Applying default resource requests to pods without any specifications is also possible with this AC.

`AlwaysPullImages` _changes the image pull policy_ for every new Pod. This is useful, for example, in multi-tenant clusters to ensure that only those with the credentials to fetch private images can access them. Without this admission controller, after an image has been pulled to a node, any pod from any user can use it just by knowing the image's name without any authorization checks. This feature must be enabled in the cluster.

`NamespaceLifecycle` _enforces that a namespace that is undergoing termination cannot have new objects_ created in it, and ensures that requests in a non-existent namespace are rejected.

And there are **dynamic** ones. See details below.

###🔬 In a scope of request processing
There are _two types_ of dynamic admission controllers in Kubernetes. They work slightly differently. Saying shortly, one just _validates_ the requests, and the other _modifies_ it if it isn’t up to spec.

⚙️ **The first type** is the **validating** admission controller `ValidatingAdmissionWebhook`, which proxies the requests to the subscribed webhooks. The Kubernetes API registers the webhooks based on the resource type and the request method. Every webhook runs some logic to validate the incoming resource, and it replies with a verdict to the API. 

In case the validation webhook rejects the request, the Kubernetes API returns a failed HTTP response to the user. Otherwise, it continues with the next admission.

⚙️ **The second type** is a **mutating** admission controller `MutatingAdmissionWebhook`, which alters the resource that the user has submitted so that default values can be set, or the schema can be verified. The API can have mutation webhooks attached by cluster administrators so that they can execute them similarly to validation. 

##Hooks! Hooks are everywhere!

Any resource type, including those that are pre-built like pods, jobs, or services, may be the primary resource type for a controller. The issue is that most built-in resources, if not all of them, already come with associated built-in controllers. In order to prevent having _many_ controllers update the status of a shared object, _custom controllers_ are frequently built for special resources. 

If resources are merely Kubernetes API endpoints, writing a controller for a resource is just a fancy **way to bind a request handler to an API endpoint**! 

Conditional resource modification can be implemented using a so-called webhook, which is essentially an [API endpoint](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#request). 

It is possible [to configure dynamically](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/) what resources are subject to what admission webhooks via `ValidatingWebhookConfiguration` or `MutatingWebhookConfiguration` kinds. 

Both are available in `admissionregistration.k8s.io/v1` API version.

```
$ kubectl api-versions | grep admiss
admissionregistration.k8s.io/v1
admissionregistration.k8s.io/v1beta1
```

##How would I activate admission controllers?

To use before changing cluster objects, the Kubernetes API server flag `--enable-admission-plugins` accepts a comma-delimited list of AC plugins. For instance, the following command line activates the `LimitRanger` and `NamespaceLifecycle` admission control plugins:

```
kube-apiserver --enable-admission-plugins=NamespaceLifecycle,LimitRanger
```

⚠️ Note: You may need to apply the parameters in different ways depending on how your Kubernetes cluster is installed and how the API server is launched. For instance, if Kubernetes is deployed using self-hosted Kubernetes, you may need to alter the manifest file for the API server [and/or the `systemd` Unit file](https://digitalis.io/blog/kubernetes/k3s-lightweight-kubernetes-made-ready-for-production-part-2/) if the API server is installed as a `systemd` service.

⚠️ Note: API kind `admissionregistration.k8s.io/v1beta1` became deprecated in 1.22+ 

##Public cloud providers' implementation
In this case, everything is already set up for you. 

To learn more about using dynamic admission controllers with Amazon EKS, see the [Amazon EKS documentation](https://docs.aws.amazon.com/eks/latest/userguide/platform-versions.html). 

[Azure AKS Policy](https://docs.microsoft.com/en-us/azure/architecture/operator-guides/aks/aks-triage-controllers), Microsoft's implementation of OPA Gatekeeper, is another interesting thing. Involving AC webhooks,  if there are problems in the admission control pipeline, it can block numerous requests to the API server.

The VMware Tanzu team followed a similar path in their [Tanzu Kubernetes Grid (TKG)](https://tanzu.vmware.com/developer/guides/platform-security-admission-control/).

Of course, OPA Gatekeeper itself is a separate and extensive topic, so more on that another time.

In the ninth article of the series, the author will talk about how smart people were able to translate the theory described above into a useful solution.

Be careful and stay tuned!

Many thanks to Leonid Sandler, Douglas Makey @douglasmakey  Mendez Molero, Luca 🐦 @LucaDiMaio11 Di Maio, Kristijan Mitevski and W.T. Chang!