Grundlagen und Audit-Grenzen

Ein Kubernetes-Cluster kann stabil laufen und trotzdem unnötig große Angriffsflächen besitzen. Ein defensiver Security Audit prüft deshalb nicht nur bekannte CVEs, sondern auch Berechtigungen, Workload-Konfiguration, Netzwerksegmentierung, Secret-Nutzung, Plattformgrenzen und wiederholbare Baselines. Ziel ist nicht, möglichst viele Kommandos auszuführen, sondern nachvollziehbare Evidence in Kontext, Risiko, Finding, Remediation und Verification zu übersetzen.

Dieser Artikel ist für eigene Lab-Cluster oder ausdrücklich autorisierte Cluster gedacht. Fast alle Checks sind read-only. YAML-Beispiele zeigen Zielbilder und Muster; sie sollten nicht ungeprüft in Produktion angewendet werden. Änderungen gehören in einen Change-Prozess mit Review, Backup, Test und Rollback-Plan.

  • Control Node: das System, auf dem kubectl, trivy oder kube-bench gestartet werden.

  • Target Cluster: der Kubernetes- oder OpenShift-/OKD-Cluster, der geprüft wird.

  • Managed Node: Worker-Node, auf dem Workloads laufen. Bei Managed Kubernetes sind manche Node- oder Control-Plane-Details nicht direkt zugänglich.

  • Scope: technische und organisatorische Grenze des Audits. Ein fehlender Zugriff ist nicht automatisch ein Finding, sondern zuerst eine Scope-Frage.

Cluster-Kontext und Bestand erfassen

Der erste Audit-Schritt ist der Kontext. Ein Administrator kann glauben, gegen staging zu arbeiten, während die kubeconfig noch auf production zeigt. `current-context` verbindet typischerweise Cluster, User und optional Namespace. Erst wenn dieser Kontext bestätigt ist, sind weitere Ergebnisse belastbar.

bash
kubectl config current-context
kubectl config view --minify
kubectl cluster-info
kubectl version
kubectl get nodes -o wide
kubectl get namespaces

Worauf achten? Notieren Sie Clustername, API-Endpunkt, Kubernetes-Version, Node-Betriebssysteme, Container Runtime, Namespace-Struktur und erkennbare Plattformkomponenten. Ein Audit ohne Inventar bewertet Findings schnell falsch: Ein fehlender Control-Plane-Check in einem Managed Cluster ist anders einzuordnen als derselbe fehlende Check in einem selbst betriebenen Cluster.

Auffällig wäre zum Beispiel ein unerwarteter Context, ein Namespace-Scope, der nicht zum Auftrag passt, sehr alte Node-Versionen, ungeklärte System-Namespaces oder fehlende Information zur Distribution. Das Risiko liegt weniger im einzelnen Kommando, sondern in falscher Entscheidungsgrundlage. Verification bedeutet: Context, Scope und Inventar im Audit-Log dokumentieren und vor Änderungen erneut prüfen.

RBAC prüfen

RBAC beantwortet, welche Identität welche API-Aktion ausführen darf. Das Modell besteht aus Subject, Binding und Role. Ein Subject ist ein User, eine Group oder ein ServiceAccount. Eine Role gilt in einem Namespace. Eine ClusterRole ist clusterweit definiert. RoleBinding und ClusterRoleBinding verbinden Subjects mit Roles oder ClusterRoles. Der Denkfluss ist: Subject -> RoleBinding oder ClusterRoleBinding -> Role oder ClusterRole -> apiGroups, resources und verbs.

bash
kubectl auth can-i --list
kubectl get roles -A
kubectl get clusterroles
kubectl get rolebindings -A
kubectl get clusterrolebindings

Die Ausgabe zeigt noch kein fertiges Risiko. Relevant sind Scope und Kombination: Ein `get` auf ConfigMaps in einem Namespace ist anders zu bewerten als `*` auf `*` clusterweit. Besonders sorgfältig geprüft werden sollten Wildcards, `cluster-admin`, Zugriff auf `secrets`, `pods/exec`, `pods/attach`, `impersonate`, `bind`, `escalate`, `serviceaccounts/token` und Rechte zum Erzeugen oder Ändern von Workloads. Diese Berechtigungen sind nicht automatisch falsch, können aber je nach Scope und Workload hohe Auswirkungen besitzen.

