CKS — kube-bench Setup & Installation
Exam Context
| Property | Value |
|---|---|
| Domain | Domain 1 — Cluster Setup |
| Weight | 10% |
| Objective | Use CIS benchmark to review the security configuration of Kubernetes components |
kube-bench is the tool you’ll use on the CKS exam to run CIS benchmark checks. You need to know how to install it, run it, and interpret its output — quickly. This topic covers all three installation methods and the output format in detail.
What Is kube-bench?
kube-bench is an open-source Go application by Aqua Security that checks whether Kubernetes is deployed securely by running the checks documented in the CIS Kubernetes Benchmark.
| Property | Details |
|---|---|
| Maintainer | Aqua Security |
| Language | Go |
| License | Apache 2.0 |
| Repository | github.com/aquasecurity/kube-bench |
| Runs on | Linux (master and worker nodes) |
| Output formats | Text (default), JSON, JUnit |
| Auto-detection | Detects Kubernetes version and selects the correct CIS benchmark |
How kube-bench Works
kube-bench operates by:
- Detecting the Kubernetes version running on the node
- Selecting the appropriate CIS benchmark configuration
- Checking running processes, configuration files, and file permissions
- Comparing actual values against expected values from the benchmark
- Producing a report categorized by PASS, FAIL, WARN, and INFO
kube-bench must run on the node itself (not remotely) because it inspects local processes and files. This is why running it as a Kubernetes Job is the most practical approach.
Installation Method 1: Binary Download
The simplest method — download the pre-compiled binary directly to the node.
Download and Install
# Set the version (check GitHub releases for latest)
KUBE_BENCH_VERSION=0.8.0
# Download the binary
curl -L https://github.com/aquasecurity/kube-bench/releases/download/v${KUBE_BENCH_VERSION}/kube-bench_${KUBE_BENCH_VERSION}_linux_amd64.tar.gz -o kube-bench.tar.gz
# Extract
tar -xvf kube-bench.tar.gz
# Move to PATH
sudo mv kube-bench /usr/local/bin/
# Verify installation
kube-bench version
Expected output:
v0.8.0
Run a Basic Scan
# Run all checks (must be run as root or with sudo)
sudo kube-bench run
# Run only master checks (on a control plane node)
sudo kube-bench run --targets master
# Run only node checks (on a worker node)
sudo kube-bench run --targets node
Configuration Files
When installed as a binary, kube-bench looks for configuration files in these locations:
# Default configuration directory
/etc/kube-bench/cfg/
# Alternative location
~/.kube-bench/cfg/
# Or specify explicitly
kube-bench run --config-dir /path/to/cfg
The configuration directory contains YAML files that define the checks:
cfg/
├── cis-1.9/
│ ├── config.yaml
│ ├── controlplane.yaml
│ ├── etcd.yaml
│ ├── master.yaml
│ ├── node.yaml
│ └── policies.yaml
└── cis-1.10/
├── config.yaml
├── controlplane.yaml
├── etcd.yaml
├── master.yaml
├── node.yaml
└── policies.yaml
Installation Method 2: Container Image
Run kube-bench as a container directly on the node using Docker or containerd.
Using Docker
# Run against the host (mount host filesystem and PID namespace)
docker run --rm \
--pid=host \
-v /etc:/etc:ro \
-v /var:/var:ro \
-v $(which kubectl):/usr/local/bin/kubectl:ro \
-v ~/.kube:/root/.kube:ro \
aquasec/kube-bench:v0.8.0 run
# Run only master checks
docker run --rm \
--pid=host \
-v /etc:/etc:ro \
-v /var:/var:ro \
aquasec/kube-bench:v0.8.0 run --targets master
# Run only node checks
docker run --rm \
--pid=host \
-v /etc:/etc:ro \
-v /var:/var:ro \
aquasec/kube-bench:v0.8.0 run --targets node
Why these mounts are required:
| Mount | Purpose |
|---|---|
--pid=host |
Access host process list to inspect running kube-apiserver, kubelet, etc. |
/etc:/etc:ro |
Access Kubernetes manifests in /etc/kubernetes/manifests/ |
/var:/var:ro |
Access kubelet configuration in /var/lib/kubelet/ |
Using crictl (containerd)
On nodes using containerd (no Docker):
# Pull the image
crictl pull docker.io/aquasec/kube-bench:v0.8.0
# Run (crictl doesn't support --pid=host directly; prefer binary or Job method)
Recommendation: On containerd-only nodes (most modern clusters), prefer the binary or Kubernetes Job method over the container method.
Installation Method 3: Kubernetes Job (Recommended)
Running kube-bench as a Kubernetes Job is the most exam-friendly and production-friendly approach. It leverages the cluster itself to distribute the scan across nodes.
kube-bench Job for Master Node
Create a file kube-bench-master-job.yaml:
apiVersion: batch/v1
kind: Job
metadata:
name: kube-bench-master
namespace: default
spec:
template:
metadata:
labels:
app: kube-bench
spec:
hostPID: true
nodeSelector:
node-role.kubernetes.io/control-plane: ""
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
containers:
- name: kube-bench
image: aquasec/kube-bench:v0.8.0
command: ["kube-bench", "run", "--targets", "master"]
volumeMounts:
- name: var-lib-etcd
mountPath: /var/lib/etcd
readOnly: true
- name: var-lib-kubelet
mountPath: /var/lib/kubelet
readOnly: true
- name: var-lib-kube-scheduler
mountPath: /var/lib/kube-scheduler
readOnly: true
- name: var-lib-kube-controller-manager
mountPath: /var/lib/kube-controller-manager
readOnly: true
- name: etc-systemd
mountPath: /etc/systemd
readOnly: true
- name: lib-systemd
mountPath: /lib/systemd/
readOnly: true
- name: srv-kubernetes
mountPath: /srv/kubernetes/
readOnly: true
- name: etc-kubernetes
mountPath: /etc/kubernetes
readOnly: true
- name: usr-bin
mountPath: /usr/local/mount-from-host/bin
readOnly: true
- name: etc-cni-netd
mountPath: /etc/cni/net.d/
readOnly: true
- name: opt-cni-bin
mountPath: /opt/cni/bin/
readOnly: true
restartPolicy: Never
volumes:
- name: var-lib-etcd
hostPath:
path: /var/lib/etcd
- name: var-lib-kubelet
hostPath:
path: /var/lib/kubelet
- name: var-lib-kube-scheduler
hostPath:
path: /var/lib/kube-scheduler
- name: var-lib-kube-controller-manager
hostPath:
path: /var/lib/kube-controller-manager
- name: etc-systemd
hostPath:
path: /etc/systemd
- name: lib-systemd
hostPath:
path: /lib/systemd
- name: srv-kubernetes
hostPath:
path: /srv/kubernetes
- name: etc-kubernetes
hostPath:
path: /etc/kubernetes
- name: usr-bin
hostPath:
path: /usr/bin
- name: etc-cni-netd
hostPath:
path: /etc/cni/net.d/
- name: opt-cni-bin
hostPath:
path: /opt/cni/bin/
backoffLimit: 0
kube-bench Job for Worker Node
Create a file kube-bench-node-job.yaml:
apiVersion: batch/v1
kind: Job
metadata:
name: kube-bench-node
namespace: default
spec:
template:
metadata:
labels:
app: kube-bench
spec:
hostPID: true
nodeSelector:
node-role.kubernetes.io/worker: ""
containers:
- name: kube-bench
image: aquasec/kube-bench:v0.8.0
command: ["kube-bench", "run", "--targets", "node"]
volumeMounts:
- name: var-lib-kubelet
mountPath: /var/lib/kubelet
readOnly: true
- name: etc-systemd
mountPath: /etc/systemd
readOnly: true
- name: lib-systemd
mountPath: /lib/systemd/
readOnly: true
- name: etc-kubernetes
mountPath: /etc/kubernetes
readOnly: true
- name: usr-bin
mountPath: /usr/local/mount-from-host/bin
readOnly: true
restartPolicy: Never
volumes:
- name: var-lib-kubelet
hostPath:
path: /var/lib/kubelet
- name: etc-systemd
hostPath:
path: /etc/systemd
- name: lib-systemd
hostPath:
path: /lib/systemd
- name: etc-kubernetes
hostPath:
path: /etc/kubernetes
- name: usr-bin
hostPath:
path: /usr/bin
backoffLimit: 0
Deploy and View Results
# Apply the master scan Job
kubectl apply -f kube-bench-master-job.yaml
# Wait for completion
kubectl wait --for=condition=complete job/kube-bench-master --timeout=120s
# View results
kubectl logs job/kube-bench-master
# Apply the node scan Job
kubectl apply -f kube-bench-node-job.yaml
# Wait for completion
kubectl wait --for=condition=complete job/kube-bench-node --timeout=120s
# View results
kubectl logs job/kube-bench-node
Cleanup
# Delete Jobs when done
kubectl delete job kube-bench-master kube-bench-node
CKS exam tip: Running kube-bench as a Job is the most common exam approach. Memorize the key elements: hostPID: true, the correct nodeSelector and tolerations for the control plane, and the hostPath volume mounts. The exam may provide partial YAML that you need to complete.
Output Format Interpretation
Understanding kube-bench output is essential for identifying and prioritizing fixes.
Result Categories
| Status | Meaning | Action Required |
|---|---|---|
| PASS | Check passed — configuration meets the benchmark | None |
| FAIL | Check failed — configuration does not meet the benchmark | Fix required |
| WARN | Cannot be automatically verified — manual review needed | Review and decide |
| INFO | Informational — provides context but no pass/fail determination | Note for reference |
Sample Output (Text Format)
[INFO] 1 Control Plane Security Configuration
[INFO] 1.1 Control Plane Node Configuration Files
[PASS] 1.1.1 Ensure that the API server pod specification file permissions are set to 600 or more restrictive
[PASS] 1.1.2 Ensure that the API server pod specification file ownership is set to root:root
[PASS] 1.1.3 Ensure that the controller manager pod specification file permissions are set to 600 or more restrictive
[PASS] 1.1.4 Ensure that the controller manager pod specification file ownership is set to root:root
[FAIL] 1.1.5 Ensure that the scheduler pod specification file permissions are set to 600 or more restrictive
[PASS] 1.1.6 Ensure that the scheduler pod specification file ownership is set to root:root
[INFO] 1.2 API Server
[FAIL] 1.2.1 Ensure that the --anonymous-auth argument is set to false
[PASS] 1.2.2 Ensure that the --token-auth-file parameter is not set
[PASS] 1.2.6 Ensure that the --authorization-mode argument is not set to AlwaysAllow
[PASS] 1.2.7 Ensure that the --authorization-mode argument includes Node
[PASS] 1.2.8 Ensure that the --authorization-mode argument includes RBAC
[WARN] 1.2.10 Ensure that the admission control plugin EventRateLimit is set
[FAIL] 1.2.16 Ensure that the --profiling argument is set to false
[FAIL] 1.2.19 Ensure that the --audit-log-path argument is set
== Remediations master ==
1.1.5 Run the below command (based on the file location on your system) on the control plane node.
chmod 600 /etc/kubernetes/manifests/kube-scheduler.yaml
1.2.1 Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml
on the control plane node and set the below parameter.
--anonymous-auth=false
1.2.16 Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml
on the control plane node and set the below parameter.
--profiling=false
1.2.19 Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.yaml
on the control plane node and set the below parameter.
--audit-log-path=/var/log/kubernetes/audit/audit.log
== Summary master ==
43 checks PASS
9 checks FAIL
11 checks WARN
0 checks INFO
Summary Section Breakdown
The summary at the bottom gives you the overall picture:
== Summary master ==
43 checks PASS ← These are fine
9 checks FAIL ← These must be fixed
11 checks WARN ← Review manually
0 checks INFO ← Informational only
Priority: Fix all FAIL results first, then review WARN results.
JSON Output
For automation and compliance reporting:
kube-bench run --json | jq .
Sample JSON structure:
{
"Controls": [
{
"id": "1",
"version": "cis-1.9",
"detected_version": "1.29",
"text": "Control Plane Security Configuration",
"tests": [
{
"section": "1.1",
"desc": "Control Plane Node Configuration Files",
"results": [
{
"test_number": "1.1.1",
"test_desc": "Ensure that the API server pod specification file permissions are set to 600 or more restrictive",
"status": "PASS",
"scored": true
},
{
"test_number": "1.2.1",
"test_desc": "Ensure that the --anonymous-auth argument is set to false",
"status": "FAIL",
"scored": true,
"remediation": "Edit the API server pod specification file..."
}
]
}
]
}
],
"Totals": {
"total_pass": 43,
"total_fail": 9,
"total_warn": 11,
"total_info": 0
}
}
Filtering JSON Output
# Get only FAIL results
kube-bench run --json | jq '.Controls[].tests[].results[] | select(.status == "FAIL")'
# Count FAILs per section
kube-bench run --json | jq '[.Controls[].tests[].results[] | select(.status == "FAIL")] | length'
# Get remediation for all FAILs
kube-bench run --json | jq '.Controls[].tests[].results[] | select(.status == "FAIL") | {test: .test_number, desc: .test_desc, fix: .remediation}'
Key Flags Reference
| Flag | Description | Example |
|---|---|---|
--targets |
Run checks for specific targets: master, node, etcd, controlplane, policies |
kube-bench run --targets master |
--check |
Run a specific check by ID | kube-bench run --check 1.2.1 |
--group |
Run all checks in a specific group | kube-bench run --group 1.2 |
--json |
Output results in JSON format | kube-bench run --json |
--junit |
Output results in JUnit XML format | kube-bench run --junit |
--benchmark |
Specify the CIS benchmark version | kube-bench run --benchmark cis-1.9 |
--config-dir |
Specify the configuration directory | kube-bench run --config-dir /etc/kube-bench/cfg |
--config |
Specify the configuration file | kube-bench run --config /path/to/config.yaml |
--noremediations |
Suppress remediation text in output | kube-bench run --noremediations |
--nosummary |
Suppress summary in output | kube-bench run --nosummary |
--nototals |
Suppress totals in output | kube-bench run --nototals |
Practical Flag Combinations
# Run only API server checks
kube-bench run --group 1.2
# Run a single check to verify a fix
kube-bench run --check 1.2.1
# Run master checks with JSON output
kube-bench run --targets master --json
# Run checks and only show the summary
kube-bench run --targets master --noremediations
Choosing the Right Installation Method
| Method | Best For | CKS Exam | Production |
|---|---|---|---|
| Binary | Quick one-off scans, SSH access to nodes | Sometimes | Ad-hoc checks |
| Container | Docker-based environments | Rarely | CI/CD integration |
| Kubernetes Job | Standard approach, no SSH needed | Most common | Automated scanning |
CKS exam recommendation: Practice the Job method until you can create the YAML from memory. Also know the binary method as a fallback — the exam may provide kube-bench pre-installed on nodes.
Practice Questions
Q1: What is kube-bench and who maintains it?
Show Answer
kube-bench is an open-source Go application maintained by Aqua Security. It automates CIS Kubernetes Benchmark checks by inspecting running processes, configuration files, and file permissions on Kubernetes nodes. It compares actual configurations against CIS recommendations and produces a PASS/FAIL/WARN/INFO report.
Q2: Why must kube-bench run on the node itself rather than remotely?
Show Answer
kube-bench inspects local processes (via /proc or ps), local configuration files (in /etc/kubernetes/manifests/, /var/lib/kubelet/), and local file permissions. These are not accessible remotely through the Kubernetes API. The tool needs hostPID access and filesystem mounts to check the actual state of the node’s configuration.
Q3: Write the key spec fields needed in a kube-bench Job to scan a control plane node.
Show Answer
The critical fields are:
spec:
template:
spec:
hostPID: true # Access host process list
nodeSelector:
node-role.kubernetes.io/control-plane: "" # Schedule on control plane
tolerations:
- key: node-role.kubernetes.io/control-plane # Tolerate control plane taint
operator: Exists
effect: NoSchedule
containers:
- name: kube-bench
image: aquasec/kube-bench:v0.8.0
command: ["kube-bench", "run", "--targets", "master"]
volumeMounts:
- name: etc-kubernetes
mountPath: /etc/kubernetes
readOnly: true
- name: var-lib-kubelet
mountPath: /var/lib/kubelet
readOnly: true
restartPolicy: Never
volumes:
- name: etc-kubernetes
hostPath:
path: /etc/kubernetes
- name: var-lib-kubelet
hostPath:
path: /var/lib/kubelet
Key points: hostPID: true, correct nodeSelector, tolerations for the control plane taint, hostPath volume mounts, and restartPolicy: Never.
Q4: A kube-bench scan shows 9 FAIL, 11 WARN, and 43 PASS results. What do you address first and why?
Show Answer
Address FAIL results first. FAIL means the configuration explicitly does not meet the CIS benchmark — these represent known security gaps. WARN results require manual review because kube-bench couldn’t automatically determine the status (the check may pass or fail depending on context).
After fixing all 9 FAIL results, review the 11 WARN results to determine which are actual risks vs. acceptable configurations. PASS results require no action.
Q5: What kube-bench command would you run to check only the API server section and output the results in JSON format?
Show Answer
kube-bench run --group 1.2 --json
--group 1.2selects only Section 1.2 (API Server checks)--jsonoutputs results in JSON format
To filter for only FAIL results:
kube-bench run --group 1.2 --json | jq '.Controls[].tests[].results[] | select(.status == "FAIL")'
Next: Learn what kube-bench checks on the control plane with Scanning Control Plane →
| ← Understanding CIS Benchmarks | Scanning Control Plane → |