Kubernetes 1.37 verrouille enfin les volumes avec noexec, nosuid et un mode sur emptyDir
La version 1.37 de Kubernetes introduit deux réglages de sécurité du stockage, encore en alpha : des options de montage bind (noexec, nosuid, nodev) et un mode de permission sur les volumes emptyDir. Activez les feature gates VolumeBindMountOptions et EmptyDirVolumeMode pour remplacer les contournements par conteneur d’initialisation.
16 septembre 2026. Kubernetes v1.37 documente deux nouveautés de durcissement du stockage, toutes deux en alpha : les options de montage bind (noexec, nosuid, nodev) et un mode de permission sur les volumes emptyDir. 16 septembre. Les ingénieurs de Red Hat qui portent la fonction détaillent le « pourquoi » dans un billet du blog officiel. 20 septembre. Aucun cluster ne les applique encore par défaut : il faut activer deux feature gates. Pourquoi c’est important : depuis toujours, un processus compromis dans un conteneur peut exécuter un binaire depuis n’importe quel volume inscriptible — même avec un système de fichiers racine en lecture seule — faute de drapeau noexec posé par défaut.
Le trou que ces deux réglages comblent
Le point de départ est un détail du kubelet et des runtimes de conteneurs que peu d’équipes mesurent : quand un volume est monté en bind mount dans un conteneur, il l’est sans les drapeaux noexec, nosuid ni nodev. Autrement dit, tout volume inscriptible — un emptyDir, un PersistentVolume, un montage hostPath — est monté avec la permission d’exécuter ce qui s’y trouve.
La conséquence est directe. Un attaquant qui a obtenu une exécution de code dans un conteneur, même avec readOnlyRootFilesystem: true, peut télécharger un binaire dans le volume inscriptible, le rendre exécutable avec chmod +x, puis le lancer. Le système de fichiers racine est verrouillé, mais le volume ne l’est pas : la protection contournée devient un exercice de confort. La faille a été documentée depuis longtemps — l’audit de sécurité Kubernetes 1.24 (NCC-E003660-7HM) pointait déjà l’impossibilité de monter un emptyDir avec noexec comme un échec de sécurité, et l’issue #48912 traînait depuis des années.
Le second trou concerne les permissions des volumes emptyDir. Par défaut, un emptyDir est créé avec un mode 0777 codé en dur : n’importe quel processus qui découvre le volume peut lire, écrire et supprimer tout ce qu’il contient, quel que soit son propriétaire. La parade existante — un conteneur d’initialisation qui exécute un chmod — fonctionne, mais elle ajoute de la complexité, elle est difficile à auditer pour la conformité, et elle ne règle pas le cas du sticky bit (mode 01777), attendu sur tout répertoire partagé digne de /tmp, ni celui des permissions restreintes comme 0750.
Deux portes d’entrée, deux leviers
La 1.37 répond aux deux problèmes par deux mécanismes distincts et complémentaires.
Le premier, bindMountOptions, s’ajoute à la spécification d’un volumeMount. Il accepte exactement les trois drapeaux du VFS Linux que l’on attend d’un montage durci : noexec (interdit l’exécution de binaires), nosuid (neutralise les bits setuid/setgid) et nodev (ignore les fichiers spéciaux de type périphérique). C’est la réponse native à l’exigence des référentiels de durcissement — CIS, NSA/CISA, PCI-DSS — qui réclament précisément ces drapeaux sur les montages inscriptibles.
Le second, mode, s’ajoute au volume source emptyDir. Il permet de fixer la permission de création du répertoire : 01777 pour un espace de travail partagé qui se comporte comme /tmp, 0750 pour un répertoire restreint au propriétaire et à son groupe. Le sticky bit de 01777 change la donne dans les pods multi-conteneurs : un processus compromis dans un conteneur ne peut plus supprimer les artefacts produits par un autre conteneur du même pod, car seul le propriétaire d’un fichier (ou root) peut le supprimer.
Les deux fonctionnalités sont indépendantes et peuvent se combiner sur le même montage — par exemple un emptyDir partagé, monté en noexec,nosuid, avec un mode 01777.
Comment l’activer dès aujourd’hui
Les deux réglages sont derrière des feature gates alpha : VolumeBindMountOptions et EmptyDirVolumeMode, à activer sur l’API server et le kubelet. En 1.37, ils ne sont pas actifs par défaut, et leur statut alpha impose la prudence : la syntaxe peut évoluer, et il faut les valider sur un cluster de test avant de généraliser.
Le manifeste minimal pour monter un emptyDir en /tmp avec les drapeaux de durcissement :
apiVersion: v1
kind: Pod
metadata:
name: hardened-bindmount-pod
spec:
os:
name: linux
containers:
- name: hardened-app
image: alpine:latest
command: ["sleep", "3600"]
securityContext:
readOnlyRootFilesystem: true
volumeMounts:
- name: temp-storage
mountPath: /tmp
bindMountOptions:
- noexec
- nosuid
volumes:
- name: temp-storage
emptyDir: {} Et la variante qui impose un sticky bit sur un répertoire partagé, en forçant le mode de création :
apiVersion: v1
kind: Pod
metadata:
name: sticky-tmp-pod
spec:
containers:
- name: app
image: alpine:latest
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir:
mode: "01777" Le second manifeste remplace le conteneur d’initialisation qui exécutait chmod 1777 /tmp avant le démarrage de l’application : une ligne déclarative à la place d’un sidecar de contournement.
Ce que ça change concrètement
Les cas d’usage exposés par les auteurs sont précis, et ils parlent directement à une équipe plateforme.
- Empêcher l’escalade sur les montages inscriptibles. Un espace de travail temporaire monté en
noexec,nosuidgarantit que, même si l’application est compromise et qu’une charge est téléchargée, la charge ne peut ni s’exécuter ni exploiter un bit setuid pour escalader sur le nœud. - Sécuriser l’espace partagé des pods multi-conteneurs. Un pod de CI/CD avec un conteneur de build et un sidecar de log peut partager un volume en mode 01777 : chacun écrit librement, mais un processus compromis ne peut plus détruire les artefacts du voisin.
- Appliquer le moindre privilège aux données. Une base de données dont le stockage temporaire est monté en 0750 n’est lisible que par l’utilisateur et le groupe attendus, refusant l’accès à tout autre sidecar du pod.
Le point commun des trois scénarios : la sécurité se déclare dans le manifeste, pas dans un script d’initialisation. C’est exactement la direction que la communauté suit depuis plusieurs versions — penser la posture de sécurité comme une configuration auditable et reproductible, pas comme une série de rustines au démarrage.
Déployer des gates alpha sans casser le nœud
Comme les deux fonctionnalités sont en alpha, quelques détails opérationnels comptent avant de basculer. Les gates doivent être activées sur le kubelet et l’API server, ce qui impose un redémarrage roulant du plan de contrôle et du parc de nœuds — à planifier plutôt qu’à découvrir en cours de route. Les volumes existants ne sont pas affectés : les nouveaux champs ne s’appliquent qu’aux pods que vous annotez explicitement avec bindMountOptions ou un emptyDir.mode, donc activer les gates ne change pas le comportement des charges que vous laissez en l’état.
Le vrai travail est la vérification. Un pod qui ignore silencieusement la demande noexec serait pire qu’un pod qui ne l’a jamais formulée : confirmez donc que les drapeaux atteignent bien le runtime, par exemple en tentant d’exécuter un binaire depuis le volume monté dans un pod de test et en attendant l’échec. Et comme certains pilotes CSI et runtimes de conteneurs traduisent les options de montage de façon incohérente, testez contre le pilote et le runtime exacts que vous utilisez en production avant de migrer quoi que ce soit de sensible.
Verdict
Si vous exploitez des clusters multi-tenant, des pods de CI/CD ou des charges soumises à un référentiel de durcissement, activez VolumeBindMountOptions et EmptyDirVolumeMode sur un cluster de test dès la 1.37, et commencez à migrer vos montages inscriptibles vers noexec,nosuid avec un mode explicite — c’est le moyen le plus propre de fermer un trou d’exécution que la plupart des clusters laissent ouvert depuis toujours. Si vous restez en 1.36 ou avant, le contournement par conteneur d’initialisation avec chmod et un securityContext correct reste la seule voie, mais documentez-le : la conformité se prouve, elle ne se devine pas. Si vous ne faites ni l’un ni l’autre, au minimum posez noexec au niveau du nœud sur les répertoires de volumes et ajoutez le montage readOnlyRootFilesystem — une posture partielle vaut toujours mieux qu’un volume inscriptible exécutable par défaut.