Completed upto lesson 35

This commit is contained in:
Mosiur Rahman
2026-08-26 19:37:55 +06:00
parent 639e69484c
commit eaef1c17a7
20 changed files with 1586 additions and 0 deletions

597
CKS-MASTERY-CHECKLIST.md Normal file
View File

@@ -0,0 +1,597 @@
# CKS Mastery Checklist
Canonical progress record for CKS preparation. Update this file after every graded task so another computer or agent can resume without relying on chat history.
## Dashboard
Last updated: 2026-08-26
| Domain | Weight | Hero | Training | Not started | Total |
|---|---:|---:|---:|---:|---:|
| Cluster Setup | 15% | 0 | 5 | 0 | 5 |
| Cluster Hardening | 15% | 0 | 3 | 1 | 4 |
| System Hardening | 10% | 0 | 2 | 2 | 4 |
| Minimize Microservice Vulnerabilities | 20% | 0 | 4 | 0 | 4 |
| Supply Chain Security | 20% | 0 | 3 | 1 | 4 |
| Monitoring, Logging and Runtime Security | 20% | 0 | 5 | 0 | 5 |
| **Total** | **100%** | **0** | **22** | **4** | **26** |
The syllabus supplied for this program contains 26 tracked topics.
## Status Legend
- `[ ] NOT STARTED`: no dedicated practical evidence.
- `[~] TRAINING`: relevant lessons exist, but the Hero gate is incomplete.
- `[x] HERO`: tool drill, timed capstone, evidence, and cold retest all passed.
- `BLOCKED`: environment prevents practice; record the exact limitation and use a valid alternate environment.
## Hero Gate
A topic becomes Hero only when every item is checked:
- [ ] Tool drill completed using the topic's primary operational tools.
- [ ] Original capstone completed at exam difficulty or harder within its time limit.
- [ ] Verification evidence saved: commands plus meaningful output, not YAML alone.
- [ ] No critical security or scope error remains after review.
- [ ] Cold retest passed in a later session without stepwise prompting.
- [ ] Evidence paths and date added to this checklist.
Minor syntax corrections during training are expected. A cold retest fails when the solution needs field-by-field coaching, grants excess privilege, breaks required behavior, omits proof, or changes resources outside scope.
## Resume Protocol
1. Read `MISSION.md`, `NOTES.md`, the newest learning record, and this file.
2. Show the dashboard and list Hero, Training, Not Started, and Blocked topics.
3. Continue `Next task` unless the learner selects another topic.
4. Save each answer under `lab/`, each lesson under `lessons/`, and durable insight under `learning-records/`.
5. After grading, update status, Hero-gate boxes, evidence, attempt log, dashboard counts, and `Next task`.
6. Show the learner the updated done-versus-remaining summary.
## Next Task
`CS-02.Q1` in progress as Lesson 0036: run a kube-bench-based CIS review and separate automated findings from manual checks across kube-apiserver, etcd, kubelet, and CoreDNS.
---
## Cluster Setup - 15%
### CS-01 - Use network security policies to restrict cluster-level access
Status: `[~] TRAINING`
Tools: `kubectl`, NetworkPolicy API, `curl`/`wget`, temporary test Pods, CNI policy observability where available.
Prior evidence: Lessons 0002, 0008, 0029, and 0034. The learner can build default-deny and selector-scoped ingress/egress policies, include CoreDNS, and combine Namespace and Pod selectors.
Question bank:
- `CS-01.Q1` - Given five namespaces and six traffic requirements, produce the minimum additive policy set and prove every allowed and denied flow with disposable client Pods.
- `CS-01.Q2` - Repair a policy where split peer items accidentally OR namespace and Pod selectors; demonstrate the over-permitted flow before and denial after.
- `CS-01.Q3` - Isolate control-plane and node endpoints from an application namespace while preserving DNS and one internal API dependency.
- `CS-01.Q4` - Hard capstone: troubleshoot a syntactically valid policy that has no effect because of selectors, CNI behavior, or existing additive policies; submit packet-flow evidence.
Hero-specific acceptance: prove ingress and egress outcomes, explain additive policy behavior, and avoid wildcard peers, IP-based shortcuts, or accidental DNS failure.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### CS-02 - Use CIS benchmarks to review Kubernetes components
Status: `[~] TRAINING`
Tools: `kube-bench`, `systemctl`, `ps`, `grep`, `kubectl`, static manifests, kubelet config, CoreDNS ConfigMap.
Prior evidence: Lessons 0015, 0022, 0028, and 0035 cover kubelet and kube-apiserver manually. Dedicated kube-bench, etcd, and CoreDNS review evidence is missing.
Question bank:
- `CS-02.Q1` - Run `kube-bench` for control-plane and node checks; classify PASS, FAIL, WARN, and manual checks without blindly applying recommendations.
- `CS-02.Q2` - Harden an etcd static manifest: client certificate authentication, peer TLS, trusted CAs, ownership, and metrics exposure; preserve cluster membership flags.
- `CS-02.Q3` - Review kubelet flags plus `KubeletConfiguration`, reconcile conflicting settings, and verify the effective running process.
- `CS-02.Q4` - Review CoreDNS deployment, ServiceAccount, RBAC, ConfigMap, image, and security context; distinguish CIS-relevant component configuration from workload hardening.
- `CS-02.Q5` - Hard capstone: given kube-bench output containing false positives and manual checks, remediate only proven failures across API server, etcd, kubelet, and CoreDNS.
Hero-specific acceptance: correlate scanner output with effective configuration and preserve required component behavior.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### CS-03 - Properly set up Ingress with TLS
Status: `[~] TRAINING`
Tools: `openssl`, `kubectl`, Ingress API, TLS Secrets, `curl -vk`, `openssl s_client`.
Prior evidence: Lesson 0016. Ingress v1 nesting and host alignment required correction; live certificate inspection needs more practice.
Question bank:
- `CS-03.Q1` - Generate a certificate and key, create a TLS Secret, configure v1 Ingress, and verify hostname, chain, and backend routing.
- `CS-03.Q2` - Repair mismatched rule host, TLS host, Secret namespace, backend schema, and path type without changing the Service.
- `CS-03.Q3` - Use `openssl s_client` and `curl --resolve` to distinguish certificate, DNS, Ingress, and backend failures.
- `CS-03.Q4` - Hard capstone: migrate two HTTP routes to TLS with separate hostnames and prove that plaintext behavior matches stated redirect requirements.
Hero-specific acceptance: certificate identity, Secret scope, route semantics, and end-to-end TLS evidence must all be correct.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### CS-04 - Protect node metadata and endpoints
Status: `[~] TRAINING`
Tools: NetworkPolicy, `curl`, cloud metadata addresses, CNI policy tools, workload identity controls, `ss`, `systemctl`, kubelet configuration, client certificates.
Prior evidence: Lessons 0015, 0028, and 0029 cover link-local metadata isolation plus kubelet anonymous auth, webhook modes, read-only port, and certificate rotation.
Question bank:
- `CS-04.Q1` - Demonstrate metadata reachability from a disposable Pod, then deny it without breaking required internal egress.
- `CS-04.Q2` - Compare broad `ipBlock` denial with positive egress allowlisting and explain residual paths through proxies or host networking.
- `CS-04.Q3` - Harden a cloud workload using both network isolation and workload identity rather than static cloud credentials.
- `CS-04.Q4` - Hard capstone: contain metadata access for selected tenants while preserving DNS, API-server access, and one external HTTPS destination.
- `CS-04.Q5` - Enumerate listening Kubernetes node endpoints and identify which require authentication, authorization, or removal.
- `CS-04.Q6` - Harden kubelet config and prove anonymous requests fail while authorized health and management paths remain functional.
- `CS-04.Q7` - Review metrics, health, debug, and read-only ports; distinguish binding exposure from application-layer authorization.
- `CS-04.Q8` - Hard capstone: remediate metadata, kubelet, and node-firewall exposure together, then prove effective endpoint behavior.
Hero-specific acceptance: show before-and-after metadata requests, verify listening sockets and authenticated endpoint behavior, and identify NetworkPolicy limitations for host-network or unsupported CNI cases.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### CS-05 - Verify platform binaries before deploying
Status: `[~] TRAINING`
Tools: `sha256sum`/`Get-FileHash`, signed checksum files, `gpg`, release metadata, package-manager verification.
Prior evidence: Lesson 0019 verifies pinned Kubernetes binaries against checksums.
Question bank:
- `CS-05.Q1` - Download a pinned Kubernetes binary and official checksum, verify it, and record provenance.
- `CS-05.Q2` - Detect a tampered binary among valid artifacts without executing any candidate.
- `CS-05.Q3` - Verify a signed checksum manifest with GPG, then verify the binary against that trusted manifest.
- `CS-05.Q4` - Hard capstone: build a repeatable verification chain for kubelet, kubectl, and a security scanner, including failure handling.
Hero-specific acceptance: pin versions, verify the trust root, fail closed on mismatch, and save exact commands and hashes.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
---
## Cluster Hardening - 15%
### CH-01 - Use RBAC to minimize exposure
Status: `[~] TRAINING`
Tools: `kubectl auth can-i`, `kubectl auth reconcile`, RBAC API, impersonation flags, structured manifest inspection.
Prior evidence: Lessons 0003, 0009, and 0024. Namespace scope, subresources, `resourceNames`, and negative permission tests are established strengths after correction.
Question bank:
- `CH-01.Q1` - Replace a wildcard Role with the smallest verbs, API groups, resources, subresources, and named resources that satisfy a workload.
- `CH-01.Q2` - Find privilege-escalation paths involving bind, escalate, impersonate, token creation, and workload creation.
- `CH-01.Q3` - Prove positive and negative permissions using impersonation for users, groups, and ServiceAccounts.
- `CH-01.Q4` - Hard capstone: remediate overlapping RoleBindings and ClusterRoleBindings without breaking one required cross-namespace workflow.
Hero-specific acceptance: no wildcard privilege, every required permission proven, and every prohibited permission denied.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### CH-02 - Exercise caution with ServiceAccounts
Status: `[~] TRAINING`
Tools: `kubectl`, TokenRequest API, projected ServiceAccount tokens, RBAC, Pod inspection.
Prior evidence: Lessons 0007 and 0034 cover automount suppression and least privilege.
Question bank:
- `CH-02.Q1` - Disable the default token for a namespace and enable a short-lived projected token only for one container with a fixed audience.
- `CH-02.Q2` - Replace use of the default ServiceAccount with a dedicated identity and minimal Role/RoleBinding.
- `CH-02.Q3` - Inspect a Pod for legacy Secret-based tokens, projected tokens, audiences, expiration, and unintended mounts.
- `CH-02.Q4` - Hard capstone: preserve one API-calling sidecar while preventing every other container from receiving cluster credentials.
Hero-specific acceptance: token exposure and RBAC authority must both be minimized and verified.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### CH-03 - Restrict access to the Kubernetes API
Status: `[~] TRAINING`
Tools: kube-apiserver flags, authentication and authorization config, admission plugins, firewall/listener inspection, audit logs.
Prior evidence: Lessons 0022 and 0035 cover anonymous auth, Node/RBAC authorization, ServiceAccount lookup, profiling, NodeRestriction, and audit integration.
Question bank:
- `CH-03.Q1` - Harden an API-server static manifest while preserving certificates, etcd, ServiceAccount signing, and admission configuration.
- `CH-03.Q2` - Restrict network reachability to the secure API endpoint and prove unauthorized and authorized outcomes.
- `CH-03.Q3` - Identify dangerous authentication files, anonymous paths, permissive authorization, and insecure profiling/debug exposure.
- `CH-03.Q4` - Hard capstone: reconcile flags with structured authentication/authorization configuration and verify the effective process.
Hero-specific acceptance: preserve control-plane availability and prove both network and request-layer restrictions.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### CH-04 - Upgrade Kubernetes to avoid vulnerabilities
Status: `[ ] NOT STARTED`
Tools: `kubeadm`, `kubectl drain`, `apt`/`dnf`, package holds, version-skew policy, release notes.
Prior evidence: none dedicated.
Question bank:
- `CH-04.Q1` - Inspect current versions, choose a supported target using version-skew rules, and produce the control-plane upgrade plan.
- `CH-04.Q2` - Upgrade `kubeadm`, run `kubeadm upgrade plan`, apply the selected version, then upgrade kubelet and kubectl safely.
- `CH-04.Q3` - Drain, upgrade, restart, and uncordon a worker while preserving workload availability.
- `CH-04.Q4` - Hard capstone: recover from a partially completed upgrade with mismatched kubeadm, kubelet, and API-server versions.
Hero-specific acceptance: version selection, node ordering, drain behavior, package holds, health verification, and rollback reasoning must be demonstrated.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
---
## System Hardening - 10%
### SH-01 - Minimize host OS footprint
Status: `[ ] NOT STARTED`
Tools: `systemctl`, `ss`, `ps`, package manager, filesystem permissions, system logs.
Prior evidence: none dedicated.
Question bank:
- `SH-01.Q1` - Inventory installed packages, running services, listening sockets, and scheduled jobs on a Kubernetes node.
- `SH-01.Q2` - Disable and remove unnecessary services without disrupting kubelet, runtime, networking, storage, or time synchronization.
- `SH-01.Q3` - Review sensitive Kubernetes directories and correct unsafe ownership or permissions.
- `SH-01.Q4` - Hard capstone: reduce an intentionally bloated node image and prove cluster health plus reduced attack surface.
Hero-specific acceptance: every removal needs a dependency justification and post-change node-health evidence.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### SH-02 - Use least-privilege host identity and access management
Status: `[ ] NOT STARTED`
Tools: Linux users/groups, `sudo`, SSH configuration, systemd unit identity, file capabilities, ownership and modes.
Prior evidence: Kubernetes RBAC experience exists, but host IAM has no dedicated practical evidence.
Question bank:
- `SH-02.Q1` - Replace shared root access with named accounts and narrowly scoped sudo commands.
- `SH-02.Q2` - Run a node service under a dedicated non-login account with minimal filesystem access.
- `SH-02.Q3` - Audit SSH root login, password authentication, authorized keys, group membership, and sudoers fragments.
- `SH-02.Q4` - Hard capstone: contain a compromised maintenance account without breaking kubelet or container runtime operation.
Hero-specific acceptance: prove denied privilege escalation and preserved operational access using audit-friendly named identities.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### SH-03 - Minimize external network access
Status: `[~] TRAINING`
Tools: `ss`, `nft`/`iptables`, cloud firewall/security groups, host firewall, `curl`, `nc`, NetworkPolicy.
Prior evidence: Lessons 0015, 0029, and 0034 cover workload and kubelet exposure; host-firewall evidence is missing.
Question bank:
- `SH-03.Q1` - Enumerate listeners and map each socket to process, interface, required clients, and authentication control.
- `SH-03.Q2` - Restrict node management ports to an administration CIDR while preserving cluster traffic.
- `SH-03.Q3` - Distinguish host firewall, cloud firewall, Service exposure, and NetworkPolicy responsibilities.
- `SH-03.Q4` - Hard capstone: reduce external exposure across a node, NodePort Service, and host-network workload, then prove allowed and denied paths.
Hero-specific acceptance: evidence must cover effective listeners and remote reachability from both permitted and prohibited sources.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### SH-04 - Use AppArmor and seccomp appropriately
Status: `[~] TRAINING`
Tools: `apparmor_parser`, `aa-status`, AppArmor profiles, seccomp profiles, Pod securityContext, runtime events.
Prior evidence: Lessons 0004, 0011, and 0033. AppArmor enforcement was blocked by the Docker Desktop/WSL2 kernel; seccomp manifest work is established.
Question bank:
- `SH-04.Q1` - Create, load, and enforce an AppArmor profile that permits required reads but denies a sensitive write.
- `SH-04.Q2` - Apply `RuntimeDefault` seccomp and diagnose a workload that requires a narrowly justified custom profile.
- `SH-04.Q3` - Compare Pod-level and container-level profile scope and prove enforcement with an attempted forbidden operation.
- `SH-04.Q4` - Hard capstone: harden a multi-container workload with different profiles and debug a node/profile-name mismatch.
Hero-specific acceptance: must run on an AppArmor-enabled Linux host for AppArmor Hero; manifest-only evidence remains Training.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
---
## Minimize Microservice Vulnerabilities - 20%
### MM-01 - Use appropriate Pod Security Standards
Status: `[~] TRAINING`
Tools: Pod Security Admission labels, PSS documentation, dry runs, admission output, workload security contexts.
Prior evidence: Lessons 0005, 0021, 0031, 0033, and 0034.
Question bank:
- `MM-01.Q1` - Classify workloads against Privileged, Baseline, and Restricted, identifying every violating field.
- `MM-01.Q2` - Migrate a namespace through warn, audit, and enforce with pinned policy versions and no avoidable outage.
- `MM-01.Q3` - Remediate a Deployment to Restricted while preserving required writable paths and network binding.
- `MM-01.Q4` - Hard capstone: manage exemptions and mixed legacy workloads without weakening the entire namespace.
Hero-specific acceptance: prove admitted compliant workloads and rejected noncompliant workloads at the correct scope.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### MM-02 - Manage Kubernetes Secrets
Status: `[~] TRAINING`
Tools: Secret API, projected volumes, encryption configuration, RBAC, `etcdctl`, rotation workflow.
Prior evidence: Lessons 0010, 0018, and 0032 cover selective projection, encryption at rest, exposure investigation, and rotation reasoning.
Question bank:
- `MM-02.Q1` - Project only one Secret key into one container with correct file mode and no environment-variable exposure.
- `MM-02.Q2` - Configure encryption at rest, rewrite existing Secrets, and prove ciphertext in etcd plus readable API behavior.
- `MM-02.Q3` - Identify Secret exposure through RBAC, Pod specs, logs, shell history, and mounted tokens; remediate each path.
- `MM-02.Q4` - Hard capstone: rotate an accessed external credential across producers and consumers without retaining the old value.
Hero-specific acceptance: minimize distribution, prove storage encryption, and demonstrate actual credential invalidation.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### MM-03 - Implement isolation and multi-tenancy
Status: `[~] TRAINING`
Tools: namespaces, RBAC, quotas, NetworkPolicy, Pod Security Admission, admission policy, RuntimeClass/sandboxed runtime.
Prior evidence: Lessons 0017, 0031, and 0034 cover scoped admission and workload/network isolation. Sandboxed runtime evidence is missing.
Question bank:
- `MM-03.Q1` - Build a tenant namespace baseline combining RBAC, quotas, PSS, default-deny networking, and dedicated ServiceAccounts.
- `MM-03.Q2` - Prevent host namespace, privileged, hostPath, and unsafe capability use with correctly scoped admission logic.
- `MM-03.Q3` - Configure and select a sandboxed RuntimeClass, then verify the effective runtime handler.
- `MM-03.Q4` - Hard capstone: isolate two tenants while preserving one explicitly shared service and administrative break-glass path.
Hero-specific acceptance: prove cross-tenant denials at API, network, storage, and runtime boundaries.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### MM-04 - Implement Pod-to-Pod encryption
Status: `[~] TRAINING`
Tools: Cilium CLI/status, WireGuard status, Istio `istioctl`, PeerAuthentication, AuthorizationPolicy, traffic capture where allowed.
Prior evidence: Lessons 0023, 0025, and 0026 cover Cilium WireGuard, Istio strict mTLS, and workload authorization.
Question bank:
- `MM-04.Q1` - Enable Cilium WireGuard and prove node encryption status plus encrypted Pod traffic.
- `MM-04.Q2` - Enforce namespace-wide Istio STRICT mTLS and identify workloads that fail because they lack sidecars.
- `MM-04.Q3` - Pair mTLS with AuthorizationPolicy so encryption does not become mistaken for authorization.
- `MM-04.Q4` - Hard capstone: diagnose mixed plaintext/encrypted traffic across namespaces and prove the final data path.
Hero-specific acceptance: use implementation-specific status tools and traffic evidence, not policy YAML alone.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
---
## Supply Chain Security - 20%
### SC-01 - Minimize base image footprint
Status: `[ ] NOT STARTED`
Tools: Docker/BuildKit, multi-stage builds, distroless or minimal images, Trivy, Dive where available.
Prior evidence: no dedicated image-rebuild and comparison task.
Question bank:
- `SC-01.Q1` - Convert a development image into a multi-stage production build with no compiler or package manager in the final stage.
- `SC-01.Q2` - Compare package count, size, users, shell availability, and vulnerability results before and after minimization.
- `SC-01.Q3` - Run the final image as non-root with a read-only root filesystem and explicit writable paths.
- `SC-01.Q4` - Hard capstone: minimize an image without breaking TLS roots, timezone data, health checks, or runtime dependencies.
Hero-specific acceptance: quantitative before/after evidence plus successful runtime behavior is required.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### SC-02 - Understand the supply chain
Status: `[~] TRAINING`
Tools: Syft, CycloneDX/SPDX, CI logs, artifact repositories, provenance/attestations, dependency metadata.
Prior evidence: Lesson 0030 generates and interprets a CycloneDX SBOM with Syft.
Question bank:
- `SC-02.Q1` - Generate CycloneDX and SPDX SBOMs with Syft and compare component identity and relationships.
- `SC-02.Q2` - Trace a deployed digest back through registry metadata, build job, source revision, and SBOM.
- `SC-02.Q3` - Use an SBOM to answer impact from a newly disclosed component vulnerability without claiming exploitability.
- `SC-02.Q4` - Hard capstone: investigate a mismatched SBOM, image digest, and deployment reference and identify the broken provenance link.
Hero-specific acceptance: distinguish inventory, vulnerability, provenance, signature, and deployment policy evidence.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### SC-03 - Secure permitted registries and validate artifacts
Status: `[~] TRAINING`
Tools: Cosign, container registry, image digests, admission policy, public-key or keyless verification, attestations.
Prior evidence: Lessons 0013 and 0019 cover digest enforcement and artifact checksum verification. Cosign signing and verification are missing.
Question bank:
- `SC-03.Q1` - Sign a pinned image digest with Cosign and verify it using the intended trust identity.
- `SC-03.Q2` - Enforce an allowed registry and immutable digest policy across regular, init, and ephemeral containers.
- `SC-03.Q3` - Validate an SBOM or provenance attestation and reject a signature from the wrong identity or repository.
- `SC-03.Q4` - Hard capstone: admit only correctly signed images from permitted registries while preserving an audited break-glass process.
Hero-specific acceptance: verification must bind identity, repository, and digest; signature presence alone is insufficient.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### SC-04 - Perform static analysis of workloads and images
Status: `[~] TRAINING`
Tools: Kubesec, KubeLinter, Trivy config/image, scanner exit codes, CI integration.
Prior evidence: Lesson 0027 uses Trivy configuration scanning. Kubesec, KubeLinter, and Trivy image scanning remain unpracticed.
Question bank:
- `SC-04.Q1` - Scan the same manifest with Kubesec, KubeLinter, and Trivy; normalize overlapping and tool-specific findings.
- `SC-04.Q2` - Scan a pinned image with Trivy, prioritize exploitable/runtime-relevant findings, and avoid equating count with risk.
- `SC-04.Q3` - Configure CI to fail on a justified severity/fixability policy while preserving machine-readable reports.
- `SC-04.Q4` - Hard capstone: remediate manifest and image findings, rerun every scanner, and explain accepted residual risk and false positives.
Hero-specific acceptance: use at least three named tools, preserve raw reports, and distinguish configuration from package-vulnerability results.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
---
## Monitoring, Logging and Runtime Security - 20%
### MR-01 - Perform behavioral analytics
Status: `[~] TRAINING`
Tools: Falco, rule files, JSON output, baseline comparison, process/network telemetry.
Prior evidence: Lesson 0020 covers runtime shell detection with Falco-style evidence.
Question bank:
- `MR-01.Q1` - Establish a workload behavior baseline and identify process, file, and network deviations.
- `MR-01.Q2` - Write and test a Falco rule for an interactive shell or sensitive file access inside a container.
- `MR-01.Q3` - Tune a noisy rule using workload identity and syscall context without hiding real attacks.
- `MR-01.Q4` - Hard capstone: correlate multiple low-confidence events into one high-confidence malicious sequence.
Hero-specific acceptance: provide triggering and non-triggering tests plus a justified noise-control strategy.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### MR-02 - Detect threats across infrastructure, apps, networks, data, users, and workloads
Status: `[~] TRAINING`
Tools: Falco, audit logs, host logs, NetworkPolicy/CNI flow logs, application logs, identity events, file-integrity evidence.
Prior evidence: Lessons 0012, 0020, and 0032 cover API and runtime signals; full cross-layer correlation is missing.
Question bank:
- `MR-02.Q1` - Map one signal source and one high-value detection to each of the six threat surfaces.
- `MR-02.Q2` - Detect suspicious node login, privileged workload creation, lateral network movement, Secret access, and runtime execution.
- `MR-02.Q3` - Separate preventive controls from detective evidence and identify blind spots in each layer.
- `MR-02.Q4` - Hard capstone: correlate host, Kubernetes, network, and application telemetry into one defensible incident timeline.
Hero-specific acceptance: identify principal, asset, action, outcome, source, and timestamp from more than one telemetry layer.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### MR-03 - Investigate phases of attack and bad actors
Status: `[~] TRAINING`
Tools: `jq`/PowerShell JSON parsing, audit logs, Falco events, Pod and RBAC inspection, timeline notes.
Prior evidence: Lessons 0012 and 0032 reconstruct escalation, Secret access, and exec activity with ordered containment.
Question bank:
- `MR-03.Q1` - Reconstruct initial access, privilege escalation, discovery, credential access, execution, and persistence from mixed logs.
- `MR-03.Q2` - Distinguish rejected attempts from successful actions using response codes and runtime outcomes.
- `MR-03.Q3` - Pivot by authenticated principal, source IP, workload identity, resource, and time without using audit IDs as identities.
- `MR-03.Q4` - Hard capstone: produce a concise incident report with evidence, confidence, blast radius, and ordered containment.
Hero-specific acceptance: include the exact structured query command and cite the event evidence for every conclusion.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### MR-04 - Ensure container immutability at runtime
Status: `[~] TRAINING`
Tools: securityContext, read-only root filesystem, volumes, image digests, admission policy, Falco/file-integrity checks.
Prior evidence: Lessons 0006, 0013, 0033, and 0034 cover immutable images and read-only roots with explicit writable volumes.
Question bank:
- `MR-04.Q1` - Harden a workload with read-only roots and discover every required writable runtime path empirically.
- `MR-04.Q2` - Enforce digest-only image references and prove mutable-tag rejection.
- `MR-04.Q3` - Detect executable creation or package installation inside a running container and contain it.
- `MR-04.Q4` - Hard capstone: combine preventive admission, runtime filesystem controls, and behavioral detection without breaking the application.
Hero-specific acceptance: prove immutable image identity, failed root writes, allowed explicit writes, and runtime alert behavior.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
### MR-05 - Use Kubernetes audit logs to monitor access
Status: `[~] TRAINING`
Tools: audit Policy, kube-apiserver flags and mounts, `jq`, log rotation, event correlation.
Prior evidence: Lessons 0012, 0014, 0032, and 0035 cover policy design, persistent logging, filtering, and incident reconstruction.
Question bank:
- `MR-05.Q1` - Design an ordered audit policy for Secrets, RBAC changes, Pod exec, authentication failures, and a Metadata catch-all.
- `MR-05.Q2` - Configure file-backend persistence and rotation in a kube-apiserver static Pod and prove the effective process flags.
- `MR-05.Q3` - Write structured queries for principal, source, verb, resource, response code, and time windows.
- `MR-05.Q4` - Hard capstone: diagnose missing events caused by rule ordering, level choice, omitted stages, path mounts, or log rotation.
Hero-specific acceptance: prove event generation end to end from API request through persisted log and structured query.
Hero gate: [ ] Tool drill [ ] Timed capstone [ ] Evidence [ ] Cold retest
---
## Attempt Log
Append one row after every graded attempt.
| Date | Task | Topic | Time | Result | Critical errors | Evidence | Next action |
|---|---|---|---:|---|---:|---|---|
| 2026-08-26 | Lesson 0035 | CH-03 / MR-05 | Not recorded | Training pass | 0 after review | `lab/lesson-35-kube-apiserver-answer.yaml`, `lab/lesson-35-audit-policy.yaml` | Cold retest later |
| 2026-08-26 | Lesson 0034 | CS-01 / MM-01 | Not recorded | Training pass | 0 after review | `lab/lesson-34-answer.yaml` | Cold retest later |
| 2026-08-25 | Lesson 0032 | MR-03 | Not recorded | Training; evidence incomplete | 0 substantive; command omitted | `lab/lesson-32-answer.md` | Require structured query next time |
## Current Summary
Hero topics: none yet.
Training topics: CS-01, CS-02, CS-03, CS-04, CS-05, CH-01, CH-02, CH-03, SH-03, SH-04, MM-01, MM-02, MM-03, MM-04, SC-02, SC-03, SC-04, MR-01, MR-02, MR-03, MR-04, MR-05.
Not started: CH-04, SH-01, SH-02, SC-01.
Blocked: AppArmor runtime enforcement on the current Docker Desktop/WSL2 kernel. Use an AppArmor-enabled Linux host for the Hero attempt.

