RBAC und ServiceAccounts
Autorisierung in Kubernetes.
Lernziele
Nach dieser Lektion kannst du das RBAC-Modell von Kubernetes erklären: Roles und ClusterRoles definieren Rechte, RoleBindings und ClusterRoleBindings weisen sie Subjects zu, und ServiceAccounts geben Pods eine Identität. Du kennst die vier Kombinationsmöglichkeiten von Role/Binding und ihre Wirkung, kannst Berechtigungen mit kubectl auth can-i prüfen und weißt, wie Least Privilege in der Praxis aussieht — inklusive der Eskalationspfade, auf die Interviewer gerne hinauswollen.
Das Problem: Authentifizierung ist nicht Autorisierung
Jeder Request an den API-Server durchläuft drei Stationen: Authentifizierung (wer bist du?), Autorisierung (darfst du das?), Admission (ist zulässig, was du anlegst?). RBAC ist Station zwei. Ohne sie gäbe es nur alles oder nichts — und „alles” heißt in Kubernetes: Secrets aller Teams lesen, fremde Workloads löschen, den Cluster übernehmen. In Multi-Team-Clustern ist Rechtetrennung keine Compliance-Kür, sondern die Grundlage dafür, dass weder Teams noch ein kompromittierter Pod den ganzen Cluster gefährden.
Role-Based Access Control beantwortet die Autorisierungsfrage über Rollen: Rechte werden nicht einzelnen Nutzern direkt gegeben, sondern in wiederverwendbaren Rollen gebündelt und dann zugewiesen. Wichtig für das Modell im Kopf: RBAC ist rein additiv. Es gibt keine Deny-Regeln — alles ist verboten, bis eine Rolle es erlaubt. Die Frage „Wie entziehe ich mit RBAC ein Recht?” beantwortet sich daher mit: gar nicht — du entfernst die Erlaubnis.
Die vier Objekte und ihre Kombinatorik
Eine Role ist eine Liste von Regeln, jeweils aus drei Zutaten: API-Groups (z. B. "" für Core, apps), Resources (pods, deployments, secrets) und Verbs (get, list, watch, create, update, patch, delete). Eine Role ist namespaced — sie kann nur Rechte innerhalb ihres Namespace beschreiben. Die ClusterRole ist das clusterweite Gegenstück; sie kann zusätzlich Dinge, die eine Role nicht kann: Rechte auf nicht-namespaced Ressourcen (Nodes, Namespaces, PersistentVolumes) und auf Non-Resource-URLs.
Zugewiesen wird per Binding: Ein RoleBinding verbindet Subjects (User, Group oder ServiceAccount) mit einer Rolle — wirksam im Namespace des Bindings. Ein ClusterRoleBinding tut dasselbe clusterweit.
Die Kombinatorik ist der Teil, den Interviews abklopfen: Role + RoleBinding = Rechte in einem Namespace (Standardfall). ClusterRole + ClusterRoleBinding = Rechte überall (Admin-Fall). Die unterschätzte dritte Kombination: ClusterRole + RoleBinding — die ClusterRole dient als wiederverwendbare Vorlage, das RoleBinding schränkt sie auf seinen Namespace ein. So definierst du „Developer-Rechte” einmal als ClusterRole und bindest sie pro Team-Namespace, statt dieselbe Role zwanzigmal zu kopieren. Kubernetes liefert dafür fertige ClusterRoles mit: view, edit, admin (alle drei für Namespace-Scope gedacht) und cluster-admin. Die vierte Kombination — Role + ClusterRoleBinding — ist ungültig.
Authentifizierung von Menschen ist übrigens bewusst ausgelagert: Kubernetes hat kein User-Objekt. User und Groups sind Strings, die der Authentifizierungsschicht entstammen (OIDC-Claims, Zertifikats-CN). In der Praxis bindest du Rollen an Gruppen aus deinem Identity Provider — nicht an einzelne Personen.
ServiceAccounts: Identität für Pods
Auch Workloads brauchen Identität: Ein CI-Runner deployt, ein Operator verwaltet CRDs, Prometheus liest über die API. Dafür gibt es ServiceAccounts — namespaced Identitätsobjekte für Maschinen. Jeder Pod läuft unter einem ServiceAccount (ohne Angabe: default seines Namespace), und das kubelet mountet ihm ein Token unter /var/run/secrets/kubernetes.io/serviceaccount/, mit dem Prozesse im Pod gegen den API-Server authentifizieren. Diese Tokens sind heute kurzlebig und automatisch rotiert — die früheren unbegrenzt gültigen Secret-Tokens sind Geschichte.
Daraus folgen zwei Betriebsregeln. Erstens: Der default-ServiceAccount sollte keinerlei Rechte gebunden bekommen — sonst erbt jeder Pod im Namespace sie stillschweigend. Pro Anwendung mit API-Bedarf ein eigener ServiceAccount mit eigener, minimaler Rolle. Zweitens: Pods, die die API gar nicht brauchen (die meisten!), sollten automountServiceAccountToken: false setzen — ein Token, das nicht im Container liegt, kann ein Angreifer nach einem Container-Breakout auch nicht stehlen. Genau dieses Szenario — kompromittierter Pod nutzt sein ServiceAccount-Token — ist der Grund, warum RBAC für Workloads genauso ernst zu nehmen ist wie für Menschen.
Least Privilege im Alltag: prüfen, schneiden, auditieren
Principle of Least Privilege heißt konkret: Verbs einzeln aufzählen statt *, Ressourcen benennen statt *, und bei sensiblen Ressourcen noch enger schneiden — eine Rolle mit get auf secrets im ganzen Namespace liest alle Secrets dort; mit resourceNames lässt sich das auf einzelne Objekte begrenzen (mit der Einschränkung, dass list sich so nicht sinnvoll begrenzen lässt).
Drei Eskalationspfade machen harmlose Rollen gefährlich: Wer Pods erstellen darf, kann einen Pod mit einem fremden, mächtigeren ServiceAccount starten und dessen Token nutzen. Wer pods/exec darf, kommt in laufende Container — inklusive deren Tokens. Und wer Roles/Bindings schreiben darf, kann sich theoretisch selbst befördern; RBAC verhindert immerhin, Rechte zu vergeben, die man selbst nicht hat. Solche Folgewirkungen zu nennen hebt eine Interview-Antwort über das Aufsagen der vier Objekte.
Zum Prüfen gibt es eingebautes Tooling: kubectl auth can-i beantwortet „darf ich/darf X das?” direkt aus der Autorisierungslogik — auch stellvertretend per --as für User und ServiceAccounts. Was tatsächlich passiert, zeichnet das Audit-Log des API-Servers auf (wer hat wann was an welcher Ressource getan) — die Grundlage für Reviews und Forensik; in Managed Clustern aktivierst du es über den Provider.
Praxis
Ein ServiceAccount mit minimaler Leserolle — anlegen, testen, Grenze erleben:
kind create cluster
kubectl create namespace team-a
kubectl create serviceaccount reader -n team-a
kubectl create role pod-reader -n team-a \
--verb=get,list,watch --resource=pods
kubectl create rolebinding reader-binding -n team-a \
--role=pod-reader --serviceaccount=team-a:reader
# Rechte stellvertretend prüfen — ohne einen einzigen Pod zu starten
kubectl auth can-i list pods -n team-a \
--as=system:serviceaccount:team-a:reader # yes
kubectl auth can-i delete pods -n team-a \
--as=system:serviceaccount:team-a:reader # no
kubectl auth can-i list pods -n default \
--as=system:serviceaccount:team-a:reader # no — Binding ist namespaced
# Aus einem Pod heraus verifizieren
kubectl run rbac-test -n team-a --serviceaccount=reader \
--image=bitnami/kubectl:latest --restart=Never -- \
kubectl get pods -n team-a
kubectl logs rbac-test -n team-a # listet Pods
kubectl run rbac-test2 -n team-a --serviceaccount=reader \
--image=bitnami/kubectl:latest --restart=Never -- \
kubectl get secrets -n team-a
kubectl logs rbac-test2 -n team-a # "Forbidden" — Rolle greift
Die Forbidden-Meldung im letzten Schritt lohnt das genaue Lesen: Sie nennt User (system:serviceaccount:team-a:reader), Verb und Ressource — exakt die drei Dinge, die du bei jedem RBAC-Problem zuerst brauchst.
Typische Stolperfallen
Binding zeigt auf eine Rolle — und friert sie ein: Ein RoleBinding lässt sich nachträglich nicht auf eine andere Rolle umbiegen (roleRef ist immutable); es muss neu erstellt werden. Wer das nicht weiß, wundert sich über Apply-Fehler.
ServiceAccount-Subject falsch geschrieben: In Bindings heißt es system:serviceaccount:<namespace>:<name> (bei --as) bzw. Kind ServiceAccount mit Namespace im Subject. Ein vergessener Namespace ist die häufigste Ursache für „Binding existiert, wirkt aber nicht”.
Rechte an den default-ServiceAccount gebunden: Bequem im Tutorial, fatal im Betrieb — jeder zukünftige Pod im Namespace erbt die Rechte mit. Immer dedizierte ServiceAccounts pro Anwendung.
get auf Secrets als „nur lesen” verharmlost: Secrets lesen heißt Credentials besitzen. Eine Leserolle über alle Secrets eines Namespace ist sicherheitstechnisch nah an Vollzugriff auf alles, was diese Credentials schützen.
Interview-Vorbereitung
Auf „Erkläre RBAC in Kubernetes” antwortest du entlang des Modells: Einordnung (Autorisierungsschicht des API-Servers, additiv, keine Denies) → Objekte (Role/ClusterRole = Regeln aus API-Group + Resource + Verb; RoleBinding/ClusterRoleBinding = Zuweisung an User, Groups, ServiceAccounts) → Kombinatorik (namespaced, clusterweit — und ClusterRole als Vorlage via RoleBinding) → Workload-Identität (ServiceAccounts, Token-Mount, default-SA meiden) → Betrieb (Least Privilege, auth can-i, Audit-Log).
Typische Follow-ups:
- „Wann ClusterRole statt Role?” — Nicht-namespaced Ressourcen, clusterweite Rechte — oder als wiederverwendbare Vorlage, die per RoleBinding pro Namespace gebunden wird.
- „Wie bekommt ein Pod API-Zugriff?” — Über seinen ServiceAccount: Token wird in den Pod gemountet, Rechte kommen aus den Bindings des ServiceAccounts.
- „Wie debuggst du einen Forbidden-Fehler?” — Fehlermeldung liefert Subject, Verb, Ressource; dann
kubectl auth can-i --as=...reproduzieren und Bindings/Rollen im betroffenen Namespace prüfen. - „Kann man mit RBAC etwas explizit verbieten?” — Nein, RBAC ist allow-only; Verbote entstehen durch Weglassen. Für echte Verbots-Policies braucht es Admission Control (z. B. ValidatingAdmissionPolicy, OPA/Kyverno).
Zusammenfassung
RBAC ist die additive Autorisierungsschicht des API-Servers: Roles und ClusterRoles bündeln Rechte aus API-Group, Resource und Verb; Bindings weisen sie User-Strings, Gruppen und ServiceAccounts zu — namespaced oder clusterweit, mit der ClusterRole-als-Vorlage-Variante für Multi-Team-Setups. ServiceAccounts geben Pods Identität, weshalb Least Privilege dort genauso gilt wie bei Menschen: dedizierte Accounts, minimale Verbs, Token-Automount aus, auth can-i zum Prüfen und das Audit-Log für die Rückschau.
Mit Networking, Storage, Scheduling und Security hast du jetzt alle Einzelteile — die nächste Lektion fügt sie zur Troubleshooting-Methodik zusammen: ein systematischer Diagnosepfad von describe über Logs bis kubectl debug.