Skip to content

Dieses Tool ist nicht mit The Linux Foundation, der Cloud Native Computing Foundation (CNCF) oder dem Kubernetes-Projekt verbunden und wird von diesen weder befürwortet noch gesponsert. Kubernetes und K8s sind eingetragene Marken von The Linux Foundation. EKS, GKE, AKS und andere Namen sind Marken ihrer jeweiligen Inhaber.

Kubernetes-Secrets und Diebstahl von Service-Account-Tokens

Secret-Diebstahl und gestohlene Service-Account-Tokens in Kubernetes-Audit-Logs erkennen: clusterweite Lists, Häufungen, TokenRequest, öffentliche IPs.

Veröffentlicht am 5 Min. Lesezeit

TL;DR. Credential-Diebstahl in Kubernetes hinterlässt zwei Arten von Spuren. Auf der Secret-Seite: ein list oder watch auf secrets ohne Namespace (jedes Secret des Clusters, samt Inhalt) oder eine Identität, die in kurzer Zeit viele verschiedene Secrets liest. Auf der Token-Seite: ein Service Account, der von einer öffentlichen IP oder mit kubectl/curl als User Agent genutzt wird, eine Häufung von kubectl auth can-i, 403-Häufungen und neue Tokens, ausgestellt über TokenRequest. Jedes gelesene Secret ist ein Zugangsdatum, das rotiert werden muss, und auf GKE werden Lesezugriffe nur protokolliert, wenn die Data-Access-Logs aktiv sind.

Secrets sind der Grund, warum sich die meisten Angreifer überhaupt mit einem Cluster befassen: Datenbankpasswörter, Cloud-Keys, Registry-Zugangsdaten, CI-Tokens, Signaturschlüssel. ATT&CK führt das unter T1552.007, Container API, die Token-Seite unter T1528, Steal Application Access Token.

Wie Secrets über die API abfließen

Die RBAC Good Practices von Kubernetes betonen einen Punkt, den viele Teams übersehen: list und watch auf Secrets geben deren Inhalt preis, genau wie get. Eine Rolle, die Secrets „nur auflistet“, liest sie alle.

RequestAudit-SpurBedeutung
kubectl get secrets -Alist auf secrets, ohne objectRef.namespaceJedes Secret des Clusters in einer Antwort
kubectl get secrets -n shoplist auf secrets, Namespace shopJedes Secret des Namespace
kubectl get secret db-creds -o yamlget auf secrets, mit NamenEin Secret
Einen Pod anlegen, der ein Secret mountetcreate auf pods mit Secret-VolumeIndirektes Lesen: Wer Pods anlegen darf, kann die gemounteten Secrets lesen

Die letzte Zeile ist wichtig: Das Recht, Workloads in einem Namespace anzulegen, gewährt implizit Zugriff auf dessen Secrets und Service-Account-Tokens. Dieser Zugriff erscheint nicht als get secrets-Event.

Auf den Standard-Levels von EKS und GKE, und in jeder vernünftigen Policy, werden Secrets auf Metadata protokolliert: Sie sehen, wer welches Secret gelesen hat, nie den Wert. Das reicht, um die Rotation einzugrenzen.

Der GKE-Vorbehalt

Auf GKE gehen get und list ins Data-Access-Audit-Log, das standardmäßig deaktiviert ist (siehe Export-Leitfaden). Ohne es hinterlassen Secret-Zugriffe gar keine Spur. Auf AKS lässt die günstigere Kategorie kube-audit-admin get und list ebenfalls weg.

Erkennungen für Secrets

Der Audit-Log-Analyzer hat zwei Regeln:

  • Secrets namespace-übergreifend aufgelistet (hoch): list oder watch auf secrets ohne Namespace, erlaubt, durch eine Nicht-System-Identität. Controller, die legitim alle Secrets beobachten (etwa Ingress- oder Zertifikats-Operatoren), müssen nach Prüfung auf die Allow-List.
  • Häufung von Secret-Lesezugriffen (mittel): eine Identität liest 10 oder mehr verschiedene Secrets innerhalb von 10 Minuten. Da verschiedene Namen gezählt werden, wird eine Anwendung, die ihr eigenes Secret erneut liest, nicht markiert.

Kubelets (system:node:*) lesen ständig die Secrets der Pods auf ihrem Node; das ist normal und ausgeschlossen.

Wie Service-Account-Tokens gestohlen werden

Pods erhalten ein Token für ihren Service Account, standardmäßig gemountet unter /var/run/secrets/kubernetes.io/serviceaccount/token. Seit Kubernetes 1.22 sind das kurzlebige, automatisch rotierte Tokens aus der TokenRequest-API; seit 1.24 werden langlebige, in Secrets gespeicherte Tokens laut der Dokumentation zu Service Accounts nicht mehr automatisch angelegt. Alte Token-Secrets, von Hand oder vor einem Upgrade angelegt, gibt es in vielen Clustern dennoch.

Typische Diebstahlwege:

  • Auslesen des gemounteten Tokens nach Ausnutzen einer Anwendung (RCE, SSRF, Path Traversal);
  • kubectl exec … cat /var/run/secrets/kubernetes.io/serviceaccount/token;
  • Lesen eines alten Token-Secrets, einer in einem Secret abgelegten kubeconfig oder einer CI-Variable;
  • ein exponiertes Dashboard oder Tool, das mit einem überprivilegierten Service Account läuft;
  • Ausstellen eines neuen Tokens mit kubectl create token (TokenRequest), wenn RBAC create auf serviceaccounts/token erlaubt.

