Veröffentlicht am

Service Accounts absichern: Token und RBAC

Teilen:
Authors

Service Accounts absichern: Token-Sicherheit und RBAC in Kubernetes

TL;DR - Kurzfassung

Jeder Kubernetes-Namespace hat einen default Service Account, der automatisch in jeden Pod gemountet wird -- mit einem nie ablaufenden Token. Das ist ein Sicherheitsrisiko. Deaktivieren Sie automountServiceAccountToken, erstellen Sie dedizierte Service Accounts pro Workload mit minimalen RBAC-Rechten, und nutzen Sie Bound Service Account Tokens oder Workload Identity für Cloud-Integrationen.


Service Accounts sind die Identität von Workloads in Kubernetes. Jeder Pod bekommt automatisch einen Service Account zugewiesen, und mit diesem Account erhält er ein Token für die Kubernetes-API. Das Problem: In der Standardkonfiguration ist dieses Token unbegrenzt gültig und hat oft mehr Rechte als nötig.

# Prüfen, welches Token in einem Pod gemountet ist
kubectl exec -it my-pod -- cat /var/run/secrets/kubernetes.io/serviceaccount/token
# Dieses Token kann für API-Zugriffe missbraucht werden

# Alle Service Accounts mit ihren Secrets auflisten
kubectl get serviceaccounts --all-namespaces -o wide

Warum der Default Service Account ein Risiko ist

Der default Service Account existiert in jedem Namespace und wird automatisch jedem Pod zugewiesen, der keinen eigenen SA definiert. Das führt zu drei konkreten Problemen:

Automatisches Token-Mount: Jeder Pod erhält unter /var/run/secrets/kubernetes.io/serviceaccount/ ein API-Token. Bei einem Container-Ausbruch hat der Angreifer sofort Zugriff auf die Kubernetes-API.

Geteilte Identität: Alle Pods ohne expliziten SA teilen dieselbe Identität. RBAC-Regeln können nicht zwischen verschiedenen Workloads unterscheiden.

Legacy-Tokens ohne Ablaufdatum: Vor Kubernetes 1.24 waren SA-Tokens als Secrets gespeichert und liefen nie ab. In vielen Clustern existieren diese Tokens noch.

Schritt 1: Auto-Mount deaktivieren

Die wichtigste Maßnahme: Verhindern Sie, dass Service Account Tokens automatisch in Pods gemountet werden.

# Option A: Auto-Mount auf Service-Account-Ebene deaktivieren
apiVersion: v1
kind: ServiceAccount
metadata:
  name: default
  namespace: production
automountServiceAccountToken: false
---
# Option B: Auto-Mount auf Pod-Ebene deaktivieren (überschreibt SA-Einstellung)
apiVersion: v1
kind: Pod
metadata:
  name: webapp
  namespace: production
spec:
  automountServiceAccountToken: false
  containers:
    - name: webapp
      image: registry.example.com/webapp:v2.1.0

Deaktivieren Sie das Auto-Mount auf dem default Service Account in jedem Namespace:

# Default SA in allen Namespaces absichern
for ns in $(kubectl get namespaces -o jsonpath='{.items[*].metadata.name}'); do
  kubectl patch serviceaccount default -n "$ns" \
    -p '{"automountServiceAccountToken": false}'
done

Schritt 2: Dedizierte Service Accounts erstellen

Jeder Workload braucht einen eigenen Service Account mit minimalen Rechten. Das ermöglicht granulare RBAC-Kontrolle und klare Zuordnung.

# Dedizierter SA für eine Backend-Anwendung
apiVersion: v1
kind: ServiceAccount
metadata:
  name: backend-api
  namespace: production
  labels:
    app: backend-api
    team: platform
automountServiceAccountToken: false
---
# Minimale RBAC-Rolle: Nur ConfigMaps lesen
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: backend-api-role
  namespace: production
rules:
  - apiGroups: ['']
    resources: ['configmaps']
    verbs: ['get', 'list', 'watch']
    resourceNames: ['backend-config', 'feature-flags']
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: backend-api-binding
  namespace: production
subjects:
  - kind: ServiceAccount
    name: backend-api
    namespace: production
roleRef:
  kind: Role
  name: backend-api-role
  apiGroup: rbac.authorization.k8s.io
---
# Deployment mit dediziertem SA
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend-api
  namespace: production
spec:
  replicas: 3
  selector:
    matchLabels:
      app: backend-api
  template:
    metadata:
      labels:
        app: backend-api
    spec:
      serviceAccountName: backend-api
      automountServiceAccountToken: true  # Gezielt aktivieren, weil die App API-Zugriff braucht
      containers:
        - name: backend-api
          image: registry.example.com/backend:v3.0.1
          securityContext:
            runAsNonRoot: true
            allowPrivilegeEscalation: false
            capabilities:
              drop: ['ALL']

Beachten Sie: automountServiceAccountToken: true wird hier bewusst gesetzt, weil die Anwendung API-Zugriff benötigt. Die RBAC-Rolle beschränkt diesen Zugriff auf das absolute Minimum.

Schritt 3: Bound Service Account Tokens nutzen