bash
NS=default
SA=default
kubectl auth can-i get secrets -A
kubectl auth can-i create pods -A
kubectl auth can-i create pods/exec -A
kubectl auth can-i impersonate users -A
kubectl auth can-i get secrets --as="system:serviceaccount:${NS}:${SA}" -n "$NS"

`kubectl auth can-i --list` zeigt die effektiven Rechte der aktuell verwendeten Identität. Einzelabfragen mit `can-i` helfen, konkrete Findings zu verifizieren. Ein `yes` ist aber nicht automatisch kritisch und ein `no` nicht automatisch ausreichend sicher. Entscheidend sind Namespace, betroffene Ressource, Datenklasse, Workload-Zweck und ob Rechte kombiniert werden können.

Konkretes Finding: Ein ServiceAccount für eine Webanwendung ist per ClusterRoleBinding an `cluster-admin` gebunden. Evidence ist das Binding mit Subject und ClusterRole. Risiko: Der Workload erhält wesentlich mehr API-Rechte als für seine Funktion erforderlich. Remediation: eigene minimale Role oder ClusterRole definieren und Binding auf Namespace und benötigte Verbs begrenzen. Verification: `kubectl auth can-i` erneut für genau diesen ServiceAccount ausführen.

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: app-config-reader
namespace: app
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: app-config-reader
namespace: app
subjects:
- kind: ServiceAccount
name: app
namespace: app
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: app-config-reader

Service Accounts und Token-Mounting verstehen

Service Accounts sind Kubernetes-Identitäten für Workloads. Wenn ein Pod mit der Kubernetes-API sprechen muss, sollte er einen anwendungsspezifischen ServiceAccount mit minimalen Rechten nutzen. Wenn er keinen API-Zugriff braucht, sollte kein Token unnötig gemountet werden. Kubernetes erstellt in jedem Namespace einen `default` ServiceAccount; ein Pod ohne expliziten `serviceAccountName` nutzt diesen Default.

bash
kubectl get serviceaccounts -A
kubectl get rolebindings -A -o wide | grep system:serviceaccount || true
kubectl get clusterrolebindings -o wide | grep system:serviceaccount || true
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.serviceAccountName}{"\t"}{.spec.automountServiceAccountToken}{"\n"}{end}'

Worauf achten? Prüfen Sie, welche Pods den `default` ServiceAccount verwenden, welche ServiceAccounts clusterweite Bindings besitzen und ob `automountServiceAccountToken` bewusst gesetzt wurde. Seit Kubernetes v1.22 werden für Pods kurzlebige, automatisch rotierende Tokens über die TokenRequest-API als projected volume bereitgestellt. Veraltete Aussagen über automatisch erzeugte, langlebige Secret-basierte Tokens dürfen deshalb nicht pauschal übernommen werden.

yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: web
namespace: app
automountServiceAccountToken: false
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: app
spec:
template:
spec:
serviceAccountName: web
automountServiceAccountToken: false
containers:
- name: web
image: registry.example.com/web:1.2.3

Dieses YAML verändert Cluster-State, wenn es angewendet wird. Im Audit dient es als Remediation-Muster. Verification: Nach der Änderung den Pod neu erzeugen lassen und die Pod-Spec prüfen. Wenn die Anwendung danach API-Fehler meldet, war API-Zugriff fachlich erforderlich und muss mit minimalem RBAC neu modelliert werden.

Pod Security und Workload-Härtung prüfen

Pod Security Standards beschreiben drei Profile. `Privileged` ist praktisch uneingeschränkt und für normale Applikationen kein Zielbild. `Baseline` verhindert bekannte problematische Privilege-Escalation-Patterns, erlaubt aber noch breite Kompatibilität. `Restricted` ist das stärker gehärtete Modell für moderne Workloads und verlangt mehr Anpassung an Images, Volumes und Laufzeitverhalten. Pod Security Admission setzt diese Profile über Namespace-Labels in den Modi `enforce`, `audit` und `warn` um.

bash
kubectl get namespaces --show-labels
kubectl get namespaces -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/enforce}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/audit}{"\t"}{.metadata.labels.pod-security\.kubernetes\.io/warn}{"\n"}{end}'

