CKS Study Path (Certified Kubernetes Security Specialist)¶
The CKS is the only K8s cert that asks you to actually fix a broken cluster against a stopwatch. Multiple-choice study guides will not save you. This path assumes you can already pass CKA cold and are now adding the security layer on top.
What You're Walking Into¶
CKS is a CNCF cert administered by the Linux Foundation, currently aligned to Kubernetes v1.27+ as of 2025-2026. It's performance-based, not multiple-choice. You get a real cluster (actually six different clusters via context switching), a terminal, and approximately 17 questions to solve in 2 hours. Passing score is 67%.
| Field | Value |
|---|---|
| Vendor | Cloud Native Computing Foundation (CNCF) / Linux Foundation |
| Code | CKS |
| Version | v1.27+ (curriculum and cluster version updated periodically) |
| Format | Performance-based, live-terminal, browser-proctored |
| Questions | ~17 tasks |
| Duration | 2 hours |
| Passing | 67% |
| Cost | $395 USD list price (regularly discounted; bundle with CKA/CKAD often available) |
| Validity | 2 years from pass date |
| Retake | One free retake included with initial registration |
| Prerequisite | CKA must be active at the time you take CKS. Not "recommended" — required. |
| Allowed during exam | One browser tab to kubernetes.io/docs, github.com/kubernetes, kubernetes.io/blog, and the docs sites for the specific tools listed in the curriculum (Falco, Trivy, etc.) |
Why this cert is different¶
Most security certs reward you for memorizing definitions. CKS rewards you for typing kubectl commands quickly while reading documentation in another tab. You will not be asked "what is a NetworkPolicy" — you will be given a cluster where two namespaces talk to each other when they shouldn't, and asked to write a NetworkPolicy YAML that fixes it, apply it, and verify.
The honest tradeoff: CKS is harder than written K8s certs because it punishes shallow knowledge brutally, but easier than something like OSCP because the scope is bounded. If you genuinely operate Kubernetes daily, 4 weeks of focused prep is realistic. If you've only used managed K8s through a UI, plan 6-8 weeks and budget time for cluster-building practice first.
Curriculum Overview¶
The published CKS curriculum has six domains. Weights below are the official CNCF percentages as of the v1.27+ refresh.
| Domain | Weight |
|---|---|
| Cluster Setup | 15% |
| Cluster Hardening | 15% |
| System Hardening | 10% |
| Minimize Microservice Vulnerabilities | 20% |
| Supply Chain Security | 20% |
| Monitoring, Logging, and Runtime Security | 20% |
Three domains tie at 20%. Together they're 60% of your score: microservice hardening, supply chain, and runtime security. If your study time is constrained, weight your prep accordingly.
Domain 1: Cluster Setup (15%)¶
Published objectives (approximately)¶
- Use Network security policies to restrict cluster level access
- Use CIS benchmark to review the security configuration of Kubernetes components (etcd, kubelet, kubeadm, kube-apiserver)
- Properly set up Ingress with TLS
- Protect node metadata and endpoints
- Verify platform binaries before deploying
What this actually means in the exam¶
You'll get a cluster where the kube-apiserver has insecure flags, the kubelet exposes its read-only port, and metadata endpoints are reachable from pods. You fix them by editing /etc/kubernetes/manifests/kube-apiserver.yaml (the static pod manifest), restarting components, and proving via curl/kubectl that the change took effect.
Nexus chapter mapping¶
- Ch 51: Kubernetes Security — primary anchor; covers control plane hardening, NetworkPolicies, ingress TLS
- Ch 31: Network Security Architecture — segmentation principles applied to pod networks
- Ch 39: Zero Trust Implementation — default-deny mindset that NetworkPolicies enforce
Labs¶
- Lab 21: Cloud Container Security — control-plane misconfig discovery
- Lab 27: K8s Attack & Defense — practice the attack-fix-verify loop you'll see on the exam
Hands-on practice (do this, don't just read about it)¶
- kube-bench: run it against a kind cluster you built yourself. Then run it against a kind cluster created with default settings. Compare. The deltas are exam questions.
- CIS Kubernetes Benchmark v1.8.0+: read the actual PDF from CIS, not a summary blog. The exam wording mirrors CIS wording.
- NetworkPolicy with Calico or Cilium: kind ships with no CNI that supports NetworkPolicy by default. Install Calico. Practice writing default-deny then opening specific ingress/egress.
- Ingress with cert-manager: deploy nginx-ingress, request a cert from a fake CA, terminate TLS. Do it from memory.
- Metadata blocking: in a cloud node,
curl http://169.254.169.254from a pod. Then write a NetworkPolicy that blocks egress to that IP. Verify both states.
Honest take on tools¶
For CIS auditing, kube-bench is the only tool you need to know for the exam. Aqua's tool. It runs as a Job, dumps a report, you read it. Alternatives like kubeaudit exist but the exam will not ask about them.
Domain 2: Cluster Hardening (15%)¶
Published objectives (approximately)¶
- Restrict access to Kubernetes API
- Use Role Based Access Controls to minimize exposure
- Exercise caution in using service accounts (e.g. disable defaults, minimize permissions on newly created ones)
- Update Kubernetes frequently
What this actually means in the exam¶
RBAC questions dominate this domain. You'll be given a YAML for a Role that grants too much, and asked to scope it down. Or you'll be given a ServiceAccount that should not be auto-mounted into a pod, and asked to fix the pod spec. You will write kubectl auth can-i commands to verify your work.
Nexus chapter mapping¶
- Ch 51: Kubernetes Security — RBAC patterns, ServiceAccount hygiene
- Ch 33: Identity & Access Security — least-privilege design principles
- Ch 46: Cloud & Container Red Team — what attackers do with overprivileged ServiceAccounts (so you know what to lock down)
Labs¶
- Lab 27: K8s Attack & Defense — RBAC abuse scenarios, then mitigation
- Lab 26: Container & K8s Red Team — attack chain that starts with a stolen SA token
Hands-on practice¶
- Disable
automountServiceAccountTokenon every default ServiceAccount in three different namespaces. Then redeploy a pod and prove the token is gone. - Write a Role that allows only
get podsinns-appfor a SA namedreader. Then write a RoleBinding. Then runkubectl auth can-i list pods --as=system:serviceaccount:ns-app:reader -n ns-appand expectno. Andget podsshould beyes. If you can do this in 90 seconds without docs, you're exam-ready for this objective. - Audit existing RBAC: install
rbac-toolfrom Insight or usekubectl-who-can. The exam itself sticks to native kubectl, but these tools train your eye for what bad RBAC looks like. - Anonymous auth: confirm
--anonymous-auth=falseon the kube-apiserver. The default in modern kubeadm clusters is false, but the exam might give you a misconfigured one.
Honest take on tools¶
The exam tests you on native kubectl + RBAC YAML. Don't waste time learning OPA Gatekeeper for this domain (it's relevant to Domain 4). Just write Roles and RoleBindings until your fingers hurt.
Domain 3: System Hardening (10%)¶
Published objectives (approximately)¶
- Minimize host OS footprint (reduce attack surface)
- Minimize IAM roles
- Minimize external access to the network
- Appropriately use kernel hardening tools such as AppArmor, seccomp
What this actually means in the exam¶
This is the smallest domain at 10%, and it's heavily about AppArmor and seccomp profiles applied to pods. Expect to be given an existing AppArmor profile on a node and asked to attach it to a pod via annotations (the older way) or securityContext.appArmorProfile (the newer way introduced in 1.30+; check which form the exam version uses).
Nexus chapter mapping¶
- Ch 51: Kubernetes Security — pod security context, seccomp, AppArmor
- Ch 46: Cloud & Container Red Team — container runtime hardening principles
Labs¶
- Lab 21: Cloud Container Security — host-level hardening exercises
- Lab 27: K8s Attack & Defense — capability dropping, syscall restriction
Hands-on practice¶
- Write a seccomp profile in JSON that blocks
unshareandmount. Place it under/var/lib/kubelet/seccomp/profiles/. Apply it to a pod viasecurityContext.seccompProfile.type: Localhost. Run the syscall from inside the pod (useunshare -r /bin/sh) and verify it's blocked. - AppArmor: write a profile that denies write to
/etc. Load it on a node withapparmor_parser. Apply it to a pod. Try totouch /etc/foofrom inside the pod. Verify the deny. runtime/defaultseccomp: set this on a pod. It's the easy mode default and the exam may accept it for partial credit on a "harden this pod" question. Know the difference betweenRuntimeDefault,Localhost, andUnconfined.- Minimize host OS: practice reading
systemctl list-units --type=service --state=runningon a node and explaining which services should not be there. The exam may ask you to disable an unnecessary service.
Honest take on tools¶
AppArmor vs seccomp vs SELinux: the exam covers AppArmor and seccomp. SELinux is mentioned in the curriculum but rarely tested deeply. Most exam clusters run Ubuntu, which uses AppArmor. Don't burn time learning SELinux policy authoring for this exam — that's a separate rabbit hole.
Domain 4: Minimize Microservice Vulnerabilities (20%)¶
Published objectives (approximately)¶
- Use appropriate pod security standards (PSS / Pod Security Admission)
- Manage Kubernetes secrets
- Understand and use container runtime sandboxes in multi-tenant environments (e.g., gvisor, kata containers)
- Implement pod-to-pod encryption using Cilium
What this actually means in the exam¶
Pod Security Admission replaced PodSecurityPolicy in 1.25. You'll label a namespace with pod-security.kubernetes.io/enforce: restricted and verify that a pod which violates the policy is rejected. Secrets questions are usually "this Secret is stored in plaintext at-rest in etcd, encrypt it" via EncryptionConfiguration.
Nexus chapter mapping¶
- Ch 51: Kubernetes Security — Pod Security Standards, secret encryption at rest
- Ch 32: Applied Cryptography — KMS providers, envelope encryption concepts
- Ch 46: Cloud & Container Red Team — runtime sandboxing tradeoffs
- Ch 39: Zero Trust Implementation — mTLS, pod-to-pod encryption
Labs¶
- Lab 21: Cloud Container Security — PSA enforcement, secrets management
- Lab 27: K8s Attack & Defense — escape attempts that sandboxing prevents
Hands-on practice¶
- Pod Security Admission: label a namespace
pod-security.kubernetes.io/enforce=baselineandpod-security.kubernetes.io/warn=restricted. Apply a privileged pod and watch it get rejected. Apply abaseline-compliant pod and watch it succeed but warn. This is exam currency. - Encrypt secrets at rest: write an
EncryptionConfigurationYAML withaescbcprovider, place it on the control plane node, point kube-apiserver at it via--encryption-provider-config, restart kube-apiserver, thenkubectl get secrets <name> -o yamland prove the data is encrypted in etcd by reading it directly withetcdctl. - gVisor (
runsc) runtime: install it on a node, register aRuntimeClass, deploy a pod withruntimeClassName: gvisor. Rundmesgfrom inside the pod (it should fail because gVisor blocks it). - OPA Gatekeeper or Kyverno: write a policy that requires every pod to have
runAsNonRoot: true. Apply a violating pod and watch the admission webhook reject it.
Honest take on policy engines¶
OPA Gatekeeper vs Kyverno: both are valid. CNCF's curriculum has historically leaned OPA Gatekeeper because OPA is also a CNCF graduated project. Kyverno is, in my opinion, friendlier for K8s-native YAML-based policies and is what most teams actually deploy in 2025-2026 because Rego is genuinely painful. For the exam: learn enough Gatekeeper to write a basic ConstraintTemplate and a Constraint. That is what's been historically tested. For the job: deploy Kyverno.
Honest take on sandboxes¶
gVisor vs Kata Containers: gVisor (Google) intercepts syscalls in userspace via runsc. Kata runs each pod in a lightweight VM. Kata gives stronger isolation but heavier overhead and worse compatibility with privileged workloads. gVisor is more commonly tested because it's easier to install on a single-node exam cluster. Know that both exist; deeply learn gVisor.
Honest take on secret management¶
The exam tests native K8s Secrets + etcd encryption. External secret managers (Vault, AWS Secrets Manager, External Secrets Operator) are not on the exam. Don't be that candidate who tries to install Vault during the test.
Domain 5: Supply Chain Security (20%)¶
Published objectives (approximately)¶
- Minimize base image footprint
- Secure your supply chain: whitelist allowed image registries, sign and validate images
- Use static analysis of user workloads (e.g., Kubernetes resources, Docker files)
- Scan images for known vulnerabilities
What this actually means in the exam¶
You'll get a Deployment YAML with a bloated ubuntu:latest base image and be asked to swap to a distroless or alpine variant. You'll get an ImagePolicyWebhook or OPA constraint that whitelists registry.example.com and have to enforce it. You'll run trivy image against a tarred image and report the highest CVSS finding.
Nexus chapter mapping¶
- Ch 54: SBOM Operations — primary anchor for software supply chain
- Ch 51: Kubernetes Security — admission controllers, image policy
- Ch 46: Cloud & Container Red Team — image hardening, base image selection
- Ch 35: DevSecOps Pipeline — CI/CD-integrated scanning patterns
- Ch 24: Supply Chain Attacks — what you're defending against
Labs¶
- Lab 21: Cloud Container Security — image scanning workflows
- Lab 26: Container & K8s Red Team — exploits that distroless images prevent
Hands-on practice¶
- Trivy image scan:
trivy image --severity HIGH,CRITICAL nginx:1.21. Read the output. Then scannginx:1.27-alpineand compare CVE counts. The delta is the value of staying current. - Dockerfile hardening: take a Dockerfile that uses
FROM ubuntu:latest, runsapt-get installfor 200 packages, and ends withUSER root. Rewrite it to usegcr.io/distroless/static-debian12andUSER 65532:65532. Build both, scan both, compare image size and CVE count. - ImagePolicyWebhook: configure the kube-apiserver with
--admission-control-config-filepointing to a config that calls an external webhook. Or use OPA Gatekeeper with a constraint that blocks any image not fromdocker.io/library/*. - Cosign + image signing: sign an image with cosign, push to a local registry, then write an admission policy that requires a valid signature. Sigstore tooling is in the curriculum scope.
- kubesec, Checkov: static analysis of YAML manifests. Run
kubesec scan deployment.yamland read the score. The exam uses kubesec specifically.
Honest take on image scanners¶
Trivy vs Grype vs Snyk: Trivy (Aqua) is the de-facto exam tool. Free, open source, scans images, filesystems, repos, and IaC. Grype (Anchore) is a strong alternative with arguably better SBOM-centric workflows. Snyk is paid SaaS and not on the exam. For CKS, learn Trivy syntax cold. Specifically: trivy image, trivy fs, trivy config, trivy k8s.
Honest take on base images¶
scratch vs distroless vs alpine: scratch is empty and only works for static binaries. Distroless (Google) gives you a minimal runtime but no shell — making forensics harder but attack surface smaller. Alpine is small but has had its share of CVEs and uses musl libc which trips up some Go binaries (DNS resolution). The exam-correct answer for "minimize footprint" is usually distroless or scratch. The job-correct answer depends on whether your team can debug a no-shell container at 2 AM.
Domain 6: Monitoring, Logging, and Runtime Security (20%)¶
Published objectives (approximately)¶
- Perform behavioral analytics of syscall process and file activities at the host and container level to detect malicious activities
- Detect threats within physical infrastructure, apps, networks, data, users, and workloads
- Detect all phases of attack regardless where it occurs and how it spreads
- Perform deep analytical investigation and identification of bad actors within environment
- Ensure immutability of containers at runtime
- Use Kubernetes audit logs to monitor access
What this actually means in the exam¶
Two big things: Falco rules and kube-apiserver audit policy. You'll be given a half-written Falco rule and asked to complete it so it triggers on a specific syscall. You'll be given an audit policy YAML and asked to log all secrets access at Metadata level but pods/exec at RequestResponse level. Container immutability questions are usually about readOnlyRootFilesystem: true in pod securityContext.
Nexus chapter mapping¶
- Ch 51: Kubernetes Security — audit logging, runtime detection patterns
- Ch 5: Detection Engineering at Scale — rule authoring methodology
- Ch 38: Advanced Threat Hunting — behavioral baseline establishment
- Ch 46: Cloud & Container Red Team — readOnlyRootFilesystem, capability dropping
Labs¶
- Lab 21: Cloud Container Security — Falco deployment and rule writing
- Lab 27: K8s Attack & Defense — runtime detection of escape attempts
Hands-on practice¶
- Falco rule authoring: install Falco on a node. Read
/etc/falco/falco_rules.yaml. Write a custom rule under/etc/falco/falco_rules.local.yamlthat triggers onopenof/etc/shadowfrom a container. Trigger it. Find the alert injournalctl -u falco. - Audit policy: write a Policy resource that logs:
secrets,configmapsatMetadatalevelpods/exec,pods/attach,pods/portforwardatRequestResponselevel- everything else at
NoneApply it via--audit-policy-fileand--audit-log-pathflags on kube-apiserver. Verify the log is written. Read it. - Immutable containers: take a Deployment, add
securityContext.readOnlyRootFilesystem: true. Watch the app crash because it tries to write to/tmp. Add an emptyDir volume mounted at/tmp. Watch it work. This pattern is exam currency. - Strace from outside: not on the exam directly, but practicing
strace -p $(pidof nginx)on a pod's PID from the node teaches you what Falco is wrapping.
Honest take on runtime tools¶
Falco vs Tetragon: Falco (Sysdig, CNCF graduated) uses kernel modules or eBPF to watch syscalls and matches against a rule DSL. Tetragon (Isovalent/Cilium, also eBPF-based) is newer, integrates tightly with Cilium, and supports inline enforcement (kill the process), not just detection. For the exam: Falco only. Tetragon is genuinely better for production runtime defense in 2025-2026 in my opinion, especially if you're already on Cilium, but CKS has not adopted it yet.
Sysdig commercial vs Falco: Sysdig is the company behind Falco. Their commercial product wraps Falco with a UI, threat feeds, and SIEM integration. Exam doesn't care.
Realistic Study Schedule¶
These timelines assume you already hold an active CKA. If you don't, stop reading this and go pass CKA first. CKS without CKA fundamentals is impossible.
Track A: Daily K8s operator (4 weeks)¶
You troubleshoot production K8s weekly. You can write a Deployment YAML from memory. You know the difference between a Service and an Ingress without thinking.
| Week | Focus | Deliverable |
|---|---|---|
| 1 | Domains 1 + 2 (Cluster Setup + Hardening). kube-bench, RBAC, NetworkPolicies. | A locally hardened kind cluster scoring ≥90% on kube-bench. |
| 2 | Domains 3 + 4 (System Hardening + Microservice). seccomp, AppArmor, PSA, secret encryption. | One pod hardened to restricted PSA with custom seccomp + AppArmor. |
| 3 | Domains 5 + 6 (Supply Chain + Runtime). Trivy, image signing, Falco, audit policy. | Working Falco install with a custom rule that detects shadow file access; a working audit policy. |
| 4 | Killer.sh simulator x2. Speed drills. Weak-area review. | Two full Killer.sh runs with score ≥75%. |
Track B: Managed K8s consumer (6-8 weeks)¶
You use EKS/GKE/AKS through cloud consoles. You've never bootstrapped a cluster with kubeadm. You know what a pod is but rarely write YAML by hand.
| Week | Focus | Deliverable |
|---|---|---|
| 1 | Pre-work: build a 3-node kubeadm cluster on Vagrant or LXC. Repeat from scratch until you can do it in 30 minutes. | Working cluster you destroyed and rebuilt three times. |
| 2 | Domain 1 (Cluster Setup). CIS benchmark, kube-bench, ingress TLS, metadata blocking. | kube-bench score ≥85% on your hand-built cluster. |
| 3 | Domain 2 (Cluster Hardening). RBAC YAML until your fingers hurt. | 20 RBAC scenarios solved without docs. |
| 4 | Domain 3 (System Hardening). AppArmor + seccomp profiles. | Custom seccomp profile blocking unshare applied to a running pod. |
| 5 | Domain 4 (Microservice Vulns). PSA, secret encryption, gVisor, OPA Gatekeeper basics. | Fully encrypted-at-rest secrets verified via etcdctl. |
| 6 | Domain 5 (Supply Chain). Trivy, distroless, image admission policies. | Hardened Dockerfile with ≤5 CRITICAL CVEs. |
| 7 | Domain 6 (Runtime). Falco rules, audit policy, immutable containers. | Custom Falco rule + custom audit policy both live and producing alerts. |
| 8 | Killer.sh x2, speed drills, exam booking. | ≥70% on second Killer.sh attempt. |
Hours per week¶
Plan for 8-12 hours/week. Of that, at least 60% must be hands-on terminal time. Reading without typing is wasted time on this exam. Watch a video, then immediately replicate what you saw on your own cluster.
What "ready" looks like¶
You're ready when you can:
- Solve any Killer.sh question in under the suggested time without consulting docs except for syntax confirmation.
- Write a NetworkPolicy YAML, RBAC Role + RoleBinding, and Pod securityContext from memory.
- Bookmark the kubernetes.io docs sections you'll need (NetworkPolicy, RBAC, Pod Security, Audit, Encryption Configuration) so you can navigate to them in <5 seconds during the exam.
Exam-Day Tactics (Killer.sh-Style)¶
Killer.sh is the practice simulator that comes free with your CKS exam registration (two attempts, each active for 36 hours). It is harder than the real exam. This is a deliberate gift. If you score 50% on Killer.sh, you'll likely pass the real CKS at 67%. If you score 70% on Killer.sh, you'll comfortably pass.
Tactical advice that actually moves the needle¶
- Set up your aliases on the very first question. The exam now ships with
alias k=kubectlpre-configured in some environments, but always verify. Addexport do='--dry-run=client -o yaml'andexport now='--grace-period=0 --force'. Save 30 seconds per question across 17 questions equals ~8 minutes — could be a full extra question. - Use
kubectl explainconstantly.k explain pod.spec.securityContext --recursive | lessshows you every field. The exam allows it. Faster than the docs tab for syntax lookups. - Always switch context first. Each question specifies which cluster/context to use. Run
kubectl config use-context <name>before anything else. Forgetting this and modifying the wrong cluster is the most common way candidates lose points. - Read the question twice. Then read it once more. CKS questions are precise. "Modify the Deployment named X in namespace Y" means exactly that pod, exactly that namespace. If you fix the wrong one, zero credit.
- Flag and skip. If a question takes longer than 8 minutes, flag it and move on. 17 questions in 120 minutes means 7 minutes average. Easy questions take 3 minutes; gnarly ones take 12. Don't let one question eat your exam.
- Verify your work. Every question has a verification step you should do yourself. After applying a NetworkPolicy, run a curl from a pod to prove it's blocked. After fixing RBAC, run
kubectl auth can-i. Submitting a fix without verifying is how you lose points to typos. - Don't memorize YAML — bookmark and copy. The kubernetes.io docs has working examples for every resource type. Find them in advance. Know which page each lives on. Copy, modify, paste. Faster than typing from scratch.
- vim or nano, your choice. Both are installed. The exam terminal has reasonable defaults but check if
set pasteor equivalent is needed before pasting YAML. Mangled indentation kills you. - The PSI proctor will be picky. Clear your desk. Multiple monitors are a no. ID needs to be the exact name on your CNCF account.
Recommended Hardening Tools by Category (Honest Opinions)¶
Image scanning¶
- Trivy (Aqua, free, open source): Exam-tested. Daily-driver good. Fast, accurate, scans almost everything (images, fs, IaC, K8s). Recommended.
- Grype (Anchore, free, open source): Strong alternative. Better integration with Syft for SBOM generation. Slightly slower in my experience.
- Clair (RedHat/Quay): Designed for registry-side scanning. Heavier to operate. Skip unless you're running Quay.
- Snyk (commercial SaaS): Excellent UX, dev-friendly. Costs money. Not relevant to CKS exam.
Runtime security¶
- Falco (Sysdig, CNCF graduated, free): Exam-tested. eBPF or kernel module. Detect-only (no inline kill). Solid rule DSL. Recommended for exam and reasonable for production detection.
- Tetragon (Isovalent/Cilium, free): eBPF-native, supports inline enforcement, integrates with Cilium policies. My recommendation for production in 2026 if you're already on Cilium. Not on the exam.
- Sysdig Secure (commercial): Falco wrapped with UI, threat intel, response automation. Worth the money for SOC teams who don't want to operate Falco raw.
Policy engines¶
- OPA Gatekeeper (CNCF graduated, free): Exam-tested. Rego language. Powerful but Rego is genuinely painful to debug. Required for exam.
- Kyverno (CNCF graduated, free): K8s-native YAML policies. Easier to write, easier to debug, faster to ship. Recommended for production, especially if your team is YAML-fluent but not Rego-fluent.
- PSA (Pod Security Admission): Built-in to K8s. Three tiers: privileged, baseline, restricted. Exam-tested. Use it. It replaced PodSecurityPolicy.
CIS benchmark scanning¶
- kube-bench (Aqua, free): Exam-tested. Only tool you need. Run as a Job, read the output.
Vulnerability discovery on a live cluster¶
- kube-hunter (Aqua, free): Active and passive K8s pentest tool. Mentioned in CKS curriculum. Run it against your kind cluster to see what an attacker sees.
SBOM generation¶
- Syft (Anchore, free): Generates SBOMs in SPDX or CycloneDX. Pairs with Grype.
- Trivy (also generates SBOMs): One-stop shop. My pick if you're already using Trivy.
Secrets at rest¶
- Native EncryptionConfiguration with
aescbcoraesgcm: Exam-tested. Sufficient for the exam. - KMS provider (AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault): Production-grade. Mentioned in curriculum but rarely deeply tested.
- External Secrets Operator + Vault: My production recommendation. Not on exam.
Image signing¶
- Cosign / Sigstore: Exam-relevant. Easy CLI, no key infrastructure required for keyless signing.
- Notary v2: OCI-native. Less common in practice than Cosign.
Common Pitfalls Real Candidates Hit¶
These are repeated patterns from candidate write-ups and forum threads — not invented stats, just patterns I've seen recur.
-
Treating CKS like a written exam. Reading three CKS books and zero hands-on terminal hours equals failure. The exam doesn't ask you to define things; it asks you to do them. Type more, read less.
-
Skipping the
kubectl config use-contextstep. You will modify the wrong cluster. You will lose points. Every. Single. Question. Switch contexts first. -
Forgetting to verify. You apply a NetworkPolicy and assume it works. The grader checks whether traffic is actually blocked. If you didn't
kubectl execinto a pod and curl the target to prove the block, the grader's automated check is the only verification — and if it fails, you lose all the points even though the YAML "looks right." -
Spending 20 minutes on one Falco rule. The runtime domain is 20% of the exam — about 3-4 questions. One Falco question is worth ~5% of your total grade. Don't bleed time.
-
Not knowing where the docs are. The exam allows kubernetes.io/docs and the docs sites for specific tools. If you've never used the K8s docs before exam day, you'll fumble the navigation. Practice docs-driven solving during prep.
-
Ignoring the audit log question. Every CKS exam in recent memory has included at least one audit policy question. Practice writing audit Policy YAML until you can do it cold.
-
Stale curriculum. The CNCF refreshes the CKS curriculum roughly annually with new K8s versions. Pod Security Admission replaced PodSecurityPolicy in 1.25 — anyone studying from a 2022 book is wasting time. Always check the official curriculum PDF on cncf.io/training before you start.
-
Underestimating Killer.sh. Candidates see their first Killer.sh score (often 30-40%) and panic, then either give up or push the exam date. Killer.sh is intentionally harder than the real exam. A Killer.sh score of 50% suggests you're pass-ready.
-
Booking the exam before you're ready. The free retake softens this, but burning a retake on an unprepared first attempt is still a waste. Take Killer.sh first, hit ~50%, then book.
-
Forgetting that kubectl is fast and you are slow. Practice typing common patterns (NetworkPolicy YAML, RBAC Role, Pod with securityContext) until your fingers know them. The exam clock is unforgiving.
After CKS: Where to Go Next¶
CKS unlocks several legitimate paths. None are "do this next" universal — pick the one that matches your actual job direction.
If you don't already hold them¶
- CKA (Certified Kubernetes Administrator): Required prerequisite for CKS, so by definition you have it. Mentioned for completeness.
- CKAD (Certified Kubernetes Application Developer): Worth holding if you write apps that run on K8s, otherwise skip.
Cloud-specific Kubernetes certs¶
- AWS Certified Security – Specialty (SCS-C02) or its EKS-focused content. Useful if EKS is your daily driver.
- Google Professional Cloud Security Engineer: GKE-heavy security cert. Solid for GKE shops.
- Azure AZ-500 (Azure Security Engineer Associate): AKS coverage included. Good for Azure-first orgs.
Honest take: cloud security certs overlap heavily with CKS on the K8s portion but add cloud IAM, KMS, and networking depth. Pick the one matching your cloud, not all three.
Adjacent cloud-native security certs¶
- PCNSE (Prisma Cloud Native Security Engineer) or similar vendor certs: Vendor-locked but useful if your org uses that vendor.
- GCSA (GIAC Cloud Security Automation): SANS, expensive, deep on infrastructure-as-code security.
Offensive K8s direction¶
- Hack The Box Certified Web Exploitation Expert or TCM Security Practical Network Penetration Tester: not K8s-specific but the methodology overlaps.
- OSCP (PEN-200): General offensive cert. If you want to red-team K8s for a living, this plus CKS is a strong combo.
- CSTM (Certified Security Testing Master) or GMOB / GCIH for IR-leaning offense.
What I'd actually recommend¶
If you just passed CKS and your job is K8s ops:
- Go deeper on Cilium + Tetragon (eBPF networking and security). Out of scope for CKS but where the industry is moving in 2026.
- Learn OPA + Conftest for IaC policy enforcement upstream of K8s.
- Pick up External Secrets Operator + Vault for production-grade secrets.
- Read every post-mortem you can find on K8s security incidents (Tesla cryptojacking, the Argo CD CVEs, the etcd exposure incidents). Pattern-match real-world failure modes.
If you just passed CKS and your job is offensive:
- Study container escape techniques cold (CVE-2022-0185, CVE-2024-21626 runc, etc.).
- Practice K8s pivoting from a compromised pod — service account token abuse, kubelet API abuse, etcd direct read.
- Stand up a deliberately vulnerable cluster (Bust-a-Kube, Kubernetes Goat) and exploit it end to end.
Mapped Resources Summary¶
| Resource | Purpose |
|---|---|
| Ch 51: Kubernetes Security | Primary CKS chapter; covers all six domains |
| Ch 46: Cloud & Container Red Team | Container runtime hardening, base image strategy |
| Ch 46: Cloud & Container Red Team | Attack perspective: what you're hardening against |
| Ch 54: SBOM Operations | Supply chain anchor for Domain 5 |
| Ch 35: DevSecOps Pipeline | CI/CD-integrated scanning patterns |
| Ch 24: Supply Chain Attacks | Threat model context for Domain 5 |
| Ch 32: Applied Cryptography | KMS, envelope encryption for secret-at-rest |
| Ch 5: Detection Engineering | Falco rule authoring methodology |
| Ch 38: Advanced Threat Hunting | Behavioral baseline for runtime detection |
| Lab 21: Cloud Container Security | Hands-on hardening |
| Lab 26: Container & K8s Red Team | Attack-side perspective |
| Lab 27: K8s Attack & Defense | Full attack-fix-verify loop |
One-Page Ready Check¶
Before booking the exam, confirm you can do all of these from memory in under the listed time:
- [ ] Build a kubeadm cluster from scratch on Linux nodes (30 min)
- [ ] Run kube-bench and interpret the output (10 min)
- [ ] Write and apply a NetworkPolicy that default-denies ingress in a namespace, then opens one specific path (5 min)
- [ ] Write a Role + RoleBinding scoped to one verb on one resource for one ServiceAccount (3 min)
- [ ] Disable
automountServiceAccountTokenon a pod and verify (2 min) - [ ] Apply a custom seccomp profile to a pod and verify a blocked syscall (8 min)
- [ ] Apply Pod Security Admission
restrictedto a namespace and prove a privileged pod is rejected (5 min) - [ ] Configure EncryptionConfiguration for secrets and verify with etcdctl (15 min)
- [ ] Scan a container image with Trivy and identify CRITICAL CVEs (3 min)
- [ ] Write a Falco rule that detects a specific file access (10 min)
- [ ] Write a kube-apiserver audit Policy and verify the log (12 min)
- [ ] Mark a container as
readOnlyRootFilesystem: trueand add the volumes it needs to still function (5 min)
If any of these take 2x the time listed or you can't do them without docs, that's your weak spot. Drill it.
Pass rate optimism: candidates who systematically check each of these boxes generally report passing. Candidates who skip the verification steps or skip Killer.sh report failing. The exam is fair but unforgiving.
YAML Patterns You Should Have Memorized¶
The exam clock punishes candidates who type from scratch. These are the patterns that appear with high frequency in exam questions and Killer.sh — practice them until you can write each in under two minutes without reference.
Default-deny NetworkPolicy¶
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: app
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Then open one path with a second policy:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend-to-backend
namespace: app
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080
The trap: forgetting that policyTypes: [Ingress, Egress] with no rules means deny-all-egress including DNS. Most candidates lose points by breaking DNS resolution. Add a separate egress allow for kube-dns on port 53/UDP.
RBAC Role + RoleBinding for a ServiceAccount¶
apiVersion: v1
kind: ServiceAccount
metadata:
name: pod-reader-sa
namespace: app
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
namespace: app
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: pod-reader-binding
namespace: app
subjects:
- kind: ServiceAccount
name: pod-reader-sa
namespace: app
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
Verify:
kubectl auth can-i list pods --as=system:serviceaccount:app:pod-reader-sa -n app
# yes
kubectl auth can-i create pods --as=system:serviceaccount:app:pod-reader-sa -n app
# no
Hardened Pod securityContext (PSA-restricted compliant)¶
apiVersion: v1
kind: Pod
metadata:
name: hardened
namespace: app
spec:
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
runAsUser: 65532
runAsGroup: 65532
fsGroup: 65532
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: registry.example.com/distroless-app:1.0
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
This pod will pass pod-security.kubernetes.io/enforce: restricted. If your exam question is "harden this pod to pass restricted PSA," this template is your answer.
EncryptionConfiguration for secrets at rest¶
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded 32-byte key>
- identity: {}
Place at /etc/kubernetes/enc/enc.yaml (any path works as long as kube-apiserver can read it). Add to kube-apiserver static pod manifest:
spec:
containers:
- command:
- kube-apiserver
- --encryption-provider-config=/etc/kubernetes/enc/enc.yaml
volumeMounts:
- name: enc
mountPath: /etc/kubernetes/enc
readOnly: true
volumes:
- name: enc
hostPath:
path: /etc/kubernetes/enc
type: DirectoryOrCreate
After restart, force re-encryption of existing secrets:
Verify with etcdctl that the data is no longer plaintext:
ETCDCTL_API=3 etcdctl \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
get /registry/secrets/default/<secret-name>
You should see k8s:enc:aescbc:v1:key1: as the prefix. If you see plaintext, you forgot to re-encrypt.
Audit Policy YAML¶
apiVersion: audit.k8s.io/v1
kind: Policy
omitStages:
- RequestReceived
rules:
- level: RequestResponse
resources:
- group: ""
resources: ["pods/exec", "pods/attach", "pods/portforward"]
- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps"]
- level: None
users: ["system:kube-proxy"]
- level: Metadata
Wire into kube-apiserver:
--audit-policy-file=/etc/kubernetes/audit/policy.yaml
--audit-log-path=/var/log/kubernetes/audit.log
--audit-log-maxage=30
--audit-log-maxbackup=10
--audit-log-maxsize=100
Mount the volumes (audit policy file and log directory) into the static pod manifest. Restart. Tail the log to verify entries appear.
Falco custom rule¶
- rule: Read sensitive file in container
desc: Detect read of /etc/shadow from inside a container
condition: >
open_read and container and fd.name in (/etc/shadow)
output: >
Sensitive file read in container
(user=%user.name container=%container.name file=%fd.name)
priority: WARNING
tags: [filesystem, secrets]
Place at /etc/falco/falco_rules.local.yaml. Restart falco. Trigger by exec'ing into a pod and running cat /etc/shadow (or head /etc/shadow). Check journalctl -u falco -f for the alert.
OPA Gatekeeper ConstraintTemplate + Constraint¶
ConstraintTemplate (defines the policy logic in Rego):
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
type: object
properties:
labels:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg}] {
required := input.parameters.labels
provided := input.review.object.metadata.labels
missing := required[_]
not provided[missing]
msg := sprintf("Missing required label: %v", [missing])
}
Constraint (applies the policy with parameters):
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: ns-must-have-owner
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
labels: ["owner"]
Apply both. Try to create a namespace without the owner label. The webhook should reject it.
Cluster Lab Setup for Practice¶
Don't pay for managed K8s during prep. Build local clusters. Two approaches that work:
Option A: kind (Kubernetes in Docker)¶
Fastest to spin up, lightest on resources. Single binary install.
Where kind-config.yaml defines a 3-node cluster:
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
Tradeoff: kind doesn't behave exactly like a real kubeadm cluster. The control plane runs in a container. You can't easily edit /etc/kubernetes/manifests/kube-apiserver.yaml because the control plane process is wrapped. For exercises that require touching static pod manifests, kind is awkward.
Option B: kubeadm on multipass / vagrant / lxc¶
Slower setup but mirrors the real exam environment. You get real nodes, real systemd, real /etc/kubernetes/manifests/, real kubelet.
# On each node, after multipass launch ubuntu instances:
sudo apt-get update && sudo apt-get install -y kubeadm kubelet kubectl
# On control plane:
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
# Apply Calico for NetworkPolicy support:
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.0/manifests/calico.yaml
# On workers, run the join command kubeadm printed.
This is the right environment for exam prep. Use it.
Option C: Killercoda free K8s playgrounds¶
killercoda.com (same company as Killer.sh) offers free interactive K8s scenarios in browser. Useful for spot-practice when you don't want to spin up a local cluster. Not a replacement for real practice clusters but good for short drills.
Quick-Reference: kube-apiserver Hardening Flags¶
CIS benchmark items that frequently appear on the exam, with the correct flag setting. Memorize the direction of each (some default to insecure, some default to secure).
| Flag | Secure setting | Why |
|---|---|---|
--anonymous-auth | false | Prevent unauthenticated API access |
--insecure-port | removed in 1.20+ | If somehow present, set to 0 |
--profiling | false | Disable Go profiling endpoints |
--audit-log-path | set to a path | Required for audit logging |
--audit-log-maxage | 30 (or per CIS) | Log retention |
--audit-log-maxbackup | 10 | Log rotation |
--audit-log-maxsize | 100 | Per-file size cap |
--encryption-provider-config | path to config | Required for secret encryption |
--authorization-mode | Node,RBAC | Never AlwaysAllow |
--enable-admission-plugins | include NodeRestriction, PodSecurity, ImagePolicyWebhook (when applicable) | Defense in depth |
--service-account-key-file | set | SA token verification |
--service-account-lookup | true | Validate SA tokens against API |
--kubelet-certificate-authority | set | Verify kubelet cert chain |
--tls-cert-file / --tls-private-key-file | set | API server TLS |
--client-ca-file | set | Client cert verification |
--etcd-cafile / --etcd-certfile / --etcd-keyfile | set | mTLS to etcd |
The exam often phrases these as "the kube-apiserver is configured insecurely. Fix it." Open /etc/kubernetes/manifests/kube-apiserver.yaml, edit the flag, save. The kubelet detects the manifest change and restarts the static pod within ~30 seconds. Don't systemctl restart kubelet unless you're sure — it's usually unnecessary.
kubelet Hardening Flags¶
Edit /var/lib/kubelet/config.yaml (or the systemd dropin at /etc/systemd/system/kubelet.service.d/10-kubeadm.conf).
| Setting | Secure value | Why |
|---|---|---|
authentication.anonymous.enabled | false | No anonymous kubelet API |
authentication.webhook.enabled | true | Use SubjectAccessReview |
authorization.mode | Webhook | Never AlwaysAllow |
readOnlyPort | 0 | Disable the unauthenticated read-only port |
protectKernelDefaults | true | Refuse to start if kernel sysctls don't match expected secure defaults |
streamingConnectionIdleTimeout | 5m (or per CIS) | Close idle exec/attach streams |
tlsCertFile / tlsPrivateKeyFile | set | kubelet API TLS |
clientCAFile | set | Verify clients (e.g., kube-apiserver) |
eventRecordQPS | 0 (per CIS, unlimited recording) | Don't drop security-relevant events |
makeIPTablesUtilChains | true | Manage iptables chains for service routing |
After editing kubelet config: systemctl restart kubelet and verify with systemctl status kubelet. If kubelet refuses to start, you have a typo. Roll back, fix, retry.
Practice Drill: Solve This in 10 Minutes¶
A representative CKS-style exam question, written in the same style as Killer.sh:
Context: cluster
cluster1, namespaceprod.A Deployment named
paymentsis running with overprivileged RBAC. The ServiceAccountpayments-sacurrently has cluster-admin via a ClusterRoleBinding namedpayments-admin-binding.Tasks: 1. Remove the cluster-admin binding for
payments-sa. 2. Create a Role in theprodnamespace namedpayments-rolethat grants onlygetandlistonpodsandconfigmaps. 3. Bind the Role topayments-sawith a RoleBinding namedpayments-binding. 4. Verifypayments-sacanget podsinprodbut cannotdelete podsor access any other namespace.Do not modify the Deployment itself.
Solution path (under 10 minutes if drilled):
kubectl config use-context cluster1
kubectl delete clusterrolebinding payments-admin-binding
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: payments-role
namespace: prod
rules:
- apiGroups: [""]
resources: ["pods", "configmaps"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: payments-binding
namespace: prod
subjects:
- kind: ServiceAccount
name: payments-sa
namespace: prod
roleRef:
kind: Role
name: payments-role
apiGroup: rbac.authorization.k8s.io
EOF
kubectl auth can-i get pods --as=system:serviceaccount:prod:payments-sa -n prod
# expected: yes
kubectl auth can-i delete pods --as=system:serviceaccount:prod:payments-sa -n prod
# expected: no
kubectl auth can-i get pods --as=system:serviceaccount:prod:payments-sa -n default
# expected: no
If you can do this drill cleanly in 10 minutes from a cold start (no docs except for syntax), you are exam-pace for this domain. If it takes 20 minutes, drill RBAC YAML more.