Veröffentlicht am

Kubernetes RBAC Audit: überberechtigte Rollen finden & Least-Privilege durchsetzen

Teilen:
Authors

Kubernetes RBAC Audit: überberechtigte Rollen finden und Least-Privilege durchsetzen

TL;DR

Ein RBAC-Audit beantwortet eine einzige Frage: Wer darf in Ihrem Cluster was — und wer dürfte es nicht? In fünf Schritten kommen Sie zur Antwort:

  1. Inventar: Alle ClusterRoleBindings und RoleBindings exportieren, verwaiste Bindings identifizieren.
  2. cluster-admin-Jagd: Skript unten listet jedes Subject mit cluster-admin und jede Rolle mit Wildcard-Verbs.
  3. Reverse-Lookup: Mit rbac-lookup und kubectl-who-can prüfen, wer kritische Aktionen ausführen darf (Secrets lesen, Pods in kube-system erstellen, Bindings ändern).
  4. ServiceAccount-Analyse: kubectl auth can-i --list --as=system:serviceaccount:... für jeden SA, der in Deployments hängt. kubeaudit findet automatisch gemountete Tokens.
  5. Remediation: Bindings auf Namespace-Rollen einschränken, Wildcards durch explizite verbs/resources ersetzen, Ergebnis erneut messen.

Welches Tool welche Lücke findet: rbac-lookup zeigt die Berechtigungslandkarte pro Subject, kubectl-who-can beantwortet die umgekehrte Frage pro Aktion, kubeaudit findet Token-Mounts und Container-Kontext-Probleme, und das jq-Skript unten fängt das, was alle Dashboards übersehen: Wildcard-Verbs in selbstgebauten Rollen.

Das Problem: niemand weiß mehr, wer im Cluster was darf

RBAC-Konfigurationen degenerieren. Nicht durch böse Absicht, sondern durch Alltag: Ein Entwickler bekommt 2023 für ein Debugging-Ticket cluster-admin "nur kurz". Ein Helm-Chart installiert sich 2024 eine ClusterRole mit verbs: ["*"], weil der Chart-Autor es sich einfach gemacht hat. Ein CI-ServiceAccount erhält Rechte auf secrets clusterweit, obwohl er nur in einem Namespace deployen muss. Drei Jahre später betreibt ein 40-Personen-SaaS-Unternehmen einen Cluster mit 120 Bindings, und niemand kann sagen, welche davon noch gebraucht werden.

Das ist kein theoretisches Risiko. Ein kompromittierter Pod mit einem überberechtigten ServiceAccount-Token ist der Standard-Eskalationspfad bei Kubernetes-Angriffen: Vom Container-Breakout zur Token-Exfiltration zu cluster-admin sind es oft nur zwei Schritte. Wer ein ISO-27001- oder TISAX-Audit vor sich hat oder unter NIS2 fällt, braucht den Nachweis eines funktionierenden Berechtigungsmanagements ohnehin — "wir haben RBAC aktiviert" reicht dem Auditor nicht.

Die gute Nachricht: Ein vollständiges RBAC-Audit für einen Cluster mittlerer Größe (5–20 Namespaces, 50–150 Bindings) ist mit den richtigen Tools ein Tagesprojekt, kein Wochenprojekt. Als Schätzung aus der Praxis: 2–4 Stunden Datensammlung und Analyse, der Rest ist Remediation und dokumentieren.

Grundlagen: was ein RBAC-Audit prüft

Kubernetes-RBAC besteht aus vier Objekttypen: Role und ClusterRole definieren Berechtigungen (Regeln aus apiGroups, resources, verbs), RoleBinding und ClusterRoleBinding verknüpfen sie mit Subjects (User, Group, ServiceAccount). Ein Audit prüft drei Ebenen:

1. Bindings und ihre Reichweite. Ein ClusterRoleBinding gilt clusterweit — auch wenn die referenzierte Rolle harmlos aussieht. Ein RoleBinding kann eine ClusterRole referenzieren und schränkt sie dann auf den Namespace ein; das ist das korrekte Muster für wiederverwendbare Rollen. Häufigster Befund: ClusterRoleBindings, wo ein RoleBinding gereicht hätte.