`enforce` blockiert nicht erlaubte Pods. `audit` schreibt Audit-Events. `warn` warnt Benutzer beim Erstellen oder Ändern. Ein Namespace ohne Labels bedeutet nicht automatisch, dass keinerlei Kontrollen existieren; Admission Controller, Policies, Plattformvorgaben oder OpenShift SCCs können zusätzlich wirken. Bewertung braucht deshalb immer Plattformkontext.

bash
kubectl get pods -A -o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,HOSTNETWORK:.spec.hostNetwork,HOSTPID:.spec.hostPID,HOSTIPC:.spec.hostIPC'
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{range .spec.containers[*]}{.name}{": privileged="}{.securityContext.privileged}{", ape="}{.securityContext.allowPrivilegeEscalation}{", rootfs="}{.securityContext.readOnlyRootFilesystem}{", uid="}{.securityContext.runAsUser}{"\n"}{end}{end}'

Auffällig sind `privileged`, `hostNetwork`, `hostPID`, `hostIPC`, `hostPath`, root-Prozesse, zusätzliche Capabilities, erlaubte Privilege Escalation und beschreibbare Root-Dateisysteme. Das ist aber kein reiner Boolean-Test: CNI, Storage-CSI, Monitoring-Agents oder Security-Komponenten können legitime Hostrechte benötigen. Bewerten Sie Purpose, Namespace, Image, ServiceAccount, Scope, Herstelleranforderung und kompensierende Kontrollen.

yaml
apiVersion: v1
kind: Pod
metadata:
name: hardened-example
namespace: app
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: registry.example.com/app:1.2.3
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
readOnlyRootFilesystem: true

`runAsNonRoot` reduziert das Risiko von Root-Prozessen im Container. `allowPrivilegeEscalation: false` verhindert, dass ein Prozess zusätzliche Privilegien erlangen darf. `capabilities.drop: ["ALL"]` entfernt Linux-Capabilities und macht benötigte Ausnahmen sichtbar. `readOnlyRootFilesystem` reduziert Schreibmöglichkeiten im Image, kann aber Anwendungen brechen, die temporäre Dateien ins Root-Dateisystem schreiben. `RuntimeDefault` nutzt das Standard-seccomp-Profil der Runtime. Verification heißt: Deployment erneut auslesen, Logs prüfen und Anwendungstests durchführen.

NetworkPolicies prüfen

NetworkPolicy beschreibt erlaubte Netzwerkflüsse für ausgewählte Pods. Sie ist keine Firewall für alles, sondern ein Kubernetes-Objekt, das nur wirkt, wenn das eingesetzte Netzwerk-Plugin die benötigte Policy-Semantik unterstützt. Ohne passende Policies ist Kommunikation zwischen Workloads je nach CNI oft breiter als fachlich notwendig.

bash
kubectl get networkpolicy -A
for ns in $(kubectl get namespaces -o jsonpath='{.items[*].metadata.name}'); do
count=$(kubectl get networkpolicy -n "$ns" --no-headers 2>/dev/null | wc -l)
printf "%s\t%s\n" "$ns" "$count"
done

Ein Namespace mit Workloads, aber ohne NetworkPolicy kann ein Finding sein, wenn die Anwendung Segmentierung braucht und das CNI NetworkPolicy unterstützt. Risiko: unnötig breite East-West-Kommunikation und schwerere Eingrenzung im Incident. Remediation: Default-Deny als Ausgangspunkt und danach explizit notwendige Flows erlauben. Verification: Policy-Bestand prüfen und tatsächliche Anwendungskommunikation testen.

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
namespace: app
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress

`podSelector: {}` wählt alle Pods im Namespace aus. `policyTypes: Ingress` und `Egress` bedeutet: eingehende und ausgehende Kommunikation ist für diese Pods nur noch erlaubt, wenn weitere Policies sie explizit freigeben. Das ist kein vollständiges Sicherheitskonzept: DNS, Monitoring, Ingress Controller, Datenbanken und externe APIs brauchen bewusst modellierte Flows.

yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns-egress
namespace: app
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53

Dieses DNS-Beispiel ist ein Muster, keine universelle Copy/Paste-Wahrheit. Namespace-Namen und Labels können je Distribution variieren. Verification: Labels im eigenen Cluster prüfen, DNS-Auflösung aus einem Testpod validieren und keine unnötigen Egress-Ziele öffnen.

