CIS benchmarks with kube-bench

Score a node against the benchmark, then remediate.

Advanced12 min · lesson 3 of 24

The CIS Kubernetes Benchmark is the industry consensus checklist for a hardened cluster — hundreds of specific, testable recommendations covering control-plane flags, file ownership and permissions, and kubelet settings. It is long and dry, which is exactly why you do not read it by hand: kube-bench runs the whole benchmark against a node and scores it, citing the benchmark item number and the remediation for every finding.

Run it per node role, because control-plane and worker nodes are scored against different sections. The output uses PASS, FAIL, WARN, and INFO — FAIL is a hard miss with a clear fix, WARN usually means “check this manually, the tool cannot see enough.” The common way to run it inside a cluster is as a Job from the aquasec/kube-bench image, but on the exam it is typically already installed on the node.

terminal
$ kube-bench run --targets master
[INFO] 1 Control Plane Security Configuration
[PASS] 1.2.6 Ensure --kubelet-certificate-authority is set (Automated)
[FAIL] 1.2.1 Ensure --anonymous-auth is set to false (Manual)
[FAIL] 1.2.19 Ensure --profiling is set to false (Automated)
[WARN] 1.1.12 Ensure the etcd data directory ownership is set to etcd:etcd
== Remediations master ==
1.2.1 Edit the API server pod spec /etc/kubernetes/manifests/kube-apiserver.yaml
on the control plane node and set --anonymous-auth=false

Read the report, then remediate in place

Each FAIL names the file and the value. Control-plane flags live in the static pod manifests, and saving the file makes the kubelet restart that component within seconds — no apply, no kubectl. Crucially, the benchmark scores the controller-manager and scheduler as well as the API server, so a real pass means editing all three manifests, not just kube-apiserver.yaml.

/etc/kubernetes/manifests/kube-controller-manager.yaml
spec:
containers:
- command:
- kube-controller-manager
- --profiling=false # 1.3.2
- --use-service-account-credentials=true # 1.3.3
# after saving, watch it restart:
# crictl ps | grep controller-manager (new container, seconds old)

Iterate tightly: fix a batch, re-run kube-bench scoped to just those checks, and confirm FAIL turned to PASS before moving on. Scoping keeps the output short enough to read and gives you a fast feedback loop instead of scrolling a hundred lines each pass.

terminal
$ kube-bench run --targets master --check 1.2.1,1.2.19,1.3.2
[PASS] 1.2.1 Ensure --anonymous-auth is set to false
[PASS] 1.2.19 Ensure --profiling is set to false
[PASS] 1.3.2 Ensure --profiling is set to false (controller-manager)
Not every FAIL is a flag
A large share of the benchmark is file ownership and permissions — chmod 600 on the manifests and kubeconfigs, chown etcd:etcd on the etcd data directory. Read the remediation before acting: some items want a chmod, not an edit, and blindly adding a flag that does not exist can crash the component. And record a written justification for anything you deliberately leave failing.