CKAD field manual

k8s SecurityContext YAML example

Linux splits “root” into capabilities (bind :80, load modules, …). These fields take them away from the container process. drop ALL, then add only what the question names.

A capital ship takes hits while the gun deck stays locked down. A capital ship takes hits while the gun deck stays locked down.
YAML
apiVersion: v1
kind: Pod
metadata:
  name: locked
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    fsGroup: 2000
  containers:
    - name: app
      image: nginx:1.27
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop: ["ALL"]
          add: ["NET_BIND_SERVICE"]
Container lock
securityContext:
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities:
    drop: ["ALL"]
    add: ["NET_BIND_SERVICE"]
Requests / limits
resources:
  requests:
    cpu: "100m"
    memory: 128Mi
  limits:
    cpu: "200m"
    memory: 256Mi

Fields

securityContext
On spec: who the process is (user/group) for every container. On a container: what that process may do.
runAsNonRoot
Uid must not be 0. Fails if the image USER is 0 and you did not set runAsUser.
runAsUser
Numeric uid for the process. Pair with runAsNonRoot so the image cannot sneak back to 0.
fsGroup
Pod field. Volume files get this gid so a non-root process can read them.
allowPrivilegeEscalation
false = the process cannot gain extra privileges later (setuid to root is blocked). Container-only.
readOnlyRootFilesystem
true = `/` is read-only. The process cannot write into the image. Mount emptyDir on /tmp if it needs scratch.
capabilities
Slices of root. A container starts with a default set, not zero. drop ALL, then add what the question names.
drop
drop: [ALL] first. That removes NET_ADMIN, SYS_ADMIN, CHOWN — every extra power.
add
After drop ALL, give back only this. NET_BIND_SERVICE = bind ports below 1024 (80, 443) without being root.
requests
What the scheduler guarantees. The Pod will not start without it.
limits
Cap. Over memory limit → OOMKilled.

Watch

  • Pod securityContext = who (runAsUser, fsGroup) for every container. Container securityContext = what that process may do. allowPrivilegeEscalation, capabilities, and readOnlyRootFilesystem are container-only — the API rejects them on the Pod.
  • allowPrivilegeEscalation: false — the process cannot become more privileged after start. A setuid binary cannot jump to root. runAsNonRoot alone does not block that.
  • readOnlyRootFilesystem: true — `/` cannot be written. The process cannot drop files into the image. If it needs /tmp, mount an emptyDir there.
  • capabilities are slices of root. A container starts with a default set, not none. drop: [ALL] removes every one. add: [NET_BIND_SERVICE] gives back only “bind TCP/UDP ports below 1024” so a uid 1000 process can still listen on :80.
  • runAsNonRoot: true fails if the image runs as 0 and you did not set runAsUser.

Official docs Security Context

Practice these objects on a live cluster →