From ac6292db204769020a1f5273a8b0bbad39fa7769 Mon Sep 17 00:00:00 2001 From: Mosiur Rahman Date: Thu, 27 Aug 2026 14:03:17 +0600 Subject: [PATCH] completed upto lab 38 --- CKS-DASHBOARD.html | 3 + CKS-MASTERY-CHECKLIST.md | 9 +- README.md | 3 + lab-environment/bootstrap.sh | 20 +- lab-environment/create-lab.sh | 7 +- lab-environment/enter-lab.ps1 | 14 +- lab-environment/enter-lab.sh | 25 +++ lab/lesson-36-controlplane-after.txt | 17 ++ lab/lesson-36-controlplane-before.txt | 183 +----------------- lab/lesson-36-worker-before.txt | 15 ++ lab/lesson-37-etcd-insecure.yaml | 47 +++++ lab/lesson-37-verify.sh | 28 +++ lab/lesson-38-effective-args.txt | 1 + lab/lesson-38-kubelet-config.yaml | 11 ++ lab/lesson-38-verify.sh | 17 ++ ...11-etcd-transport-and-metrics-hardening.md | 7 + .../0012-kubelet-effective-configuration.md | 7 + .../0037-etcd-static-manifest-hardening.html | 4 + .../0038-kubelet-effective-configuration.html | 6 + 19 files changed, 220 insertions(+), 204 deletions(-) create mode 100644 CKS-DASHBOARD.html create mode 100644 lab-environment/enter-lab.sh create mode 100644 lab/lesson-36-controlplane-after.txt create mode 100644 lab/lesson-36-worker-before.txt create mode 100644 lab/lesson-37-etcd-insecure.yaml create mode 100644 lab/lesson-37-verify.sh create mode 100644 lab/lesson-38-effective-args.txt create mode 100644 lab/lesson-38-kubelet-config.yaml create mode 100644 lab/lesson-38-verify.sh create mode 100644 learning-records/0011-etcd-transport-and-metrics-hardening.md create mode 100644 learning-records/0012-kubelet-effective-configuration.md create mode 100644 lessons/0037-etcd-static-manifest-hardening.html create mode 100644 lessons/0038-kubelet-effective-configuration.html diff --git a/CKS-DASHBOARD.html b/CKS-DASHBOARD.html new file mode 100644 index 0000000..20314ee --- /dev/null +++ b/CKS-DASHBOARD.html @@ -0,0 +1,3 @@ +CKS mastery dashboard

CKS mastery dashboard · updated 27 August 2026

Build confidence into evidence.

Lab ready · Kubernetes v1.34 · Linux tools installed · 2 CIS labs passed today

85%topic coverage

22 of 26 topics have practical training evidence.

Hero is deliberately strict: tool drill, capstone, evidence, scope review, and cold retest.

22training
4not started
0heroes—yet

Coverage by domain

training / total
Cluster Setup
5/5
Cluster Hardening
3/4
System Hardening
2/4
Microservices
4/4
Supply Chain
3/4
Monitoring & Runtime
5/5

CS-02 Hero checklist

CIS components
Tool drillskube-bench, etcd, and kubelet practised
Timed capstonemulti-component remediation
Evidence & cold retestsaved PASS groups, then repeat later

Next win

CS-02.Q4 — secure CoreDNS component review

Deployment, ServiceAccount, RBAC, ConfigMap, image, and security context.