View File

@@ -3,3 +3,7 @@
- Learner goal: career advancement and deeper technical security skills. - Learner goal: career advancement and deeper technical security skills.
- Background: CKA, CKAD, and KodeKloud CKS training completed. - Background: CKA, CKAD, and KodeKloud CKS training completed.
- Priority: build confidence through timed retrieval and hands-on feedback, not rewatching broad course material. - Priority: build confidence through timed retrieval and hands-on feedback, not rewatching broad course material.
- Learner prefers original performance-based tasks at public CKS curriculum level or harder, with multi-control requirements and strict verification, so the real exam feels comparatively easy.
- Review preference: list all detected issues, then correct only one issue per round.
- Mastery tracking: use `CKS-MASTERY-CHECKLIST.md` as the canonical cross-session dashboard. Never award Hero from lesson completion alone; require the topic's tool drill, timed capstone, verification evidence, and cold retest.
- Confidence priority: deliberately rotate through named CKS tools instead of relying mainly on hand-written YAML.

50
lab/lesson-33-answer.yaml Normal file
View File

@@ -0,0 +1,50 @@
apiVersion: v1
kind: Namespace
metadata:
name: context-lab
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: report-api
namespace: context-lab
spec:
replicas: 1
selector:
matchLabels:
app: report-api
template:
metadata:
labels:
app: report-api
spec:
securityContext:
seccompProfile:
type: RuntimeDefault
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
volumes:
- name: log-exporter-vol
emptyDir: {}
containers:
- name: api
image: nginxinc/nginx-unprivileged:1.27-alpine
ports:
- containerPort: 8080
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
- name: log-exporter
image: busybox:1.37
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
readOnlyRootFilesystem: true
command: ["sh", "-c", "while true; do date >> /var/cache/exporter/events.log; sleep 30; done"]
volumeMounts:
- name: log-exporter-vol
mountPath: /var/cache/exporter