2. ServiceAccount-Tokens. Jeder Pod bekommt per Default das Token seines ServiceAccounts unter /var/run/secrets/kubernetes.io/serviceaccount/token gemountet — auch wenn die Anwendung nie mit der API spricht. Ein Angreifer im Container liest das Token und agiert mit allen Rechten des SA. Das Audit prüft: Welche SAs haben überhaupt Bindings, und welche Pods mounten Tokens ohne Notwendigkeit?

3. Escalation-Pfade. Bestimmte Berechtigungen sind implizit äquivalent zu cluster-admin: create auf pods in kube-system (Pod mit hostPath auf Node-Root), create/update auf clusterrolebindings, das escalate- und bind-Verb auf Rollen, create auf pods/exec in fremden Namespaces, get auf secrets clusterweit (dort liegen SA-Tokens älterer Bauart). Wer diese Verbs vergibt, vergibt faktisch Root im Cluster.

Wenn Ihnen die RBAC-Objektlogik noch nicht vertraut ist, lesen Sie zuerst unsere Kubernetes RBAC Best Practices — dieser Artikel setzt die Grundlagen voraus.

Praxis: der Audit-Workflow mit rbac-lookup, kubectl auth can-i und kubeaudit

Schritt 1: Inventar exportieren

Bevor Sie Tools anwerfen, sichern Sie den Ist-Zustand als Datei. Das ist gleichzeitig Ihr Audit-Beweisstück:

kubectl get clusterroles,clusterrolebindings -o yaml > rbac-cluster-scope-$(date +%F).yaml
kubectl get roles,rolebindings -A -o yaml > rbac-namespaced-$(date +%F).yaml

Einen ersten Überblick über die Dimensionen liefert:

kubectl get clusterrolebindings --no-headers | wc -l
kubectl get rolebindings -A --no-headers | wc -l

Schritt 2: cluster-admin und Wildcards finden (das Skript)

Das folgende Skript listet jedes Subject, das über ein ClusterRoleBinding an cluster-admin hängt, und jede selbstgebaute ClusterRole mit Wildcard-Verbs oder Wildcard-Resources. Es braucht nur kubectl und jq:

#!/usr/bin/env bash
set -euo pipefail