Open checklist
diff --git a/CKS-MASTERY-CHECKLIST.md b/CKS-MASTERY-CHECKLIST.md index e5d872d..4f5f1e1 100644 --- a/CKS-MASTERY-CHECKLIST.md +++ b/CKS-MASTERY-CHECKLIST.md @@ -58,18 +58,18 @@ Minor syntax corrections during training are expected. A cold retest fails when ## Next Task -Finish the one-time local lab installation after Windows restarts, then run `CS-02.Q1` as revised Lesson 0036 on `kind-cks-lab`. Do not use the learner's Kubernetes v1.36 production cluster: kube-bench v0.16.0 has automatic version mappings only through v1.34. +Run `CS-02.Q4`: review CoreDNS deployment, ServiceAccount, RBAC, ConfigMap, image, and security context; distinguish CIS-relevant component configuration from workload hardening. Do not use the learner's Kubernetes v1.36 production cluster. ## Local Lab Environment -Status: `WINDOWS RESTART REQUIRED` +Status: `READY` - Platform: Ubuntu 24.04 on WSL2, Docker Engine, two-node Kind cluster, and Calico. - Kubernetes: pinned to v1.34.0; kube-bench: pinned to v0.16.0. - Cluster and context: `cks-lab` / `kind-cks-lab`. - Kubeconfig: `/opt/cks-lab/kubeconfig`; it is never merged with a production config. - Setup and recovery files: `lab-environment/`. -- Resume after restart: run `lab-environment\\02-install-and-build.ps1`, then `lab-environment\\verify-lab.ps1`. +- Enter the ready lab with `lab-environment\\enter-lab.ps1`; verify or rebuild it with `lab-environment\\verify-lab.ps1` and `lab-environment\\02-install-and-build.ps1`. - Lesson scope: use Kind nodes for Kubernetes tasks and the disposable Ubuntu WSL2 VM for host/kernel hardening tasks. --- @@ -603,6 +603,9 @@ Append one row after every graded attempt. | Date | Task | Topic | Time | Result | Critical errors | Evidence | Next action | |---|---|---|---:|---|---:|---|---| +| 2026-08-27 | Lesson 0038 | CS-02 | Not recorded | Training pass | 0 after verifier correction | `lab/lesson-38-verify.sh /tmp/lesson-38-kubelet.yaml`: all PASS | Continue CS-02.Q4 | +| 2026-08-27 | Lesson 0037 | CS-02 | Not recorded | Training pass | 0 after one correction | `lab/lesson-37-verify.sh /tmp/lesson-37-etcd.yaml`: all PASS | Continue CS-02.Q3 | +| 2026-08-27 | Lesson 0036 | CS-02 | 90 minutes | Partial training evidence | etcd and worker checks not captured | `lab/lesson-36-controlplane-after.txt` shows 1.2.1 and 1.2.7 PASS | Run focused CS-02.Q2, then require PASS evidence | | 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 | diff --git a/README.md b/README.md index e69de29..359b175 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,3 @@ +# CKS training workspace + +Start with the [CKS Mastery Dashboard](CKS-DASHBOARD.html). The [Mastery Checklist](CKS-MASTERY-CHECKLIST.md) is the canonical record of evidence, Hero gates, and the next task. diff --git a/lab-environment/bootstrap.sh b/lab-environment/bootstrap.sh index 47051d7..bc73dcb 100644 --- a/lab-environment/bootstrap.sh +++ b/lab-environment/bootstrap.sh @@ -20,7 +20,15 @@ EOF export DEBIAN_FRONTEND=noninteractive apt-get update -apt-get install -y ca-certificates curl gnupg jq vim git iproute2 iptables conntrack socat +apt-get install -y \ + bash-completion ca-certificates conntrack curl dnsutils git gnupg iproute2 \ + iptables iputils-ping jq less lsof man-db nano netcat-openbsd procps psmisc \ + socat strace tcpdump tree vim wget yq + +cat >/etc/profile.d/cks-lab.sh <<'EOF' +alias k=kubectl +complete -o default -F __start_kubectl k 2>/dev/null || true +EOF install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc @@ -45,20 +53,20 @@ curl -fsSLo "$tmp_dir/kubectl.sha256" "https://dl.k8s.io/release/${KUBECTL_VERSI printf '%s %s\n' "$(cat "$tmp_dir/kubectl.sha256")" "$tmp_dir/kubectl" | sha256sum --check --status install -m 0755 "$tmp_dir/kubectl" /usr/local/bin/kubectl -curl -fsSLo "$tmp_dir/kind" "https://kind.sigs.k8s.io/dl/${KIND_VERSION}/kind-linux-amd64" +curl -fsSLo "$tmp_dir/kind-linux-amd64" "https://kind.sigs.k8s.io/dl/${KIND_VERSION}/kind-linux-amd64" curl -fsSLo "$tmp_dir/kind.sha256sum" "https://kind.sigs.k8s.io/dl/${KIND_VERSION}/kind-linux-amd64.sha256sum" (cd "$tmp_dir" && sha256sum --check --status kind.sha256sum) -install -m 0755 "$tmp_dir/kind" /usr/local/bin/kind +install -m 0755 "$tmp_dir/kind-linux-amd64" /usr/local/bin/kind -curl -fsSLo "$tmp_dir/kube-bench.tar.gz" \ +curl -fsSLo "$tmp_dir/kube-bench_${KUBE_BENCH_VERSION}_linux_amd64.tar.gz" \ "https://github.com/aquasecurity/kube-bench/releases/download/v${KUBE_BENCH_VERSION}/kube-bench_${KUBE_BENCH_VERSION}_linux_amd64.tar.gz" curl -fsSLo "$tmp_dir/checksums.txt" \ "https://github.com/aquasecurity/kube-bench/releases/download/v${KUBE_BENCH_VERSION}/kube-bench_${KUBE_BENCH_VERSION}_checksums.txt" (cd "$tmp_dir" && grep " kube-bench_${KUBE_BENCH_VERSION}_linux_amd64.tar.gz$" checksums.txt | sha256sum --check --status) rm -rf /opt/cks-lab/tools/kube-bench install -d /opt/cks-lab/tools/kube-bench -tar -xzf "$tmp_dir/kube-bench.tar.gz" -C /opt/cks-lab/tools/kube-bench +tar -xzf "$tmp_dir/kube-bench_${KUBE_BENCH_VERSION}_linux_amd64.tar.gz" -C /opt/cks-lab/tools/kube-bench ln -sfn /opt/cks-lab/tools/kube-bench/kube-bench /usr/local/bin/kube-bench -printf 'Installed kubectl %s, Kind %s, and kube-bench %s.\n' \ +printf 'Installed CKS command-line tools plus kubectl %s, Kind %s, and kube-bench %s.\n' \ "$KUBECTL_VERSION" "$KIND_VERSION" "$KUBE_BENCH_VERSION" diff --git a/lab-environment/create-lab.sh b/lab-environment/create-lab.sh index a30226f..b230884 100644 --- a/lab-environment/create-lab.sh +++ b/lab-environment/create-lab.sh @@ -31,9 +31,9 @@ if [[ "$context" != "kind-${CLUSTER_NAME}" ]]; then exit 1 fi -kubectl apply -f "https://raw.githubusercontent.com/projectcalico/calico/${CALICO_VERSION}/manifests/operator-crds.yaml" -kubectl apply -f "https://raw.githubusercontent.com/projectcalico/calico/${CALICO_VERSION}/manifests/tigera-operator.yaml" -kubectl apply -f "https://raw.githubusercontent.com/projectcalico/calico/${CALICO_VERSION}/manifests/custom-resources.yaml" +kubectl apply --server-side --validate=false -f "https://raw.githubusercontent.com/projectcalico/calico/${CALICO_VERSION}/manifests/operator-crds.yaml" +kubectl apply --server-side --validate=false -f "https://raw.githubusercontent.com/projectcalico/calico/${CALICO_VERSION}/manifests/tigera-operator.yaml" +kubectl apply --server-side --validate=false -f "https://raw.githubusercontent.com/projectcalico/calico/${CALICO_VERSION}/manifests/custom-resources.yaml" kubectl wait --for=condition=Available deployment/tigera-operator -n tigera-operator --timeout=300s kubectl wait --for=condition=Ready nodes --all --timeout=600s @@ -43,4 +43,3 @@ for node in "${CLUSTER_NAME}-control-plane" "${CLUSTER_NAME}-worker"; do docker cp /opt/cks-lab/tools/kube-bench "$node":/opt/kube-bench docker exec "$node" /opt/kube-bench/kube-bench version done - diff --git a/lab-environment/enter-lab.ps1 b/lab-environment/enter-lab.ps1 index 69ec1f5..75ba54d 100644 --- a/lab-environment/enter-lab.ps1 +++ b/lab-environment/enter-lab.ps1 @@ -1,17 +1,9 @@ $ErrorActionPreference = 'Stop' $distribution = 'Ubuntu-24.04' +$linuxScript = (& wsl.exe --distribution $distribution --user root --exec wslpath -a "$PSScriptRoot/enter-lab.sh").Trim() +if (-not $linuxScript) { throw 'Could not locate the Linux lab entry script.' } -& wsl.exe --distribution $distribution --user root --exec bash -lc @' -export KUBECONFIG=/opt/cks-lab/kubeconfig -context="$(kubectl config current-context 2>/dev/null || true)" -if [[ "$context" != "kind-cks-lab" ]]; then - echo "Safety check failed: expected kind-cks-lab, got ${context:-none}." >&2 - exit 1 -fi -echo "CKS lab: $(kubectl version --output=json | jq -r .serverVersion.gitVersion)" -echo "Context: $context" -exec bash -'@ +& wsl.exe --distribution $distribution --user root --exec bash $linuxScript if ($LASTEXITCODE -ne 0) { throw 'Could not enter the isolated CKS lab.' } diff --git a/lab-environment/enter-lab.sh b/lab-environment/enter-lab.sh new file mode 100644 index 0000000..5ef4584 --- /dev/null +++ b/lab-environment/enter-lab.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +export KUBECONFIG=/opt/cks-lab/kubeconfig +expected_context=kind-cks-lab +context="$(kubectl config current-context 2>/dev/null || true)" + +if [[ "$context" != "$expected_context" ]]; then + echo "Safety check failed: expected $expected_context, got ${context:-none}." >&2 + exit 1 +fi + +echo "CKS lab: $(kubectl version --output=json | jq -r .serverVersion.gitVersion)" +echo "Context: $context" +required_tools=(kubectl kube-bench nano vim curl wget jq yq dig nc ss ps less) +missing_tools=() +for tool in "${required_tools[@]}"; do + command -v "$tool" >/dev/null 2>&1 || missing_tools+=("$tool") +done +if (( ${#missing_tools[@]} )); then + echo "Lab setup incomplete; missing: ${missing_tools[*]}. Run ./02-install-and-build.ps1." >&2 + exit 1 +fi +echo "Tools: ready (nano, curl, wget, jq, yq, dig, nc, tcpdump, ss); alias k=kubectl" +exec bash diff --git a/lab/lesson-36-controlplane-after.txt b/lab/lesson-36-controlplane-after.txt new file mode 100644 index 0000000..bb3124c --- /dev/null +++ b/lab/lesson-36-controlplane-after.txt @@ -0,0 +1,17 @@ +root@cks-lab-control-plane:/opt/kube-bench# ./kube-bench --benchmark cis-1.12 --config-dir cfg run --targets master --check 1.2.1,1.2.7,2.2,2.3 +[INFO] 1 Control Plane Security Configuration +[INFO] 1.2 API Server +[PASS] 1.2.1 Ensure that the --anonymous-auth argument is set to false (Manual) +[PASS] 1.2.7 Ensure that the --authorization-mode argument includes Node (Automated) + +== Summary master == +2 checks PASS +0 checks FAIL +0 checks WARN +0 checks INFO + +== Summary total == +2 checks PASS +0 checks FAIL +0 checks WARN +0 checks INFO \ No newline at end of file diff --git a/lab/lesson-36-controlplane-before.txt b/lab/lesson-36-controlplane-before.txt index 374e577..597c2e1 100644 --- a/lab/lesson-36-controlplane-before.txt +++ b/lab/lesson-36-controlplane-before.txt @@ -1,6 +1,7 @@ [INFO] 1 Control Plane Security Configuration [INFO] 1.2 API Server [WARN] 1.2.1 Ensure that the --anonymous-auth argument is set to false (Manual) +[PASS] 1.2.7 Ensure that the --authorization-mode argument includes Node (Automated) == Remediations master == 1.2.1 Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml @@ -9,191 +10,13 @@ on the control plane node and set the below parameter. == Summary master == -0 checks PASS +1 checks PASS 0 checks FAIL 1 checks WARN 0 checks INFO -[INFO] 2 Etcd Node Configuration - -== Summary etcd == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 3 Control Plane Configuration - -== Summary controlplane == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 4 Worker Node Security Configuration - -== Summary node == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 5 Kubernetes Policies - -== Summary policies == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - == Summary total == -0 checks PASS +1 checks PASS 0 checks FAIL 1 checks WARN 0 checks INFO - - -[INFO] 1 Control Plane Security Configuration -[INFO] 1.2 API Server -[PASS] 1.2.7 Ensure that the --authorization-mode argument includes Node (Automated) - -== Summary master == -1 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 2 Etcd Node Configuration - -== Summary etcd == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 3 Control Plane Configuration - -== Summary controlplane == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 4 Worker Node Security Configuration - -== Summary node == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 5 Kubernetes Policies - -== Summary policies == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -== Summary total == -1 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - - -[INFO] 1 Control Plane Security Configuration - -== Summary master == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 2 Etcd Node Configuration -[INFO] 2 Etcd Node Configuration -[PASS] 2.2 Ensure that the --client-cert-auth argument is set to true (Automated) - -== Summary etcd == -1 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 3 Control Plane Configuration - -== Summary controlplane == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 4 Worker Node Security Configuration - -== Summary node == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 5 Kubernetes Policies - -== Summary policies == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -== Summary total == -1 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 1 Control Plane Security Configuration - -== Summary master == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 2 Etcd Node Configuration -[INFO] 2 Etcd Node Configuration -[PASS] 2.3 Ensure that the --auto-tls argument is not set to true (Automated) - -== Summary etcd == -1 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 3 Control Plane Configuration - -== Summary controlplane == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 4 Worker Node Security Configuration - -== Summary node == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -[INFO] 5 Kubernetes Policies - -== Summary policies == -0 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO - -== Summary total == -1 checks PASS -0 checks FAIL -0 checks WARN -0 checks INFO diff --git a/lab/lesson-36-worker-before.txt b/lab/lesson-36-worker-before.txt new file mode 100644 index 0000000..a8c834d --- /dev/null +++ b/lab/lesson-36-worker-before.txt @@ -0,0 +1,15 @@ +root@cks-lab-worker:/opt/kube-bench# ./kube-bench --benchmark cis-1.12 --config-dir cfg run --targets master --check 4.2.1,4.2.2,4.2.3 +Warning: Kubernetes version was not auto-detected because kubectl could not connect to the Kubernetes server. This may be because the kubeconfig information is missing or has credentials that do not match the server. Assuming default version 1.18 +[INFO] 1 Control Plane Security Configuration + +== Summary master == +0 checks PASS +0 checks FAIL +0 checks WARN +0 checks INFO + +== Summary total == +0 checks PASS +0 checks FAIL +0 checks WARN +0 checks INFO diff --git a/lab/lesson-37-etcd-insecure.yaml b/lab/lesson-37-etcd-insecure.yaml new file mode 100644 index 0000000..792e5a2 --- /dev/null +++ b/lab/lesson-37-etcd-insecure.yaml @@ -0,0 +1,47 @@ +apiVersion: v1 +kind: Pod +metadata: + name: etcd + namespace: kube-system + labels: + component: etcd +spec: + hostNetwork: true + containers: + - name: etcd + image: registry.k8s.io/etcd:3.6.4-0 + command: + - etcd + - --name=controlplane + - --data-dir=/var/lib/etcd + - --listen-client-urls=http://127.0.0.1:2379,https://10.0.0.10:2379 + - --advertise-client-urls=https://10.0.0.10:2379 + - --initial-advertise-peer-urls=https://10.0.0.10:2380 + - --listen-peer-urls=https://10.0.0.10:2380 + - --initial-cluster=controlplane=https://10.0.0.10:2380 + - --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=false + - --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 + - --peer-auto-tls=true + - --listen-metrics-urls=http://0.0.0.0:2381 + volumeMounts: + - name: etcd-data + mountPath: /var/lib/etcd + - name: etcd-certs + mountPath: /etc/kubernetes/pki/etcd + readOnly: true + volumes: + - name: etcd-data + hostPath: + path: /var/lib/etcd + type: DirectoryOrCreate + - name: etcd-certs + hostPath: + path: /etc/kubernetes/pki/etcd + type: DirectoryOrCreate diff --git a/lab/lesson-37-verify.sh b/lab/lesson-37-verify.sh new file mode 100644 index 0000000..1b5fc4a --- /dev/null +++ b/lab/lesson-37-verify.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +manifest=${1:?Usage: lesson-37-verify.sh PATH_TO_MANIFEST} +[[ -f "$manifest" ]] || { echo "FAIL manifest not found"; exit 1; } + +required=( + '--client-cert-auth=true' + '--auto-tls=false' + '--peer-client-cert-auth=true' + '--peer-auto-tls=false' + '--trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt' + '--peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt' + '--listen-metrics-urls=http://127.0.0.1:2381' +) +for flag in "${required[@]}"; do + if grep -Fqx " - $flag" "$manifest"; then + echo "PASS $flag" + else + echo "FAIL $flag" + fi +done + +if grep -Eq 'http://0\.0\.0\.0:2381|http://127\.0\.0\.1:2379' "$manifest"; then + echo 'FAIL insecure etcd listener remains' +else + echo 'PASS no insecure etcd listener' +fi diff --git a/lab/lesson-38-effective-args.txt b/lab/lesson-38-effective-args.txt new file mode 100644 index 0000000..0015a09 --- /dev/null +++ b/lab/lesson-38-effective-args.txt @@ -0,0 +1 @@ +/usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf --config=/tmp/lesson-38-kubelet.yaml --anonymous-auth=false --authentication-token-webhook=true --authorization-mode=Webhook --read-only-port=0 --rotate-certificates=true diff --git a/lab/lesson-38-kubelet-config.yaml b/lab/lesson-38-kubelet-config.yaml new file mode 100644 index 0000000..5133f61 --- /dev/null +++ b/lab/lesson-38-kubelet-config.yaml @@ -0,0 +1,11 @@ +apiVersion: kubelet.config.k8s.io/v1beta1 +kind: KubeletConfiguration +authentication: + anonymous: + enabled: true + webhook: + enabled: false +authorization: + mode: AlwaysAllow +readOnlyPort: 10255 +rotateCertificates: false diff --git a/lab/lesson-38-verify.sh b/lab/lesson-38-verify.sh new file mode 100644 index 0000000..21503ff --- /dev/null +++ b/lab/lesson-38-verify.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +config=${1:?Usage: lesson-38-verify.sh PATH_TO_CONFIG} +[[ -f "$config" ]] || { echo "FAIL configuration not found"; exit 1; } + +check() { + local label=$1 expected=$2 query=$3 actual + actual="$(yq -r "$query" "$config")" + if [[ "$actual" == "$expected" ]]; then echo "PASS $label"; else echo "FAIL $label (got: $actual)"; fi +} + +check 'anonymous authentication disabled' false '.authentication.anonymous.enabled' +check 'webhook authentication enabled' true '.authentication.webhook.enabled' +check 'webhook authorization selected' Webhook '.authorization.mode' +check 'read-only port disabled' 0 '.readOnlyPort' +check 'certificate rotation enabled' true '.rotateCertificates' diff --git a/learning-records/0011-etcd-transport-and-metrics-hardening.md b/learning-records/0011-etcd-transport-and-metrics-hardening.md new file mode 100644 index 0000000..76b45f2 --- /dev/null +++ b/learning-records/0011-etcd-transport-and-metrics-hardening.md @@ -0,0 +1,7 @@ +# etcd transport and metrics hardening + +The learner independently remediated an etcd static manifest to require client and peer certificates, disable automatic TLS, eliminate HTTP client exposure, and bind metrics to loopback while preserving the existing CA and certificate paths. This establishes a reliable baseline for the next CIS drill: reconciling kubelet configuration with its effective process. + +## Evidence + +`lab/lesson-37-verify.sh /tmp/lesson-37-etcd.yaml` reported every required control as PASS on 2026-08-27. diff --git a/learning-records/0012-kubelet-effective-configuration.md b/learning-records/0012-kubelet-effective-configuration.md new file mode 100644 index 0000000..e7ab06d --- /dev/null +++ b/learning-records/0012-kubelet-effective-configuration.md @@ -0,0 +1,7 @@ +# Kubelet configuration and effective flags + +The learner reconciled an insecure KubeletConfiguration with approved effective flags, independently setting anonymous authentication off, webhook authentication and authorization on, the read-only port to zero, and certificate rotation on. Future CIS practice can now combine configuration-file review with process-argument verification. + +## Evidence + +`lab/lesson-38-verify.sh /tmp/lesson-38-kubelet.yaml` reported all five controls as PASS on 2026-08-27. diff --git a/lessons/0037-etcd-static-manifest-hardening.html b/lessons/0037-etcd-static-manifest-hardening.html new file mode 100644 index 0000000..b777eb9 --- /dev/null +++ b/lessons/0037-etcd-static-manifest-hardening.html @@ -0,0 +1,4 @@ +Lesson 37: etcd static-manifest hardening