View File

@@ -0,0 +1,28 @@
apiVersion: v1
kind: Namespace
metadata:
name: context-lab
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: report-api
namespace: context-lab
spec:
replicas: 1
selector:
matchLabels:
app: report-api
template:
metadata:
labels:
app: report-api
spec:
containers:
- name: api
image: nginxinc/nginx-unprivileged:1.27-alpine
ports:
- containerPort: 8080
- name: log-exporter
image: busybox:1.37
command: ["sh", "-c", "while true; do date >> /var/cache/exporter/events.log; sleep 30; done"]

106
lab/lesson-34-answer.yaml Normal file
View File

@@ -0,0 +1,106 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders-api
namespace: orders-prod
spec:
replicas: 2
selector:
matchLabels:
app: orders-api
template:
metadata:
labels:
app: orders-api
tier: backend
spec:
automountServiceAccountToken: false
serviceAccountName: orders-api
securityContext:
runAsNonRoot: true
runAsUser: 10001
runAsGroup: 10001
fsGroup: 10001
seccompProfile:
type: RuntimeDefault
volumes:
- name: orders
emptyDir: {}
- name: srv
emptyDir: {}
containers:
- name: api
image: busybox:1.37
volumeMounts:
- name: orders
mountPath: /var/log/orders
- name: srv
mountPath: /srv
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
command: ["sh", "-c", "mkdir -p /srv; echo ready > /srv/index.html; httpd -f -p 8080 -h /srv"]
ports:
- name: http
containerPort: 8080
- name: audit-writer
image: busybox:1.37
command: ["sh", "-c", "while true; do date >> /var/log/orders/audit.log; sleep 20; done"]
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
volumeMounts:
- name: orders
mountPath: /var/log/orders
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: orders-api-boundary
namespace: orders-prod
spec:
podSelector:
matchLabels:
app: orders-api
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: edge
podSelector:
matchLabels:
app: edge-gateway
ports:
- protocol: TCP
port: 8080
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: data
podSelector:
matchLabels:
app: orders-db
ports:
- protocol: TCP
port: 5432
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53

