Certified Kubernetes Security Specialist (CKS)
Minimize Microservice Vulnerabilities
Admission Controllers
In this article, we explore admission controllers in Kubernetes—powerful components that validate, mutate, or reject API requests before they are persisted. Typically, users interact with the Kubernetes cluster using the kubectl utility. When a command such as creating a pod is issued, the request reaches the API server and is ultimately saved in the etcd database.
Request Lifecycle in Kubernetes
When a request is sent to the API server, it undergoes several critical steps:
Authentication:
The API server authenticates the request. For instance, when using kubectl, the KubeConfig file supplies the necessary certificates. You can view a snippet from the KubeConfig file using:cat ~/.kube/config
apiVersion: v1 clusters: - cluster: certificate-authority-data: LS0tLS1CRUdJTiBDRVUx...
Note
Only a portion of the base64-encoded certificate data is shown for brevity.
Authorization:
After authentication, the request is authorized. Kubernetes uses role-based access control (RBAC) to determine if the user has permission to perform the requested operation. For example, a role allowing the manipulation of pods might be defined as:apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: developer rules: - apiGroups: [""] resources: ["pods"] verbs: ["list", "get", "create", "update", "delete"]
More granular permissions can also be established. For instance, the following role permits a developer to create only specific pods:
apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: developer rules: - apiGroups: [""] resources: ["pods"] verbs: ["create"] resourceNames: ["blue", "orange"]
In this case, the developer is restricted to creating pods named either "blue" or "orange."
The Role of Admission Controllers
Beyond basic authentication and authorization, there are scenarios that require additional validations or modifications to incoming requests. Consider a pod creation request, where you might want to:
- Ensure that images are only pulled from an approved internal registry.
- Enforce that the image tag is not set to "latest."
- Reject requests if the container runs as the root user.
- Modify the container’s security context or enforce specific metadata labels.
Take this pod manifest as an example:
apiVersion: v1
kind: Pod
metadata:
name: web-pod
spec:
containers:
- name: ubuntu
image: ubuntu:latest
command: ["sleep", "3600"]
securityContext:
runAsUser: 0
capabilities:
add: ["MAC_ADMIN"]
RBAC does not cover these complex validations or modifications. That is where admission controllers come into play; they provide an additional security layer by examining, modifying, or rejecting API requests before they reach etcd.
Built-In Admission Controllers
Kubernetes includes several pre-built admission controllers, such as:
- Always Pull Images: Ensures that images are pulled on each pod creation.
- Default Storage Class: Automatically assigns a default storage class to persistent volume claims if none is specified.
- Event Rate Limit: Restricts the number of requests processed by the API server concurrently.
- Namespace Exists: Verifies that the specified namespace exists, rejecting requests for non-existent namespaces.
Namespace-Related Admission Controllers
Namespace Exists Admission Controller
If you attempt to create a pod in a non-existent namespace, the namespace exists admission controller will reject the request. For example:
kubectl run nginx --image nginx --namespace blue
The flow is as follows:
- The API server authenticates and authorizes the request.
- The namespace exists admission controller verifies if the "blue" namespace is available.
- Since the namespace does not exist, the request is rejected.
Namespace Auto-Provision Admission Controller
An alternate admission controller, the namespace auto-provision admission controller, can automatically create a namespace if it does not exist. Note that this controller is not enabled by default. Without auto-provisioning, running the command:
kubectl run nginx --image nginx --namespace blue
results in:
Error from server (NotFound): namespaces "blue" not found
To see which admission controllers are enabled by default, run:
kube-apiserver -h | grep enable-admission-plugins
If your cluster uses a kubeadm-based setup, execute this command within the kube-apiserver control plane pod:
kubectl exec kube-apiserver-controlplane -n kube-system -- kube-apiserver -h | grep enable-admission-plugins
Tip
Using these commands helps ensure that you're aware of all the active admission controllers in your cluster.
Configuring Admission Controllers
Enabling Admission Controllers
To enable additional admission controllers, update the --enable-admission-plugins
flag on the kube-apiserver. In a kubeadm-based setup, this update is performed in the kube-apiserver manifest file. For example, you might configure the API server service as follows:
ExecStart=/usr/local/bin/kube-apiserver \\
--advertise-address=${INTERNAL_IP} \\
--allow-privileged=true \\
--apiserver-count=3 \\
--authorization-mode=Node,RBAC \\
--bind-address=0.0.0.0 \\
--enable-swagger-ui=true \\
--etcd-servers=https://127.0.0.1:2379 \\
--event-ttl=1h \\
--runtime-config=api/all \\
--service-cluster-ip-range=10.32.0.0/24 \\
--service-node-port-range=30000-32767 \\
--v=2 \\
--enable-admission-plugins=NodeRestriction,NamespaceAutoProvision
When the API server runs as a pod in a kubeadm-based setup, the manifest might look like this:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: kube-apiserver
namespace: kube-system
spec:
containers:
- name: kube-apiserver
image: k8s.gcr.io/kube-apiserver-amd64:v1.11.3
command:
- kube-apiserver
- --authorization-mode=Node,RBAC
- --advertise-address=172.17.0.107
- --allow-privileged=true
- --enable-bootstrap-token-auth=true
- --enable-admission-plugins=NodeRestriction,NamespaceAutoProvision
To disable specific admission controller plugins, leverage the --disable-admission-plugins
flag in a similar way.
Testing Auto-Provisioning
After enabling the desired admission controllers, a pod creation request in a non-existent namespace behaves differently. With the namespace auto-provision controller enabled, executing:
kubectl run nginx --image nginx --namespace blue
will successfully create the pod. Upon listing namespaces with:
kubectl get namespaces
you should observe that the "blue" namespace has been automatically created:
NAME STATUS AGE
blue Active 3m
default Active 23m
kube-public Active 24m
kube-system Active 24m
Deprecation Notice
Note that the namespace auto-provision and namespace existence admission controllers have been deprecated and replaced by the namespace lifecycle admission controller. The namespace lifecycle admission controller now ensures that requests targeting non-existent namespaces are rejected, while also safeguarding critical namespaces (such as default, kube-system, and kube-public) from deletion.
Conclusion
Admission controllers represent an advanced layer of security within Kubernetes by allowing for complex validations and modifications to API requests. They operate seamlessly in the background, ensuring that your cluster adheres to stringent security and operational policies. Practice deploying and configuring these controllers to strengthen your understanding and enhance your Kubernetes security posture.
For further details, consider reviewing additional Kubernetes documentation on Admission Controllers and RBAC.
Watch Video
Watch video content
Practice Lab
Practice lab