Lesson 0037 · 15 minutes · Linux performance lab · Cluster Setup

Harden etcd without breaking membership

This is a focused CIS remediation drill. It deliberately removes the cluster-entry and package-installation friction from the previous attempt.

Scope discipline: change only the insecure transport, authentication, and metrics flags. Preserve identity, data, listen/advertise peer addresses, initial cluster membership, certificates, mounts, and image.

Task

On the Linux lab shell, create /tmp/lesson-37-etcd.yaml from lab/lesson-37-etcd-insecure.yaml. Make it pass the supplied verifier.

Do not edit the original fixture or verifier. Do not use kubectl apply; this is a static-manifest file exercise.

Start and prove it

cd /mnt/c/Cloud-Team/04_Learning_and_Reference/Training/CKS
+cp lab/lesson-37-etcd-insecure.yaml /tmp/lesson-37-etcd.yaml
+nano /tmp/lesson-37-etcd.yaml
+bash lab/lesson-37-verify.sh /tmp/lesson-37-etcd.yaml

Completion means every line reports PASS. Send that output only.

Documentation

Use the official etcd transport security guide if needed. The CKS objective is preserving the required configuration while closing only the proven exposure.

diff --git a/lessons/0038-kubelet-effective-configuration.html b/lessons/0038-kubelet-effective-configuration.html new file mode 100644 index 0000000..71dfa46 --- /dev/null +++ b/lessons/0038-kubelet-effective-configuration.html @@ -0,0 +1,6 @@ +Lesson 38: kubelet effective configuration