View File

@@ -0,0 +1,82 @@
apiVersion: v1
kind: Namespace
metadata:
name: orders-prod
---
apiVersion: v1
kind: Namespace
metadata:
name: edge
---
apiVersion: v1
kind: Namespace
metadata:
name: data
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders-api
namespace: orders-prod
spec:
replicas: 2
selector:
matchLabels:
app: orders-api
template:
metadata:
labels:
app: orders-api
tier: backend
spec:
serviceAccountName: orders-api
containers:
- name: api
image: busybox:1.37
command: ["sh", "-c", "mkdir -p /srv; echo ready > /srv/index.html; httpd -f -p 8080 -h /srv"]
ports:
- name: http
containerPort: 8080
- name: audit-writer
image: busybox:1.37
command: ["sh", "-c", "while true; do date >> /var/log/orders/audit.log; sleep 20; done"]
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: edge-gateway
namespace: edge
spec:
replicas: 1
selector:
matchLabels:
app: edge-gateway
template:
metadata:
labels:
app: edge-gateway
spec:
containers:
- name: gateway
image: busybox:1.37
command: ["sleep", "1d"]
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders-db
namespace: data
spec:
replicas: 1
selector:
matchLabels:
app: orders-db
template:
metadata:
labels:
app: orders-db
spec:
containers:
- name: database
image: busybox:1.37
command: ["sleep", "1d"]

