Skip to content

Cet outil n'est ni affilié à The Linux Foundation, à la Cloud Native Computing Foundation (CNCF) ou au projet Kubernetes, ni approuvé ni sponsorisé par eux. Kubernetes et K8s sont des marques déposées de The Linux Foundation. EKS, GKE, AKS et les autres noms sont des marques de leurs propriétaires respectifs.

Secrets Kubernetes et vol de tokens de compte de service

Détecter le vol de secrets et de tokens de compte de service Kubernetes dans les logs d'audit : list globaux, rafales, TokenRequest, IP publiques, can-i.

Publié le 7 min de lecture

TL;DR. Le vol d'identifiants dans Kubernetes laisse deux types de traces. Côté secrets : un list ou un watch sur secrets sans namespace (tous les secrets du cluster, contenu compris), ou une identité qui lit beaucoup de secrets différents en peu de temps. Côté tokens : un compte de service utilisé depuis une IP publique ou avec kubectl/curl comme user agent, une rafale de kubectl auth can-i, des rafales de 403, et de nouveaux tokens émis via TokenRequest. Chaque secret lu est un identifiant à faire tourner, et sur GKE les lectures ne sont journalisées que si les logs Data Access sont activés.

Les secrets sont la raison pour laquelle la plupart des attaquants s'intéressent à un cluster : mots de passe de bases de données, clés cloud, identifiants de registry, tokens de CI, clés de signature. ATT&CK classe cela sous T1552.007, Container API, et le côté tokens sous T1528, Steal Application Access Token.

Comment les secrets fuient via l'API

Les bonnes pratiques RBAC de Kubernetes insistent sur un point que beaucoup d'équipes ratent : list et watch sur les secrets révèlent leur contenu, exactement comme get. Un rôle qui « ne fait que lister » les secrets est un rôle qui les lit tous.

RequêteTrace d'auditSignification
kubectl get secrets -Alist sur secrets, sans objectRef.namespaceTous les secrets du cluster, en une réponse
kubectl get secrets -n shoplist sur secrets, namespace shopTous les secrets du namespace
kubectl get secret db-creds -o yamlget sur secrets, avec un nomUn secret
Créer un pod qui monte un secretcreate sur pods avec un volume secretLecture indirecte : qui peut créer des pods peut lire les secrets qu'ils montent

La dernière ligne compte : le droit de créer des workloads dans un namespace donne implicitement accès à ses secrets et à ses tokens de compte de service. Cette lecture n'apparaît pas comme un événement get secrets.

Aux niveaux par défaut d'EKS et de GKE, et dans toute politique raisonnable, les secrets sont journalisés en Metadata : vous voyez qui a lu quel secret, jamais la valeur. C'est suffisant pour cadrer la rotation.

La réserve GKE

Sur GKE, get et list vont dans le log d'audit Data Access, désactivé par défaut (voir le guide d'export). Sans lui, les lectures de secrets ne laissent aucune trace. Sur AKS, la catégorie moins chère kube-audit-admin exclut aussi get et list.

Détections côté secrets

