<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Rbac on Zwindler's Reflection</title><link>https://blog.zwindler.fr/tags/rbac/</link><description>Recent content in Rbac on Zwindler's Reflection</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>Licensed under CC BY-SA 4.0</copyright><lastBuildDate>Tue, 28 Apr 2026 10:00:00 +0200</lastBuildDate><atom:link href="https://blog.zwindler.fr/tags/rbac/index.xml" rel="self" type="application/rss+xml"/><item><title>UserNamespaces dans Kubernetes : la feature géniale qui sert (presque) à rien</title><link>https://blog.zwindler.fr/2026/04/28/kubernetes-usernamespaces/</link><pubDate>Tue, 28 Apr 2026 10:00:00 +0200</pubDate><guid>https://blog.zwindler.fr/2026/04/28/kubernetes-usernamespaces/</guid><description>&lt;img src="https://blog.zwindler.fr/2026/04/usernamespaces.webp" alt="Featured image of post UserNamespaces dans Kubernetes : la feature géniale qui sert (presque) à rien" /&gt;&lt;h2 id="linfographie-qui-ma-trigger"&gt;L&amp;rsquo;infographie qui m&amp;rsquo;a trigger
&lt;/h2&gt;&lt;p&gt;Depuis quelques jours, les infographies se suivent (et se ressemblent) sur Linkedin. Kubernetes 1.36 est sorti et une des features qui fait le plus parler, c&amp;rsquo;est la sortie en GA des &lt;strong&gt;UserNamespaces&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est un sujet que je suis depuis 2018 (talk &lt;a class="link" href="https://blog.zwindler.fr/2018/05/03/recap-du-premier-jour-de-kubecon-europe-2018/" target="_blank" rel="noopener"
&gt;The Route to rootless container&lt;/a&gt; à la kubecon EU de 2018) donc je peux dire que je suis content de voir l&amp;rsquo;aboutissement de ce long chemin. Cependant, je suis &amp;ldquo;profondément choqué&amp;rdquo; de voir la façon dont c&amp;rsquo;est présenté sur LinkedIn, visiblement par des gens qui n&amp;rsquo;ont aucune idée de comment ça fonctionne (et qui probablement, s&amp;rsquo;en fichent).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Kubernetes just made root safer. Just add &lt;code&gt;hostUsers: false&lt;/code&gt; to your Pod spec.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Le visuel : un roi tout-puissant &amp;ldquo;inside the container&amp;rdquo; et un mendiant impuissant &amp;ldquo;outside on the host&amp;rdquo;. La promesse : &amp;ldquo;No Host Access. No Privilege Escalation. No Lateral Movement. No Node Takeover.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;C&amp;rsquo;est accrocheur.&lt;/p&gt;
&lt;p&gt;Mais c&amp;rsquo;est surtout hyper grave de le présenter comme ça, parce que ça occulte des pans entiers de sécurité applicative et opérationnelle. Vendre &lt;code&gt;hostUsers: false&lt;/code&gt; comme le remède universel au problème du &amp;ldquo;root dans les containers&amp;rdquo;, c&amp;rsquo;est une simplification dramatique qui va pousser des équipes à ignorer les vraies &lt;strong&gt;priorités&lt;/strong&gt; de sécurité.&lt;/p&gt;
&lt;h2 id="ce-que-les-usernamespaces-font-réellement-sans-bullshit"&gt;Ce que les UserNamespaces font réellement, sans bullshit
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Le threat model : le container escape&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Avant tout, de quoi parle-t-on exactement ? Un &lt;strong&gt;container escape&lt;/strong&gt; (évasion de container), c&amp;rsquo;est quand un attaquant réussit à sortir de son container et à accéder directement au kernel ou au système de fichiers de l&amp;rsquo;hôte, en bypassant complètement les mécanismes d&amp;rsquo;isolation habituels.&lt;/p&gt;
&lt;p&gt;Ce type de vulnérabilité est &lt;strong&gt;rare&lt;/strong&gt;, mais des exemples bien réels existent :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a class="link" href="https://nvd.nist.gov/vuln/detail/CVE-2019-5736" target="_blank" rel="noopener"
&gt;CVE-2019-5736&lt;/a&gt;&lt;/strong&gt; (runc) : écriture dans &lt;code&gt;/proc/self/exe&lt;/code&gt; du process hôte depuis le container&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a class="link" href="https://nvd.nist.gov/vuln/detail/CVE-2022-0492" target="_blank" rel="noopener"
&gt;CVE-2022-0492&lt;/a&gt;&lt;/strong&gt; (cgroups v1) : escape via &lt;code&gt;unshare&lt;/code&gt; dans certaines configurations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a class="link" href="https://nvd.nist.gov/vuln/detail/CVE-2024-21626" target="_blank" rel="noopener"
&gt;CVE-2024-21626&lt;/a&gt;&lt;/strong&gt; (runc, &amp;ldquo;Leaky Vessels&amp;rdquo;) : fuite de file descriptor vers le répertoire de travail de l&amp;rsquo;hôte&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;S&amp;rsquo;il y a une faille de ce type sur votre Node ET qu&amp;rsquo;un process est compromis ET s&amp;rsquo;il tourne en root dans le container ET qu&amp;rsquo;il n&amp;rsquo;a pas les UserNamespaces, l&amp;rsquo;attaquant obtient &lt;strong&gt;root sur l&amp;rsquo;hôte&lt;/strong&gt;, c&amp;rsquo;est &lt;strong&gt;game over&lt;/strong&gt;. Accès à tous les fichiers du Node, à tous les secrets montés par les autres pods, possibilité d&amp;rsquo;installer un rootkit ou d&amp;rsquo;exfiltrer les données de tous les tenants présents sur le Node.&lt;/p&gt;
&lt;p&gt;Ca reste possible, mais ça fait beaucoup de &amp;ldquo;si&amp;rdquo;. Quoiqu&amp;rsquo;il en soit, c&amp;rsquo;est exactement ce scénario que les UserNamespaces adressent. Ils introduisent un &lt;strong&gt;mapping d&amp;rsquo;UID&lt;/strong&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;L&amp;rsquo;UID 0 dans le container est mappé vers un UID non-privilégié sur l&amp;rsquo;hôte (ex: 100000, propre à chaque pod)&lt;/li&gt;
&lt;li&gt;Si un attaquant réussit à s&amp;rsquo;échapper du container via un exploit kernel, il se retrouve &lt;strong&gt;&lt;code&gt;nobody&lt;/code&gt;&lt;/strong&gt; sur le node, l&amp;rsquo;escape réussit, mais l&amp;rsquo;impact post-escape est dramatiquement réduit&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;C&amp;rsquo;est le scénario &amp;ldquo;Breakouts Lose Impact&amp;rdquo; de l&amp;rsquo;infographie, et là-dessus, &lt;strong&gt;l&amp;rsquo;infographie dit vrai&lt;/strong&gt;. C&amp;rsquo;est le vrai apport de la feature.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cas particulier : le multi-tenant même en non-root&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Même sans container root, les UserNamespaces apportent aussi quelque chose dans un contexte &lt;strong&gt;vraiment multi-tenant&lt;/strong&gt; (plusieurs clients différents sur le même cluster). Sans UserNamespaces, si deux pods de clients différents tournent tous les deux avec &lt;code&gt;runAsUser: 1000&lt;/code&gt;, ils partagent le même UID 1000 sur le node. En cas d&amp;rsquo;escape sur l&amp;rsquo;un, l&amp;rsquo;attaquant peut accéder aux fichiers de l&amp;rsquo;autre pod qui ont le même propriétaire. Le mapping UID de UserNamespaces, en donnant un offset unique à chaque pod, isole les UID entre pods même à valeur identique dans le container.&lt;/p&gt;
&lt;p&gt;Pour les clusters internes où vous contrôlez tous les workloads, ce scénario est théorique. Pour une plateforme SaaS multi-tenant ou un service de build public, c&amp;rsquo;est une vraie ligne de défense.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prérequis techniques&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Pour pouvoir bénéficier de cette feature, il y a quelques prérequis, mais la majorité des clusters à jour devraient pouvoir se qualifier.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kernel Linux ≥ 5.19&lt;/li&gt;
&lt;li&gt;Runtime compatible (containerd ≥ 1.7, CRI-O ≥ 1.25)&lt;/li&gt;
&lt;li&gt;Support des &lt;em&gt;idmapped mounts&lt;/em&gt; pour les volumes persistants (XFS, ext4, mais pas NFS dans tous les cas par exemple)&lt;/li&gt;
&lt;li&gt;Kubernetes ≥ 1.33 (Beta), ≥ 1.36 (GA)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="ce-que-linfographie-exagère-et-ce-quelle-oublie"&gt;Ce que l&amp;rsquo;infographie exagère (et ce qu&amp;rsquo;elle oublie)
&lt;/h2&gt;&lt;p&gt;L&amp;rsquo;infographie a donc raison sur un point précis : UserNamespaces réduit l&amp;rsquo;impact d&amp;rsquo;un container escape réussi. C&amp;rsquo;est réel. Le problème, c&amp;rsquo;est qu&amp;rsquo;elle vend la feature comme solution universelle au &amp;ldquo;root dans les containers&amp;rdquo;, et là c&amp;rsquo;est n&amp;rsquo;importe quoi.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. L&amp;rsquo;isolation de l&amp;rsquo;UID n&amp;rsquo;est pas une isolation des privilèges applicatifs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;infographie promet &amp;ldquo;No Lateral Movement&amp;rdquo;. C&amp;rsquo;est faux (et archi faux).&lt;/p&gt;
&lt;p&gt;Un container root avec &lt;code&gt;hostUsers: false&lt;/code&gt; peut toujours lire le &lt;strong&gt;ServiceAccount Token&lt;/strong&gt; monté dans &lt;code&gt;/var/run/secrets/kubernetes.io/serviceaccount/token&lt;/code&gt;. Si ce token a des permissions RBAC étendues (ce qui arrive, on en reparlera peut être dans un autre article prochainement), l&amp;rsquo;attaquant peut appeler l&amp;rsquo;API Server, énumérer les ressources du cluster, et se déplacer latéralement, le tout sans jamais toucher le Node hôte.&lt;/p&gt;
&lt;p&gt;Le mapping d&amp;rsquo;UID protège l&amp;rsquo;hôte. Il ne protège pas le cluster.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Un container root reste root dans le container&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Install Anything ✅&amp;rdquo; — c&amp;rsquo;est littéralement écrit dans l&amp;rsquo;infographie, présenté comme un avantage 😖.&lt;/p&gt;
&lt;p&gt;Dans un container root (même avec UserNS), un attaquant qui prend la main peut :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Installer &lt;code&gt;nmap&lt;/code&gt;, &lt;code&gt;curl&lt;/code&gt;, &lt;code&gt;nc&lt;/code&gt; pour scanner le réseau interne&lt;/li&gt;
&lt;li&gt;Modifier les fichiers de l&amp;rsquo;application, les binaires, les configurations&lt;/li&gt;
&lt;li&gt;Lire tous les fichiers montés en volume&lt;/li&gt;
&lt;li&gt;Persister dans le container entre les redémarrages si le filesystem est writable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Les UserNamespaces ne retirent aucun de ces vecteurs d&amp;rsquo;attaque. Pouvoir ajouter des logiciels, c&amp;rsquo;est la garantie d&amp;rsquo;un mouvement latéral rapide (là encore).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. C&amp;rsquo;est pas si facile, surtout pour le sto&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Activer &lt;code&gt;hostUsers: false&lt;/code&gt; casse le stockage existant dans la plupart des cas.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;UID 0 du container est mappé sur l&amp;rsquo;UID 100000+ sur l&amp;rsquo;hôte (chaque container a son propre &amp;ldquo;offset&amp;rdquo;). Si un volume persistant (NFS, EBS, Ceph RBD) appartient à l&amp;rsquo;UID 1000, le container root ne peut ni lire ni écrire dessus. Le résultat : des &lt;code&gt;Permission Denied&lt;/code&gt; contre intuitifs, potentiellement complexes à diagnostiquer car l&amp;rsquo;application n&amp;rsquo;a probablement pas été conçue, si elle est root, pour ne pas avoir accès à ses propres fichiers.&lt;/p&gt;
&lt;p&gt;La solution technique existe (&lt;em&gt;idmapped mounts&lt;/em&gt;), mais elle nécessite un kernel récent et un filesystem compatible. Voir la &lt;a class="link" href="https://www.kernel.org/doc/html/latest/filesystems/idmappings.html" target="_blank" rel="noopener"
&gt;documentation officielle des idmapped mounts&lt;/a&gt; pour les détails.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. Idem, mais pour le réseau&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;hostUsers: false&lt;/code&gt; est incompatible avec &lt;code&gt;hostNetwork: true&lt;/code&gt;. C&amp;rsquo;est un détail, mais il piège les workloads réseau (agents de monitoring, CNI plugins, etc.).&lt;/p&gt;
&lt;p&gt;Note : cela dit, avoir des containers en hostNetwork est &lt;strong&gt;un autre souci de sécurité&lt;/strong&gt;, donc bon&amp;hellip;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="comparaison-sans-bullshit--userns-vs-les-alternatives-existantes"&gt;Comparaison sans bullshit : UserNS vs les alternatives existantes
&lt;/h2&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left"&gt;Vecteur d&amp;rsquo;attaque&lt;/th&gt;
&lt;th style="text-align: center"&gt;UserNS (root inside)&lt;/th&gt;
&lt;th style="text-align: center"&gt;Non-root (UID 1000)&lt;/th&gt;
&lt;th style="text-align: center"&gt;Distroless / Scratch&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;Impact post-escape si container escape réussi&lt;/td&gt;
&lt;td style="text-align: center"&gt;✅ Nobody sur l&amp;rsquo;hôte&lt;/td&gt;
&lt;td style="text-align: center"&gt;⚠️ UID 1000 sur l&amp;rsquo;hôte&lt;/td&gt;
&lt;td style="text-align: center"&gt;⚠️ UID 1000 sur l&amp;rsquo;hôte&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;Isolation UID entre pods (multi-tenant)&lt;/td&gt;
&lt;td style="text-align: center"&gt;✅ Offset unique par pod&lt;/td&gt;
&lt;td style="text-align: center"&gt;❌ UID partagé sur le node&lt;/td&gt;
&lt;td style="text-align: center"&gt;❌ UID partagé sur le node&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;Installation de malwares dans le container&lt;/td&gt;
&lt;td style="text-align: center"&gt;❌ Facile&lt;/td&gt;
&lt;td style="text-align: center"&gt;⚠️ Difficile&lt;/td&gt;
&lt;td style="text-align: center"&gt;✅ Quasi impossible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;Persistance dans le container&lt;/td&gt;
&lt;td style="text-align: center"&gt;❌ Totale&lt;/td&gt;
&lt;td style="text-align: center"&gt;⚠️ Limitée&lt;/td&gt;
&lt;td style="text-align: center"&gt;✅ Quasi impossible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;Mouvement latéral via SA Token&lt;/td&gt;
&lt;td style="text-align: center"&gt;❌ Possible&lt;/td&gt;
&lt;td style="text-align: center"&gt;❌ Possible&lt;/td&gt;
&lt;td style="text-align: center"&gt;⚠️ Potentiellement difficile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;Complexité opérationnelle&lt;/td&gt;
&lt;td style="text-align: center"&gt;❌ Parfois élevée&lt;/td&gt;
&lt;td style="text-align: center"&gt;✅ Souvent quasi nulle&lt;/td&gt;
&lt;td style="text-align: center"&gt;✅ Souvent faible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;Compatibilité stockage existant&lt;/td&gt;
&lt;td style="text-align: center"&gt;❌ Parfois problématique&lt;/td&gt;
&lt;td style="text-align: center"&gt;✅ Standard&lt;/td&gt;
&lt;td style="text-align: center"&gt;✅ Standard&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;La lecture de la table révèle la vraie nature d&amp;rsquo;UserNamespaces, il excelle sur &lt;strong&gt;exactement deux lignes&lt;/strong&gt; :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;l&amp;rsquo;impact post-escape&lt;/li&gt;
&lt;li&gt;l&amp;rsquo;isolation UID en multi-tenant.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sur tout le reste, non-root + distroless fait mieux, ou aussi bien, sans la complexité opérationnelle. Et ce sont ces &amp;ldquo;tout le reste&amp;rdquo; (persistance, installation de malwares, mouvement latéral via SA Token) qui représentent la grande majorité des vecteurs d&amp;rsquo;attaque réels, bien plus fréquents qu&amp;rsquo;un container escape. On en reparlera dans la section &lt;a class="link" href="#o%c3%b9-investir-son-budget-s%c3%a9curit%c3%a9" &gt;Où investir son budget sécurité&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="les-vrais-cas-dusage"&gt;Les vrais cas d&amp;rsquo;usage
&lt;/h2&gt;&lt;p&gt;Ce serait malhonnête de tout rejeter. Il existe trois scénarios où les UserNamespaces ne sont pas une option &amp;ldquo;fainéante&amp;rdquo; mais une &lt;em&gt;nécessité&lt;/em&gt; technique (et encore, ça se discute).&lt;/p&gt;
&lt;h3 id="1-build-as-a-service-buildah-rootless-podman"&gt;1. Build-as-a-Service (Buildah, rootless Podman)
&lt;/h3&gt;&lt;p&gt;Pour construire une image Docker, le moteur de build doit pouvoir faire des &lt;code&gt;chown&lt;/code&gt;, &lt;code&gt;chmod&lt;/code&gt; et &lt;code&gt;mknod&lt;/code&gt;. Ces opérations nécessitent &lt;code&gt;CAP_CHOWN&lt;/code&gt; et &lt;code&gt;CAP_FOWNER&lt;/code&gt;. Avant les UserNamespaces, la solution était de lancer le pod en &lt;code&gt;--privileged&lt;/code&gt;, ce qui est évidemment une porte ouverte sur l&amp;rsquo;hôte.&lt;/p&gt;
&lt;p&gt;Avec &lt;code&gt;hostUsers: false&lt;/code&gt;, le moteur de build a l&amp;rsquo;illusion d&amp;rsquo;être root pour manipuler ses fichiers, mais il est incapable d&amp;rsquo;impacter l&amp;rsquo;hôte. C&amp;rsquo;est le seul cas où &amp;ldquo;root inside&amp;rdquo; est une contrainte technique et non de la dette.&lt;/p&gt;
&lt;p&gt;Note : &lt;a class="link" href="https://github.com/GoogleContainerTools/kaniko" target="_blank" rel="noopener"
&gt;Kaniko&lt;/a&gt;, longtemps la référence pour le build in-cluster, est archivé depuis juin 2025 et ne reçoit plus de mises à jour de sécurité. Buildah ou rootless Podman sont les alternatives actives.&lt;/p&gt;
&lt;p&gt;Mon avis : ça peut être éventuellement utile pour les plateformes CI/CD mutualisées (GitLab Runners, Tekton) qui refusent les pods privilégiés. Mais si l&amp;rsquo;isolation est critique (plateforme publique, multi-tenant agressif), les microVMs (Kata Containers, Firecracker) offrent une garantie bien supérieure pour un overhead devenu raisonnable.&lt;/p&gt;
&lt;h3 id="2-multi-tenancy-hostile-plateformes-de-code-utilisateur"&gt;2. Multi-tenancy hostile (plateformes de code utilisateur)
&lt;/h3&gt;&lt;p&gt;Si votre métier est de faire tourner du code fourni par des inconnus (PaaS, éditeur de code en ligne, CI/CD publique), vous savez d&amp;rsquo;avance que l&amp;rsquo;utilisateur &lt;em&gt;va&lt;/em&gt; essayer d&amp;rsquo;escalader ses privilèges. Dans ce contexte, l&amp;rsquo;UserNS est une barrière supplémentaire contre les 0-day kernel.&lt;/p&gt;
&lt;p&gt;Mon avis : honnêtement, si l&amp;rsquo;environnement est vraiment &lt;strong&gt;hostile&lt;/strong&gt;, l&amp;rsquo;UserNS seul n&amp;rsquo;est pas suffisant. Les microVMs (Kata Containers, Firecracker) offrent une isolation matérielle réelle et sont le choix correct pour ce cas. L&amp;rsquo;UserNS peut être un complément, pas un substitut.&lt;/p&gt;
&lt;h3 id="3-legacy-hard-coded-postfix-dovecot-bind"&gt;3. Legacy &amp;ldquo;hard-coded&amp;rdquo; (Postfix, Dovecot, BIND)
&lt;/h3&gt;&lt;p&gt;Certains vieux démons UNIX démarrent en root pour ouvrir un port &amp;lt; 1024 ou lire des fichiers de config sensibles, puis &amp;ldquo;drop&amp;rdquo; leurs privilèges via &lt;code&gt;setuid()&lt;/code&gt;. Ce mécanisme échoue dans un container non-root classique.&lt;/p&gt;
&lt;p&gt;Les UserNamespaces permettent à ces processus de croire qu&amp;rsquo;ils peuvent faire leurs appels système de gestion d&amp;rsquo;identité, car ils sont root dans leur namespace.&lt;/p&gt;
&lt;p&gt;Voici un exemple concret écrit par un collègue (thanks Louis 😘) :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;apiVersion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;v1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;Pod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;postfix&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;hostUsers: false # mapping UID &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;root dans le container → nobody sur l&amp;#39;hôte&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;securityContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runAsNonRoot: false # autorisé en PSS Restricted *uniquement* grâce à hostUsers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;fsGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;103&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# GID postfix&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;postfix&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;postfix:latest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;securityContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runAsNonRoot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# idem, cf. https://kubernetes.io/docs/concepts/workloads/pods/user-namespaces/#integration-with-pod-security-admission-checks&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;allowPrivilegeEscalation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;readOnlyRootFilesystem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;seccompProfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;RuntimeDefault&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ALL&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# d&amp;#39;abord, on drop tout&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;add&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;SETUID &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# on ajoute SETUID mais le drop de privilèges via setuid() &lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# est fait par postfix lui-même au démarrage &lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;SETGID &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# idem pour les groupes&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;CHOWN &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# chown sur les queues au démarrage&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;FOWNER &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# opérations sur fichiers sans être propriétaire&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="l"&gt;FSETID &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# conserver le setuid bit après écriture&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;DAC_OVERRIDE # OBLIGATOIRE &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;root dans UserNS n&amp;#39;est pas &amp;#34;vrai&amp;#34; root,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# les vérifications DAC ne sont pas contournées automatiquement&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Ce manifest illustre plusieurs choses importantes.&lt;/p&gt;
&lt;p&gt;D&amp;rsquo;abord, c&amp;rsquo;est très pénible de rendre une application legacy secure avec les UserNS, et il faut faire des compromis, notamment sur les capabilities (on est loin de la feature magique qui sécurise les apps root).&lt;/p&gt;
&lt;p&gt;Ensuite, on remarque des trucs rigolos. Normalement, la policy &lt;code&gt;Restricted&lt;/code&gt; (Pod Security Standard) interdit &lt;code&gt;runAsNonRoot: false&lt;/code&gt;. Kubernetes fait une exception quand &lt;code&gt;hostUsers: false&lt;/code&gt; est présent. C&amp;rsquo;est documenté &lt;a class="link" href="https://kubernetes.io/docs/concepts/workloads/pods/user-namespaces/#integration-with-pod-security-admission-checks" target="_blank" rel="noopener"
&gt;ici&lt;/a&gt;. Sans UserNamespaces, ce pod serait rejeté par l&amp;rsquo;admission controller.&lt;/p&gt;
&lt;p&gt;De plus, on doit ajouter la &lt;strong&gt;capacité &lt;code&gt;DAC_OVERRIDE&lt;/code&gt;&lt;/strong&gt;, ce qui est contre-intuitif. root dans un UserNS n&amp;rsquo;est pas un vrai root du point de vue du kernel pour les vérifications DAC (Discretionary Access Control). Quand Postfix essaie de faire &lt;code&gt;set-permissions&lt;/code&gt; pour &lt;code&gt;chown&lt;/code&gt; ses queues, le kernel vérifie quand même les permissions ; et les refuse si &lt;code&gt;DAC_OVERRIDE&lt;/code&gt; n&amp;rsquo;est pas là. C&amp;rsquo;est exactement le genre de surprise opérationnelle invisible jusqu&amp;rsquo;au premier déploiement en production.&lt;/p&gt;
&lt;p&gt;On notera malgré tout qu&amp;rsquo;on a pu garder &lt;code&gt;readOnlyRootFilesystem: true&lt;/code&gt; et &lt;code&gt;allowPrivilegeEscalation: false&lt;/code&gt; ; le legacy ne justifie pas de tout sacrifier.&lt;/p&gt;
&lt;p&gt;Mon avis : c&amp;rsquo;est le seul cas d&amp;rsquo;usage où l&amp;rsquo;UserNS est vraiment acceptable. Pas de code tiers non maîtrisé, pas de plateforme hostile, juste du legacy bien identifié &lt;strong&gt;avec un plan de migration&lt;/strong&gt; ultérieur. Les deux autres cas sont &amp;ldquo;acceptables sous conditions&amp;rdquo;, le legacy reste le plus propre des trois.&lt;/p&gt;
&lt;h2 id="quelques-contre-arguments"&gt;Quelques contre-arguments
&lt;/h2&gt;&lt;p&gt;Je vous vois arriver avec quelques contre arguments, donc pour gagner du temps à tout le monde, je vais faire les questions et les réponses :&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;C&amp;rsquo;est de la défense en profondeur.&amp;rdquo;&lt;/strong&gt;
&amp;ldquo;Vrai, mais&amp;rdquo;&amp;hellip; La défense en profondeur suppose qu&amp;rsquo;on a déjà posé les couches de base. Si vous n&amp;rsquo;avez pas encore migré vos images vers un user non-root, mettre de l&amp;rsquo;énergie sur l&amp;rsquo;UserNS est un non-sens. Et une fois en non-root, le gain marginal de l&amp;rsquo;UserNS est négligeable face à la complexité qu&amp;rsquo;il introduit.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;On ne contrôle pas les images tierces.&amp;rdquo;&lt;/strong&gt;
Argument un peu faible, à mon avis : si vous avez une image blackbox de votre éditeur propriétaire, qui est codée pour tourner en root, il y a de fortes chances :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;soit qu&amp;rsquo;elle en ait réellement besoin pour fonctionner (typiquement, le cas pour certains outils de sécurité propriétaires)&lt;/li&gt;
&lt;li&gt;soit qu&amp;rsquo;elle gère mal le mapping d&amp;rsquo;UID (cf. le problème de stockage).
L&amp;rsquo;UserNS n&amp;rsquo;est pas une baguette magique qui rend n&amp;rsquo;importe quelle image tierce compatible et sécurisée.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;C&amp;rsquo;est un garde-fou contre les erreurs humaines.&amp;rdquo;&lt;/strong&gt;
Il est aussi facile d&amp;rsquo;oublier &lt;code&gt;hostUsers: false&lt;/code&gt; que d&amp;rsquo;oublier &lt;code&gt;runAsNonRoot: true&lt;/code&gt;. La vraie solution centralisée, ce sont les &lt;strong&gt;Pod Security Standards&lt;/strong&gt; ou un Admission Controller (Kyverno, OPA) qui rejettent purement et simplement les pods root. C&amp;rsquo;est plus simple, plus fiable, et ça ne casse pas le stockage.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;On en a besoin pour la compliance SOC2/PCI-DSS/&amp;hellip;&amp;rdquo;&lt;/strong&gt;
Si votre compliance exige une isolation stricte entre tenants, l&amp;rsquo;UserNS sera probablement jugé insuffisant par vos auditeurs. Les VMs ou microVMs restent le standard. Utiliser l&amp;rsquo;UserNS pour la compliance, c&amp;rsquo;est choisir l&amp;rsquo;outil le plus complexe à maintenir pour un résultat discutable.&lt;/p&gt;
&lt;h2 id="où-investir-son-budget-sécurité-"&gt;Où investir son budget sécurité ?
&lt;/h2&gt;&lt;p&gt;Si on met de côté le marketing, voici où l&amp;rsquo;effort paye vraiment, du plus impactant au plus niche :&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Priorité 1 — Images non-root + &lt;code&gt;nobody&lt;/code&gt; (UID 65534)&lt;/strong&gt;
Passer les images en non-root, idéalement vers l&amp;rsquo;utilisateur &lt;code&gt;nobody&lt;/code&gt; (le moins privilégié du système). Si une application est compromise sous &lt;code&gt;nobody&lt;/code&gt;, l&amp;rsquo;attaquant ne peut pratiquement rien faire, même sur le filesystem du container. À combiner avec &lt;code&gt;readOnlyRootFilesystem: true&lt;/code&gt; et &lt;code&gt;capabilities: drop: [&amp;quot;ALL&amp;quot;]&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;securityContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runAsNonRoot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;runAsUser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;65534&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# nobody&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;seccompProfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;RuntimeDefault&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;containers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;- &lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;app&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;my-app:distroless&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;securityContext&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;allowPrivilegeEscalation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ALL&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;readOnlyRootFilesystem&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Priorité 2 — Pod Security Standards (PSS) en mode &lt;code&gt;Baseline&lt;/code&gt; ou &lt;code&gt;Restricted&lt;/code&gt;&lt;/strong&gt;
Bloquer le root et les privilèges sans rien casser au niveau infra. Ça nécessite d&amp;rsquo;avoir déjà fait le point n°1, mais c&amp;rsquo;est gratuit, standard, et ça s&amp;rsquo;applique à tout le cluster via un label de namespace (et ça peut s&amp;rsquo;overrider par namespace si nécessaire). Plus de risque d&amp;rsquo;oubli possible. C&amp;rsquo;est déjà configuré par défaut sur plusieurs types de Kubernetes (je pense à Talos, mais ce n&amp;rsquo;est pas le seul).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Priorité 3 — MicroVMs (Kata Containers, Firecracker)&lt;/strong&gt;
Pour les workloads vraiment non-fiables. Isolation matérielle réelle, overhead devenu raisonnable sur les générations récentes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Priorité 4 — UserNamespaces&lt;/strong&gt;
When all else fail. Uniquement pour les cas légitimes identifiés ci-dessus (build, legacy, multi-tenancy hostile). C&amp;rsquo;est vraiment littéralement la &lt;strong&gt;dernière&lt;/strong&gt; chose à faire.&lt;/p&gt;
&lt;h2 id="conclusion"&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;Les UserNamespaces dans Kubernetes 1.36 sont l&amp;rsquo;aboutissement d&amp;rsquo;un chantier qui aura pris &amp;ldquo;officiellement&amp;rdquo; cinq ans (KEP-127 date de 2021) et dont on parle quasiment depuis la genèse de Kubernetes. Pour les plateformes de build mutualisées et les SaaS multi-tenants qui font tourner du code utilisateur, c&amp;rsquo;est une brique potentiellement intéressante (notamment pour éviter qu&amp;rsquo;une app d&amp;rsquo;un client lise les apps d&amp;rsquo;un autre en cas de container escape sans élévation de privilège).&lt;/p&gt;
&lt;p&gt;Pour le reste (c&amp;rsquo;est-à-dire 99% des clusters de production) c&amp;rsquo;est une distraction.&lt;/p&gt;
&lt;p&gt;Les infographies LinkedIn qui vendent une sécurité sans effort sont dangereuses : &amp;ldquo;gardez votre image root de 800 Mo pleine d&amp;rsquo;outils, ajoutez juste &lt;code&gt;hostUsers: false&lt;/code&gt;, et vous êtes protégés&amp;rdquo;. C&amp;rsquo;est exactement &lt;strong&gt;l&amp;rsquo;inverse de la bonne démarche&lt;/strong&gt;. La vraie sécurité container se construit dans le Dockerfile, pas dans le PodSpec.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Si vous activez les UserNamespaces pour sécuriser une application dont vous possédez le code source, vous avez probablement raté une étape dans votre cycle de développement sécurisé.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="références"&gt;Références
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/127-user-namespaces/README.md" target="_blank" rel="noopener"
&gt;KEP-127 : Support for User Namespaces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/docs/concepts/workloads/pods/user-namespaces/" target="_blank" rel="noopener"
&gt;Kubernetes docs — User Namespaces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://kubernetes.io/docs/concepts/security/pod-security-standards/" target="_blank" rel="noopener"
&gt;Pod Security Standards&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://nvd.nist.gov/vuln/detail/CVE-2019-5736" target="_blank" rel="noopener"
&gt;CVE-2019-5736&lt;/a&gt; — runc : écriture dans &lt;code&gt;/proc/self/exe&lt;/code&gt; du process hôte depuis le container&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://nvd.nist.gov/vuln/detail/CVE-2022-0492" target="_blank" rel="noopener"
&gt;CVE-2022-0492&lt;/a&gt; — cgroups v1 : escape via &lt;code&gt;unshare&lt;/code&gt;, UserNS aide mais &lt;code&gt;runAsNonRoot&lt;/code&gt; aussi&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://nvd.nist.gov/vuln/detail/CVE-2024-21626" target="_blank" rel="noopener"
&gt;CVE-2024-21626&lt;/a&gt; — runc &amp;ldquo;Leaky Vessels&amp;rdquo; : fuite de file descriptor vers le répertoire de travail de l&amp;rsquo;hôte&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/GoogleContainerTools/distroless" target="_blank" rel="noopener"
&gt;Distroless containers — GoogleContainerTools&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>