View File

@@ -0,0 +1,26 @@
apiVersion: audit.k8s.io/v1 # This is required.
kind: Policy
omitStages:
- "RequestReceived"
rules:
- level: RequestResponse
namespaces: ["payments","orders-prod"]
resources:
- group: ""
resources: ["secrets"]
- level: Metadata
verbs: ["create","update","patch","delete","deletecollection"]
resources:
- group: "rbac.authorization.k8s.io"
resources: ["roles","rolebindings","clusterroles","clusterrolebindings"]
- level: Request
resources:
- group: ""
resources: ["pods/exec"]
- level: Metadata
omitStages:
- "RequestReceived"

View File

@@ -0,0 +1,57 @@
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver
namespace: kube-system
labels:
component: kube-apiserver
tier: control-plane
spec:
hostNetwork: true
priorityClassName: system-node-critical
containers:
- name: kube-apiserver
image: registry.k8s.io/kube-apiserver:v1.34.1
command:
- kube-apiserver
- --anonymous-auth=false
- --authorization-mode=Node,RBAC
- --profiling=false
- --service-account-lookup=true
- --enable-admission-plugins=NamespaceLifecycle,ServiceAccount,NodeRestriction
- --audit-policy-file=/etc/kubernetes/audit-policy.yaml
- --audit-log-path=/var/log/kubernetes/audit/audit.log
- --audit-log-maxage=14
- --audit-log-maxbackup=10
- --audit-log-maxsize=100
- --etcd-servers=https://127.0.0.1:2379
- --service-cluster-ip-range=10.96.0.0/12
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
- --service-account-issuer=https://kubernetes.default.svc.cluster.local
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-account-signing-key-file=/etc/kubernetes/pki/sa.key
- --allow-privileged=true
volumeMounts:
- name: k8s-certs
mountPath: /etc/kubernetes/pki
readOnly: true
- name: audit-config
mountPath: /etc/kubernetes/audit-policy.yaml
readOnly: true
- name: audit-log
mountPath: /var/log/kubernetes/audit
volumes:
- name: k8s-certs
hostPath:
path: /etc/kubernetes/pki
type: DirectoryOrCreate
- name: audit-config
hostPath:
path: /etc/kubernetes/audit-policy.yaml
type: File
- name: audit-log
hostPath:
path: /var/log/kubernetes/audit
type: DirectoryOrCreate

View File

@@ -0,0 +1,40 @@
apiVersion: v1
kind: Pod
metadata:
name: kube-apiserver
namespace: kube-system
labels:
component: kube-apiserver
tier: control-plane
spec:
hostNetwork: true
priorityClassName: system-node-critical
containers:
- name: kube-apiserver
image: registry.k8s.io/kube-apiserver:v1.34.1
command:
- kube-apiserver
- --anonymous-auth=true
- --authorization-mode=AlwaysAllow
- --profiling=true
- --service-account-lookup=false
- --enable-admission-plugins=NamespaceLifecycle,ServiceAccount
- --audit-log-path=-
- --etcd-servers=https://127.0.0.1:2379
- --service-cluster-ip-range=10.96.0.0/12
- --client-ca-file=/etc/kubernetes/pki/ca.crt
- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
- --service-account-issuer=https://kubernetes.default.svc.cluster.local
- --service-account-key-file=/etc/kubernetes/pki/sa.pub
- --service-account-signing-key-file=/etc/kubernetes/pki/sa.key
- --allow-privileged=true
volumeMounts:
- name: k8s-certs
mountPath: /etc/kubernetes/pki
readOnly: true
volumes:
- name: k8s-certs
hostPath:
path: /etc/kubernetes/pki
type: DirectoryOrCreate

View File

@@ -0,0 +1,32 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: coredns
namespace: kube-system
spec:
replicas: 2
selector:
matchLabels:
k8s-app: kube-dns
template:
metadata:
labels:
k8s-app: kube-dns
spec:
serviceAccountName: coredns
automountServiceAccountToken: true
containers:
- name: coredns
image: registry.k8s.io/coredns/coredns:v1.12.1
args: ["-conf", "/etc/coredns/Corefile"]
securityContext:
runAsUser: 0
allowPrivilegeEscalation: true
readOnlyRootFilesystem: false
ports:
- name: dns
containerPort: 53
protocol: UDP
- name: dns-tcp
containerPort: 53
protocol: TCP

31
lab/lesson-36-etcd.yaml Normal file
View File

@@ -0,0 +1,31 @@
apiVersion: v1
kind: Pod
metadata:
name: etcd
namespace: kube-system
spec:
hostNetwork: true
containers:
- name: etcd
image: registry.k8s.io/etcd:3.6.4-0
command:
- etcd
- --listen-client-urls=https://127.0.0.1:2379,https://10.0.0.10:2379
- --client-cert-auth=false
- --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
- --cert-file=/etc/kubernetes/pki/etcd/server.crt
- --key-file=/etc/kubernetes/pki/etcd/server.key
- --auto-tls=true
- --peer-client-cert-auth=true
- --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
- --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt
- --peer-key-file=/etc/kubernetes/pki/etcd/peer.key
volumeMounts:
- name: etcd-certs
mountPath: /etc/kubernetes/pki/etcd
readOnly: true
volumes:
- name: etcd-certs
hostPath:
path: /etc/kubernetes/pki/etcd
type: DirectoryOrCreate

View File