Secrets und Images prüfen

Ein Kubernetes Secret ist ein API-Objekt für sensitive Daten. Base64 ist dabei nur eine Kodierung, keine Verschlüsselung. Ein defensiver Audit gibt keine Secret-Werte aus. Er prüft, welche Secret-Objekte existieren, welche Workloads sie referenzieren, welche Subjects sie lesen dürfen, wie Rotation und Lifecycle geregelt sind und ob Encryption at Rest aktiviert ist.

bash
kubectl get secrets -A --field-selector type!=kubernetes.io/service-account-token
kubectl auth can-i get secrets -A
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{range .spec.containers[*]}{range .env[*]}{.valueFrom.secretKeyRef.name}{","}{end}{end}{"\n"}{end}'

Secret-Read-Rechte sind sensibel, weil sie Zugriff auf Datenbankpasswörter, API-Schlüssel oder Pull-Credentials bedeuten können. Secrets können als Environment-Variablen oder Volumes bereitgestellt werden. Keine Methode ist pauschal immer sicher: Prozessumgebung, Logs, Debugging, Dateisystem, Rotation und Anwendungsverhalten beeinflussen das Risiko. Verification: RBAC-Abfragen für konkrete ServiceAccounts, Workload-Referenzen und Rotation-Prozess dokumentieren.

Image-Scanner wie Trivy finden bekannte Schwachstellen in Paketen und Artefakten. Sie beantworten aber nicht automatisch, ob eine CVE im konkreten Codepfad erreichbar ist, ob der Workload besondere Rechte besitzt oder ob ein realistischer Angriffspfad existiert. Image-Scanning ist deshalb ein Baustein, nicht der gesamte Audit.

bash
IMAGE="registry.example.com/app:1.2.3"
trivy image --severity HIGH,CRITICAL --ignore-unfixed "$IMAGE"
trivy k8s --report summary cluster

Bei `trivy image` sind Severity, Installed Version und Fixed Version die wichtigsten Felder. Nicht jede CVE ist ein Critical Incident, aber jede relevante High/Critical-Finding-Linie braucht Bewertung. Der Kubernetes-Scan von Trivy ist laut Dokumentation experimentell; er kann Orientierung geben, ersetzt aber keine manuelle Analyse.

CIS, kube-bench und Plattformvarianten

Der CIS Kubernetes Benchmark ist eine strukturierte Sicherheitsbaseline. kube-bench prüft viele Kontrollen automatisiert und orientiert sich an den CIS-Checks. Benchmark Compliance ist aber nicht gleich Sicherheit: Ein Cluster kann benchmarknah sein und trotzdem architektonische Risiken besitzen. Umgekehrt können Abweichungen technisch begründet sein, wenn sie dokumentiert, begrenzt und kompensiert sind.

bash
kube-bench --version
kube-bench

Worauf achten? `PASS` bedeutet, dass ein Check erfüllt wurde. `FAIL` braucht Kontext, Owner und Remediation-Entscheidung. `WARN` ist ein Hinweis, kein automatisches Risiko. kube-bench kann je nach Betriebsmodell Host- oder Node-Zugriff benötigen; führen Sie es nur in einer geeigneten, autorisierten Umgebung aus.

Bei Managed Kubernetes ist Verantwortung geteilt. Provider betreiben häufig Control Plane oder bestimmte Komponenten; Kunden bleiben typischerweise verantwortlich für RBAC, Workloads, Namespaces, NetworkPolicies, Secrets, Images, Identity-Integration und Plattformkonfiguration. Die genaue Grenze unterscheidet sich je Anbieter und muss dokumentiert werden.

OpenShift und OKD ergänzen Kubernetes um Security Context Constraints. SCCs sind eine OpenShift-spezifische Kontrollschicht und dürfen nicht mit Pod Security Admission oder den Kubernetes Pod Security Standards vermischt werden. Sie steuern unter anderem privileged Container, Capabilities, Host-Verzeichnisse, SELinux-Kontext, User IDs, Host Namespaces, FSGroup, seccomp und Volume-Typen.

bash
oc get scc
oc adm policy who-can use scc privileged

