Exercises
Hands-on tasks for a RHEL 10 VM, each with its own verification commands.
Exercise: deny everything, then open one port
Namespace `prod`, a default-deny policy, and exactly one allowed flow. 6 minutes.
Exercise: the AND/OR selector trap
Two policies that look identical and behave differently. 7 minutes.
Exercise: block the cloud metadata endpoint
Deny 169.254.169.254 for every Pod, keep DNS and everything else. 5 minutes.
Exercise: kube-bench, then fix two controls
Run the CIS benchmark on the control plane, fix anonymous auth and profiling, prove PASS. 10 minutes.
Exercise: Ingress with TLS in four commands
Self-signed certificate, typed secret, working HTTPS on a named host. 6 minutes.
Exercise: find the tampered binary
Three binaries, one checksum file each, one lies. 5 minutes.
Exercise: a user who can read logs and nothing else
Role, RoleBinding, and a can-i proof that the denial is real. 7 minutes.
Exercise: stop the token from being mounted
automountServiceAccountToken in both places, then prove there is no token file. 6 minutes.
Exercise: harden the API server and survive it
NodeRestriction, anonymous auth off, then read a failure out of crictl. 12 minutes.
Exercise: cordon, drain, upgrade a kubelet
The node-level half of an upgrade, without touching the control plane. 10 minutes.
Exercise: a profile that blocks writes to /tmp
Author, load on the right node, attach through the 1.30+ field, prove it. 12 minutes.
Exercise: block mkdir with a seccomp profile
Custom JSON in the kubelet seccomp root, attached at container level. 10 minutes.
Exercise: harden a running Deployment
Non-root, no escalation, all caps dropped, read-only root, seccomp — without a CrashLoop. 10 minutes.
Exercise: restricted PSA, and why one Pod is rejected
Label a namespace, predict the rejection, then make the Pod compliant. 9 minutes.
Exercise: encrypt Secrets at rest and prove it
EncryptionConfiguration, static pod mounts, re-save the secrets, read etcd. 15 minutes.
Exercise: a Gatekeeper policy that requires a label
ConstraintTemplate in Rego, Constraint, and a rejected Pod. 15 minutes.
Exercise: run a Pod in a sandboxed runtime
RuntimeClass + gVisor + a proof that the kernel is not the host's. 12 minutes.
Exercise: STRICT mTLS in the namespace
Istio if present; if not, say so and do certificate-based mTLS. 10 minutes.
Exercise: find and remove the vulnerable workload
Scan every running image, then delete the offender — the right object, not the Pod. 12 minutes.
Exercise: SBOM and a signature you can verify
Generate an SBOM, sign the image, verify it, and prove a tampered tag fails. 12 minutes.
Exercise: registry allow-list through ImagePolicyWebhook
The admission plugin almost nobody practises: config, kubeconfig, flags, denial. 20 minutes.
Exercise: fix the manifest the linter rejects
kube-linter and kubesec, then the five fields that make both happy. 8 minutes.
Exercise: audit logging, from policy to proof
The single most repeated CKS task. Policy, mounts, restart, query. 15 minutes.
Exercise: override a Falco rule and prove the alert
Copy the whole rule into the local file, change the output, trigger it. 10 minutes.
Exercise: make the workload immutable without killing it
readOnlyRootFilesystem plus exactly the writable mounts the app needs. 8 minutes.
Exercise: find what the compromised Pod is doing
Resolve the container PID on the node, trace the syscalls, name the behaviour. 12 minutes.