@@ -0,0 +1,202 @@
{
"Controls": [
{
"id": "1",
"version": "cis-1.11",
"detected_version": "v1.34.1",
"text": "Control Plane Security Configuration",
"node_type": "master",
"tests": [
{
"section": "1.2",
"type": "controlplane",
"pass": 1,
"fail": 2,
"warn": 1,
"info": 0,
"desc": "API Server",
"results": [
{
"test_number": "1.2.1",
"test_desc": "Ensure that the --anonymous-auth argument is set to false (Automated)",
"audit": "Inspect the kube-apiserver process arguments",
"type": "Automated",
"remediation": "Set --anonymous-auth=false in the kube-apiserver static Pod manifest.",
"test_info": [],
"status": "FAIL",
"actual_value": "--anonymous-auth=true",
"scored": true,
"expected_result": "false"
},
{
"test_number": "1.2.7",
"test_desc": "Ensure that the --authorization-mode argument includes Node and RBAC (Automated)",
"audit": "Inspect the kube-apiserver process arguments",
"type": "Automated",
"remediation": "Set --authorization-mode=Node,RBAC.",
"test_info": [],
"status": "FAIL",
"actual_value": "--authorization-mode=AlwaysAllow",
"scored": true,
"expected_result": "Node,RBAC"
},
{
"test_number": "1.2.21",
"test_desc": "Ensure that the --service-account-lookup argument is set to true (Automated)",
"audit": "Inspect the kube-apiserver process arguments",
"type": "Automated",
"remediation": "Set --service-account-lookup=true.",
"test_info": [],
"status": "PASS",
"actual_value": "--service-account-lookup=true",
"scored": true,
"expected_result": "true"
},
{
"test_number": "1.2.22",
"test_desc": "Ensure that the audit log path is configured (Manual)",
"audit": "Review the audit backend path and persistence mounts",
"type": "Manual",
"remediation": "Configure a persistent audit log file and verify its host mount.",
"test_info": ["A non-empty flag alone does not prove persistence."],
"status": "WARN",
"actual_value": "--audit-log-path=-",
"scored": false,
"expected_result": "persistent file path"
}
]
}
]
},
{
"id": "2",
"version": "cis-1.11",
"detected_version": "v1.34.1",
"text": "etcd Node Configuration",
"node_type": "etcd",
"tests": [
{
"section": "2",
"type": "etcd",
"pass": 1,
"fail": 2,
"warn": 0,
"info": 0,
"desc": "etcd",
"results": [
{
"test_number": "2.2",
"test_desc": "Ensure that the --client-cert-auth argument is set to true (Automated)",
"audit": "Inspect the etcd process arguments",
"type": "Automated",
"remediation": "Set --client-cert-auth=true and configure --trusted-ca-file.",
"test_info": [],
"status": "FAIL",
"actual_value": "--client-cert-auth=false",
"scored": true,
"expected_result": "true"
},
{
"test_number": "2.3",
"test_desc": "Ensure that the --auto-tls argument is not set to true (Automated)",
"audit": "Inspect the etcd process arguments",
"type": "Automated",
"remediation": "Set --auto-tls=false and use trusted certificate files.",
"test_info": [],
"status": "FAIL",
"actual_value": "--auto-tls=true",
"scored": true,
"expected_result": "false"
},
{
"test_number": "2.4",
"test_desc": "Ensure that the --peer-client-cert-auth argument is set to true (Automated)",
"audit": "Inspect the etcd process arguments",
"type": "Automated",
"remediation": "Set --peer-client-cert-auth=true.",
"test_info": [],
"status": "PASS",
"actual_value": "--peer-client-cert-auth=true",
"scored": true,
"expected_result": "true"
}
]
}
]
},
{
"id": "4",
"version": "cis-1.11",
"detected_version": "v1.34.1",
"text": "Worker Node Security Configuration",
"node_type": "node",
"tests": [
{
"section": "4.2",
"type": "node",
"pass": 1,
"fail": 3,
"warn": 0,
"info": 0,
"desc": "Kubelet",
"results": [
{
"test_number": "4.2.1",
"test_desc": "Ensure that anonymous authentication is disabled (Automated)",
"audit": "Inspect KubeletConfiguration authentication.anonymous.enabled",
"type": "Automated",
"remediation": "Set authentication.anonymous.enabled=false.",
"test_info": [],
"status": "FAIL",
"actual_value": "enabled: true",
"scored": true,
"expected_result": "false"
},
{
"test_number": "4.2.2",
"test_desc": "Ensure that webhook authentication is enabled (Automated)",
"audit": "Inspect KubeletConfiguration authentication.webhook.enabled",
"type": "Automated",
"remediation": "Set authentication.webhook.enabled=true.",
"test_info": [],
"status": "FAIL",
"actual_value": "enabled: false",
"scored": true,
"expected_result": "true"
},
{
"test_number": "4.2.3",
"test_desc": "Ensure that the authorization mode is Webhook (Automated)",
"audit": "Inspect KubeletConfiguration authorization.mode",
"type": "Automated",
"remediation": "Set authorization.mode=Webhook.",
"test_info": [],
"status": "FAIL",
"actual_value": "mode: AlwaysAllow",
"scored": true,
"expected_result": "Webhook"
},
{
"test_number": "4.2.4",
"test_desc": "Ensure that the read-only port is disabled (Automated)",
"audit": "Inspect KubeletConfiguration readOnlyPort",
"type": "Automated",
"remediation": "Set readOnlyPort=0.",
"test_info": [],
"status": "PASS",
"actual_value": "readOnlyPort: 0",
"scored": true,
"expected_result": "0"
}
]
}
]
}
],
"Totals": {
"total_pass": 3,
"total_fail": 7,
"total_warn": 1,
"total_info": 0
}
}

View File

@@ -0,0 +1,11 @@
# Audit impact and containment order
The learner completed the substantive reasoning in Lesson 32. They distinguished a rejected RBAC attempt from a successful RoleBinding creation by checking `responseStatus.code`, identified the authenticated ServiceAccount principal, traced Secret access and Pod exec, and ordered containment as RBAC revocation, workload isolation, then credential rotation.
## Evidence
The incident note correctly identifies `system:serviceaccount:checkout:release-bot`, RoleBinding `checkout/release-bot-secret-reader`, Secret `checkout/payment-gateway`, and the exec target `checkout/checkout-api-6d8f`.
## Remaining evidence gap
The answer does not include the exact structured JSON filter command requested by the lesson. Continue requiring commands or output when a task asks for reproducible investigation evidence.

View File

@@ -0,0 +1,11 @@
# SecurityContext placement retrieval
The learner completed Lesson 33 and explicitly preferred its manifest-hardening format. The final static manifest correctly separates Pod-wide identity and seccomp settings from container-level privilege escalation, capabilities, and read-only-root controls. It also confines the sidecar's writable state to an `emptyDir` mount.
## Coaching adjustment
Increase subsequent work to original, timed, multi-control tasks aligned with the public CKS curriculum or harder. Preserve exam-style brevity, require verification evidence, and continue listing all issues while correcting one per review round.
## Evidence limitation
The manifest passed static review. Runtime rollout and filesystem verification were not observed in the teaching shell.

View File

@@ -0,0 +1,15 @@
# Multi-control workload and network boundary
The learner completed Lesson 34, an original hard-mode task combining a hardened two-container Deployment with one bidirectional NetworkPolicy. The final static manifest correctly preserves workload fields, disables automatic token mounting, applies Pod- and container-level security controls, provides only deliberate writable paths, and composes namespace and Pod selectors in the same NetworkPolicy peer.
## Evidence
The final NetworkPolicy isolates ingress and egress, permits only the edge gateway, database, and CoreDNS flows, and includes TCP and UDP DNS. The learner corrected schema placement and exact resource naming during review.
## Evidence limitation
Elapsed time was not recorded. Runtime rollout and connectivity checks were not observed in the teaching shell.
## Coaching adjustment
Continue with original multi-file, node-level, and multi-domain tasks at public CKS curriculum difficulty or harder. Require the learner to preserve unrelated operational configuration while correcting security weaknesses.

View File

@@ -0,0 +1,11 @@
# Hero-based CKS mastery system
The learner requested an exhaustive, persistent checklist for every public CKS syllabus topic, with several tool-based questions per topic and visible done-versus-remaining status. The canonical state is stored in `CKS-MASTERY-CHECKLIST.md` so a different computer or agent can resume from repository files.
## Hero standard
A topic receives Hero only after the learner completes its tool drill, a timed original capstone at exam difficulty or harder, supplies verification evidence, and passes a cold retest on a later session without stepwise prompting. Existing lessons count as training evidence but do not grant Hero retroactively.
## Coaching behavior
At the start and end of each future CKS session, update the checklist dashboard, topic evidence, attempt log, next task, and done-versus-remaining summary. Prefer tools that have not yet been exercised enough, including kube-bench, kubeadm, Kubesec, KubeLinter, Trivy image scanning, Syft, Cosign, Falco, AppArmor tooling, and host-network inspection tools.

View File

@@ -0,0 +1,60 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Lesson 33: SecurityContext placement</title>
<link rel="stylesheet" href="../assets/course.css">
</head>
<body>
<main>
<p class="eyebrow">Lesson 0033 · 25 minutes · Minimize Microservice Vulnerabilities</p>
<h1>Place hardening controls at the correct scope</h1>
<p class="lede">A correct control at the wrong YAML level is still an invalid solution. Harden both containers while preserving the sidecar's one required writable path.</p>
<h2>Timed task: 15 minutes</h2>
<p>Read <code>lab/lesson-33-fixture.yaml</code>. Create <code>lab/lesson-33-answer.yaml</code> from scratch. Preserve the namespace, Deployment name, replica count, selector, labels, container names, images, commands, and port.</p>
<p>Your completed Deployment must:</p>
<ul>
<li>run the Pod as non-root UID and GID <code>1000</code>;</li>
<li>apply <code>RuntimeDefault</code> seccomp to the whole Pod;</li>
<li>disable privilege escalation in both containers;</li>
<li>drop all Linux capabilities in both containers;</li>
<li>make both container root filesystems read-only; and</li>
<li>give only <code>log-exporter</code> a writable <code>emptyDir</code> mounted at <code>/var/cache/exporter</code>.</li>
</ul>
<p>Do not duplicate Pod-wide fields under each container, mount the writable volume into <code>api</code>, add capabilities, or change either image.</p>
<div class="callout"><strong>Placement reflex:</strong> identity and Pod-wide syscall policy belong under <code>template.spec.securityContext</code>. Privilege escalation, capabilities, and root-filesystem mutability belong under each entry in <code>template.spec.containers</code>.</div>
<h2>Verification</h2>
<pre><code>kubectl apply --dry-run=client -f .\lab\lesson-33-answer.yaml
kubectl apply -f .\lab\lesson-33-answer.yaml
kubectl -n context-lab rollout status deployment/report-api --timeout=90s
kubectl -n context-lab exec deploy/report-api -c log-exporter -- test -f /var/cache/exporter/events.log
kubectl -n context-lab exec deploy/report-api -c api -- sh -c 'touch /root/blocked'</code></pre>
<p>Expected: schema validation passes, the rollout completes, the sidecar writes its event file, and the API container cannot write to its root filesystem.</p>
<h2>Retrieval check</h2>
<div class="quiz">
<h3>Question</h3>
<p>Where does <code>readOnlyRootFilesystem</code> belong?</p>
<label><input type="radio" name="q" value="container">Inside each container's securityContext.</label>
<label><input type="radio" name="q" value="podspec">Directly under the Pod specification.</label>
<label><input type="radio" name="q" value="metadata">Inside the Pod template metadata.</label>
<button onclick="check()">Check answer</button>
<p id="feedback" class="feedback" aria-live="polite"></p>
</div>
<h2>Documentation target</h2>
<p>Use the official Kubernetes <a href="https://kubernetes.io/docs/tasks/configure-pod-container/security-context/">security context documentation</a> after your first attempt. Use <code>kubectl explain deployment.spec.template.spec.securityContext</code> and <code>kubectl explain deployment.spec.template.spec.containers.securityContext</code> to confirm scope.</p>
<h2>What to send me</h2>
<p>Save the YAML, then say <em>check</em>. I will list all issues and help you correct only one per round. Ask me a follow-up question whenever a field's scope is unclear.</p>
<footer>Previous: <a href="0032-audit-success-vs-attempt.html">Audit success versus attempt</a> · CKS path: Minimize Microservice Vulnerabilities</footer>
</main>
<script>
function check(){const c=document.querySelector('input[name=q]:checked'),f=document.getElementById('feedback');if(!c){f.textContent='Choose an answer.';f.className='feedback bad';return;}if(c.value==='container'){f.textContent='Correct. Root-filesystem mutability is configured per container.';f.className='feedback good';}else{f.textContent='Not quite. This control belongs in each container securityContext.';f.className='feedback bad';}}
</script>
</body>
</html>

