Sommaire
Introduction
Un cluster Kubernetes est un système distribué doté d’une API capable de lancer n’importe quel code, de lire n’importe quel secret et de modifier n’importe quelle règle réseau, selon qui la sollicite. La plupart des compromissions de Kubernetes n’ont rien de sophistiqué. Elles viennent d’une API ou d’un tableau de bord laissé ouvert sur Internet, d’un compte de service doté de cluster-admin, d’un conteneur exécuté en root avec le système de fichiers de l’hôte monté, ou d’un contrôleur d’ingress jamais mis à jour. Chacune transforme un pod compromis en cluster compromis, et souvent en compte cloud compromis.
Ce guide durcit un cluster couche par couche : le plan de contrôle, l’identité et le RBAC, les paramètres des charges de travail, la politique d’admission, le réseau, la chaîne d’approvisionnement, les secrets, les nœuds et la détection à l’exécution. Il s’applique aux services managés comme EKS, GKE et AKS comme aux clusters que vous construisez vous-même, et chaque section contient une configuration à adapter. Une liste de contrôle et une correspondance avec l’OWASP Kubernetes Top 10 concluent l’article.
Comment les clusters Kubernetes sont compromis
Les incidents réels suivent un petit nombre de chemins. Les connaître indique quels contrôles construire en premier.
- Interfaces d’administration exposées. En 2018, des attaquants ont trouvé une console Kubernetes de Tesla sans mot de passe, y ont récupéré des identifiants cloud et ont lancé des mineurs de cryptomonnaie. Des tableaux de bord ouverts, des serveurs d’API qui acceptent les requêtes anonymes et des kubelets qui acceptent les appels non authentifiés sont encore trouvés chaque semaine par des scans d’Internet.
- Composants de cluster vulnérables. En 2018, CVE-2018-1002105 dans le serveur d’API permettait à certains utilisateurs de transformer une requête ordinaire en accès complet aux kubelets et aux serveurs d’API agrégés. En 2025, CVE-2025-1974, notée CVSS 9.8, permettait à tout ce qui se trouvait sur le réseau des pods de prendre le contrôle d’ingress-nginx via son webhook d’admission et de lire les Secrets auxquels il avait accès, c’est-à-dire par défaut tous les Secrets du cluster. Le projet Kubernetes indiquait alors que plus de 40 % des clusters utilisaient ingress-nginx.
- RBAC trop large. Un attaquant qui obtient un jeton autorisé à créer des pods, lire des secrets ou lier des rôles peut généralement atteindre cluster-admin. Aqua Security a documenté en 2023 une campagne qui créait son propre ClusterRole et sa propre liaison comme porte dérobée, après être entrée par un serveur d’API mal configuré.
- Évasion de conteneur. Les pods privilégiés, les montages hostPath, le réseau de l’hôte et les noyaux non corrigés permettent à un conteneur compromis d’atteindre le nœud, puis depuis le nœud chaque pod et chaque identifiant qu’il héberge.
- Vol d’identifiants cloud. Un pod qui peut joindre le point de métadonnées du cloud, ou qui s’exécute avec un rôle de nœud puissant, donne à l’attaquant un accès à l’API cloud au-delà du cluster.
- Images empoisonnées. Les images de registres publics, les tags non figés et les chaînes de build compromises font entrer des logiciels malveillants par la grande porte.
Les référentiels à suivre
| Référentiel | Ce qu’il apporte | À utiliser pour |
|---|---|---|
| CIS Kubernetes Benchmark | Des centaines de contrôles de configuration précis pour le plan de contrôle, les nœuds et les politiques, avec des variantes pour les services managés | Scans de conformité automatisés avec kube-bench et preuves d’audit |
| Guide de durcissement Kubernetes de la NSA et de la CISA | Recommandations gouvernementales sur la sécurité des pods, la séparation réseau, l’authentification, la journalisation et les mises à jour | Un socle lisible et une justification pour la direction |
| OWASP Kubernetes Top 10 | Les dix risques Kubernetes les plus courants, de K01 à K10, mis à jour en 2025 | Prioriser le travail et former les ingénieurs |
| Liste de contrôle de sécurité Kubernetes | La liste des contrôles de base du projet lui-même, reliée à la documentation | Vérifier un nouveau cluster avant qu’il reçoive du trafic de production |
| Matrice conteneurs de MITRE ATT&CK et Threat Matrix for Kubernetes de Microsoft | Techniques d’attaque transposées à l’environnement Kubernetes | Ingénierie de détection et modélisation des menaces |
Verrouillez le serveur d’API, etcd et les kubelets
Le serveur d’API est la porte d’entrée de tout. Il ne doit pas être joignable depuis Internet. Sur les services managés, utilisez un point de terminaison privé ou limitez le point public à une courte liste de réseaux, comme votre VPN et vos runners de CI. Désactivez l’authentification anonyme, utilisez OIDC avec votre fournisseur d’identité pour les personnes, et tenez les fichiers de jetons statiques et l’authentification basique hors de la configuration.
- Point d’API privé. L’accès passe par un VPN, un bastion avec des identifiants de courte durée, ou le chemin d’accès privé du fournisseur cloud.
- Aucun accès anonyme. Définissez --anonymous-auth=false sur le serveur d’API là où vous le contrôlez, et vérifiez que system:anonymous et system:unauthenticated n’ont aucune liaison au-delà des valeurs par défaut.
- etcd isolé. Seul le serveur d’API peut joindre etcd, en TLS mutuel. Quiconque peut lire etcd peut lire tous les Secrets, traitez donc ses sauvegardes avec le même soin.
- Authentification du kubelet activée. L’API du kubelet sur le port 10250 peut exécuter des commandes dans n’importe quel pod du nœud. Désactivez l’accès anonyme et le port en lecture seule, et confiez les décisions d’autorisation au serveur d’API.
- Versions supportées. Kubernetes supporte les trois versions mineures les plus récentes, chacune pendant environ quatorze mois. Mettez à jour avant de sortir de cette fenêtre, car les correctifs de sécurité s’arrêtent.
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
authentication:
anonymous:
enabled: false
webhook:
enabled: true
x509:
clientCAFile: /etc/kubernetes/pki/ca.crt
authorization:
mode: Webhook
readOnlyPort: 0
protectKernelDefaults: true
rotateCertificates: true
serverTLSBootstrap: trueChiffrez les Secrets au repos
Les Secrets Kubernetes sont seulement encodés en base64 par défaut, et ils sont stockés dans etcd en clair tant que vous ne configurez pas de chiffrement. Utilisez le fournisseur KMS v2 pour que la clé de chiffrement réside dans votre KMS cloud ou votre HSM, et non sur le disque du plan de contrôle. Les services managés le proposent sous forme d’option, comme le chiffrement par enveloppe sur EKS et le chiffrement des secrets au niveau applicatif sur GKE.
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
- resources: ["secrets"]
providers:
- kms:
apiVersion: v2
name: cloud-kms
endpoint: unix:///var/run/kmsplugin/socket.sock
timeout: 3s
- identity: {}Activez la journalisation d’audit
Les journaux d’audit sont la seule trace de qui a fait quoi via l’API. Activez-les dès le premier jour et envoyez-les hors du cluster. Journalisez les métadonnées des lectures de secrets, les corps complets de requête et de réponse pour les modifications du RBAC, et chaque exec, attach et demande de jeton. Sur les services managés, activez le journal d’audit du plan de contrôle dans la console du fournisseur et dirigez-le vers votre SIEM.
apiVersion: audit.k8s.io/v1
kind: Policy
omitStages: ["RequestReceived"]
rules:
- level: None
resources:
- group: ""
resources: ["events"]
- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps"]
- level: RequestResponse
verbs: ["create", "update", "patch", "delete"]
resources:
- group: "rbac.authorization.k8s.io"
- group: ""
resources: ["pods/exec", "pods/attach", "serviceaccounts/token"]
- level: MetadataRBAC et comptes de service
Le RBAC décide de ce que chaque personne et chaque pod peut faire via l’API. Il est additif et n’a pas de règles de refus, la seule façon d’être en sécurité est donc d’accorder peu. Liez les personnes à des rôles via des groupes de votre fournisseur d’identité, limitez les rôles aux namespaces autant que possible, et réservez cluster-admin à des comptes de secours surveillés et rarement utilisés.
Certaines permissions valent bien plus qu’elles n’en ont l’air, car chacune mène à cluster-admin en quelques étapes. Examinez chaque liaison qui les accorde.
| Permission | Pourquoi elle est dangereuse |
|---|---|
| create sur pods, deployments ou jobs | Lancer un pod qui monte n’importe quel compte de service ou le système de fichiers de l’hôte dans ce namespace |
| get ou list sur secrets | Lire chaque jeton et identifiant stocké dans le namespace |
| escalate, bind | S’attribuer des rôles plus puissants que ceux que l’on détient |
| impersonate | Agir en tant que n’importe quel utilisateur, groupe ou compte de service |
| nodes/proxy | Atteindre l’API du kubelet et exécuter des commandes dans les pods de ce nœud |
| create sur serviceaccounts/token | Émettre des jetons pour des comptes de service disposant de plus de droits |
| update sur les configurations de webhooks de validation ou de mutation | Désactiver la politique ou réécrire chaque pod créé |
| jokers (*) dans les verbes ou les ressources | Inclure tout ce qui précède, ainsi que toute ressource ajoutée plus tard |
# Every subject bound to cluster-admin
kubectl get clusterrolebindings -o json | jq -r '
.items[] | select(.roleRef.name == "cluster-admin")
| .metadata.name + ": " + ([.subjects[]? | .kind + "/" + .name] | join(", "))'
# Everything one service account is allowed to do in its namespace
kubectl auth can-i --list \
--as=system:serviceaccount:payments:api -n paymentsComptes de service et identité cloud
- Ne montez pas les jetons par défaut. Définissez automountServiceAccountToken: false sur les comptes de service et les pods, et ne l’activez que pour les charges de travail qui appellent l’API Kubernetes.
- Un compte de service par charge de travail. Le compte de service par défaut de chaque namespace ne doit avoir aucune liaison ni jeton monté.
- Utilisez des jetons liés et de courte durée. Les jetons projetés expirent et sont liés au pod. Supprimez les anciens Secrets de jetons de longue durée, qui n’expirent jamais.
- Utilisez l’identité de charge de travail pour le cloud. EKS Pod Identity ou IRSA, GKE Workload Identity et Azure Workload Identity donnent à un pod son propre rôle cloud restreint. Ne comptez jamais sur le rôle du nœud pour l’accès applicatif.
- Bloquez le point de métadonnées. Sur AWS, exigez IMDSv2 avec une limite de sauts de 1 pour que les pods ne puissent pas atteindre les identifiants du nœud. Sur GKE, Workload Identity masque le serveur de métadonnées du nœud aux pods.
Paramètres de charge de travail qui empêchent les évasions de conteneur
La plupart des évasions de conteneur exigent un paramètre que quelqu’un a choisi : mode privilégié, montage hostPath, réseau de l’hôte, capacités Linux supplémentaires ou exécution en root. Les Pod Security Standards définissent trois niveaux, privileged, baseline et restricted, et le contrôleur intégré Pod Security Admission les applique par namespace à l’aide d’un label. Appliquez restricted à chaque namespace applicatif, et gardez les rares charges qui ont besoin de plus, comme les pilotes CNI et de stockage, dans leurs propres namespaces.
apiVersion: v1
kind: Namespace
metadata:
name: payments
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
pod-security.kubernetes.io/warn: restricted
pod-security.kubernetes.io/audit: restrictedapiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: payments
spec:
replicas: 3
selector:
matchLabels: { app: api }
template:
metadata:
labels: { app: api }
spec:
serviceAccountName: api
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
runAsUser: 10001
seccompProfile: { type: RuntimeDefault }
containers:
- name: api
image: registry.example.com/payments/api@sha256:4f1c9a0d3b2e7f6a5c8d9e0b1a2f3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities: { drop: ["ALL"] }
resources:
requests: { cpu: 250m, memory: 256Mi }
limits: { memory: 512Mi }
volumeMounts:
- { name: tmp, mountPath: /tmp }
volumes:
- { name: tmp, emptyDir: { sizeLimit: 64Mi } }Appliquez la politique à l’admission
Pod Security Admission ne couvre que les paramètres des pods. Un moteur de politiques permet d’imposer le reste : images uniquement depuis votre registre et figées par digest, signatures vérifiées, labels obligatoires, pas de services LoadBalancer dans certains namespaces, pas de jokers dans les rôles. ValidatingAdmissionPolicy, stable depuis Kubernetes 1.30, exécute des règles CEL dans le serveur d’API sans composant supplémentaire. Kyverno et OPA Gatekeeper ajoutent la mutation, la vérification des signatures d’images et une large bibliothèque de politiques prêtes à l’emploi.
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: trusted-images
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: [""]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["pods"]
variables:
- name: images
expression: >-
object.spec.containers.map(c, c.image) +
(has(object.spec.initContainers) ? object.spec.initContainers.map(c, c.image) : [])
validations:
- expression: >-
variables.images.all(i, i.startsWith('registry.example.com/') && i.contains('@sha256:'))
message: "Images must come from registry.example.com and be pinned by digest"
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: trusted-images
spec:
policyName: trusted-images
validationActions: [Deny]
matchResources:
namespaceSelector:
matchExpressions:
- key: kubernetes.io/metadata.name
operator: NotIn
values: ["kube-system"]Segmentez le réseau
Par défaut, chaque pod peut parler à tous les autres pods du cluster, dans tous les namespaces, et à Internet. Un pod compromis peut alors scanner et atteindre les bases de données, les webhooks d’admission et les API internes. NetworkPolicy corrige cela, mais seulement si votre plugin CNI l’applique, comme Calico ou Cilium, ou l’option de politique réseau managée de votre fournisseur. Appliquez un refus par défaut dans chaque namespace, puis n’autorisez que les flux dont chaque application a besoin, en entrée comme en sortie.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny
namespace: payments
spec:
podSelector: {}
policyTypes: [Ingress, Egress]
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-dns
namespace: payments
spec:
podSelector: {}
policyTypes: [Egress]
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- { protocol: UDP, port: 53 }
- { protocol: TCP, port: 53 }- Contrôlez le trafic sortant. La plupart des charges ont besoin de quelques hôtes externes, pas de tout Internet. Autorisez-les explicitement, et faites passer le reste par une passerelle de sortie ou un proxy qui journalise les connexions.
- Protégez les services internes. Les webhooks d’admission, les points de métriques et les bases de données ne doivent accepter que le trafic des pods qui en ont besoin. La vulnérabilité d’ingress-nginx était exploitable parce que son webhook était joignable depuis n’importe quel pod.
- Chiffrez le trafic des pods là où c’est important. Un service mesh comme Istio ou Linkerd, ou Cilium avec WireGuard, ajoute le TLS mutuel et l’identité des charges entre services.
- Maintenez la bordure à jour. Les contrôleurs d’ingress sont exposés à Internet et détiennent des clés TLS. Le projet Kubernetes a annoncé en novembre 2025 le retrait d’ingress-nginx, avec une maintenance au mieux uniquement jusqu’en mars 2026. Si vous l’utilisez encore, prévoyez une migration vers la Gateway API ou un autre contrôleur maintenu.
Images et chaîne d’approvisionnement
Tout ce qui s’exécute dans le cluster est arrivé sous forme d’image. Contrôlez d’où viennent les images, ce qu’elles contiennent et qui les a construites. Partez d’images de base réduites comme distroless ou une image d’OS minimale, analysez-les en CI et dans le registre, signez-les dans la chaîne de build, et déployez-les par digest pour qu’un tag ne puisse pas être déplacé à votre insu.
IMAGE=registry.example.com/payments/api@sha256:4f1c9a0d3b2e7f6a5c8d9e0b1a2f3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
# Fail the build on fixable high and critical vulnerabilities
trivy image --severity HIGH,CRITICAL --ignore-unfixed --exit-code 1 "$IMAGE"
# Keyless signature tied to the CI workflow identity
cosign sign --yes "$IMAGE"- Utilisez un registre privé. Faites un miroir des images publiques dont vous avez besoin, analysez-les à l’import, et n’autorisez les téléchargements que depuis votre registre via la politique d’admission.
- Vérifiez les signatures au déploiement. Kyverno et Gatekeeper avec le policy controller de Sigstore peuvent rejeter les images qui n’ont pas été signées par votre chaîne de build.
- Produisez un SBOM. Générez-en un par image pour savoir en quelques minutes si une vulnérabilité nouvellement publiée vous concerne.
- Analysez ce qui tourne. De nouvelles CVE apparaissent après le déploiement. Réanalysez quotidiennement les images en cours d’exécution et alertez sur les nouvelles découvertes critiques.
Gestion des secrets
Quiconque peut lire un objet Secret, lister les secrets d’un namespace ou lancer un pod qui le monte peut lire sa valeur. Le chiffrement au repos protège etcd, pas l’API. Gardez réduit l’ensemble des identités ayant accès aux secrets, et envisagez de conserver la source de vérité hors du cluster.
- Utilisez un coffre externe. L’External Secrets Operator ou le Secrets Store CSI Driver récupère les valeurs depuis Vault, AWS Secrets Manager, Azure Key Vault ou Google Secret Manager, de sorte que la rotation et les journaux d’accès y résident.
- Montez-les en fichiers, pas en variables. Les variables d’environnement apparaissent plus souvent que les fichiers dans les vidages mémoire, les pages de débogage et les listes de processus.
- Gardez les secrets hors de Git. Les manifestes et les valeurs Helm doivent référencer les secrets, jamais les contenir. Si vous devez les stocker dans Git, chiffrez-les avec Sealed Secrets ou SOPS.
- Faites tourner en cas d’exposition. Considérez comme divulgué tout secret lisible par un pod ou un compte compromis.
Durcissez les nœuds
Un nœud exécute de nombreux pods et détient leurs identifiants, donc la compromission d’un nœud équivaut au moins à celle d’un namespace. Utilisez un OS minimal orienté conteneurs comme Bottlerocket, Talos, Flatcar ou Container-Optimized OS, remplacez les nœuds plutôt que de les corriger sur place, et supprimez l’accès SSH au profit d’outils de secours audités.
- Corrigez par remplacement. Faites tourner les pools de nœuds vers de nouvelles images selon un calendrier, et rapidement pour les correctifs du noyau et du runtime de conteneurs.
- Séparez les charges sensibles. Utilisez des pools de nœuds dédiés avec des taints pour les charges qui traitent des données de paiement, des secrets ou du code non fiable, afin qu’une évasion ailleurs n’atterrisse pas à côté d’elles.
- Isolez le code non fiable. Une RuntimeClass avec gVisor ou Kata Containers place une frontière plus solide autour des pods qui exécutent du code client ou des tâches de build.
- Restreignez les permissions des nœuds. Gardez le plugin d’admission NodeRestriction actif pour qu’un kubelet ne puisse modifier que son propre nœud et ses pods, et ne donnez au rôle cloud du nœud que ce dont le kubelet a besoin.
Détectez les attaques à l’exécution
La prévention laissera passer quelque chose. La détection à l’exécution observe ce que font réellement les conteneurs : un shell qui démarre dans un pod de production, un processus qui lit un jeton de compte de service, un binaire absent de l’image, une connexion sortante vers un pool de minage. Falco, Tetragon et les agents d’exécution des plateformes commerciales de sécurité cloud utilisent tous eBPF pour voir ces événements avec peu de surcoût.
- rule: Shell spawned in production container
desc: An interactive shell started inside a container in a production namespace
condition: >
spawned_process and container
and proc.name in (bash, sh, zsh, ash)
and proc.tty != 0
and k8s.ns.name startswith "prod"
output: >
Shell in container (user=%user.name ns=%k8s.ns.name pod=%k8s.pod.name
image=%container.image.repository cmd=%proc.cmdline)
priority: WARNING
tags: [container, shell, mitre_execution]Combinez les événements d’exécution avec le journal d’audit de l’API dans votre SIEM. Parmi les détections utiles : les exec dans des pods de namespaces de production, les nouveaux ClusterRoleBindings, la lecture de nombreux secrets par une même identité, les pods créés avec des paramètres privilégiés dans des namespaces qui ne devraient pas en avoir, les jetons utilisés depuis des adresses IP hors de vos réseaux, et les modifications des webhooks d’admission.
Répondre à une charge de travail compromise
Les pods ont une courte durée de vie, les preuves disparaissent donc à leur redémarrage. Rédigez la procédure à l’avance et assurez-vous que les personnes d’astreinte disposent des accès nécessaires.
- Isolez, ne supprimez pas. Appliquez une NetworkPolicy qui bloque tout le trafic vers et depuis le pod, et passez le nœud en cordon pour que rien de nouveau n’y soit planifié.
- Capturez les preuves. Enregistrez la spécification du pod, les journaux, les événements et le digest de l’image. Prenez un checkpoint du conteneur ou un instantané mémoire et disque du nœud si votre plateforme le permet.
- Révoquez les identifiants. Supprimez et recréez le compte de service pour invalider ses jetons, et faites tourner chaque secret et identifiant cloud que le pod pouvait lire.
- Délimitez l’accès. Recherchez dans le journal d’audit chaque requête faite avec l’identité du pod, et cherchez les nouveaux rôles, liaisons, webhooks, DaemonSets et CronJobs.
- Reconstruisez. Remplacez les nœuds concernés et redéployez depuis une image saine connue. Ne nettoyez pas un nœud compromis sur place.
- Corrigez la cause. Fermez le chemin qui a permis l’entrée de l’attaquant, puis ajoutez une détection correspondante.
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
kubectl wait --for=condition=complete job/kube-bench --timeout=300s
kubectl logs job/kube-benchCorrespondance des contrôles avec l’OWASP Kubernetes Top 10
| Risque | Principaux contrôles |
|---|---|
| K01 Insecure Workload Configurations | Pod Security Standard restricted, systèmes de fichiers en lecture seule, pas de root |
| K02 Overly Permissive Authorization Configurations | Rôles limités aux namespaces, pas de jokers, verbes d’élévation examinés |
| K03 Secrets Management Failures | Chiffrement KMS au repos, coffres de secrets externes, accès restreint |
| K04 Lack of Cluster Level Policy Enforcement | ValidatingAdmissionPolicy, Kyverno ou Gatekeeper, images signées |
| K05 Missing Network Segmentation Controls | NetworkPolicy de refus par défaut, contrôle du trafic sortant, mTLS |
| K06 Overly Exposed Kubernetes Components | Point d’API privé, pas de tableaux de bord publics, webhooks et kubelets protégés |
| K07 Misconfigured and Vulnerable Cluster Components | Authentification du kubelet, versions supportées, extensions corrigées, scans CIS Benchmark |
| K08 Cluster to Cloud Lateral Movement | Identité de charge de travail, point de métadonnées bloqué, rôles de nœud restreints |
| K09 Broken Authentication Mechanisms | OIDC pour les personnes, jetons liés, aucun accès anonyme |
| K10 Inadequate Logging and Monitoring | Journaux d’audit de l’API, détection à l’exécution, règles SIEM |
Liste de contrôle de durcissement du cluster
- API. Le serveur d’API est privé ou limité à des réseaux connus, avec l’accès anonyme désactivé et OIDC pour les personnes.
- Données. Les Secrets sont chiffrés au repos avec KMS, et etcd n’est joignable que par le serveur d’API.
- Kubelets. L’accès anonyme et le port en lecture seule sont désactivés, et l’autorisation utilise le mode webhook.
- Audit. Les journaux d’audit sont actifs et arrivent au SIEM, avec des détections pour les exec, les modifications du RBAC et les lectures de secrets.
- RBAC. Aucune liaison cluster-admin inattendue, aucun joker, et les permissions d’élévation sont examinées.
- Identité. Les jetons des comptes de service ne sont pas montés par défaut, et l’accès cloud utilise l’identité de charge de travail.
- Charges de travail. Les namespaces applicatifs appliquent le Pod Security Standard restricted.
- Politique. La politique d’admission n’autorise que des images signées provenant de votre registre, figées par digest.
- Réseau. Chaque namespace a une politique de refus par défaut, le trafic sortant est contrôlé et le point de métadonnées est bloqué.
- Nœuds. Images d’OS minimales, remplacées selon un calendrier, sans accès SSH courant.
- Exécution. La détection à l’exécution est déployée et ses alertes sont traitées.
- Versions. Le cluster et ses extensions utilisent des versions supportées et corrigées.
Conclusion
Kubernetes offre de solides contrôles de sécurité, mais presque aucun n’est actif par défaut. Les clusters compromis ont généralement une API ouverte, un rôle trop large, un pod privilégié ou un composant que personne n’a mis à jour. Fermez l’API, accordez peu, appliquez les paramètres de pod restricted, refusez le trafic réseau par défaut, contrôlez quelles images peuvent s’exécuter, et surveillez le journal d’audit et l’exécution. Lancez kube-bench contre le CIS Benchmark pour mesurer où vous en êtes, corrigez les constats par ordre d’exposition, et relancez-le après chaque mise à jour.
Sources
- Documentation Kubernetes, Security Checklist.
- Documentation Kubernetes, Pod Security Standards.
- Documentation Kubernetes, Role Based Access Control Good Practices.
- Documentation Kubernetes, Service Accounts.
- Documentation Kubernetes, authentification et autorisation du kubelet.
- Documentation Kubernetes, utilisation d’un fournisseur KMS pour le chiffrement des données.
- Documentation Kubernetes, Auditing.
- Documentation Kubernetes, Validating Admission Policy.
- Documentation Kubernetes, Network Policies.
- Documentation Kubernetes, bonnes pratiques pour les Secrets Kubernetes.
- Versions de Kubernetes et durée de support.
- CIS Kubernetes Benchmark.
- NSA et CISA, Kubernetes Hardening Guide, version 1.2 (août 2022).
- OWASP Kubernetes Top 10 (2025).
- MITRE ATT&CK, matrice Containers.
- Microsoft, Threat Matrix for Kubernetes.
- Blog Kubernetes, Ingress-nginx CVE-2025-1974: What You Need to Know (mars 2025).
- Wiz Research, IngressNightmare (mars 2025).
- Blog Kubernetes, Ingress NGINX Retirement: What You Need to Know (novembre 2025).
- Aqua Security, RBAC Buster : porte dérobée dans les clusters via le RBAC Kubernetes (2023).
- Wired, cryptojacking du cloud de Tesla via une console Kubernetes ouverte (février 2018).
- Ticket Kubernetes 71411, CVE-2018-1002105, élévation de privilèges dans le serveur d’API.
- kube-bench, Aqua Security.
- Documentation de Trivy.
- Documentation de signature Sigstore cosign.
- Documentation de Kyverno.
- Documentation d’OPA Gatekeeper.
- Documentation de l’External Secrets Operator.
- Documentation de Falco.
- Kubernetes
- Sécurité des conteneurs
- RBAC
- Pod Security Standards
- Politiques réseau
- Contrôle d’admission
- Chaîne d’approvisionnement
- CIS Benchmark
- OWASP Kubernetes Top 10
- Durcissement