L'analyseur de logs d'audit a deux règles :

  • Secrets listés sur tous les namespaces (élevée) : list ou watch sur secrets sans namespace, autorisé, par une identité non système. Les contrôleurs qui surveillent légitimement tous les secrets (par exemple des opérateurs d'ingress ou de certificats) doivent être mis en liste blanche après vérification.
  • Rafale de lectures de secrets (moyenne) : une identité qui lit 10 secrets différents ou plus en 10 minutes. Compter les noms distincts évite de signaler une application qui relit son propre secret.

Les kubelets (system:node:*) lisent en permanence les secrets des pods planifiés sur leur nœud ; c'est normal et exclu.

Comment les tokens de compte de service sont volés

Les pods reçoivent un token pour leur compte de service, monté par défaut dans /var/run/secrets/kubernetes.io/serviceaccount/token. Depuis Kubernetes 1.22, ce sont des tokens de courte durée, renouvelés automatiquement et obtenus via l'API TokenRequest ; depuis la 1.24, les tokens longue durée stockés dans des Secrets ne sont plus créés automatiquement, selon la documentation des comptes de service. Des Secrets de tokens hérités, créés à la main ou avant une mise à niveau, traînent encore dans beaucoup de clusters.

Chemins de vol typiques :

  • lecture du token monté après exploitation d'une application (RCE, SSRF, path traversal) ;
  • kubectl exec … cat /var/run/secrets/kubernetes.io/serviceaccount/token ;
  • lecture d'un Secret de token hérité, d'un kubeconfig stocké dans un Secret, ou d'une variable de CI ;
  • un dashboard ou un outil exposé qui tourne avec un compte de service surprivilégié ;
  • émission d'un nouveau token avec kubectl create token (TokenRequest) quand RBAC autorise create sur serviceaccounts/token.

À quoi ressemble un token rejoué

Un token utilisé par son workload suit un schéma stable : IP de pods, user agent propre à l'application, les mêmes quelques appels d'API. Un token rejoué casse ce schéma :

SignalRègle de l'analyseurSévérité
Requête d'un compte de service depuis une IP publique (Internet)Token de compte de service utilisé depuis une IP publiqueÉlevée
Compte de service avec un user agent kubectl/, curl/, python-requests/, Go-http-client/…Token de compte de service utilisé avec kubectl / curlMoyenne
5 selfsubjectaccessreviews / selfsubjectrulesreviews ou plus en 5 minutesÉnumération de permissions (kubectl auth can-i)Moyenne
10 réponses 403 ou plus en 10 minutesRafale de requêtes refuséesMoyenne
User agent de kube-hunter, peirates, kubeletctl, kubiscan…User agent d'un outil d'attaque KubernetesÉlevée
create sur serviceaccounts/tokenToken de compte de service émisMoyenne

kubectl auth can-i --list produit une SelfSubjectRulesReview ; kubectl auth can-i create pods une SelfSubjectAccessReview. Les workloads appellent rarement l'une ou l'autre : une rafale depuis un compte de service, c'est quelqu'un qui découvre ce que permet son token volé (ATT&CK T1613).

Réserves à garder en tête :

  • Le user agent est contrôlé par le client. Son absence ne prouve rien ; sa présence reste une bonne piste.
  • L'IP source provient de la dernière entrée de sourceIPs. Sur les clusters derrière un proxy ou avec un endpoint privé, une adresse « publique » peut ne jamais apparaître.
  • Certains opérateurs écrits en Go utilisent un agent générique Go-http-client. Vérifiez avant d'escalader.

Suivre un token

Les versions récentes de Kubernetes ajoutent un identifiant de credential (le JTI du token) dans user.extra pour les tokens de compte de service. Quand il est présent, il permet de distinguer deux tokens d'un même compte de service : celui du pod et celui que l'attaquant a copié ou émis. Pivotez dessus comme sur une IP.

Pour une TokenRequest, le corps de la requête (journalisé au niveau Request sur EKS et dans la politique recommandée) montre expirationSeconds et les audiences. Un token demandé pour un an (31536000) par un client interactif est une étape de persistance, pas un renouvellement de workload. L'API server peut plafonner la durée de vie des tokens avec --service-account-max-token-expiration.

Délimitation et remédiation

  1. Listez chaque secret lu par les identités compromises, y compris ceux des réponses de list globaux : pour un list sur tout le cluster, considérez que tous les secrets ont été exposés.
  2. Faites-les tourner à la source : le mot de passe de la base, la clé d'accès cloud, l'identifiant de registry, pas seulement l'objet Secret Kubernetes.
  3. Invalidez les tokens. Les tokens liés meurent avec l'objet auquel ils sont liés ; les tokens émis via TokenRequest restent valides jusqu'à expiration sauf si vous supprimez le compte de service. Supprimer puis recréer le compte de service, puis redémarrer ses workloads, est la sortie fiable. Supprimez les Secrets de tokens hérités.
  4. Trouvez le point d'entrée : le pod qui a laissé fuir le token, le dashboard, le job de CI.
  5. Coupez le chemin : automountServiceAccountToken: false là où l'API n'est pas nécessaire, rôles au moindre privilège sans list sur les secrets, et pas de create sur serviceaccounts/token hors contrôleurs.

Vérifiez aussi le côté cloud : une clé cloud volée dans un Secret s'utilise contre l'API cloud, pas contre Kubernetes. Les sites frères AWS Forensics, GCP Forensics et Azure Forensics couvrent ces logs.

Articles liés

Articles liés

Détecter le crypto-minage dans Kubernetes via les logs d'audit : images et arguments de mineurs, registries inhabituels, persistance CronJob et DaemonSet.
Repérer une évasion de conteneur en préparation dans les logs d'audit Kubernetes : pods privilégiés, hostPID, hostPath sur /, DaemonSets dans kube-system.
Repérer l'escalade de privilèges RBAC Kubernetes dans les logs d'audit : bindings cluster-admin, verbes escalate, bind, impersonate, accès anonyme.

Cet outil n'est ni affilié à The Linux Foundation, à la Cloud Native Computing Foundation (CNCF) ou au projet Kubernetes, ni approuvé ni sponsorisé par eux. Kubernetes et K8s sont des marques déposées de The Linux Foundation. EKS, GKE, AKS et les autres noms sont des marques de leurs propriétaires respectifs.