View File

@@ -0,0 +1,70 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Lesson 34: Harden and isolate orders-api</title>
<link rel="stylesheet" href="../assets/course.css">
</head>
<body>
<main>
<p class="eyebrow">Lesson 0034 · 35 minutes · Hard mode · Multi-domain</p>
<h1>Harden and isolate a production API</h1>
<p class="lede">This original performance task is deliberately denser than a focused drill. Secure the workload and its traffic boundary without changing its application contract.</p>
<h2>Task</h2>
<p>Apply <code>lab/lesson-34-fixture.yaml</code>. Create <code>lab/lesson-34-answer.yaml</code> containing exactly two resources: the corrected <code>orders-api</code> Deployment and one NetworkPolicy named <code>orders-api-boundary</code>.</p>
<p>Preserve the Deployment's name, namespace, replicas, selector, labels, ServiceAccount name, container names, images, commands, and port.</p>
<h2>Workload requirements</h2>
<ul>
<li>Disable automatic ServiceAccount-token mounting.</li>
<li>Run the whole Pod as non-root UID and GID <code>10001</code>, and set Pod-level <code>fsGroup: 10001</code> so the non-root processes can write to their mounted volumes.</li>
<li>Apply <code>RuntimeDefault</code> seccomp to the whole Pod.</li>
<li>For both containers, disable privilege escalation, drop all capabilities, and make the root filesystem read-only.</li>
<li>Create a shared <code>emptyDir</code> mounted at <code>/var/log/orders</code> in both containers.</li>
<li>Create a separate <code>emptyDir</code> mounted at <code>/srv</code> only in <code>api</code>, allowing its preserved startup command to create the served file.</li>
</ul>
<h2>Network requirements</h2>
<p>The single NetworkPolicy must select only <code>app=orders-api</code>, isolate both ingress and egress, and allow only:</p>
<ul>
<li>ingress from Pods labelled <code>app=edge-gateway</code> in namespace <code>edge</code>, TCP port <code>8080</code>;</li>
<li>egress to Pods labelled <code>app=orders-db</code> in namespace <code>data</code>, TCP port <code>5432</code>; and</li>
<li>egress to Pods labelled <code>k8s-app=kube-dns</code> in namespace <code>kube-system</code>, UDP and TCP port <code>53</code>.</li>
</ul>
<p>Use the immutable namespace label <code>kubernetes.io/metadata.name</code>. Do not use <code>ipBlock</code>, empty peer selectors, additional policies, or wildcard ports.</p>
<div class="callout"><strong>Hard-mode traps:</strong> a Namespace selector and Pod selector must be in the same peer item to mean AND. Separate list items mean OR. NetworkPolicies are additive, DNS needs both protocols, and a read-only root filesystem needs every required writable path mounted explicitly.</div>
<h2>Verification</h2>
<pre><code>kubectl apply --dry-run=client -f .\lab\lesson-34-answer.yaml
kubectl apply -f .\lab\lesson-34-answer.yaml
kubectl -n orders-prod rollout status deployment/orders-api --timeout=90s
kubectl -n orders-prod get deployment orders-api -o jsonpath='{.spec.template.spec.automountServiceAccountToken}{"\n"}'
kubectl -n orders-prod exec deploy/orders-api -c api -- sh -c 'test -f /srv/index.html && touch /var/log/orders/api.log'
kubectl -n orders-prod exec deploy/orders-api -c audit-writer -- test -f /var/log/orders/audit.log</code></pre>
<h2>Retrieval check</h2>
<div class="quiz">
<h3>Question</h3>
<p>How do you require both a namespace label and a Pod label for one NetworkPolicy peer?</p>
<label><input type="radio" name="q" value="same">Place both selectors inside the same peer list item.</label>
<label><input type="radio" name="q" value="split">Place each selector inside a separate peer list item.</label>
<label><input type="radio" name="q" value="policy">Place each selector inside a separate NetworkPolicy object.</label>
<button onclick="check()">Check answer</button>
<p id="feedback" class="feedback" aria-live="polite"></p>
</div>
<h2>Documentation targets</h2>
<p>After your first attempt, use the official Kubernetes <a href="https://kubernetes.io/docs/tasks/configure-pod-container/security-context/">Security Context</a> and <a href="https://kubernetes.io/docs/concepts/services-networking/network-policies/">NetworkPolicy</a> documentation.</p>
<h2>What to send me</h2>
<p>Save the two-resource answer and record your elapsed time. Then say <em>check</em>. I will list all issues and correct one per round. Ask a follow-up question whenever a requirement is ambiguous.</p>
<footer>Previous: <a href="0033-security-context-placement.html">SecurityContext placement</a> · Public curriculum alignment: CKS v1.34</footer>
</main>
<script>
function check(){const c=document.querySelector('input[name=q]:checked'),f=document.getElementById('feedback');if(!c){f.textContent='Choose an answer.';f.className='feedback bad';return;}if(c.value==='same'){f.textContent='Correct. Selectors in one peer are ANDed; separate peers are ORed.';f.className='feedback good';}else{f.textContent='Not quite. Keep both selectors in one peer to require both conditions.';f.className='feedback bad';}}
</script>
</body>
</html>

View File