Lesson 0038 · 15 minutes · Linux performance lab · Cluster Setup

Reconcile kubelet configuration with effective flags

Kubelet security faults often come from believing a configuration file is the whole truth. Inspect the effective arguments, then make the structured configuration agree with the required boundary.

Scope: the effective arguments in this task are the approved cluster policy. Correct the supplied KubeletConfiguration; do not change the argument file or add unrelated fields.

Task

On the Linux lab shell, create /tmp/lesson-38-kubelet.yaml from lab/lesson-38-kubelet-config.yaml. It must match the security posture expressed by lab/lesson-38-effective-args.txt.

Bring all five controls into agreement: anonymous authentication, webhook authentication, authorization mode, read-only port, and certificate rotation.

Start and verify

cd /mnt/c/Cloud-Team/04_Learning_and_Reference/Training/CKS
+cat lab/lesson-38-effective-args.txt
+cp lab/lesson-38-kubelet-config.yaml /tmp/lesson-38-kubelet.yaml
+nano /tmp/lesson-38-kubelet.yaml
+bash lab/lesson-38-verify.sh /tmp/lesson-38-kubelet.yaml

Completion means five PASS lines. Send only that output.

Exam-speed inspection

docker exec cks-lab-worker ps -ef | grep '[k]ubelet'
+docker exec cks-lab-worker sed -n '1,120p' /var/lib/kubelet/config.yaml

Use these after the task to compare the fixture with the real disposable worker. Do not modify the live worker configuration for this drill.