Objective
The CIS Kubernetes Benchmark defines security best practices for cluster configuration. kube-bench automates the assessment. This exercise runs a full benchmark scan, parses the results into a prioritised backlog using a risk matrix, implements remediation for the 10 most impactful failing checks, and re-validates to measure the improvement in compliance score.
Prerequisites
- Access to a Kubernetes cluster with control plane access (self-managed or kubeadm)
- Node SSH access or ability to run Jobs on master nodes
- kube-bench binary or container image (aquasecurity/kube-bench)
- jq and Python3 for output parsing
Steps
Run kube-bench as a Kubernetes Job
Running kube-bench as a Job on the master node gives it access to the actual configuration files at the paths the CIS Benchmark expects.
# Run kube-bench Job on the control plane cat << 'EOF' | kubectl apply -f - apiVersion: batch/v1 kind: Job metadata: name: kube-bench spec: template: spec: hostPID: true nodeSelector: node-role.kubernetes.io/control-plane: "" tolerations: - key: node-role.kubernetes.io/control-plane effect: NoSchedule containers: - name: kube-bench image: aquasec/kube-bench:latest command: ["kube-bench", "--json", "run", "--targets", "master,etcd,policies"] volumeMounts: - name: var-lib-etcd mountPath: /var/lib/etcd 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-etcd hostPath: { path: /var/lib/etcd } - name: etc-kubernetes hostPath: { path: /etc/kubernetes } - name: usr-bin hostPath: { path: /usr/bin } EOF # Wait for completion and save output kubectl wait job/kube-bench --for=condition=Complete --timeout=120s kubectl logs job/kube-bench > kube-bench-results.json # Run worker node checks separately kubectl delete job kube-bench # Modify job above to targets: "node" and run on worker nodes
Parse results and calculate initial score
# Parse JSON output with Python
python3 << 'EOF'
import json, sys
with open('kube-bench-results.json') as f:
data = json.load(f)
total_pass = total_fail = total_warn = 0
failures = []
for control in data.get('Controls', []):
for group in control.get('tests', []):
for test in group.get('results', []):
status = test.get('status', '')
if status == 'PASS':
total_pass += 1
elif status == 'FAIL':
total_fail += 1
failures.append({
'id': test.get('test_number'),
'desc': test.get('test_desc'),
'remediation': test.get('remediation', '')[:100],
'scored': test.get('scored', True)
})
elif status == 'WARN':
total_warn += 1
total = total_pass + total_fail
score = (total_pass / total * 100) if total > 0 else 0
print(f"=== CIS Benchmark Results ===")
print(f"PASS: {total_pass}")
print(f"FAIL: {total_fail}")
print(f"WARN: {total_warn}")
print(f"Score: {score:.1f}%")
print(f"\nTop 10 Failures:")
for i, f in enumerate(failures[:10], 1):
print(f" {i}. [{f['id']}] {f['desc'][:80]}")
EOFPrioritise remediations with risk matrix
Not all failures are equal. Use impact (what an attacker gains) × exploitability (how easy it is) to prioritise. Focus on these common high-impact failures first:
| CIS ID | Check | Impact | Effort | Priority |
|---|---|---|---|---|
| 1.2.1 | API server anonymous-auth=false | Critical | Low | P1 |
| 1.2.6 | API server audit logging enabled | High | Medium | P1 |
| 1.2.22 | Admission plugins include NodeRestriction | High | Low | P1 |
| 2.1 | etcd TLS for client connections | Critical | Medium | P1 |
| 3.2.1 | Logging verbosity <= 2 | Medium | Low | P2 |
| 4.2.1 | kubelet anonymous-auth=false | Critical | Low | P1 |
| 4.2.6 | kubelet protectKernelDefaults=true | Medium | Low | P2 |
| 5.1.3 | No wildcards in ClusterRoles | High | High | P2 |
Implement common remediations
# Remediation 1.2.1: Disable anonymous auth on API server # Edit /etc/kubernetes/manifests/kube-apiserver.yaml # Add: --anonymous-auth=false sudo sed -i 's/--anonymous-auth=true/--anonymous-auth=false/' \ /etc/kubernetes/manifests/kube-apiserver.yaml # API server pod will restart automatically (static pod) # Remediation 1.2.6: Enable audit logging cat > /etc/kubernetes/audit-policy.yaml << 'POLICY' apiVersion: audit.k8s.io/v1 kind: Policy rules: - level: RequestResponse resources: - group: "" resources: ["secrets"] - level: Request resources: - group: "rbac.authorization.k8s.io" resources: ["clusterroles", "clusterrolebindings"] - level: Metadata omitStages: ["RequestReceived"] POLICY # Add to kube-apiserver.yaml: # --audit-policy-file=/etc/kubernetes/audit-policy.yaml # --audit-log-path=/var/log/kubernetes/audit.log # --audit-log-maxage=30 # --audit-log-maxbackup=10 # --audit-log-maxsize=100 # Remediation 4.2.1: Disable anonymous auth on kubelet # Edit /var/lib/kubelet/config.yaml cat >> /var/lib/kubelet/config.yaml << 'KUBELET' authentication: anonymous: enabled: false webhook: enabled: true authorization: mode: Webhook KUBELET sudo systemctl restart kubelet
Re-run kube-bench and measure delta
# Re-run kube-bench after remediations kubectl apply -f kube-bench-job.yaml kubectl wait job/kube-bench --for=condition=Complete --timeout=120s kubectl logs job/kube-bench > kube-bench-results-v2.json # Compare pass rates python3 << 'EOF' import json def get_score(filename): with open(filename) as f: data = json.load(f) p = f = 0 for control in data.get('Controls', []): for group in control.get('tests', []): for test in group.get('results', []): s = test.get('status', '') if s == 'PASS': p += 1 elif s == 'FAIL': f += 1 total = p + f return p, f, (p/total*100) if total > 0 else 0 p1, f1, s1 = get_score('kube-bench-results.json') p2, f2, s2 = get_score('kube-bench-results-v2.json') print(f"Before: {s1:.1f}% ({p1} pass, {f1} fail)") print(f"After: {s2:.1f}% ({p2} pass, {f2} fail)") print(f"Delta: +{s2-s1:.1f}% (+{p2-p1} checks fixed)") EOF
Success Criteria
Further Reading
- kube-bench — github.com/aquasecurity/kube-bench
- CIS Kubernetes Benchmark — cisecurity.org/benchmark/kubernetes
- NSA/CISA K8s Hardening Guide — media.defense.gov/2022/Aug/29/2003066362
- Kubernetes API server flags — kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver