CKSKubernetes 1.35

Lessons

CIS benchmark with kube-bench: run it, then actually fix it

updated 2026-10-22 by seed

Run it

# as a Job, cluster-wide (control plane checks run against the local node)
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
kubectl logs job/benchmark
kubectl delete job benchmark

# or directly on a node, when the task says "on controlplane"
kube-bench run --targets master,node
kube-bench run --targets master --check 1.2.1     # one control

The output is a table of [PASS] [FAIL] [WARN] [INFO] with a control number and
a remediation hint. The exam wants the FAIL fixed, not reported.

The controls that actually show up

API server (/etc/kubernetes/manifests/kube-apiserver.yaml)

controlflag
1.2.1 anonymous auth--anonymous-auth=false (or remove; default is true)
1.2.6 insecure port--insecure-port=0
1.2.7 profiling--profiling=false
1.2.8/9 audit--audit-log-path, --audit-policy-file
1.2.11 admission--enable-admission-plugins=NodeRestriction
1.2.16/17 authz--authorization-mode=Node,RBAC
1.2.21 service account keys--service-account-key-file, --service-account-signing-key-file

etcd (/etc/kubernetes/manifests/etcd.yaml)

controlflag
2.1 client cert auth--client-cert-auth=true
2.2/2.4 certs--cert-file, --key-file, --trusted-ca-file
2.3/2.5 peer--peer-client-cert-auth=true, --peer-cert-file, --peer-key-file

kubelet (/var/lib/kubelet/config.yaml)

authentication:
  anonymous: {enabled: false}
  webhook: {enabled: true}
authorization:
  mode: Webhook
readOnlyPort: 0
protectKernelDefaults: true
makeIPTablesUtilChains: true

controller-manager / scheduler (/etc/kubernetes/manifests/*.yaml)

--profiling=false, --bind-address=127.0.0.1, --use-service-account-credentials=true.

Editing a static pod without breaking the cluster

The API server, controller-manager, scheduler and etcd are static pods: the
kubelet watches the manifest directory and restarts the container when the file
changes. There is no systemctl restart kube-apiserver.

sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
# wait for the container to come back
sudo crictl ps | grep kube-apiserver
kubectl get --raw /healthz

Traps:

  • YAML must stay valid. One bad indent and the API server is gone, kubectl stops working, and you fix it with vi in the same SSH session. That is survivable — panic is what kills the task.
  • Back up first: cp kube-apiserver.yaml /root/apiserver.bak. Two seconds.
  • If the API server is down, kubectl cannot help you. crictl ps -a, crictl logs <id>, and the kubelet journal (journalctl -u kubelet) are your only tools.
  • Some flags need a matching volume mount (audit policy file, cert files). A flag pointing at a file that is not mounted fails at startup.

Re-run and prove it

kube-bench run --targets master --check 1.2.1
kubectl get --raw /healthz

The task is done when the control reads [PASS] and the cluster still serves
requests. Both halves are marked.