CKS for Kindergarteners
The whole exam in one picture: the cluster is a castle, and you are the one who locks it up at night.
Someone else built the castle (that's CKA). Your job is to walk every room and ask: who can get in, what can they touch, and would we know if they did? Every CKS task is one of those three questions.
- Rooms are namespaces. Guests are pods. Keys are RBAC.
- The bouncer at the door is admission control — Pod Security Admission is the bouncer with a checklist.
- The safe is where secrets should be; a sticky note on the fridge is where they are by default.
- The visitor book is the audit log. The guard dog is Falco.
- Delivery boxes are container images — check them for tampering before you bring them inside.
The exam's favourite trick: "lock it down without breaking it." After every lock you add, check the guest can still do their job.
1. Minimize Microservice Vulnerabilities (20%) — "the bouncer and the safe"
The bouncer with a checklist (Pod Security Admission)
Analogy: you don't write rules; you hang a sign on the room's door
saying which checklist the bouncer uses — privileged (no checklist),
baseline (no obvious weapons), restricted (full pat-down).
What to look for: "enforce the restricted standard," "this Deployment is blocked, make it comply."
# ask the bouncer who'd be turned away BEFORE you flip the sign
k label --dry-run=server --overwrite ns ROOM pod-security.kubernetes.io/enforce=restricted
# flip the sign
k label ns ROOM pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/warn=restricted \
pod-security.kubernetes.io/audit=restricted --overwrite
restricted means every guest must show all four:
spec:
securityContext: { runAsNonRoot: true, seccompProfile: { type: RuntimeDefault } }
containers:
- securityContext: { allowPrivilegeEscalation: false, capabilities: { drop: [ALL] } }
Kindergarten rule: the bouncer checks your paperwork; the room checks
who you actually are. A guest whose papers say "not root" but who is
secretly root gets past the bouncer and then can't sit down
(CreateContainerConfigError). Use a non-root image.
Check both ways: a privileged pod is refused; your fixed one is Ready.
The safe, not the sticky note (secrets)
Analogy: a Secret is written in a code a five-year-old can crack (base64). Anyone who finds the ledger (etcd) can read every password. The fix is a real safe: encrypt what's in the ledger.
# prove the problem: read it straight from the ledger
etcdctl get /registry/secrets/ROOM/NAME | strings | grep password
# /etc/kubernetes/enc/enc.yaml — the safe's combination
kind: EncryptionConfiguration
resources:
- resources: [secrets]
providers:
- aescbc: { keys: [{ name: key1, secret: <32 bytes, base64> }] } # first = used for writing
- identity: {} # still able to read old plaintext
Add --encryption-provider-config=… to the API server and mount the
folder, then rewrite every secret so it goes into the safe:
k get secrets -A -o json | k replace -f -
Kindergarten rule — the one that bites: if you take the safe away while
things are still locked in it, they are gone forever. To turn encryption
off: put identity first, rewrite everything (unlock), then remove the
config. Never lose the combination.
A padded room (RuntimeClass / sandboxing)
Analogy: some guests you don't trust near the real walls. gVisor is a padded room inside the room.
kind: RuntimeClass
metadata: { name: gvisor }
handler: runsc
---
spec: { runtimeClassName: gvisor }
If the padded room isn't built on that floor, the guest waits forever
(FailedCreatePodSandBox).
Whispering in code (mTLS)
Guests talk to each other in a code only badge-holders can read. In Istio:
PeerAuthentication with mode: STRICT — see the ICA doc.
2. Supply Chain Security (20%) — "check the delivery boxes"
X-ray the box (image scanning)
Analogy: every image is a box delivered to the castle. Trivy is the X-ray. Old boxes are full of known problems.
trivy image --severity HIGH,CRITICAL nginx:1.21-alpine # look inside
trivy image --exit-code 1 --severity CRITICAL IMG # refuse the box if bad
trivy image --format cyclonedx -o sbom.json IMG # the packing list (SBOM)
What to look for: "reduce vulnerabilities," "use a smaller base." The
answer is nearly always a newer, smaller box — alpine → distroless.
Fewer things in the box, fewer things to go wrong.
Read the label before you open it (static analysis)
kubesec scan pod.yaml # scores the paperwork: non-root? caps dropped? read-only?
kube-linter lint pod.yaml
Fix what it names. privileged: true is minus thirty points — nothing
outweighs it.
Only boxes from stores we trust (registries, signing)
A policy at the door that reads the return address:
validate:
pattern: { spec: { containers: [{ image: "registry.corp/*" }] } }
cosign verify IMG checks the box was sealed by someone we know.
sha256sum -c checks a downloaded tool wasn't swapped in transit.
3. Monitoring, Logging & Runtime Security (20%) — "would we know?"
The visitor book (audit logging)
Analogy: every request at the order window gets written in a book — who, what, when. You decide how much detail per page.
What to look for: "log access to secrets," "record who ran exec."
# /etc/kubernetes/audit/policy.yaml
kind: Policy
rules:
- level: Metadata # WHO touched a secret — never write the secret itself down
resources: [{ group: "", resources: [secrets] }]
- level: RequestResponse # full detail for these
resources: [{ group: "", resources: [pods, "pods/exec"] }]
- level: None # ignore everything else
Then four flags on the API server and two volumes (the book and the rulebook must be inside the office, not left in the hallway):
- --audit-policy-file=/etc/kubernetes/audit/policy.yaml
- --audit-log-path=/var/log/kubernetes/audit/audit.log
Kindergarten rule: rules are read top to bottom, first match wins. Forget
the volumes and the office won't open — go fix it with crictl.
Read the book:
jq -r 'select(.objectRef.subresource=="exec") | "\(.user.username) -> \(.objectRef.name)"' audit.log
Glue the furniture down (runtime immutability)
Analogy: if a burglar gets into a room where nothing can be moved, they can't hide anything or leave a trap.
securityContext: { readOnlyRootFilesystem: true }
volumeMounts: [{ name: tmp, mountPath: /tmp }] # unglue ONLY the drawer they actually need
volumes: [{ name: tmp, emptyDir: {} }]
Turn it on, read the crash log for which drawer it needed, unglue that one,
repeat. Check: k exec P -- touch /x fails; app still Ready.
The guard dog (Falco)
Analogy: the visitor book only sees the door. The dog sees what
happens inside the room — someone opening a shell, writing to /etc.
k -n falco logs -l app.kubernetes.io/name=falco | grep -i warning # what the dog barked at
A rule has a condition (what to watch), an output (the bark), a
priority.
4. Cluster Setup (15%) — "the outer walls"
Walls between rooms (NetworkPolicy)
Lock every door, then let specific friends in — see the CKA doc. The CKS
twist is cluster-level: block the exit to the cloud's ID desk
(169.254.169.254) so nobody can borrow the building's own keys.
The fire inspector (CIS benchmark / kube-bench)
Analogy: an inspector with a clipboard walks the building and ticks boxes. You fix what's ticked red, then ask them to walk it again.
kube-bench run --targets=master # run it ON the control-plane node, with hostPID
kube-bench run --targets=master --check 1.1.1
Common red ticks and the fix:
chmod 600 /etc/kubernetes/manifests/*.yaml; chown root:root /etc/kubernetes/manifests/*.yaml
Kindergarten rule: [WARN] is not a pass — it's "I couldn't check this,
you check it." And re-run after fixing; "I ran chmod" is not evidence.
The front door has a lock too (Ingress with TLS)
openssl req -x509 -nodes -newkey rsa:2048 -days 365 -keyout k.key -out c.crt \
-subj "/CN=shop.local" -addext "subjectAltName=DNS:shop.local" # the name MUST be on the cert
k create secret tls shop-tls --cert=c.crt --key=k.key
k create ingress shop --class=nginx --rule="shop.local/*=shop:80,tls=shop-tls"
5. Cluster Hardening (15%) — "who has keys"
Fewer keys (RBAC least privilege)
Analogy: the fewer doors on a badge, the less a lost badge matters. The CKS version of the CKA task is taking keys away.
k get clusterrolebindings -o json | jq -r '.items[] | select(.roleRef.name=="cluster-admin") | .metadata.name' # who has the master key?
k auth can-i --list --as=system:serviceaccount:ROOM:guest # what can this guest open?
The key under the mat (ServiceAccount tokens)
Analogy: every pod is born with a key taped to its back. Most never need it. A burglar in the room finds it in seconds.
k -n ROOM patch sa default -p '{"automountServiceAccountToken":false}' # no more free keys
k -n ROOM create token guest --duration=1h # a key that expires
If a guest truly needs one, give a projected token — it expires, and it
only opens one specific door (audience).
Fewer ways in (restrict the API)
--anonymous-auth=false, --authorization-mode=Node,RBAC,
NodeRestriction admission, and a NetworkPolicy so ordinary rooms can't
even reach the order window.
Patch the walls (upgrade)
Same dance as CKA — front office first, one version at a time. The CKS framing is "there's a hole in this version."
6. System Hardening (10%) — "leashes"
The leash (seccomp)
Analogy: a guest can only make the moves on their leash-card. The
default card (RuntimeDefault) already bans the dangerous ones.
securityContext:
seccompProfile: { type: RuntimeDefault } # the usual answer
seccompProfile: { type: Localhost, localhostProfile: profiles/mine.json } # a custom card — RELATIVE path
The custom card must be on every floor (/var/lib/kubelet/seccomp/).
Build one by starting with "log everything" (SCMP_ACT_LOG) and seeing
what the guest actually does.
The other leash (AppArmor)
securityContext: { appArmorProfile: { type: Localhost, localhostProfile: deny-write } }
The leash must be loaded on the floor first — apparmor_parser,
aa-status. (This lab's floors can't load them; the LFCS VM can.)
Empty the shed (minimise the host)
Turn off what isn't used (systemctl disable --now), close windows
(ss -tlnp), no root SSH.
Kindergarten rules for the whole exam
- Read the sentence twice for scope words — "this room only," "without an exemption," "do not weaken." The narrowest lock that satisfies it wins.
- After you lock it, check the guest can still work — is the pod Ready?
- Prove the lock — show a refused pod, a denied request, a reset connection. An allowed one proves nothing.
- If you touched the front office (
kube-apiserver.yaml), wait for/readyzand be ready withcrictl. - Never take a safe away with things inside it.