Pod admission, Pod Security and priority

Where admission sits in the API server and which plugins are on, how Pod Security labels block unsafe Pods, and how PriorityClasses decide which Pods go first.

40 min 3 hands-on tasksWorkloads · 15% of the exam

Key ideas in this lesson · tap one for a simple explanation

What you will be able to do

  • Find the admission plugins a kube-apiserver enables in its static Pod manifest, and say what the common ones do.
  • Enforce a Pod Security Standard on a namespace with labels, and write a Pod that the restricted level admits.
  • Create a PriorityClass, use it from a Pod, and predict when the scheduler will preempt other Pods.

Before the saves a new , it sends the request through admission. Admission is a set of plugins that can fill in values, change the request, or reject it. You have already met two of them. and from the requests and limits lesson are admission plugins.

Example: your team's must never run Pods as root. A Pod Security on the namespace makes the API server refuse such Pods before they ever start. This lesson covers how plugins are switched on, , and the Priority plugin, which decides which Pods the serves first.

Where admission sits

Every change you send to the API server goes through the same steps, in order:

The path of a request

Authentication

who are you?

Authorization

are you allowed? (RBAC)

Admission

change, then check the object

etcd

the object is saved

Any step can reject the request, and kubectl prints the reason.

  • Admission works in two passes. First, mutating plugins may change the object, for example to fill in defaults. Then validating plugins may only accept or reject it.
  • Built-in plugins are part of kube-apiserver. The flag --enable-admission-plugins switches more of them on; it adds to a default set.
  • The flag --disable-admission-plugins turns off plugins from the default set.
Which plugins does this API server run?
# Explicitly enabled plugins (exam: ssh to the control plane node, then sudo grep)
docker exec cka-control-plane grep -- --enable-admission-plugins /etc/kubernetes/manifests/kube-apiserver.yaml
#    - --enable-admission-plugins=NodeRestriction

# The same flag from the API, without a node shell
kubectl -n kube-system describe pod -l component=kube-apiserver | grep admission

These are the plugins worth knowing for this exam:

PluginOn by defaultWhat it does
NamespaceLifecycleYesRejects objects in a namespace that does not exist or is being deleted. Also stops anyone from deleting default, kube-system and kube-public
LimitRangerYesApplies LimitRange defaults, minimums and maximums
ResourceQuotaYesRejects objects that would go over a quota
PodSecurityYesEnforces Pod Security Standards from namespace labels
PriorityYesTurns priorityClassName into a number in spec.priority
NodeRestrictionNo, but turns it onLets a change only its own Node and the Pods on it

Other default plugins do jobs you meet in other lessons:

To change the flag, you edit the API server's file. How that works, and how to do it safely, is in Control plane and node components.

Pod Security Admission

Some Pod settings are dangerous: running as root, using the 's network, or mounting the node's disk. Kubernetes defines three Pod Security Standards, from loose to strict:

LevelAllows
privilegedEverything. No checks at all
baselineMost apps. It blocks privileged , the node's own namespaces (network, PID, IPC), hostPath volumes, host ports, and dangerous added capabilities
restrictedBaseline, plus: runAsNonRoot: true, allowPrivilegeEscalation: false, capabilities.drop: ["ALL"], a RuntimeDefault or Localhost seccomp profile, and only safe volume types (configMap, secret, emptyDir, projected, downwardAPI, and )

A namespace picks a level with a label of the form pod-security.kubernetes.io/<mode>: <level>. There are three modes:

ModeWhat happens to a Pod that breaks the level
enforceIt is rejected
warnIt is created, and whoever created it sees a warning
auditIt is created, and a note is added to the API server's audit log

One trap: warn and audit also check the Pod templates inside and other workloads, but enforce checks only Pods. So a Deployment whose Pods are rejected looks fine. You only see the problem in its 's events.

Label a namespace, but look first
# Dry run on the server: lists existing Pods that would violate, changes nothing
kubectl label --dry-run=server --overwrite ns wl-psa pod-security.kubernetes.io/enforce=restricted

kubectl label --overwrite ns wl-psa pod-security.kubernetes.io/enforce=restricted pod-security.kubernetes.io/warn=restricted
kubectl get ns wl-psa --show-labels

# A rejected Pod names every missing field:
#   violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false (...), unrestricted capabilities (...),
#   runAsNonRoot != true (...), seccompProfile (...)

Here is a Pod with every setting the restricted level asks for:

A Pod the restricted level admits
apiVersion: v1
kind: Pod
metadata:
  name: tidy
  namespace: wl-psa
