~10 minutes
Cet article fait partie de la série OWASP Top 10 Kubernetes 2026. Retrouvez le tableau de bord complet des dix risques et la matrice STRIDE sur la page d’entrée de la série.
Le risque K01 couvre deux familles de problèmes distinctes, même si elles se rejoignent sur la même cible.
La première, c’est l’authentification défaillante : clusters déployés avec --anonymous-auth=true (la valeur par défaut avant Kubernetes 1.16 et encore présente dans certains guides “quick start”), tokens de service accounts (SA) avec des durées de vie illimitées, accès directs à l’API via kubectl proxy laissé ouvert sur 0.0.0.0, kubeconfigs d’administrateurs partagés dans des variables d’environnement ou des repos git.
La seconde, c’est l’autorisation trop permissive : RBAC désactivé (--authorization-mode=AlwaysAllow), ClusterRoles avec wildcard sur les verbes et les ressources, binding de cluster-admin distribués comme des confettis à chaque friction opérationnelle. On y reviendra dans K08 pour le RBAC en détail ; ici, on se concentre sur la couche d’accès à l’API.
L’API Server Kubernetes n’est pas un service parmi d’autres : c’est le plan de contrôle de tout le cluster. Sa compromission revient à compromettre chaque workload, chaque secret, chaque configuration réseau du cluster.
Vecteurs d’attaque
Le cluster exposé avec auth anonyme
Le scénario le plus fréquent que l’on rencontre : un cluster monté depuis un tutoriel, --anonymous-auth non désactivé, port 6443 accessible depuis un VLAN interne un peu trop large. Un scanner de ports suffit à découvrir l’API Server. Une requête vers /api/v1/namespaces sans token retourne la liste complète des namespaces. À partir de là, l’attaquant navigue dans les secrets, les configmaps, les pods en cours d’exécution.
Je préfère l’évoquer tout de suite; le guide officiel d’un hébergeur cloud que je ne nommerai pas conseillait
--anonymous-auth=truepour “simplifier les premiers tests”.
Sur un audit conduit sur un cluster Kube d’une PME(ayant choisi cet hébergeur….), le port 6443 était joignable depuis l’ensemble du réseau bureautique. Un curl sans header d’authentification retournait la liste complète des namespaces, dont un
productionavec ses ConfigMaps contenant des chaînes de connexion en clair. L’équipe avait suivi un guide “getting started” d’un hébergeur cloud ; personne n’avait pensé à vérifier--anonymous-auth.
Et paf(pas le chien …) => Temps entre la découverte et le premier accès non autorisé lors du pentest : 4 minutes.
Ce n’est pas théorique. L’incident Shopify de 2020 (bounty de 25 000 $) portait sur un endpoint Kubernetes accessible sans authentification depuis leur réseau interne. L’accès anonyme n’est pas un risque hypothétique, c’est un risque documenté et régulièrement exploité.
Pour vérifier rapidement si un cluster expose son API sans authentification :
curl -sk https://<api-server>:6443/api/v1/namespaces
Si la réponse retourne du JSON valide sans 401, le cluster est vulnérable.
Les tokens de service accounts longue durée
Les tokens de service accounts générés avant Kubernetes 1.24 sont des JWTs sans expiration. Ils restent valides jusqu’à la suppression du secret associé ; dans les faits, ces secrets s’accumulent des mois ou des années sans qu’on y touche, et les tokens restent actifs bien après leur dernière utilisation légitime. La surface d’attaque croît silencieusement.
Les tokens créés manuellement avec kubectl create token sans argument --duration restent des tokens longue durée même sur les versions récentes de Kubernetes. C’est une erreur fréquente dans les pipelines CI : le token est généré une fois, stocké dans une variable d’environnement ou un secret système, et n’a aucune date d’expiration visible pour l’équipe qui le consomme.
Le vecteur d’attaque est simple : compromission d’un système qui stocke un token de SA (base de code, variable d’environnement, artifact de CI), puis utilisation de ce token pour accéder à l’API avec les permissions du service account concerné. Si ce SA a un ClusterRole trop permissif, game over.
L’API Server via un pod compromis
Depuis l’intérieur d’un pod, l’API Server est accessible via https://kubernetes.default.svc. Le token du SA est monté automatiquement dans /var/run/secrets/kubernetes.io/serviceaccount/token, à moins qu’automountServiceAccountToken: false ne soit explicitement positionné.
Un attaquant qui compromet un pod sans restriction (via une vulnérabilité applicative, une image compromise, un RCE dans une dépendance) dispose immédiatement d’un token valide et d’un accès réseau vers l’API Server. Les permissions de ce token dépendent du SA associé au pod, mais même un SA “par défaut” peut permettre de lister les pods, les secrets ou de découvrir la topologie du cluster si les Roles ne sont pas correctement restreints.
La règle à appliquer : tout pod qui n’a pas besoin de parler à l’API Kubernetes doit avoir
automountServiceAccountToken: falsedans sa spec. C’est une ligne de YAML ; elle supprime un vecteur d’attaque entier.
Mitigations à mettre en œuvre (le minimum syndical)
Désactiver l’authentification anonyme
Depuis Kubernetes 1.16, --anonymous-auth=false est recommandé par défaut mais pas toujours appliqué par les distributions.
On vérifie avec kube-bench (voir l’article dédié) : le check CIS 1.2.1 valide ce paramètre.
Activer l’audit logging au niveau Metadata minimum
L’audit logging de l’API Server est désactivé par défaut. Sans lui, on n’a aucune visibilité sur qui fait quoi sur le cluster ; toute compromission devient indétectable a posteriori.
On l’active avec
--audit-policy-file=/etc/kubernetes/audit-policy.yamlet--audit-log-path=/var/log/kubernetes/audit.log. Les logs sont ensuite consommés par Falco ou forwardés vers un SIEM.
Sans cela lors de votre première réponse à un incident Kubernetes sans audit log actif, vous n’aurez que des traces réseau, des logs applicatifs, et strictement rien sur ce qui s’était passé côté API Server. Vous passerez du temps avec Coca et Pizza à reconstituer la chronologie.
Désactiver le montage automatique des tokens SA
Pour les pods qui n’ont pas besoin de parler à l’API Kubernetes, on pose automountServiceAccountToken: false dans la spec du pod. Le champ existe aussi au niveau du service account lui-même ; si on le désactive là, tous les pods qui l’utilisent en héritent sans qu’on ait à modifier chaque Deployment.
On peut également l’imposer à l’échelle du namespace via une ClusterPolicy Kyverno en mode Enforce, ce qui bloque à l’admission tout pod qui ne déclare pas explicitement ce champ ; le manifest complet est dans le contenu premium.
Tokens SA avec durée de vie limitée (Kubernetes 1.24+)
Depuis Kubernetes 1.24, les tokens montés automatiquement dans les pods sont liés au cycle de vie du pod et expirent toutes les heures par défaut ; le kubelet les renouvelle de manière transparente. Pour les tokens créés manuellement, on passe l’argument --duration pour forcer une expiration courte.
Pour les pipelines CI/CD :
- AWS donne des tokens OIDC scopés à un rôle IAM précis et à durée de vie courte
- Sur GCP et Azure, les équivalents existent (Workload Identity, Workload Identity Federation) ; le principe est le même
Résultat : Plus aucun token SA longue durée stocké dans les secrets du système CI.
Audit et remédiation continue avec Kubescape
Kubescape couvre les checks NSA/CISA et OWASP Kubernetes Top 10, dont K01.
Intègrer un scan hebdomadaire dans le pipeline de monitoring en ciblant les namespaces de production ; Kubescape retourne un score de conformité et identifie précisément les régressions sur la configuration de l’API Server avant qu’elles n’atteignent un auditeur externe.
Kubescape remonte parfois des faux positifs sur les namespaces système, notamment sur les DaemonSets de logging qui ont besoin de monter des paths hôte. Filtrer systématiquement kube-system et kube-public des scans de conformité applicatifs, sinon le score ne veut plus rien dire pour l’équipe qui le lit.
Intégrer K01 dans la chaîne CI/CD
Ce n’est presque jamais la mauvaise configuration qui arrive en production qui me surprend, c’est celle qui aurait pu être bloquée trois étapes avant.
- Token hardcodé qu’on a vu passer en revue Git sans alerter personne
- Deployment sans
automountServiceAccountTokenvalidé par un reviewer fatigué - ClusterRoleBinding wildcard mergé un vendredi soir.
Voici comment instrumenter la chaîne pour que ces écarts ne dépendent plus de la vigilance individuelle.
Ce contenu représente de nombreuses heures de travail, d'expérience etc... J'ai remarqué que mon contenu était repris par certaines sociétés/personnes et j'ai donc décidé de donner du contenu minimal sur ce blog. C'est pourquoi je vous invite a me contacter sur LinkedIn en mentionnant cet article pour plus d'informations.
- ✓ Désactiver l'auth anonyme immédiatement :
--anonymous-auth=falsesur l'API Server. Vérifiable avec kube-bench check CIS 1.2.1. - ✓ Activer l'audit logging au niveau Metadata minimum pour les secrets et configmaps. Sans logs, toute compromission est indétectable a posteriori.
- ✓ Poser
automountServiceAccountToken: falsesur tout pod qui n'a pas besoin de l'API Kubernetes. Une ligne de YAML, un vecteur d'attaque supprimé. - ✓ Migrer vers les tokens SA liés au cycle de vie du pod (Kubernetes 1.24+). Supprimer tous les tokens générés avant cette version.
- ✓ Intégrer Kubescape dans les pipelines CI/CD pour détecter les régressions de configuration API Server avant la production.