
Here's a question that's been nagging me since Topic 4: I can list a dozen ways a cluster gets popped, but how do I actually prove mine isn't sitting wide open? "I think it's fine" isn't an answer I'd accept from anyone else. So Topic 5 is about getting a real scorecard instead of a gut feeling, and the two things that make that possible are CIS Benchmarks and a little tool called Kube-Bench.
If you've ever built a box from scratch and had that quiet worry that you forgot something, this one's for you. Let's turn the worry into a checklist you can measure against.
Hardening, and why a checklist beats a hunch
Before the benchmarks make sense, it helps to be clear on what hardening even means. Say I spin up a fresh Ubuntu server for a project. Out of the box it's convenient, not safe. Convenient and safe are usually opposites, and the gap between them is the work.
A few concrete examples of that work. Someone with physical access could walk up and plug in a USB stick loaded with malware, so unused USB and peripheral slots get disabled. Logging in directly as root is asking for trouble, so instead I'd give each admin their own account with sudo when they need it. That one change buys you accountability: now every privileged action has a name attached, and a fat-fingered or malicious change is a lot easier to trace.
The short version of what I'd lock down on a fresh host:
- Scope sudo tightly so only the people who genuinely need elevated rights have them.
- Put firewall or iptables rules in front of it that permit only the traffic the box actually needs.
- Switch off services you're not using, while keeping the ones you can't live without (time sync via NTP being the classic example).
- Fix file permissions and drop filesystems that have no business being mounted.
- Turn on auditing and logging so changes and intrusion attempts leave a trail.
And none of this is a one-and-done. New bugs land every week, so patching and re-checking is the ongoing tax you pay to stay hardened. The obvious follow-up: who decides what "hardened" looks like? You could invent your own list, but smarter people have already written one.
Enter CIS Benchmarks
CIS is the Center for Internet Security, a non-profit that turns hard-won security experience into practical, agreed-upon guidance. The benchmarks are their flagship output: consensus checklists, written and reviewed by a community rather than one vendor, that tell you exactly how to configure a given piece of tech safely. They cover a genuinely huge spread, north of 25 categories, including:
- Operating systems (Linux, Windows, macOS)
- Public cloud (AWS, Azure, Google Cloud)
- Mobile (iOS, Android)
- Network gear (Cisco, Juniper, Palo Alto, Check Point)
- Desktop software (browsers, MS Office, Zoom)
- Server software (Nginx, Tomcat and friends), plus Docker and Kubernetes
Linux, Windows, macOS
AWS, Azure, GCP
iOS, Android
Cisco, Juniper, Palo Alto
Browsers, Office, Zoom
Nginx, Docker, Kubernetes
You register on the CIS website and pull down whichever benchmark matches your stack. What I like is how each recommendation is structured. It doesn't just bark an order at you. For every item you get the risk (what actually goes wrong if you ignore it), a way to check whether you're exposed, with the exact command to run, and then the fix. So a check as small as "is USB storage loadable?" comes with something you can paste straight in:
# modprobe -n -v usb-storage
Running that against every recommendation by hand would take forever, which is why CIS also ships a tool to do it for you. CIS-CAT (the Configuration Assessment Tool) compares a machine's real config against the benchmark and spits out a tidy HTML report of what passed, what failed, and a score per section.
| Section | Pass | Fail | Score |
|---|---|---|---|
| Filesystem configuration | 28 | 6 | 82% |
| Configure sudo | 9 | 1 | 90% |
| Services | 41 | 12 | 77% |
| Logging and auditing | 22 | 9 | 71% |
The nice part is you can click into any group and see the individual checks, right down to which specific setting failed and why. That's the difference between "your score is 47%" and "these seven filesystem mounts aren't disabled".
| Check | Status | Ref |
|---|---|---|
| Ensure a separate partition exists for /tmp | PASS | 1.1.2 |
| Ensure unused filesystems are disabled | FAIL | 1.1.1 |
| Ensure SSH root login is disabled | PASS | 5.2.8 |
| Ensure the auditd service is enabled | FAIL | 4.1.2 |
| Ensure sudo commands use a pty | WARN | 1.3.1 |
The workflow is a loop, and that's the whole point. Assess, read the report, fix what failed, then run it again to confirm the score actually moved. Hardening you can't measure isn't hardening, it's hope.
The CIS Benchmark for Kubernetes
Kubernetes gets its own benchmark, and it's the one I care about here. The current document I've been reading targets Kubernetes 1.16 through 1.18, and it's aimed at pretty much everyone who touches a cluster: platform admins, app owners, security folk and auditors alike.
It's big. Hundreds of recommendations, split across the control plane and the worker nodes. A lot of it is refreshingly boring, in a good way. Take the API server's pod spec file: the benchmark wants its permissions set to 644 so only an admin can edit it, and it hands you both the check and the fix.
stat -c %a /etc/kubernetes/manifests/kube-apiserver.yaml
chmod 644 /etc/kubernetes/manifests/kube-apiserver.yaml
| Ref | File | Required |
|---|---|---|
| 1.1.1 | API server pod spec | 644 |
| 1.1.3 | Controller manager pod spec | 644 |
| 1.1.5 | Scheduler pod spec | 644 |
| 1.1.7 | etcd pod spec | 644 |
| 1.1.11 | etcd data directory | 700 |
| 1.1.13 | admin.conf | 600 |
Plenty of the meatier recommendations are about how the kube-apiserver is actually launched, its command-line flags. A few that stood out to me: turn off anonymous authentication, don't rely on basic-auth or static token files, and insist on HTTPS with certificates set up properly.
| Ref | Flag | Required value |
|---|---|---|
| 1.2.1 | --anonymous-auth | false |
| 1.2.2 | --token-auth-file | not set |
| 1.2.5 | --kubelet-certificate-authority | set |
| 1.2.6 | --authorization-mode | not AlwaysAllow |
| 1.2.8 | --authorization-mode includes RBAC | true |
--anonymous-auth=false and "don't set --basic-auth-file". None of it is glamorous, but it's exactly the default-on-but-insecure config Topic 4's attack walked straight through.Scoring the cluster with Kube-Bench
Kube-Bench is an open-source checker from Aqua Security that runs the CIS Kubernetes Benchmark against your cluster and tells you, check by check, where you pass and where you fail. Every CIS recommendation maps to a test, so instead of reading a hundred-page PDF and squinting at your config, you get a clean pass/fail run you can act on.
| Ref | Recommendation |
|---|---|
| 1.2.1 | Ensure --anonymous-auth is set to false |
| 1.2.6 | Ensure --authorization-mode is not AlwaysAllow |
| 1.2.16 | Ensure an admission control plugin such as PodSecurity is set |
Installing it is quick. Grab a stable release that matches your Kubernetes version from the GitHub repo, drop the package on, and check it runs:
curl -L https://github.com/aquasecurity/kube-bench/releases/download/v0.12.0/kube-bench_0.12.0_linux_amd64.deb -o kube-bench_0.12.0_linux_amd64.deb
sudo dpkg -i kube-bench_0.12.0_linux_amd64.deb
kube-bench version
From there the simplest thing is to just let it detect what it can and run everything:
sudo kube-bench
sudo kube-bench run: control plane checks streaming past as PASS and the odd WARN, each tied back to a CIS recommendation number.You can also scope it to just the control plane or just the workers, which is handy when you only own one side of the cluster:
kube-bench run --targets master
kube-bench run --targets node
And if you'd rather keep the output to chew on later or feed into something else, dump it as JSON:
kube-bench --json > kube-bench-results.json
For a cluster you don't want to SSH into directly, the cleaner approach is to run Kube-Bench as a Kubernetes Job. You apply the official manifest, let the job run to completion, then read its logs:
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
kubectl logs job/kube-bench
This is the one I'd lean towards for anything ongoing, since you can schedule it and keep the assessment inside the cluster. The other options are running it as a plain Docker container in isolation, or building from source if you want to tweak it.
From vibes to numbers
What I like about this pair is that it drags cluster security out of vibes and into numbers. CIS Benchmarks give you the standard, Kube-Bench tells you how far off it you are, and the fix-and-rescan loop turns "I think it's fine" into a score you can defend. If you've used full Kube-Bench and hit sharp edges I'd love to hear where.
If this was useful, come say hi on LinkedIn or through the contact page, and tell me which CIS control you'd want me to break down properly in a future post.
Further reading
- Center for Internet Security (CIS Benchmarks)
- Kube-Bench on GitHub (Aqua Security)
- Kubernetes documentation
FAQ
What is the CIS Kubernetes Benchmark?
A community-agreed checklist of secure configuration settings for a cluster. It spells out what solid looks like for the API server, kubelet, etcd and more, so you are not guessing at hardening.
What does kube-bench do?
kube-bench runs the CIS Kubernetes Benchmark against a live cluster and reports pass, fail or warn per check. It turns a long PDF of recommendations into an actual score you can act on.
How often should I run kube-bench?
Run it once for a baseline, then again after any upgrade or config change, and on a schedule. Clusters drift, so a one-off scan goes stale fast.
Related reading
- Topic 4: The 4Cs of cloud native security (the security model)
- Topic 6: Security primitives and authentication (authentication next)
- Topic 9: Authorization and RBAC (RBAC and least privilege)
- Browse the whole Kubernetes Journey