spec:
  securityContext:              # Pod level: applies to every container
    runAsNonRoot: true
    runAsUser: 1000             # needed when the image would run as root
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: app
      image: busybox:1.36
      command: ["sleep", "3600"]
      securityContext:          # container level: these two only exist here
        allowPrivilegeEscalation: false
        capabilities:
          drop: ["ALL"]
  • runAsNonRoot: true alone is not enough for images that run as root by default, such as busybox and nginx. The API admits the Pod, but then the kubelet refuses to start the container: container has runAsNonRoot and image will run as root. Set a numeric runAsUser, or use an image built to run as a normal user.
  • Labeling a namespace never removes Pods that are already running. That is why the server-side dry run above is the honest check.

PriorityClass and preemption

When the cluster is full, which Pods go first? A gives Pods a number: the higher the number, the more important the Pod. Example: your checkout Pods get a higher priority than a nightly report, so checkout always gets room first.

A class and a Pod that uses it
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
  name: business-critical
value: 1000000                   # higher wins; user classes go up to 1,000,000,000
globalDefault: false             # true makes it the default for Pods without a class
preemptionPolicy: PreemptLowerPriority   # or Never
description: "Customer-facing services"
---
apiVersion: v1
kind: Pod
metadata:
  name: checkout
  namespace: wl-prio
spec:
  priorityClassName: business-critical
  containers:
    - name: nginx
      image: nginx:1.27
# Imperative: kubectl create priorityclass business-critical --value=1000000 --description="Customer-facing services"

How a Pod gets its priority

  • The Pod names a class in priorityClassName.
  • When the Pod is created, the Priority plugin copies the class's value into spec.priority.
  • A Pod that names a class that does not exist is rejected. A Pod with no class gets the global default class, or 0.
  • A class's value cannot be edited: delete the class and create it again. Pods that already exist keep the priority they were given.

Preemption

  • The scheduler serves higher-priority Pods first.
  • If such a Pod fits on no node, the scheduler looks for a node where removing lower-priority Pods would make room. It then stops those Pods gracefully. This is called preemption.
  • preemptionPolicy: Never keeps the Pod's place at the front of the queue, but it never removes anyone.
Preemption, step by step

High-priority Pod

Pending: no node has room

Scheduler

finds lower-priority Pods to remove

Lower-priority Pods

stopped to make room

High-priority Pod

scheduled on that node

In the official docs· open on exam day too

Hands-on task 1 of 3wl-psa-1
~8 min6% weightWorkloads

Enforce the restricted standard and make a Pod comply

Configure namespace wl-psa so that the API server rejects Pods that violate the restricted Pod Security Standard and also warns about such violations. Then create the Pod defined in /tmp/cka/wl-psa/secure.yaml. As written it will be rejected: change only its security settings until it is admitted and running. Keep its name, image and command.

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-psa-1/setup | bash
  2. 2

    Solve it in your terminal

    Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under /tmp/cka/.

  3. 3

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-psa-1/verify | bash
    Got FAIL? Read which check failed, fix it, run it again.
  4. 4

    Clean up (optional)

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-psa-1/cleanup | bash
Hands-on task 2 of 3wl-psa-2
~5 min4% weightWorkloads

A non-preempting PriorityClass

Create a PriorityClass wl-batch-high with value 100000. It must not be the cluster-wide default, and Pods using it must never preempt other Pods. Then create a Pod important in namespace wl-prio (image nginx:1.27) that uses this class.

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-psa-2/setup | bash
  2. 2

    Solve it in your terminal

    Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under /tmp/cka/.

  3. 3

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-psa-2/verify | bash
    Got FAIL? Read which check failed, fix it, run it again.
  4. 4

    Clean up (optional)

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-psa-2/cleanup | bash
Hands-on task 3 of 3wl-psa-3
~4 min3% weightWorkloads

Report the enabled admission plugins

Find the admission plugins that this cluster's kube-apiserver enables explicitly, in addition to its built-in defaults, as configured in its static Pod manifest on the control plane node. Write the plugin names to /tmp/cka/admission-plugins.txt, one per line. (Lab: docker exec cka-control-plane …; exam: ssh to the control plane node.)

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-psa-3/setup | bash
  2. 2

    Solve it in your terminal

    Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under /tmp/cka/.

  3. 3

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-psa-3/verify | bash
    Got FAIL? Read which check failed, fix it, run it again.
  4. 4

    Clean up (optional)

    curl -fsSL https://codewithmuh.com/labs/cka/t/wl-psa-3/cleanup | bash

Finished this lesson?

0 of 3 tasks passed. Your readiness counts tasks, so run them before you move on.