kube-bench, developed by Aqua Security, is an open-source Go application that checks whether a Kubernetes cluster (control-plane nodes, etcd nodes, and worker nodes) is deployed according to the CIS Kubernetes Benchmark. Where kube-hunter tests a cluster from an attacker’s perspective by actively probing it, kube-bench tests it from a compliance perspective by inspecting configuration files, running processes, and file permissions on each node and comparing them against the benchmark’s recommended settings.
kube-bench automatically detects the Kubernetes version and platform (self-managed, EKS, GKE, AKS, OpenShift, RKE, k3s, etc.) and selects the correct benchmark test set (cis-1.23, cis-1.24, eks-1.2.0, gke-1.2.0, etc.). Each check has a unique ID (e.g. 1.2.1), a description, a remediation suggestion, and a result of PASS, FAIL, WARN, or INFO.
Installation
Method 1 – Binary release (Kali/Debian, most common):
curl -L https://github.com/aquasecurity/kube-bench/releases/download/v0.9.3/kube-bench_0.9.3_linux_amd64.deb -o kube-bench.deb
sudo dpkg -i kube-bench.deb
Method 2 – Install via Go:
go install github.com/aquasecurity/kube-bench@latest
Method 3 – Run as a Docker container against the host:
docker run --pid=host -v /etc:/etc:ro -v /var:/var:ro -v /usr/bin/kubectl:/usr/bin/kubectl:ro \
-v $(which kubelet):/usr/bin/kubelet:ro \
aquasec/kube-bench:latest --version 1.24
Method 4 – Run as a Kubernetes Job inside the cluster (recommended for control-plane checks):
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
kubectl logs -l app=kube-bench
Verify installation:
kube-bench version
Expected output:
kube-bench version: 0.9.3
Syntax
kube-bench [command] [flags]
Primary command is run, optionally scoped with --targets.
Command-Line Options
| Flag | Description |
|---|---|
run | Run the benchmark checks (default command) |
--targets | Node types to test: master,node,etcd,policies,controlplane |
--benchmark | Force a specific benchmark version (e.g. cis-1.24, eks-1.2.0, gke-1.2.0) |
--version | Force a specific Kubernetes version’s test set |
-f, --check | Run only specific check IDs, comma-separated (e.g. 1.1.1,1.1.2) |
-s, --skip | Skip specific check IDs |
--config-dir | Path to the directory containing benchmark YAML definitions |
--config | Path to config.yaml defining node type mappings |
-j, --json | Output results as JSON |
--outputfile | Write output to a specified file |
-D, --dashboard | Output for the kube-bench dashboard format |
--include-test-output | Include raw command output for each check in the report |
--noremediations | Suppress remediation text in output |
--noresults | Suppress the actual PASS/FAIL results (summary only) |
--nosummary | Suppress the summary line |
-v, --v | Log verbosity level |
-h, --help | Show help |
Basic Usage
sudo kube-bench run --targets master,node
Expected output (truncated):
[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 (Automated)
[FAIL] 1.1.9 Ensure that the admission control plugin AlwaysPullImages is set (Automated)
[WARN] 1.1.20 Ensure that the Kubernetes PKI directory and file ownership is set to root:root (Manual)
== Summary master ==
45 checks PASS
12 checks FAIL
8 checks WARN
0 checks INFO
[INFO] 4 Worker Node Security Configuration
[PASS] 4.1.1 Ensure that the kubelet service file permissions are set to 600 or more restrictive (Automated)
[FAIL] 4.2.6 Ensure that the --protect-kernel-defaults argument is set to true (Automated)
== Summary node ==
20 checks PASS
5 checks FAIL
2 checks WARN
== Summary total ==
65 checks PASS
17 checks FAIL
10 checks WARN
0 checks INFO
Practical Examples with Output
Example 1 – Run only the master/control-plane checks:
sudo kube-bench run --targets master
[INFO] 1 Control Plane Security Configuration
[PASS] 1.2.1 Ensure that the --anonymous-auth argument is set to false (Automated)
[FAIL] 1.2.6 Ensure that the --kubelet-certificate-authority argument is set as appropriate (Automated)
== Summary master ==
38 checks PASS
9 checks FAIL
6 checks WARN
Example 2 – Force a specific benchmark for a managed EKS cluster:
kube-bench run --benchmark eks-1.2.0
[INFO] 3 Worker Node Security Configuration
[PASS] 3.1.1 Ensure that the kubeconfig file permissions are set to 644 or more restrictive (Automated)
[FAIL] 3.2.1 Ensure that a minimal audit policy is created (Automated)
== Summary total ==
24 checks PASS
6 checks FAIL
Example 3 – Output results as JSON:
sudo kube-bench run --targets node --json > node-results.json
cat node-results.json | python3 -m json.tool | head -25
{
"Controls": [
{
"id": "4",
"text": "Worker Node Security Configuration",
"tests": [
{
"section": "4.1",
"results": [
{
"test_number": "4.1.1",
"test_desc": "Ensure that the kubelet service file permissions are set to 600 or more restrictive",
"status": "PASS"
}
]
}
]
}
]
}
Example 4 – Run a single check by ID:
sudo kube-bench run --check 1.2.6
[FAIL] 1.2.6 Ensure that the --kubelet-certificate-authority argument is set as appropriate (Automated)
== Remediation ==
Follow the Kubernetes documentation and set the --kubelet-certificate-authority
parameter to the path to the cert file for the certificate authority.
== Summary ==
0 checks PASS
1 checks FAIL
0 checks WARN
Example 5 – Skip known/accepted-risk checks:
sudo kube-bench run --targets node --skip 4.2.6,4.2.10
== Summary node ==
23 checks PASS
3 checks FAIL
2 checks WARN
(2 checks skipped)
Example 6 – Run inside the cluster as a Job and view logs:
kubectl apply -f job.yaml
kubectl get pods -l app=kube-bench
kubectl logs kube-bench-4kjpl
NAME READY STATUS RESTARTS AGE
kube-bench-4kjpl 0/1 Completed 0 8s
[INFO] 4 Worker Node Security Configuration
[PASS] 4.1.1 Ensure that the kubelet service file permissions are set to 600 or more restrictive
== Summary total ==
21 checks PASS
4 checks FAIL
Example 7 – Suppress remediation text for a shorter report:
sudo kube-bench run --targets master --noremediations
[FAIL] 1.1.9 Ensure that the admission control plugin AlwaysPullImages is set (Automated)
[FAIL] 1.2.6 Ensure that the --kubelet-certificate-authority argument is set as appropriate (Automated)
== Summary master ==
45 checks PASS
12 checks FAIL
Example 8 – Write output to a file with test command output included:
sudo kube-bench run --targets node --include-test-output --outputfile node-detailed.txt
cat node-detailed.txt | head -15
[PASS] 4.1.1 Ensure that the kubelet service file permissions are set to 600 or more restrictive
Command: 'stat -c permissions=%a /etc/systemd/system/kubelet.service.d/10-kubeadm.conf'
Output: permissions=644
Example 9 – Run using a custom config directory for a non-standard distro:
sudo kube-bench run --config-dir /opt/kube-bench/cfg --benchmark rke-cis-1.6
[INFO] Using benchmark: RKE CIS 1.6
[PASS] 1.1.1 Ensure that the API server pod specification file permissions are set to 600 or more restrictive
== Summary total ==
30 checks PASS
5 checks FAIL
Common Use Cases
- Pre-production compliance gate for newly provisioned Kubernetes clusters, self-managed or managed.
- Continuous compliance monitoring via a scheduled Kubernetes CronJob that runs kube-bench and ships results to a dashboard.
- Audit evidence generation for SOC2/ISO27001/PCI-DSS assessments that require CIS Benchmark alignment.
- Post-upgrade validation — re-running after a Kubernetes version upgrade to catch new/changed benchmark controls.
- Managed cloud cluster hardening — using platform-specific benchmarks (
eks-1.2.0,gke-1.2.0,aks-1.2.0) to validate provider-recommended settings.
Automation with Bash
#!/usr/bin/env bash
# kube-bench-audit.sh - Run kube-bench cluster-wide and summarize failures
set -euo pipefail
OUTPUT="kube-bench-$(date +%F).json"
echo "[*] Running kube-bench across all targets..."
sudo kube-bench run --targets master,node,etcd,policies --json > "$OUTPUT"
FAIL_COUNT=$(python3 -c "
import json
data = json.load(open('$OUTPUT'))
count = 0
for control in data.get('Controls', []):
for test in control.get('tests', []):
for r in test.get('results', []):
if r.get('status') == 'FAIL':
count += 1
print(count)
")
echo "[*] Total FAIL checks: $FAIL_COUNT"
if [ "$FAIL_COUNT" -gt 0 ]; then
echo "[!] Cluster failed $FAIL_COUNT CIS benchmark checks. See $OUTPUT"
exit 1
fi
echo "[+] Cluster passed all CIS Kubernetes Benchmark checks."
Schedule as a weekly CronJob inside the cluster, or via host cron:
crontab -e
0 3 * * 0 /opt/scripts/kube-bench-audit.sh >> /var/log/kube-bench-cron.log 2>&1
Tips and Best Practices
- Always let kube-bench auto-detect the benchmark version first; only force
--benchmarkwhen auto-detection picks the wrong managed-platform variant. - Run separately on each node type (
master,node,etcd) rather than always running all targets — some checks are only meaningful on specific node roles. - On managed clusters (EKS/GKE/AKS), expect many control-plane checks to show
INFOsince the cloud provider manages that layer — focus remediation effort on worker-node and policy checks you actually control. - Track FAIL count over time as a trend metric, not just a pass/fail gate — CIS compliance is rarely 100% achievable immediately and should improve incrementally.
- Combine kube-bench (compliance posture) with kube-hunter (active exploitability) for a complete picture: a FAIL in kube-bench doesn’t always mean it’s currently exploitable, and a PASS doesn’t guarantee no exploitable paths exist.
- Store historical JSON reports in version control or an artifact store to demonstrate compliance trends to auditors.
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
error: unable to detect the Kubernetes version | Running outside cluster context without kubeconfig | Set --version manually or run as an in-cluster Job |
All checks show [INFO] only | Wrong --targets for the node role | Confirm node role and set --targets accordingly |
permission denied reading config files | Not run with sudo/root | Re-run with sudo |
| Wrong benchmark selected on managed cluster | Auto-detection heuristic mismatch | Explicitly pass --benchmark eks-1.2.0 (or gke/aks equivalent) |
Job pod stuck in Pending | Missing node selector/tolerations for control-plane nodes | Edit job-master.yaml tolerations to match your control-plane taints |
References
- GitHub repository: https://github.com/aquasecurity/kube-bench
- CIS Kubernetes Benchmark: https://www.cisecurity.org/benchmark/kubernetes
- Aqua Security documentation: https://aquasecurity.github.io/kube-bench/