So sieht ein wiederverwendetes Token aus

Ein Token, das sein Workload nutzt, folgt einem stabilen Muster: Pod-IPs, der eigene User Agent der Anwendung, immer dieselben wenigen API-Aufrufe. Ein wiederverwendetes Token bricht dieses Muster:

SignalRegel im AnalyzerSchweregrad
Service-Account-Request von einer öffentlichen (Internet-)IPService-Account-Token von öffentlicher IP verwendetHoch
Service Account mit User Agent kubectl/, curl/, python-requests/, Go-http-client/…Service-Account-Token mit kubectl / curl verwendetMittel
5 oder mehr selfsubjectaccessreviews / selfsubjectrulesreviews in 5 MinutenBerechtigungs-Enumeration (kubectl auth can-i)Mittel
10 oder mehr 403-Antworten in 10 MinutenHäufung verweigerter RequestsMittel
User Agent von kube-hunter, peirates, kubeletctl, kubiscan…User Agent eines Kubernetes-AngriffstoolsHoch
create auf serviceaccounts/tokenService-Account-Token ausgestelltMittel

kubectl auth can-i --list erzeugt ein SelfSubjectRulesReview, kubectl auth can-i create pods ein SelfSubjectAccessReview. Workloads rufen beides selten auf; eine Häufung von einem Service Account ist also jemand, der herausfindet, was sein gestohlenes Token darf (ATT&CK T1613).

Vorbehalte, die Sie im Kopf behalten sollten:

  • Der User Agent wird vom Client gesetzt. Sein Fehlen beweist nichts; sein Vorhandensein ist trotzdem eine gute Spur.
  • Die Quell-IP stammt aus dem letzten Eintrag von sourceIPs. Bei Clustern hinter einem Proxy oder mit privatem Endpunkt erscheint eine „öffentliche“ Adresse womöglich nie.
  • Manche in Go geschriebenen Operatoren nutzen den generischen Agent Go-http-client. Prüfen Sie, bevor Sie eskalieren.

Einem Token folgen

Neuere Kubernetes-Versionen fügen für Service-Account-Tokens eine Credential-ID (die JTI des Tokens) in user.extra ein. Ist sie vorhanden, lassen sich zwei Tokens desselben Service Accounts unterscheiden: das des Pods und das, das der Angreifer kopiert oder ausgestellt hat. Pivotieren Sie darüber wie über eine IP.

Bei einem TokenRequest zeigt der Request-Body (auf EKS und in der empfohlenen Policy auf Level Request protokolliert) expirationSeconds und die Audiences. Ein Token, das ein interaktiver Client für ein Jahr (31536000) anfordert, ist ein Persistenzschritt, keine Workload-Erneuerung. Der API-Server kann Token-Laufzeiten mit --service-account-max-token-expiration begrenzen.

Eingrenzung und Behebung

  1. Listen Sie jedes Secret auf, das die kompromittierten Identitäten gelesen haben, einschließlich der Antworten clusterweiter list-Aufrufe: Bei einem clusterweiten List gilt jedes Secret als offengelegt.
  2. Rotieren Sie an der Quelle: Datenbankpasswort, Cloud-Access-Key, Registry-Zugangsdaten, nicht nur das Kubernetes-Secret-Objekt.
  3. Entwerten Sie Tokens. Gebundene Tokens sterben mit dem Objekt, an das sie gebunden sind; über TokenRequest ausgestellte Tokens bleiben bis zum Ablauf gültig, sofern Sie den Service Account nicht löschen. Den Service Account löschen, neu anlegen und seine Workloads neu starten ist der zuverlässige Weg. Löschen Sie alte Token-Secrets.
  4. Finden Sie den Einstiegspunkt: den Pod, der das Token verloren hat, das Dashboard, den CI-Job.
  5. Schließen Sie den Weg: automountServiceAccountToken: false, wo die API nicht gebraucht wird, Least-Privilege-Rollen ohne list auf Secrets und kein create auf serviceaccounts/token außerhalb von Controllern.

Prüfen Sie auch die Cloud-Seite: Ein aus einem Secret gestohlener Cloud-Key wird gegen die Cloud-API eingesetzt, nicht gegen Kubernetes. Die Schwesterseiten AWS Forensics, GCP Forensics und Azure Forensics decken diese Logs ab.

Verwandte Artikel

Verwandte Artikel

Krypto-Mining in Kubernetes-Clustern über Audit-Logs erkennen: Miner-Images und -Argumente, unübliche Registries, Persistenz per CronJob und DaemonSet.
Vorbereitung eines Container-Escapes in Kubernetes-Audit-Logs erkennen: privilegierte Pods, hostPID, hostNetwork, hostPath auf / und DaemonSets in kube-system.
Kubernetes-RBAC-Rechteausweitung in Audit-Logs finden: Bindings an cluster-admin, Verben escalate, bind und impersonate, Impersonation und anonymer Zugriff.

Dieses Tool ist nicht mit The Linux Foundation, der Cloud Native Computing Foundation (CNCF) oder dem Kubernetes-Projekt verbunden und wird von diesen weder befürwortet noch gesponsert. Kubernetes und K8s sind eingetragene Marken von The Linux Foundation. EKS, GKE, AKS und andere Namen sind Marken ihrer jeweiligen Inhaber.