echo "=== ClusterRoleBindings auf cluster-admin ==="
kubectl get clusterrolebindings -o json | jq -r '
  .items[]
  | select(.roleRef.name == "cluster-admin")
  | .metadata.name as $binding
  | (.subjects // [])[]
  | [$binding, .kind, (.namespace // "-"), .name]
  | @tsv' | column -t

echo ""
echo "=== ClusterRoles mit Wildcard-verbs oder Wildcard-resources (ohne system:) ==="
kubectl get clusterroles -o json | jq -r '
  .items[]
  | select(.metadata.name | startswith("system:") | not)
  | select(
      [ .rules[]?
        | select(((.verbs // []) | index("*")) or ((.resources // []) | index("*")))
      ] | length > 0
    )
  | .metadata.name'

echo ""
echo "=== Bindings, die auf diese Wildcard-Rollen zeigen ==="
WILDCARD_ROLES=$(kubectl get clusterroles -o json | jq -r '
  .items[]
  | select(.metadata.name | startswith("system:") | not)
  | select([.rules[]? | select(((.verbs // []) | index("*")) or ((.resources // []) | index("*")))] | length > 0)
  | .metadata.name')

for role in $WILDCARD_ROLES; do
  kubectl get clusterrolebindings -o json | jq -r --arg r "$role" '
    .items[]
    | select(.roleRef.name == $r)
    | .metadata.name as $binding
    | (.subjects // [])[]
    | [$r, $binding, .kind, (.namespace // "-"), .name]
    | @tsv'
done | column -t

Beispiel-Output aus einem realen Audit-Szenario (Namen anonymisiert):

=== ClusterRoleBindings auf cluster-admin ===
cluster-admin                     Group           -            system:masters
legacy-admin-binding              User            -            j.mueller@example.de
cicd-deployer-admin               ServiceAccount  ci           gitlab-runner
helm-tiller-leftover              ServiceAccount  kube-system  tiller

=== ClusterRoles mit Wildcard-verbs oder Wildcard-resources (ohne system:) ===
cluster-admin
internal-tools-operator
monitoring-full-access

=== Bindings, die auf diese Wildcard-Rollen zeigen ===
internal-tools-operator  tools-operator-binding  ServiceAccount  tools    operator-sa
monitoring-full-access   prometheus-binding      ServiceAccount  monitor  prometheus

Jede Zeile hier ist ein Finding. system:masters ist erwartbar (das ist der eingebaute Break-Glass-Zugang), aber ein GitLab-Runner mit cluster-admin und ein Tiller-Rest aus Helm-2-Zeiten sind klassische Altlasten mit maximalem Schadenspotenzial.

Schritt 3: Reverse-Lookup mit rbac-lookup und kubectl-who-can

rbac-lookup von Fairwinds beantwortet die Frage "welche Rechte hat Subject X?" über alle Bindings hinweg:

kubectl krew install rbac-lookup
kubectl rbac-lookup --kind serviceaccount --output wide
kubectl rbac-lookup gitlab-runner --output wide

Das Aqua-Security-Plugin kubectl-who-can dreht die Frage um: "Wer darf Aktion Y ausführen?" Es wird von Aqua nur noch minimal gepflegt, ist aber weiterhin über krew als who-can installierbar und funktioniert unverändert. Genau diese Perspektive braucht das Audit für die Escalation-Pfade:

kubectl krew install who-can
kubectl who-can get secrets --all-namespaces
kubectl who-can create pods -n kube-system
kubectl who-can create clusterrolebindings
kubectl who-can create pods/exec -n production

Alles, was in diesen vier Abfragen auftaucht und kein Cluster-Operator ist, gehört auf die Remediation-Liste.

Schritt 4: effektive Rechte pro ServiceAccount prüfen

Für jeden SA, der in einem Deployment referenziert wird, zeigt kubectl auth can-i --list die effektiven Rechte aus Sicht der API:

# Welche SAs sind ueberhaupt in Workloads im Einsatz?
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.spec.serviceAccountName}{"\n"}{end}' | sort -u

# Effektive Rechte eines konkreten SA
kubectl auth can-i --list --as=system:serviceaccount:ci:gitlab-runner

Ein gesunder Workload-SA zeigt hier fast nichts außer den SelfSubjectReview-APIs. Wenn stattdessen secrets [get list watch] oder *.* [*] erscheint, haben Sie Ihr Finding. Falls Sie bei solchen Tests auf Error from server (Forbidden) stoßen und die Ursache nicht offensichtlich ist: Unser Artikel zum Debuggen von Forbidden-Fehlern in RBAC zeigt, wie Sie die Auswertungskette der API nachvollziehen.

Schritt 5: kubeaudit für Token-Mounts und Kontext

kubeaudit prüft Workload-Manifeste gegen Security-Best-Practices, darunter automatisch gemountete SA-Tokens:

kubeaudit sat -n production          # automountServiceAccountToken-Findings
kubeaudit all -n production          # kompletter Check inkl. Capabilities, rootfs, Privileged

Typischer Befund: 80–90 Prozent der Workloads brauchen kein API-Token, mounten es aber. Die Behebung ist eine Zeile im Pod-Spec oder am ServiceAccount:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: webapp-sa
  namespace: production
automountServiceAccountToken: false

Ergänzend lohnt sich kube-bench für die CIS-Benchmark-Sicht auf die API-Server-Konfiguration (Stichwort --authorization-mode=Node,RBAC). kube-hunter, lange die Standard-Empfehlung für die Angreifer-Perspektive von außen, wird von Aqua nicht mehr aktiv weiterentwickelt — Aqua verweist als Nachfolger auf trivy k8s. Beides gehört eher in ein vollständiges Kubernetes Security Audit als in den reinen RBAC-Teil.

Überberechtigte Bindings beheben: Least-Privilege Schritt für Schritt

Remediation nach Hebel sortiert, nicht nach Aufwand:

1. cluster-admin-Bindings eliminieren. Für jedes Finding aus Schritt 2 die Frage stellen: Was macht dieses Subject wirklich? Der GitLab-Runner aus dem Beispiel deployt in zwei Namespaces — er bekommt zwei RoleBindings auf eine dedizierte Deploy-Rolle statt cluster-admin:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: ci-deployer
rules:
  - apiGroups: ['apps']
    resources: ['deployments', 'replicasets']
    verbs: ['get', 'list', 'watch', 'create', 'update', 'patch']
  - apiGroups: ['']
    resources: ['services', 'configmaps']
    verbs: ['get', 'list', 'create', 'update', 'patch']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ci-deployer
  namespace: production
subjects:
  - kind: ServiceAccount
    name: gitlab-runner
    namespace: ci
roleRef:
  kind: ClusterRole
  name: ci-deployer
  apiGroup: rbac.authorization.k8s.io

Beachten Sie das Muster: eine ClusterRole (wiederverwendbar), gebunden per RoleBinding (namespace-beschränkt). Kein secrets in den resources — Secrets bezieht der Workload zur Laufzeit, nicht die CI-Pipeline.

2. Wildcards durch explizite Listen ersetzen. Öffnen Sie jede Wildcard-Rolle und ersetzen Sie verbs: ["*"] durch das, was tatsächlich genutzt wird. Wenn Sie unsicher sind: API-Server-Audit-Logs für 14 Tage mitschneiden und auswerten, welche Verbs das Subject real aufruft. Das ist der empirische Weg zu Least-Privilege statt Raten.

3. Verwaiste Bindings löschen. Bindings, deren Subject nicht mehr existiert (gelöschte SAs, ausgeschiedene Mitarbeiter-Identitäten), sind risikofrei löschbar. Wichtig zu wissen: Die RBAC-API dereferenziert Subjects nicht. Wird ein ServiceAccount gelöscht, bleibt sein Eintrag im Binding unverändert stehen — ein Query auf leere subjects-Listen findet diese Leichen deshalb nicht, sondern nur Bindings, die von vornherein ohne Subjects angelegt wurden. Verwaiste Bindings finden Sie nur per Cross-Check: referenzierte Subjects extrahieren und gegen die tatsächlich existierenden Objekte abgleichen. Für ServiceAccounts geht das vollständig im Cluster:

#!/usr/bin/env bash
set -euo pipefail

# 1. Alle existierenden ServiceAccounts als namespace/name
kubectl get sa -A -o jsonpath='{range .items[*]}{.metadata.namespace}/{.metadata.name}{"\n"}{end}' \
  | sort -u > sa-existing.txt

# 2. Alle ServiceAccount-Subjects aus allen Bindings als namespace/name + Binding
{
  kubectl get clusterrolebindings -o json | jq -r '
    .items[] | .metadata.name as $b
    | (.subjects // [])[]
    | select(.kind == "ServiceAccount")
    | "\(.namespace)/\(.name)\tClusterRoleBinding/\($b)"'
  kubectl get rolebindings -A -o json | jq -r '
    .items[] | .metadata.name as $b | .metadata.namespace as $ns
    | (.subjects // [])[]
    | select(.kind == "ServiceAccount")
    | "\(.namespace)/\(.name)\tRoleBinding/\($ns)/\($b)"'
} | sort -u > sa-referenced.txt

# 3. Referenziert, aber nicht existent = verwaistes Binding
while IFS=$'\t' read -r sa binding; do
  grep -qxF "$sa" sa-existing.txt || echo "VERWAIST: $binding -> $sa"
done < sa-referenced.txt

User- und Group-Subjects lassen sich so nicht prüfen — die existieren nur im Identity-Provider und müssen dort gegen die aktuelle Mitarbeiter- und Gruppenliste abgeglichen werden (siehe Fallstricke unten). Bindings mit komplett leerer subjects-Liste sind ebenfalls löschbar, aber ein Randfall: jq 'select((.subjects // []) | length == 0)' über die Binding-Items fängt nur diese Sonderform, nicht die eigentlichen Waisen.

4. Vorher testen, dann einschränken. Mit Impersonation prüfen Sie jede neue Rolle, bevor die alte fällt:

kubectl auth can-i create deployments -n production --as=system:serviceaccount:ci:gitlab-runner
kubectl auth can-i get secrets -n production --as=system:serviceaccount:ci:gitlab-runner   # muss "no" liefern

5. Neue Manifeste im Review absichern. Least-Privilege hält nur, wenn keine neuen Wildcards nachwachsen. Prüfen Sie RBAC-Manifeste vor dem Merge — unser YAML-Validator lintet Kubernetes-Manifeste unter anderem auf genau solche RBAC-Verstöße.

RBAC-Audit-Checkliste: 10 Punkte zum Abhaken

#PrüfpunktTool/Befehl
1Alle ClusterRoleBindings auf cluster-admin gelistet und begründetSkript oben
2Keine Wildcard-Verbs/-Resources in eigenen RollenSkript oben
3Kein Workload-SA mit Rechten auf secrets clusterweitkubectl who-can get secrets -A
4Niemand außer Operatoren darf clusterrolebindings erstellenkubectl who-can create clusterrolebindings
5Kein Fremdzugriff auf pods/exec in Produktions-Namespaceskubectl who-can create pods/exec -n production
6automountServiceAccountToken: false wo kein API-Zugriff nötigkubeaudit sat
7Kein Workload läuft unter dem default-SAPod-Inventar aus Schritt 4
8Verwaiste Bindings (Subjects ohne Existenz) entferntCross-Check-Skript oben
9Rechte-Landkarte pro Subject dokumentiert und exportiertkubectl rbac-lookup --output wide
10Audit-Export mit Datum archiviert (Compliance-Nachweis)YAML-Exporte aus Schritt 1

Fallstricke aus der Praxis

Der default-ServiceAccount als blinder Fleck. Deployments ohne explizites serviceAccountName laufen unter default. Wenn irgendjemand irgendwann dem default-SA eines Namespaces Rechte gegeben hat, erben alle diese Workloads sie stillschweigend. Der default-SA darf niemals Bindings haben.

Third-Party-Helm-Charts mit cluster-admin. Auffällig viele Charts — gerade Operatoren und Monitoring-Stacks — bringen ClusterRoles mit Wildcards mit. Vor jedem helm install lohnt der Blick: helm template <chart> | grep -A 20 'kind: ClusterRole'. Wenn ein Chart cluster-admin verlangt, ist das ein Grund für Nachfragen beim Maintainer oder ein eigenes, engeres Rollen-Set über Chart-Values.

Aggregierte ClusterRoles. Rollen mit aggregationRule (etwa die eingebauten admin, edit, view) sammeln Regeln aus gelabelten Rollen ein. Wer eine ClusterRole mit dem Label rbac.authorization.k8s.io/aggregate-to-admin: "true" deployt, erweitert unbemerkt die admin-Rolle in allen Namespaces. Das jq-Skript oben findet die Einzelrolle — die Wirkung sehen Sie nur über den Reverse-Lookup mit who-can.

Gruppen aus dem Identity-Provider. Bei OIDC- oder Cloud-IAM-Anbindung (AKS + Entra ID, EKS + IAM) binden Sie Gruppen, deren Mitgliedschaft außerhalb des Clusters gepflegt wird. Das RBAC-Audit im Cluster sieht nur den Gruppennamen — wer drin ist, muss parallel im IdP auditiert werden. Ein Binding auf eine Gruppe mit 200 Mitgliedern ist faktisch ein Binding auf 200 Personen.

Node-Zugriff schlägt RBAC. Wer SSH auf einen Node oder create auf Pods mit hostPath hat, umgeht RBAC vollständig über die Kubelet-Credentials. RBAC-Audit ohne Node-Hardening ist eine halbe Übung.

FAQ

Wie oft sollten wir ein RBAC-Audit durchführen? Vollaudit quartalsweise, bei Teams mit hoher Fluktuation oder vielen Chart-Installationen alle 6–8 Wochen. Wichtiger als die Frequenz ist die Drift-Erkennung dazwischen: Das Skript aus diesem Artikel läuft in unter einer Minute und eignet sich als wöchentlicher CronJob mit Alert bei neuen cluster-admin-Bindings.

Lässt sich das RBAC-Audit in CI/CD automatisieren? Ja, zweistufig. Präventiv: RBAC-Manifeste in der Pipeline gegen Policies prüfen (Conftest/OPA oder Kyverno im Audit-Mode; Regel: kein Wildcard-Verb, kein cluster-admin-roleRef außerhalb einer Allowlist). Detektiv: das Inventar-Skript als Scheduled-Job, Diff gegen den letzten Snapshot, Alert bei Abweichung. Trivia am Rande: Auch trivy k8s --scanners misconfig deckt einen Teil der RBAC-Checks mit ab, ersetzt aber den Reverse-Lookup nicht.

Reicht das Audit als Nachweis für ISO 27001 / NIS2? Als Baustein ja, alleinstehend nein. Auditoren wollen drei Dinge sehen: den dokumentierten Ist-Stand (Ihre YAML-Exporte mit Datum), einen definierten Vergabeprozess (wer genehmigt neue Bindings?) und den Nachweis regelmäßiger Überprüfung (wiederholte Audit-Reports). Die Checkliste oben deckt den technischen Teil ab; den Prozessteil müssen Sie organisatorisch ergänzen.

Wann lohnt sich ein externer Dienstleister für das RBAC-Audit? Für einen einzelnen Cluster reichen die Tools aus diesem Artikel — das ist bewusst ein Selbstmach-Leitfaden. Ein externer RBAC-Audit-Dienstleister lohnt sich in drei Situationen: wenn das Audit als unabhängiger Nachweis für ISO 27001, TISAX oder NIS2 dienen soll (Selbst-Audits gewichten Auditoren schwächer als eine externe Prüfung), wenn intern niemand die Kubernetes-Security-Erfahrung hat, Findings korrekt zu priorisieren und ohne Betriebsunterbrechung zu remediieren, oder bei Multi-Cluster-Umgebungen mit mehreren Teams, wo das Audit ohne dedizierte Kapazität schlicht liegen bleibt. Ob Sie überhaupt ein tiefes Audit brauchen, klärt vorab unser kostenloser Kubernetes Security Quick-Check in 10 Minuten.

Was ist der Unterschied zwischen rbac-lookup und kubectl auth can-i? rbac-lookup wertet die RBAC-Objekte statisch aus und zeigt die Landkarte aller Bindings pro Subject. kubectl auth can-i fragt die API selbst und liefert die effektive Entscheidung inklusive Webhook-Authorizern und Admission-Effekten. Für das Audit brauchen Sie beide: die Landkarte zum Finden, die API-Antwort zum Verifizieren.

Unsere Entwickler brauchen doch Zugriff zum Debuggen — bricht Least-Privilege nicht den Betrieb? Nein, wenn Sie gestuft vorgehen: view-Rolle als Default für alle, edit im jeweiligen Team-Namespace, pods/exec und port-forward über eine dedizierte Debug-Rolle, die nur in Nicht-Prod-Namespaces gebunden wird. Für Produktionszugriff im Incident-Fall: ein Break-Glass-Binding, das per Skript temporär erzeugt und nach vier Stunden automatisch gelöscht wird. Das ist in einem Nachmittag gebaut und beendet die Dauer-cluster-admin-Diskussion.

Fazit

Ein RBAC-Audit ist kein Hexenwerk: Inventar exportieren, cluster-admin- und Wildcard-Findings mit dem Skript einsammeln, Reverse-Lookups für die kritischen Verbs fahren, ServiceAccounts prüfen, dann nach Hebel remediieren. Die Tools — rbac-lookup, kubectl-who-can, kubeaudit, jq — sind frei verfügbar und in einer Stunde installiert. Der eigentliche Wert entsteht in der Wiederholung: Ein Audit-Snapshot pro Quartal plus automatisierte Drift-Erkennung verwandelt RBAC von einer Blackbox in einen belegbaren Compliance-Baustein.

Wenn Sie den Zustand Ihres Clusters nicht nur bei RBAC, sondern über alle Security-Ebenen hinweg wissen wollen — Netzwerk-Policies, Pod-Security, Secrets-Handling, Exposure —, machen Sie den kostenlosen Kubernetes Security Quick-Check: strukturierte Selbsteinschätzung in 10 Minuten, konkrete Findings statt Bauchgefühl.

Kubernetes-Beratung gesucht?

Wir helfen deutschen Unternehmen bei der Kubernetes-Implementierung, Migration und Optimierung. DSGVO-konform und praxiserprobt.

📖 Verwandte Artikel

Weitere interessante Beiträge zu ähnlichen Themen