click the screen · press Enter
← back to blog
Kubernetes Journey · Topic 5

CIS Benchmarks Turn Cluster Security from Vibes into a Score

Hardening Kubernetes with CIS Benchmarks and Kube-Bench - Kubernetes Journey

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.

HARDENED HOST
Physical / USB
Access & sudo
Network
Services
Filesystems
Logging
Auditing
Hardening isn't one setting, it's a spread: physical ports, access, network, services, filesystems, logging and auditing all get pinned down.

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
Operating systems

Linux, Windows, macOS

Public cloud

AWS, Azure, GCP

Mobile

iOS, Android

Network gear

Cisco, Juniper, Palo Alto

Desktop software

Browsers, Office, Zoom

Server software

Nginx, Docker, Kubernetes

Just a slice of what CIS covers. Kubernetes sits under the server category, which is the one I care about here.

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.

CIS-CAT, summary by section
SectionPassFailScore
Filesystem configuration28682%
Configure sudo9190%
Services411277%
Logging and auditing22971%
The CIS-CAT summary: pass/fail counts and a percentage score for each group, so you can see at a glance where a host is weakest.

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".

CIS-CAT, detailed results
CheckStatusRef
Ensure a separate partition exists for /tmpPASS1.1.2
Ensure unused filesystems are disabledFAIL1.1.1
Ensure SSH root login is disabledPASS5.2.8
Ensure the auditd service is enabledFAIL4.1.2
Ensure sudo commands use a ptyWARN1.3.1
Drilling in: each benchmark item with its own pass/fail, plus a handy "display failures only" view for triage.

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
CIS Kubernetes Benchmark, 1.1 control plane files
RefFileRequired
1.1.1API server pod spec644
1.1.3Controller manager pod spec644
1.1.5Scheduler pod spec644
1.1.7etcd pod spec644
1.1.11etcd data directory700
1.1.13admin.conf600
An excerpt from the CIS Kubernetes Benchmark: master node file recommendations, all about permissions and ownership on the control plane specs.

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.

CIS Kubernetes Benchmark, 1.2 API server flags
RefFlagRequired value
1.2.1--anonymous-authfalse
1.2.2--token-auth-filenot set
1.2.5--kubelet-certificate-authorityset
1.2.6--authorization-modenot AlwaysAllow
1.2.8--authorization-mode includes RBACtrue
The API server section: flags like --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.
One catch worth knowing The free "lite" build of CIS-CAT only covers a handful of benchmarks, things like Windows, Ubuntu, Chrome and macOS. Kubernetes isn't in there. So for a cluster you need a different tool, and happily there's a good open-source one.

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.

RefRecommendation
1.2.1Ensure --anonymous-auth is set to false
1.2.6Ensure --authorization-mode is not AlwaysAllow
1.2.16Ensure an admission control plugin such as PodSecurity is set
sudo kube-bench
[PASS] 1.2.1 --anonymous-auth is false [FAIL] 1.2.6 --authorization-mode is AlwaysAllow [WARN] 1.2.16 admission plugin not configured
Left, the written benchmark. Right, Kube-Bench turning those same recommendations into coloured PASS/FAIL lines you can actually work through.

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
[INFO] 1.1 Control plane node configuration files [PASS] 1.1.1 API server pod spec file permissions 644 [PASS] 1.1.2 API server pod spec file ownership root:root [WARN] 1.1.12 etcd data directory ownership etcd:etcd [PASS] 1.1.13 admin.conf file permissions 600 == 1.1 summary: 11 PASS 2 WARN 0 FAIL ==
A real 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.

The loop that matters However you run it, the shape is the same: assess, read the pass/fail report, work out which failures actually matter for your setup, apply the fixes it suggests, then run it again to prove the gaps closed.
Keep it fresh Both Kubernetes and the CIS guidance keep moving, so a green run today isn't a permanent pass. Update the tool and re-scan every so often, otherwise your "compliant" cluster quietly drifts.

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

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.