Auffällig wäre nicht nur, dass ein Workload eine weitreichende SCC nutzen kann, sondern warum: Ist es ein CNI, ein CSI-Treiber, ein Operator oder eine normale Anwendung? Remediation kann eine eigene, eng begrenzte SCC, ein anderes Deployment-Modell oder die Entfernung unnötiger Rechte sein. Verification: `oc adm policy who-can` erneut ausführen und betroffene Workloads neu bewerten.

Findings priorisieren und beheben

Nicht jedes auffällige Ergebnis ist automatisch eine Schwachstelle. Ein privileged CNI-Plugin, ein Storage-CSI-Treiber mit hostPath, ein Operator mit clusterweitem Watch oder ein Monitoring-Agent mit Host-Zugriff kann technisch notwendig sein. Professionelle Bewertung kombiniert technische Notwendigkeit, Scope, Exposure, kompensierende Kontrollen und Betriebsverantwortung.

  • Excessive RBAC: Evidence ist ein Binding auf `cluster-admin` oder Wildcards. Risiko ist übermäßiger API-Zugriff. Kontext sind Namespace, Workload, Datenklasse und ServiceAccount. Remediation ist eine minimale Role. Verification erfolgt mit `kubectl auth can-i` für genau diese Identität.

  • Fehlende oder zu breite Netzwerksegmentierung: Evidence ist ein Namespace mit Workloads ohne passende NetworkPolicies. Risiko ist unnötige Kommunikation. Kontext sind CNI-Fähigkeit und notwendige Flows. Remediation ist Default-Deny plus explizite Freigaben. Verification erfolgt durch Policy-Prüfung und Funktionstest.

  • Privilegierter Workload: Evidence ist `privileged`, Host-Namespace oder hostPath. Risiko ist eine verschobene Trust Boundary zum Node. Kontext sind Plattformrolle, Herstelleranforderung und Kompensationen. Remediation ist SecurityContext-Härtung oder Architekturänderung. Verification erfolgt durch erneute Spec-Prüfung und Anwendungstest.

Priorisierung sollte Exposure, Privilege, Exploitability, Blast Radius, Datensensitivität, Business Impact und kompensierende Kontrollen berücksichtigen. Ein Audit ohne Remediation bleibt Bestandsaufnahme. Ein tragfähiger Ablauf ist: Finding -> Root Cause -> Change Design -> Test -> Deployment -> Verification -> Close oder bewusstes Risk Acceptance. Bei internen Audits spricht man meist von Verification oder Re-Assessment; bei formalen Penetrationstests kann ein Retest ein eigener definierter Schritt sein.

Audit-Checkliste

  • Cluster Context und Scope bestätigt.

  • API, Version, Nodes, Namespaces und Plattformgrenzen erfasst.

  • ClusterRoleBindings und weitreichende Rechte geprüft.

  • ServiceAccount-Permissions bewertet.

  • Token-Mounting und Default-ServiceAccounts geprüft.

  • Pod Security Admission, Namespace-Labels und Plattform-Policies geprüft.

  • Privilegierte Workloads und Host-Zugriffe kontextualisiert.

  • NetworkPolicy Coverage und Default-Deny-Fähigkeit geprüft.

  • Secret-Zugriff und Secret-Verwendung ohne Werte-Dump überprüft.

  • Images gescannt und Ergebnisse kontextualisiert.

  • CIS/kube-bench Baseline geprüft und Grenzen dokumentiert.

  • Findings priorisiert, Remediation geplant und Änderungen verifiziert.

Audit vs. Penetrationstest

Ein Kubernetes Security Audit ist kein Penetrationstest. Er bewertet Konfiguration, Berechtigungen, Workload-Härtung, Netzwerkflüsse, Secrets, Images und Baselines defensiv. Ein Penetrationstest prüft unter vereinbartem Scope, ob Schwachstellen praktisch ausnutzbar sind. Für die Auswahl zwischen Security Assessment, Vulnerability Scan und Penetrationstest hilft der Decision Guide.

Decision Guide zu Security Assessment, Vulnerability Scan und Penetrationstest Penetrationstest

Professionelle Unterstützung

Kubernetes-Sicherheitsniveau professionell prüfen

Wenn Sie Ihren Cluster nicht nur selbst prüfen, sondern ein strukturiertes Security Assessment, Hardening oder eine unabhängige Validierung benötigen, unterstützt ForgeOne bei Analyse, Priorisierung, Remediation und Verification.