CKA Certification Course - Certified Kubernetes Administrator

Scheduling

2025 Updates Admission Controllers

In this lesson, we explore admission controllers in Kubernetes and understand how they enhance security and enforce policies before object persistence in etcd. Every operation performed using the kubectl command-line utility—such as creating a pod—is first sent as a request to the API server. The API server then processes the request and stores its information.

When a request reaches the API server, it is first handled by an authentication process. For instance, when using kubectl, the required certificates for authentication are provided in the KubeConfig file:

cat ~/.kube/config
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVU...

After successful authentication, the request undergoes an authorization process using role-based access control (RBAC). For example, a role may be defined to allow specific operations on pods:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["list", "get", "create", "update", "delete"]

This configuration permits a user assigned to the developer role to list, get, create, update, and delete pods. RBAC rules can be further refined to target specific resource names. For instance, to restrict a developer so they can only create pods with designated names:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["create"]
  resourceNames: ["blue", "orange"]

However, object-level permissions may not be sufficient in certain scenarios. When a pod creation request is received, you might need to inspect the configuration—for example, verifying that the pod does not use images from public registries, enforcing the use of a designated registry, or disallowing the "latest" tag. You might also enforce security policies, such as ensuring the container is not running as the root user or rejecting certain capability configurations. Consider the following pod specification:

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"]

Standard RBAC rules operate only at the API level and cannot inspect or modify an object’s contents. This limitation is overcome by admission controllers, which validate or even mutate requests prior to persisting objects. Admission controllers can enforce specific policies, such as:

  • Changing requests based on internal guidelines.
  • Enforcing container image policies.
  • Ensuring that certain metadata labels are always applied.

Kubernetes includes a variety of built-in admission controllers. Some common examples include:

  • Always Pull Images: Forces the pod to pull images from the registry every time.
  • Default Storage Class: Automatically adds a default storage class to PersistentVolumeClaims (PVCs) when none is provided.
  • Event Rate Limit: Restricts the API server’s request-handling rate.
  • Namespace Exists: Ensures that requested namespaces exist before proceeding.

Namespace Admission Controllers

The namespace admission controller ensures that pods are created only in existing namespaces. For example, if you run:

kubectl run nginx --image nginx --namespace blue

and if the "blue" namespace does not exist, you will receive an error like:

Error from server (NotFound): namespaces "blue" not found

In this situation, after authentication and authorization, the namespace admission controller checks for the existence of the "blue" namespace and rejects the request since it does not exist.

Alternatively, Kubernetes offers the namespace auto-provision admission controller, which automatically creates a namespace if it does not exist (this feature is disabled by default). With the auto-provision controller enabled, executing the same command:

kubectl run nginx --image nginx --namespace blue

results in the automatic creation of the "blue" namespace and a successful pod creation.

To view the admission controllers enabled by default, run:

kube-apiserver -h | grep enable-admission-plugins

This command will list plugins such as NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, among others. If you are using a kubeadm-based setup, run the command within the kube-apiserver control plane pod using kubectl exec.

Enabling Admission Controllers

To add an admission controller, update the --enable-admission-plugins flag on the Kube API server. In a kubeadm-based setup, this involves modifying the Kube API server manifest. For example, update the ExecStart command in the systemd service file as below:

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

For kubeadm-based setups where the API server runs as a pod, the manifest might look like this:

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - 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
    image: k8s.gcr.io/kube-apiserver-amd64:v1.11.3
    name: kube-apiserver

To disable specific admission controller plugins, use the --disable-admission-plugins flag similarly.

After updating your configuration, running the following command in a non-existent namespace:

kubectl run nginx --image nginx --namespace blue

should output:

Pod/nginx created!

Verifying the available namespaces:

kubectl get namespaces

will display:

NAME         STATUS   AGE
blue         Active   3m
default      Active   23m
kube-public  Active   24m
kube-system  Active   24m

This demonstrates how admission controllers not only reject invalid requests but can also perform backend operations like automatically creating a namespace.

Note

Both the namespace auto-provision and namespace existence admission controllers are deprecated. They have been replaced by the namespace lifecycle admission controller, which enforces that requests to non-existent namespaces are rejected and protects default namespaces (default, kube-system, and kube-public) from deletion.

That’s it for now. Practice using admission controllers in your exercises to reinforce your learnings. See you in the next lesson!

Watch Video

Watch video content

Practice Lab

Practice lab

Previous
Configuring Scheduler Profiles