@@ -0,0 +1,80 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Lesson 35: API server and audit hard mode</title>
<link rel="stylesheet" href="../assets/course.css">
</head>
<body>
<main>
<p class="eyebrow">Lesson 0035 · 45 minutes · Hard mode · Control plane</p>
<h1>Harden the API server and preserve forensic evidence</h1>
<p class="lede">Repair an insecure static Pod and connect it to an ordered audit policy. Treat this as a control-plane maintenance task: preserve required configuration, make paths persistent, and avoid using <code>kubectl apply</code>.</p>
<h2>Task</h2>
<p>Read <code>lab/lesson-35-kube-apiserver-insecure.yaml</code>. Create both:</p>
<ul>
<li><code>lab/lesson-35-kube-apiserver-answer.yaml</code>, a complete replacement static-Pod manifest; and</li>
<li><code>lab/lesson-35-audit-policy.yaml</code>, the referenced audit policy.</li>
</ul>
<p>Preserve every metadata field, Pod field, container field, image, PKI mount, and command flag unless a requirement below explicitly changes it.</p>
<h2>API-server requirements</h2>
<ul>
<li>Disable anonymous authentication and profiling.</li>
<li>Use authorization modes <code>Node,RBAC</code>.</li>
<li>Enable ServiceAccount lookup.</li>
<li>Preserve existing admission plugins and additionally enable <code>NodeRestriction</code>.</li>
<li>Read the audit policy at <code>/etc/kubernetes/audit-policy.yaml</code>.</li>
<li>Write audit events to <code>/var/log/kubernetes/audit/audit.log</code>.</li>
<li>Retain audit logs for 14 days, keep 10 backups, and rotate at 100 MB.</li>
<li>Mount host file <code>/etc/kubernetes/audit-policy.yaml</code> read-only at the identical container path using hostPath type <code>File</code>.</li>
<li>Mount host directory <code>/var/log/kubernetes/audit</code> read-write at the identical container path using hostPath type <code>DirectoryOrCreate</code>.</li>
</ul>
<h2>Audit-policy requirements</h2>
<p>Use <code>audit.k8s.io/v1</code>, kind <code>Policy</code>, globally omit <code>RequestReceived</code>, and order rules so the first match produces:</p>
<ul>
<li><code>RequestResponse</code> for all Secret requests in namespaces <code>payments</code> and <code>orders-prod</code>;</li>
<li><code>Metadata</code> for <code>create</code>, <code>update</code>, <code>patch</code>, <code>delete</code>, and <code>deletecollection</code> on Roles, RoleBindings, ClusterRoles, and ClusterRoleBindings;</li>
<li><code>Request</code> for all <code>pods/exec</code> requests; and</li>
<li><code>Metadata</code> for every remaining request.</li>
</ul>
<p>Do not add a <code>None</code> rule, omit any existing required flag, use a relative path, mount the audit log directory read-only, or apply the static manifest to the API server.</p>
<div class="callout"><strong>Hard-mode traps:</strong> audit rules are first-match wins; RBAC resources use group <code>rbac.authorization.k8s.io</code>; exec is resource <code>pods</code> with subresource <code>exec</code>, represented as <code>pods/exec</code>; and API-server file paths are useless unless the static Pod mounts their host locations.</div>
<h2>Verification</h2>
<pre><code># These are configuration files, not objects to apply.
grep -E -- '--anonymous-auth|--authorization-mode|--profiling|--service-account-lookup|--enable-admission-plugins|--audit-' lab/lesson-35-kube-apiserver-answer.yaml
# Confirm the two mount paths appear in commands, mounts, and hostPath volumes.
grep -nE '/etc/kubernetes/audit-policy.yaml|/var/log/kubernetes/audit' lab/lesson-35-kube-apiserver-answer.yaml
# Inspect rule order and spelling.
cat lab/lesson-35-audit-policy.yaml</code></pre>
<h2>Retrieval check</h2>
<div class="quiz">
<h3>Question</h3>
<p>Why must the Secret rule appear before the catch-all Metadata rule?</p>
<label><input type="radio" name="q" value="first">The first matching rule determines the recorded audit level.</label>
<label><input type="radio" name="q" value="merge">All matching rules merge into one combined audit event.</label>
<label><input type="radio" name="q" value="last">The final matching rule determines the recorded audit level.</label>
<button onclick="check()">Check answer</button>
<p id="feedback" class="feedback" aria-live="polite"></p>
</div>
<h2>Documentation targets</h2>
<p>After your first attempt, use the official Kubernetes <a href="https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/">kube-apiserver flag reference</a> and <a href="https://kubernetes.io/docs/tasks/debug/debug-cluster/audit/">auditing documentation</a>.</p>
<h2>What to send me</h2>
<p>Save both files and say <em>check</em>. I will list all detected issues and correct one per round. Ask a follow-up question whenever a flag, mount, or audit-rule match is unclear.</p>
<footer>Previous: <a href="0034-harden-and-isolate-orders-api.html">Harden and isolate orders-api</a> · Public curriculum alignment: CKS v1.34</footer>
</main>
<script>
function check(){const c=document.querySelector('input[name=q]:checked'),f=document.getElementById('feedback');if(!c){f.textContent='Choose an answer.';f.className='feedback bad';return;}if(c.value==='first'){f.textContent='Correct. A catch-all placed first would shadow every specific rule.';f.className='feedback good';}else{f.textContent='Not quite. Kubernetes stops at the first matching audit rule.';f.className='feedback bad';}}
</script>
</body>
</html>

View File

@@ -0,0 +1,73 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Lesson 36: kube-bench CIS triage</title>
<link rel="stylesheet" href="../assets/course.css">
</head>
<body>
<main>
<p class="eyebrow">Lesson 0036 · 35 minutes · Tool drill · Cluster Setup</p>
<h1>Triage kube-bench findings without obeying the scanner blindly</h1>
<p class="lede">A scanner accelerates inspection; it does not replace component knowledge. Extract non-passing checks, verify them against configuration, identify uncovered components, and prioritize fixes by impact.</p>
<h2>Environment note</h2>
<p>The current Windows shell has no Docker, WSL, Kubernetes CLI, or Linux node access. Use the provided kube-bench JSON report for this training attempt. Hero remains unavailable until you rerun kube-bench on a Linux control-plane and worker node.</p>
<h2>Task: 25 minutes</h2>
<p>Analyze these files without modifying them:</p>
<ul>
<li><code>lab/lesson-36-kube-bench.json</code></li>
<li><code>lab/lesson-35-kube-apiserver-insecure.yaml</code></li>
<li><code>lab/lesson-36-etcd.yaml</code></li>
<li><code>lab/lesson-28-kubelet-review.yaml</code></li>
<li><code>lab/lesson-36-coredns.yaml</code></li>
</ul>
<p>Create <code>lab/lesson-36-answer.md</code> containing:</p>
<ol>
<li>The exact PowerShell command used to extract every non-PASS result from the JSON.</li>
<li>A table for all seven FAIL results and the one WARN result: check ID, component, status, scanner evidence, configuration evidence, verdict, and precise remediation.</li>
<li>Your first three remediations in operational priority order, with one sentence of justification each.</li>
<li>At least four security findings from the CoreDNS Deployment that kube-bench did not report.</li>
<li>One paragraph explaining why WARN does not mean FAIL, why PASS is not universal proof, and why CoreDNS requires manual review here.</li>
<li>The exact Linux commands you would use to install pinned kube-bench v0.16.0, verify its checksum, run control-plane/etcd/node/policies targets as root, save JSON, and make CI return a nonzero code when checks fail.</li>
</ol>
<div class="callout"><strong>Tool reflex:</strong> kube-bench has PASS, FAIL, WARN, and INFO states. A WARN commonly needs manual attention. A failed check can also reflect an execution or detection problem, so compare <code>actual_value</code> and <code>reason</code> with effective configuration before changing a node.</div>
<h2>PowerShell starting shape</h2>
<pre><code>$report = Get-Content .\lab\lesson-36-kube-bench.json -Raw | ConvertFrom-Json
$report.Controls.tests.results |
Where-Object status -ne 'PASS' |
Select-Object test_number, status, test_desc, actual_value, reason</code></pre>
<h2>Linux Hero rerun shape</h2>
<pre><code># Run on a Linux node with access to component processes and files.
sudo kube-bench run --targets master,etcd,node,policies \
--json --outputfile kube-bench.json --exit-code 42</code></pre>
<p>You must determine and record the complete pinned installation and checksum-verification commands yourself.</p>
<h2>Retrieval check</h2>
<div class="quiz">
<h3>Question</h3>
<p>kube-bench reports WARN for a manual check. What should you do?</p>
<label><input type="radio" name="q" value="verify">Inspect the effective configuration and record a manual verdict.</label>
<label><input type="radio" name="q" value="fail">Treat the warning as a proven configuration failure immediately.</label>
<label><input type="radio" name="q" value="ignore">Ignore the warning because only automated checks matter.</label>
<button onclick="check()">Check answer</button>
<p id="feedback" class="feedback" aria-live="polite"></p>
</div>
<h2>Documentation targets</h2>
<p>Use the official <a href="https://github.com/aquasecurity/kube-bench">kube-bench repository</a>, its <a href="https://github.com/aquasecurity/kube-bench/blob/main/docs/installation.md">installation guide</a>, and the applicable CIS benchmark guidance after your first analysis.</p>
<h2>What to send me</h2>
<p>Save the Markdown answer and say <em>check</em>. I will list every issue and correct one per round. This attempt can advance CS-02 training, but the Hero tool gate requires a later real-node run.</p>
<footer>Previous: <a href="0035-apiserver-audit-hard-mode.html">API server and audit hard mode</a> · Tracker: <a href="../CKS-MASTERY-CHECKLIST.md">CKS Mastery Checklist</a></footer>
</main>
<script>
function check(){const c=document.querySelector('input[name=q]:checked'),f=document.getElementById('feedback');if(!c){f.textContent='Choose an answer.';f.className='feedback bad';return;}if(c.value==='verify'){f.textContent='Correct. WARN requires a manual, evidence-based verdict.';f.className='feedback good';}else{f.textContent='Not quite. The scanner has not proved either compliance or failure.';f.className='feedback bad';}}
</script>
</body>
</html>