CIS benchmark with kube-bench: run it, then actually fix it
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)
| control | flag |
|---|---|
| 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)
| control | flag |
|---|---|
| 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,
kubectlstops working, and you fix it withviin 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,
kubectlcannot 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.