- Authors

- Name
- Phillip Pham
- @ddppham
Kubernetes CIS Benchmark Hardening: kube-bench Anleitung & Checkliste 2026
TL;DR
Der CIS Kubernetes Benchmark umfasst je nach Version über 120 Prüfpunkte -- aber in der Praxis entscheiden rund 15 wiederkehrende Failed Checks über 80 Prozent Ihres Risikos. Dieser Guide zeigt, wie Sie kube-bench korrekt ausführen (als Job im Cluster oder als Binary auf dem Node), den Report nach Automated/Level-1-Findings priorisieren und die häufigsten FAILs mit konkreten Flags an kube-apiserver, etcd und Kubelet beheben. Dazu: ergänzendes Hardening mit Pod Security Standards und NetworkPolicies, eine Checkliste zum Abhaken und die Fallstricke bei EKS, AKS und GKE, wo die Control-Plane-Checks außerhalb Ihres Zugriffs liegen.
Das Problem: CIS-Benchmark gefordert, Report hat hunderte Zeilen
Der Auslöser ist fast immer extern: Ein Enterprise-Kunde schickt einen Security-Fragebogen, der Cyber-Versicherer fragt nach Hardening-Standards, oder die NIS2-Vorbereitung verlangt "Stand der Technik" mit Nachweis. Der CIS (Center for Internet Security) Kubernetes Benchmark ist dafür die Referenz -- Auditoren, Pentester und Compliance-Scanner beziehen sich darauf.
Dann läuft der erste kube-bench-Scan und produziert hunderte Zeilen Output mit Dutzenden FAILs und WARNs. Das ist normal: Die Standardkonfiguration von kubeadm und den meisten Distributionen ist nicht CIS-konform, und der Benchmark prüft bewusst streng. Das eigentliche Problem ist nicht der Scan, sondern die Priorisierung. Ein Team mit 10 bis 100 Mitarbeitern hat kein dediziertes Security-Team, das wochenlang Findings abarbeitet.
Die gute Nachricht: Die FAILs verteilen sich nicht gleichmäßig. In kubeadm-basierten Clustern tauchen immer wieder dieselben 15 bis 20 Checks auf, und ein Großteil davon ist mit einem einzelnen Flag oder einer Zeile in der Kubelet-Konfiguration behoben. Genau diese Checks behandelt dieser Artikel.
Grundlagen: Wie der CIS-Benchmark aufgebaut ist
Der Benchmark gliedert sich in fünf Abschnitte:
| Abschnitt | Umfang | Wer ist verantwortlich |
|---|---|---|
| 1. Control Plane Components | kube-apiserver, Controller-Manager, Scheduler, Manifeste, PKI-Dateirechte | Sie (self-managed) / Provider (managed) |
| 2. etcd | TLS, Client-Zertifikate, Peer-Kommunikation | Sie (self-managed) / Provider (managed) |
| 3. Control Plane Configuration | Authentifizierung, Audit-Logging | geteilt |
| 4. Worker Nodes | Kubelet-Konfiguration, Dateirechte auf dem Node | Sie -- immer |
| 5. Policies | RBAC, Pod Security, NetworkPolicies, Secrets-Handling | Sie -- immer |
Zwei Unterscheidungen sind für die Priorisierung entscheidend:
- Automated vs. Manual (in älteren Benchmark-Versionen "Scored" vs. "Not Scored"): Automated-Checks prüft kube-bench maschinell und liefert PASS/FAIL. Manual-Checks (z. B. "Minimieren Sie den Einsatz von Wildcard-RBAC") erfordern eigene Bewertung und erscheinen als WARN.
- Level 1 vs. Level 2: Level 1 ist Basis-Härtung ohne nennenswerte Funktionseinschränkung -- die sollte jeder Produktions-Cluster erfüllen. Level 2 ist strenger und kann Workloads brechen (etwa
AlwaysPullImages).
kube-bench von Aqua Security ist das Standard-Tool, um den Benchmark automatisiert zu prüfen. Es erkennt Kubernetes-Version und Distribution und wählt die passende Benchmark-Variante (generisch, EKS, AKS, GKE, RKE2, K3s). Wichtig: Die Check-Nummern verschieben sich zwischen Benchmark-Versionen leicht. Die Nummern in diesem Artikel folgen dem generischen CIS Benchmark ab v1.9 -- prüfen Sie im Report immer die Beschreibung, nicht nur die Nummer.
Praxis: kube-bench ausführen und den Report priorisiert lesen
Die sauberste Methode für einen self-managed Cluster ist ein Job direkt im Cluster, der die relevanten Host-Pfade read-only mountet:
apiVersion: batch/v1
kind: Job
metadata:
name: kube-bench-master
namespace: kube-system
spec:
template:
spec:
hostPID: true
nodeSelector:
node-role.kubernetes.io/control-plane: ""
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
containers:
- name: kube-bench
image: docker.io/aquasec/kube-bench:latest
command: ["kube-bench", "run", "--targets", "master,etcd"]
volumeMounts:
- name: var-lib-kubelet
mountPath: /var/lib/kubelet
readOnly: true
- name: etc-kubernetes
mountPath: /etc/kubernetes
readOnly: true
- name: etc-systemd
mountPath: /etc/systemd
readOnly: true
restartPolicy: Never
volumes:
- name: var-lib-kubelet
hostPath:
path: /var/lib/kubelet
- name: etc-kubernetes
hostPath:
path: /etc/kubernetes
- name: etc-systemd
hostPath:
path: /etc/systemd
backoffLimit: 0
Für die Worker-Nodes derselbe Job ohne Control-Plane-nodeSelector und mit --targets node,policies. Alternativ als Binary direkt auf dem Node:
# Scan starten und Ergebnis lesen
kubectl apply -f kube-bench-job.yaml
kubectl logs -n kube-system job/kube-bench-master
# Oder als Binary auf dem Control-Plane-Node
sudo ./kube-bench run --targets master,etcd,node,policies
# JSON-Output zur Triage und Archivierung
sudo ./kube-bench run --json --outputfile cis-results.json
Den Report lesen Sie priorisiert, nicht linear. Mit jq filtern Sie zuerst die automatisierten FAILs -- das ist Ihre Arbeitsliste:
# Nur FAILs, sortiert nach Sektion
jq -r '.Controls[].tests[].results[] | select(.status=="FAIL") | "\(.test_number) \(.test_desc)"' cis-results.json
# Zaehlung pro Status als Fortschritts-Metrik
jq '[.Controls[].tests[].results[].status] | group_by(.) | map({(.[0]): length}) | add' cis-results.json
WARNs (Manual-Checks) kommen in die zweite Runde: Dort bewerten Sie selbst, dokumentieren die Entscheidung und haken ab. Ein Cluster mit 0 FAILs und begründeten WARNs ist audit-fähig -- ein Cluster mit 40 unbearbeiteten FAILs nicht.
Die Top-15 Failed Checks und ihre Remediation
Die folgenden Checks scheitern in kubeadm-Standardinstallationen erfahrungsgemäß am häufigsten (Einschätzung aus Praxis-Audits, keine offizielle CIS-Statistik). Erst die Übersicht, dann die konkreten Konfigurationen.
| # | Check (CIS ab v1.9) | Komponente | Remediation |
|---|---|---|---|
| 1 | 1.2.1 anonymous-auth | kube-apiserver | --anonymous-auth=false |
| 2 | 1.2.5 kubelet-certificate-authority | kube-apiserver | --kubelet-certificate-authority=/etc/kubernetes/pki/ca.crt |
| 3 | 1.2.16 profiling | kube-apiserver | --profiling=false |
| 4 | 1.2.17 audit-log-path | kube-apiserver | --audit-log-path=/var/log/kubernetes/audit/audit.log |
| 5 | 1.2.18-1.2.20 audit-log-Rotation | kube-apiserver | --audit-log-maxage=30 --audit-log-maxbackup=10 --audit-log-maxsize=100 |
| 6 | 1.2.22 service-account-lookup | kube-apiserver | --service-account-lookup=true |
| 7 | 1.2.29 encryption-provider-config | kube-apiserver | Secrets-Verschlüsselung at rest (siehe unten) |
| 8 | 1.3.2 profiling | kube-controller-manager | --profiling=false |
| 9 | 1.3.6 RotateKubeletServerCertificate | kube-controller-manager | --feature-gates=RotateKubeletServerCertificate=true |
| 10 | 1.4.1 profiling | kube-scheduler | --profiling=false |
| 11 | 2.2 / 2.3 etcd Client-Auth | etcd | --client-cert-auth=true --auto-tls=false |
| 12 | 4.2.1 anonymous-auth | Kubelet | authentication.anonymous.enabled: false |
| 13 | 4.2.2 authorization-mode | Kubelet | authorization.mode: Webhook |
| 14 | 4.2.4 read-only-port | Kubelet | readOnlyPort: 0 |
| 15 | 4.2.6 protect-kernel-defaults | Kubelet | protectKernelDefaults: true (Vorsicht, siehe Fallstricke) |
kube-apiserver (Checks 1-7)
Die Flags gehören in das statische Pod-Manifest /etc/kubernetes/manifests/kube-apiserver.yaml. Der Kubelet startet den API-Server nach dem Speichern automatisch neu -- planen Sie 30 bis 60 Sekunden API-Nichtverfügbarkeit pro Control-Plane-Node ein und ändern Sie bei HA-Setups einen Node nach dem anderen.
# /etc/kubernetes/manifests/kube-apiserver.yaml (Auszug: command)
spec:
containers:
- name: kube-apiserver
command:
- kube-apiserver
- --anonymous-auth=false
- --authorization-mode=Node,RBAC
- --enable-admission-plugins=NodeRestriction
- --kubelet-certificate-authority=/etc/kubernetes/pki/ca.crt
- --profiling=false
- --service-account-lookup=true
- --audit-log-path=/var/log/kubernetes/audit/audit.log
- --audit-log-maxage=30
- --audit-log-maxbackup=10
- --audit-log-maxsize=100
- --encryption-provider-config=/etc/kubernetes/enc/encryption-config.yaml
- --tls-min-version=VersionTLS12
Zwei Punkte, die kube-bench nicht erzwingt, aber ohne die die Flags wirkungslos sind: Der Audit-Log-Pfad muss als hostPath-Volume in das Manifest gemountet werden, sonst schreibt der API-Server ins Container-Dateisystem und die Logs verschwinden beim Neustart. Und die Encryption-Konfiguration braucht die Datei, auf die das Flag zeigt:
# /etc/kubernetes/enc/encryption-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources:
- secrets
providers:
- aescbc:
keys:
- name: key1
secret: <base64-encoded-32-byte-key>
- identity: {}
Nach dem Aktivieren sind nur neue Secrets verschlüsselt. Bestehende Secrets schreiben Sie einmalig um:
kubectl get secrets --all-namespaces -o json | kubectl replace -f -
Controller-Manager, Scheduler, etcd (Checks 8-11)
Dieselbe Mechanik, andere Manifeste:
# /etc/kubernetes/manifests/kube-controller-manager.yaml (Auszug)
- --profiling=false
- --feature-gates=RotateKubeletServerCertificate=true
- --terminated-pod-gc-threshold=100
# /etc/kubernetes/manifests/kube-scheduler.yaml (Auszug)
- --profiling=false
# /etc/kubernetes/manifests/etcd.yaml (Auszug)
- --client-cert-auth=true
- --auto-tls=false
- --peer-client-cert-auth=true
- --peer-auto-tls=false
etcd verdient besondere Aufmerksamkeit: Dort liegt der komplette Cluster-State inklusive aller Secrets. Wer etcd ohne Client-Zertifikat erreicht, besitzt den Cluster -- unabhängig von jedem RBAC-Setup.
Kubelet (Checks 12-15)
Auf jedem Node gilt: Konfiguration über /var/lib/kubelet/config.yaml, nicht über deprecated Kommandozeilen-Flags. Nach der Änderung sudo systemctl restart kubelet.
# /var/lib/kubelet/config.yaml (Auszug)
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
authentication:
anonymous:
enabled: false
webhook:
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
readOnlyPort: 0
protectKernelDefaults: true
streamingConnectionIdleTimeout: 5m
makeIPTablesUtilChains: true
rotateCertificates: true
serverTLSBootstrap: true
tlsMinVersion: VersionTLS12
Der offene Read-Only-Port 10255 (Check 4.2.4) und anonyme Kubelet-API-Zugriffe (4.2.1) sind die beiden Findings mit dem direktesten Angriffspfad: Beide liefern einem Angreifer im Pod-Netz Pod-Listen, Umgebungsvariablen und teils Exec-Zugriff, ganz ohne Credentials.
Ergänzendes Hardening: Pod Security Standards und NetworkPolicy
Der Policies-Abschnitt (Sektion 5) besteht überwiegend aus Manual-Checks -- kube-bench sagt Ihnen also nicht automatisch, ob Sie hier gut dastehen. Zwei Maßnahmen decken den Großteil ab.
Pod Security Standards per Namespace-Label (Check 5.2.x). Das baseline-Profil blockiert privilegierte Container und Host-Namespaces, restricted erzwingt zusätzlich Non-Root und Capability-Drop:
kubectl label namespace produktion pod-security.kubernetes.io/enforce=baseline pod-security.kubernetes.io/warn=restricted pod-security.kubernetes.io/audit=restricted
Die Kombination aus enforce=baseline und warn=restricted ist der pragmatische Einstieg: Nichts Kritisches läuft mehr, und die Warnings zeigen, welche Workloads für restricted noch angepasst werden müssen. Details zu den Profilen und der Migration bestehender Workloads finden Sie in unserer Kubernetes-Security-Hardening-Checkliste.
Default-Deny-NetworkPolicy pro Namespace (Check 5.3.2). Ohne NetworkPolicies darf jeder Pod mit jedem reden -- ein kompromittierter Pod erreicht damit auch etcd-Ports, Kubelet-APIs und interne Dienste:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: produktion
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Danach geben Sie benötigte Verbindungen explizit frei (DNS zuerst, sonst löst nichts mehr auf). Für die RBAC-Seite von Sektion 5 -- Wildcard-Rollen, cluster-admin-Bindings, Service-Account-Token-Automount -- lohnt ein separater Durchgang mit rbac-lookup und kubeaudit; eine schnelle Standortbestimmung über alle Security-Ebenen liefert unser kostenloser Kubernetes Security Quick-Check.
Härtungs-Checkliste zum Abhaken
Control Plane (self-managed):
-
--anonymous-auth=falseam API-Server -
--authorization-mode=Node,RBAC(kein AlwaysAllow, kein ABAC) -
--kubelet-certificate-authoritygesetzt - Audit-Logging aktiv, Log-Pfad als hostPath gemountet, Rotation konfiguriert
-
--profiling=falsean API-Server, Controller-Manager, Scheduler - EncryptionConfiguration für Secrets aktiv, Bestandssecrets umgeschrieben
- etcd:
--client-cert-auth=true,--auto-tls=false, Peer-TLS erzwungen
Worker Nodes (immer Ihre Verantwortung):
- Kubelet: anonymous auth aus,
authorization.mode: Webhook -
readOnlyPort: 0 -
protectKernelDefaults: truenach Sysctl-Vorbereitung - Zertifikatsrotation aktiv (
rotateCertificates,serverTLSBootstrap) - Dateirechte: Kubelet-
config.yamlund kubeconfig maximal 600, Owner root:root
Policies:
- Pod Security Standards: mindestens
enforce=baselineauf allen Workload-Namespaces - Default-Deny-NetworkPolicy in jedem Namespace, Freigaben explizit
-
automountServiceAccountToken: falsewo kein API-Zugriff nötig - Keine Wildcard-Verbs/-Resources in Rollen, cluster-admin-Bindings inventarisiert
Prozess:
- kube-bench als wiederkehrender Job oder CI-Schritt, JSON-Ergebnisse archiviert
- Manifeste vor dem Deploy gegen Best Practices geprüft (z. B. mit unserem YAML-Validator, Trivy oder Polaris)
- Für akzeptierte WARNs/FAILs: dokumentierte Risikobewertung ("comply or explain")
Fallstricke
Managed Kubernetes: Die Control Plane gehört Ihnen nicht. Bei EKS, AKS und GKE laufen API-Server und etcd beim Provider -- die Sektionen 1 bis 3 des generischen Benchmarks können Sie weder prüfen noch ändern. Ein generischer kube-bench-Lauf liefert dort irreführende Ergebnisse. Nutzen Sie die plattformspezifischen Benchmarks (kube-bench run --benchmark eks-1.5.0, analog für AKS und GKE; die verfügbaren Versionen listet das kube-bench-Repository). Ihre Verantwortung bleibt: Node-Konfiguration (Sektion 4) und komplett Sektion 5.
protectKernelDefaults kann den Kubelet-Start verhindern. Das Flag lässt den Kubelet abbrechen, wenn Kernel-Parameter nicht seinen Erwartungen entsprechen. Setzen Sie vorher auf jedem Node die Sysctls (vm.overcommit_memory=1, kernel.panic=10, kernel.panic_on_oops=1) und testen Sie auf einem Node, bevor Sie die Änderung ausrollen.
Check-Nummern wandern. CIS 1.2.16 in Benchmark v1.9 ist nicht zwingend 1.2.16 in der nächsten Version. Verlassen Sie sich in Skripten und Ausnahme-Dokumentation auf die Beschreibung plus Benchmark-Version, nie auf die Nummer allein.
Nicht jeder FAIL ist ein Fehler. AlwaysPullImages (Level 2) erhöht Registry-Last und Startzeiten erheblich; EventRateLimit ist ein Alpha-Admission-Plugin. Bewusstes Abweichen mit dokumentierter Begründung ist legitim -- stilles Ignorieren nicht.
kube-bench prüft Konfiguration, nicht Laufzeit. Ein perfekter CIS-Score sagt nichts über verwundbare Images, exponierte Ingresses oder kompromittierte Workloads. Für Runtime-Erkennung brauchen Sie Falco, für Image-Scanning Trivy. Wie die Bausteine zusammenspielen, zeigt unser Überblick zum Cluster-Absichern mit Security-Check.
FAQ
Wie oft sollte ich kube-bench ausführen?
Mindestens wöchentlich automatisiert plus nach jeder Änderung an Control-Plane- oder Kubelet-Konfiguration und nach jedem Kubernetes-Upgrade (Upgrades setzen gern Manifest-Änderungen zurück). In regulierten Umgebungen (NIS2, KRITIS, ISO 27001) ist ein täglicher Lauf mit Alerting auf neue FAILs sinnvoll.
Wie integriere ich kube-bench in die CI/CD-Pipeline?
Als Job gegen den Zielcluster mit JSON-Output, dann per jq die FAIL-Anzahl gegen eine Baseline vergleichen: Pipeline rot, wenn neue FAILs gegenüber dem letzten akzeptierten Stand dazukommen. Absolute Null-FAIL-Gates scheitern in der Praxis an bewusst akzeptierten Abweichungen -- der Baseline-Vergleich ist robuster.
Was ist bei EKS, AKS und GKE anders?
Die Control-Plane-Checks (Sektionen 1-3) liegen beim Provider; Sie prüfen mit den plattformspezifischen Benchmarks nur Nodes und Policies. Zusätzlich verschieben sich Kubelet-Defaults: Managed Node Groups liefern teils bereits readOnlyPort: 0 und Webhook-Authorization. Prüfen statt annehmen -- gerade selbstverwaltete Node-Pools und Custom-Images weichen oft ab.
Muss ich alle Checks bestehen?
Nein. Ziel ist: alle Level-1-Automated-Checks auf PASS, alle Manual-Checks bewertet und dokumentiert, Level-2-Checks selektiv nach Risikoabwägung. Auditoren akzeptieren begründete Abweichungen ("comply or explain") -- was sie nicht akzeptieren, sind unbearbeitete Reports.
Was ist der Unterschied zwischen kube-bench und Trivy oder kubescape?
kube-bench prüft ausschließlich den CIS-Benchmark, dafür am gründlichsten. Trivy scannt zusätzlich Images, Dependencies und Manifeste; kubescape deckt neben CIS auch NSA/CISA-Guidelines und MITRE ATT&CK ab. Für den CIS-Nachweis gegenüber Auditoren ist kube-bench das Referenz-Tool, die anderen ergänzen es.
Fazit
CIS-Hardening ist kein Projekt für ein Quartal, sondern zwei fokussierte Arbeitstage plus Automatisierung: kube-bench laufen lassen, die Top-15-FAILs mit den gezeigten Flags beheben, Pod Security Standards und Default-Deny-NetworkPolicies setzen, Scan in die Pipeline. Damit sind Sie besser aufgestellt als die Mehrheit der Produktions-Cluster -- und haben für Kunden-Fragebögen und Audits belastbare Nachweise statt Absichtserklärungen.
Die Cluster-Konfiguration ist die eine Hälfte, Ihre Workload-Manifeste die andere: Privilegierte Container, fehlende Resource-Limits und automatisch gemountete Service-Account-Tokens macht kein API-Server-Flag ungeschehen.
Prüfen Sie Ihre Deployments jetzt im kostenlosen Kubernetes-YAML-Validator -- er lintet Ihre Manifeste direkt im Browser gegen Security-Best-Practices sowie DSGVO-/BSI-relevante Anforderungen, ohne dass Daten Ihren Rechner verlassen.
📖 Verwandte Artikel
Weitere interessante Beiträge zu ähnlichen Themen
§ 30 BSIG auf Kubernetes übersetzt: technische Pflichten
Die zehn Maßnahmenkategorien aus § 30 BSIG auf Kubernetes übersetzt: Audit-Policy, etcd-Backup, Secrets, RBAC, NetworkPolicies, Pod Security Standards.
Kubernetes Cluster absichern: Security-Checkliste 2026
Kubernetes Cluster absichern: 30-Minuten-Security-Check mit kube-bench, Trivy & Polaris plus 12-Punkte-Härtungs-Checkliste mit YAML-Templates für Audits.
Kubernetes Penetration Test: Ablauf, Tools & Kosten 2026
Kubernetes Penetration Test: 5-Phasen-Ablauf mit kube-hunter, kube-bench und Trivy — typische Findings sowie ein ehrlicher Aufwands- und Kostenrahmen.
Kubernetes RBAC Audit: Least-Privilege durchsetzen
Kubernetes RBAC Audit: überberechtigte Rollen, verwaiste Bindings und Escalation-Pfade finden — der komplette Audit-Workflow mit rbac-lookup und kubeaudit.
NIS2-Meldepflicht für Kubernetes-Vorfälle: Ablauf in Stunden
Meldepflicht nach NIS2/§ 32 BSIG für Kubernetes-Vorfälle: 24h-Erstmeldung, 72h-Meldung, Abschlussbericht. Welche Cluster-Ereignisse die Frist auslösen.
Kubernetes RBAC Best Practices 2026: Rollen, Bindings & Least Privilege
Kubernetes RBAC Best Practices mit vollständigen Role-, ClusterRole- und RoleBinding-Manifesten: Least-Privilege-Rollen für Entwickler, CI/CD und Auditoren bauen, mit kubectl auth can-i und rbac-lookup verifizieren und die häufigsten Fehlkonfigurationen systematisch eliminieren.
Kubernetes Compliance: DSGVO, BSI & regulatorische Anforderungen (2026)
Kubernetes Compliance: DSGVO, BSI IT-Grundschutz und regulatorische Anforderungen erfüllen. Praxis-Guide für deutsche Enterprise-Teams.
Kubernetes Security Hardening Checkliste
Kubernetes härten nach BSI und DSGVO: RBAC, Network Policies, Pod Security Standards und Secrets Management mit YAML-Beispielen.