Seit Kubernetes 1.22 unterstützt der API-Server Bound Service Account Tokens. Diese haben drei entscheidende Vorteile gegenüber Legacy-Tokens:

  • Zeitlich begrenzt: Tokens laufen nach einer konfigurierbaren Dauer ab (Standard: 1 Stunde)
  • An einen Pod gebunden: Das Token wird ungültig, wenn der Pod gelöscht wird
  • Audience-beschränkt: Das Token ist nur für einen bestimmten Empfänger gültig
# Token-Projektion mit begrenzter Gültigkeit
apiVersion: v1
kind: Pod
metadata:
  name: secure-app
  namespace: production
spec:
  serviceAccountName: backend-api
  automountServiceAccountToken: false  # Standard-Mount deaktivieren
  containers:
    - name: app
      image: registry.example.com/app:v1.0.0
      volumeMounts:
        - name: sa-token
          mountPath: /var/run/secrets/tokens
          readOnly: true
  volumes:
    - name: sa-token
      projected:
        sources:
          - serviceAccountToken:
              path: api-token
              expirationSeconds: 3600  # Token läuft nach 1 Stunde ab
              audience: api.internal    # Nur für diesen Empfänger gültig

Das kubelet erneuert das Token automatisch, bevor es abläuft. Die Anwendung muss das Token bei jedem API-Aufruf erneut von der Datei lesen, anstatt es beim Start einmalig im Speicher zu halten.

Schritt 4: Workload Identity in der Cloud

In Cloud-Umgebungen ersetzt Workload Identity die manuelle Verwaltung von Cloud-Credentials in Kubernetes-Secrets. Der Pod authentifiziert sich über seinen Service Account direkt beim Cloud-Provider.

CloudFeatureMechanismus
GKEWorkload IdentitySA wird mit Google SA verknüpft
EKSIAM Roles for Service AccountsOIDC-basierte Federation
AKSWorkload Identity (Azure AD)Federated Credentials

Beispiel: AWS EKS mit IAM Roles for Service Accounts

# Service Account mit IAM-Role-Annotation
apiVersion: v1
kind: ServiceAccount
metadata:
  name: s3-reader
  namespace: data-pipeline
  annotations:
    # Diese Annotation verknüpft den K8s-SA mit einer AWS IAM-Rolle
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/s3-read-only
automountServiceAccountToken: false
---
apiVersion: v1
kind: Pod
metadata:
  name: data-processor
  namespace: data-pipeline
spec:
  serviceAccountName: s3-reader
  containers:
    - name: processor
      image: registry.example.com/processor:v2.0.0
      # AWS SDK erkennt die projected Credentials automatisch
      # Kein AWS_ACCESS_KEY_ID oder AWS_SECRET_ACCESS_KEY nötig

Der Vorteil: Es gibt keine statischen Cloud-Credentials mehr im Cluster. Die temporären Tokens werden vom Cloud-Provider ausgestellt und automatisch rotiert.

Service Accounts auditieren

Prüfen Sie regelmäßig, welche Service Accounts existieren und welche Rechte sie haben:

# Alle SAs mit Auto-Mount-Status auflisten
kubectl get serviceaccounts --all-namespaces \
  -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.automountServiceAccountToken}{"\n"}{end}'

# Rechte eines spezifischen SA prüfen
kubectl auth can-i --list \
  --as=system:serviceaccount:production:backend-api

# Ungenutzte SAs finden (keine Pods referenzieren sie)
kubectl get pods --all-namespaces \
  -o jsonpath='{range .items[*]}{.spec.serviceAccountName}{"\n"}{end}' | \
  sort -u > /tmp/used-sas.txt

FAQ

Kann ich den Default Service Account einfach löschen?

Nein. Kubernetes erstellt den default Service Account automatisch in jedem Namespace neu. Stattdessen sollten Sie automountServiceAccountToken: false auf dem Default SA setzen. So existiert er zwar weiterhin, wird aber nicht mehr automatisch in Pods gemountet.

Was passiert mit laufenden Pods, wenn ich Auto-Mount deaktiviere?

Laufende Pods sind nicht betroffen. Die Änderung wirkt sich nur auf neue Pods aus. Bestehende Pods behalten ihr gemountetes Token bis zum nächsten Neustart.

Wie erkenne ich Legacy-Tokens in meinem Cluster?

Legacy-Tokens sind als Secrets vom Typ kubernetes.io/service-account-token gespeichert. Mit kubectl get secrets --all-namespaces --field-selector type=kubernetes.io/service-account-token finden Sie alle. In Clustern ab Version 1.24 werden diese nicht mehr automatisch erstellt.

Braucht jeder Pod einen eigenen Service Account?

Nicht zwingend jeder Pod, aber jeder Workload-Typ sollte einen eigenen SA haben. Pods, die dieselbe Anwendung in verschiedenen Replicas ausführen, können denselben SA teilen. Unterschiedliche Anwendungen sollten getrennte SAs mit spezifischen RBAC-Regeln bekommen.

Funktioniert Workload Identity auch On-Premises?

Workload Identity ist ein Cloud-spezifisches Feature. On-Premises können Sie eine ähnliche Architektur mit SPIFFE/SPIRE aufbauen, das Pod-Identitäten über X.509-Zertifikate bereitstellt und mit externen Systemen wie HashiCorp Vault integriert werden kann.


Kubernetes-Security & Compliance?

Security-Audits, Penetration Tests und Compliance-Beratung für Ihre Container-Infrastruktur. BSI-Grundschutz, DSGVO, ISO 27001.

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