User namespaces stabiel in Kubernetes 1.36: pod-isolatie zonder gVisor

Kubernetes 1.36 promoveert user namespaces naar stable. Een proces dat als root draait in een pod wordt op de host gemapt naar een onbevoegde UID, waardoor de impact van container-escapes beperkt blijft zonder de compatibiliteits- en prestatiekosten van gVisor of Kata Containers.

Kubernetes 1.36 verschijnt op 22 april en daarmee bereikt de UserNamespacesSupport feature gate de stable-status. De feature is al standaard ingeschakeld sinds 1.33, dus het GA-label draait niet om nieuwe functionaliteit. Het is een commitment: de API is bevroren, het gedrag is productiewaardig en de feature wordt niet meer verwijderd. Voor platform engineers die werken aan pod-isolatiestrategieën bieden user namespaces een duidelijke positie: sterkere isolatie dan runAsNonRoot alleen, zonder de compatibiliteits- en prestatiekosten van gVisor of Kata Containers.

TL;DR

  • User namespaces mappen container-UIDs naar onbevoegde host-UIDs. Root in de pod (UID 0) wordt op de node een hoge, onbevoegde UID (bijvoorbeeld 196608).
  • De opt-in is één veld: spec.hostUsers: false. Sinds 1.33 hoef je geen feature gate meer aan te zetten.
  • Runtime-vereisten: containerd 2.0+, Linux-kernel 6.3+ en een filesystem dat idmap mounts ondersteunt.
  • NFS-volumes ondersteunen geen idmap mounts en zijn een harde blocker.
  • User namespaces verkleinen de blast radius na een escape, maar vergroten het bereikbare kernel-aanvalsoppervlak. Combineer ze altijd met seccomp-profielen.

Inhoudsopgave

Wat user namespaces doen op kernelniveau

Linux user namespaces (CLONE_NEWUSER, beschikbaar sinds kernel 3.8) zorgen ervoor dat een proces met een andere UID/GID-mapping kan draaien dan de host. De kernel houdt twee sets IDs bij: de namespace-lokale IDs (wat het proces ziet) en de host-IDs (wat de kernel daadwerkelijk gebruikt voor permissiechecks op het bestandssysteem).

Als een pod hostUsers: false instelt, wijst de kubelet een unieke, niet-overlappende range van 65536 UIDs toe op de host. Een proces dat zichzelf als root (UID 0) ziet in de container draait op de node in werkelijkheid als een hoge onbevoegde UID – bijvoorbeeld 196608. Capabilities als CAP_SYS_ADMIN gelden alleen binnen de namespace en hebben geen autoriteit op de host.

Het praktische gevolg voor container-escapes: als een aanvaller uit de container runtime ontsnapt (zoals bij CVE-2024-21626, het runc file descriptor lek), komt die terecht als onbevoegde gebruiker op de host. Root-bestanden zoals kubeconfig of SSH-keys zijn onbereikbaar. De Kubernetes-blog beschrijft deze klasse van mitigatie als "greatly mitigated" voor meerdere historische CVEs, waaronder CVE-2019-5736 (runc binary overwrite) en CVE-2022-0492 (cgroup-escape).

De andere kritieke kernel-feature is idmap mounts (Linux 5.12+). Een idmap mount toont een filesystem met andere UID/GID-eigenaarschap zonder de on-disk inodes aan te passen. containerd 2.0 gebruikt dit voor de container-image rootfs via overlayfs: geen bestanden worden gechownd, geen storage wordt gedupliceerd en de opstarttijd wordt niet beïnvloed. Dat is een directe verbetering ten opzichte van containerd 1.7, dat bij het aanmaken van een pod fysiek elk bestand in de container-image chownde – met meetbare storage-overhead en langzamere opstarttijden tot gevolg.

Van alpha naar stable: de KEP-127 tijdlijn

User namespaces in Kubernetes worden bijgehouden onder KEP-127. Het duurde vier jaar om stable te bereiken, grotendeels omdat het runtime- en kernel-ecosysteem tijd nodig had om aan te sluiten.

Versie Status Belangrijkste wijziging
1.25 Alpha Alleen stateless pods; gate UserNamespacesStatelessPodsSupport
1.27 Alpha (herontwerp) Hernoemd naar UserNamespacesSupport; overschakeling naar idmap mounts
1.28 Alpha Stateless-beperking opgeheven; ondersteunt volumes
1.30 Beta Custom UID/GID-ranges; runtime moet support bevestigen
1.33 Beta, standaard aan Geen feature gate nodig
1.36 GA Feature gate vergrendeld; API bevroren

De 1.36-release introduceert ook een nieuwe alpha-feature: UserNamespacesHostNetworkSupport (KEP-5607). Hiermee kan een pod hostNetwork: true combineren met hostUsers: false, een combinatie die eerder door de API-server werd afgewezen. Dat is relevant voor CNI-plugins en node-level agents die host-netwerktoegang nodig hebben maar wel baat hebben bij UID-isolatie.

User namespaces inschakelen

De opt-in is één veld in de pod-spec:

apiVersion: v1
kind: Pod
metadata:
  name: isolated-workload
spec:
  hostUsers: false
  containers:
    - name: app
      image: my-app:latest

Sinds 1.33 is geen feature gate-configuratie meer nodig. De kubelet kent automatisch een unieke range van 65536 UIDs toe per pod.

Runtime- en kernelvereisten

Component Minimumversie
containerd 2.0 (ook een algemene 1.36-vereiste)
CRI-O 1.25+ (met crun)
runc 1.2+
crun 1.9+ (1.13+ aanbevolen)
Linux-kernel 6.3+

De kernel 6.3-vereiste draait specifiek om tmpfs idmap mount-ondersteuning. Kubernetes mount Secrets, ConfigMaps en service account tokens als tmpfs; zonder tmpfs idmap-ondersteuning falen die mounts voor user-namespaced pods. Overlayfs idmap mounts (voor de container-image rootfs) vereisen kernel 5.19+, maar 6.3 is de bindende constraint.

Combinaties die de API-server afwijst

  • hostUsers: false + hostPID: true
  • hostUsers: false + hostIPC: true
  • hostUsers: false + hostNetwork: true (tenzij de UserNamespacesHostNetworkSupport alpha-gate is ingeschakeld)
  • hostUsers: false + volumeDevices (raw block-volumes)

Wat er breekt (en wat niet)

NFS-volumes. NFS ondersteunt geen idmap mounts in de Linux-kernel. Pods met NFS PersistentVolumeClaims kunnen hostUsers: false niet gebruiken. Dit is waarschijnlijk de meest voorkomende productie-blocker.

Host-level capabilities werken niet meer. CAP_SYS_ADMIN in een user-namespaced pod kan geen kernelmodules laden of de systeemtijd wijzigen. Workloads die afhankelijk zijn van host-level capabilities (sommige monitoring agents, privileged DaemonSets) moeten op hostUsers: true blijven.

Cross-pod gedeelde volumes. Twee pods met verschillende UID-mappings die naar hetzelfde volume schrijven, zien elkaars bestanden als eigendom van unmapped UIDs. Als je cross-pod file sharing nodig hebt, moeten de pods hostUsers: true gebruiken.

Pod Security Standards. Onder het restricted Pod Security Standard is runAsNonRoot: true normaal gesproken verplicht. Met hostUsers: false versoepelt het beleid die check. De redenering: de non-root garantie op de host komt van de namespace-mapping, ongeacht de UID in de container.

Wat wel gewoon blijft werken: de meeste standaard workloads. De UID-remapping is transparant op kernelniveau. Een proces dat als root draait in de container leest en schrijft bestanden normaal; idmap mounts regelen de vertaling. fsGroup, runAsUser en supplementalGroups in securityContext verwijzen naar in-container UIDs, en de kubelet vertaalt die via de mapping naar host-UIDs.

User namespaces vs. de alternatieven

runAsNonRoot Seccomp User namespaces gVisor Kata Containers
Isolatie UID-afdwinging Syscall-filtering UID-remapping User-space kernel Hardware VM
UID na escape Zelfde UID op host Root als root Onbevoegde host-UID N.v.t. (geen host-kernel) N.v.t. (gastkernel)
Syscall-compat Volledig Volledig (min geblokte) Volledig ~76 niet geïmplementeerd Volledig
Perf. overhead Geen Verwaarloosbaar Geen Workload-afhankelijk ~150–300ms opstart
Volume-compat Volledig Volledig Geen NFS, geen raw block Beperkt Beperkt
Kernel-oppervlak Onveranderd Verkleind Vergroot Geminimaliseerd Geminimaliseerd

runAsNonRoot dwingt de in-container UID af maar biedt geen host-isolatie. Een escaped proces met UID 1000 in de container is ook UID 1000 op de host, met toegang tot alles van die UID.

Seccomp verkleint het aanvalsoppervlak door syscalls te filteren, maar mapt geen UIDs. Een rootcontainer met seccomp blijft na een escape gewoon root op de host. Het Kubernetes RuntimeDefault-profiel blokkeert circa 44 syscalls.

gVisor plaatst een user-space kernel (geschreven in Go) tussen de applicatie en de host-kernel. Sterkere pre-escape isolatie (de host-kernel wordt nooit direct aangesproken), maar 76 syscalls zijn niet geïmplementeerd en I/O-intensieve workloads merken meetbare overhead.

Kata Containers biedt hardware-afgedwongen isolatie via lichtgewicht VMs. De sterkste beschikbare isolatie, maar met 150–300ms opstarttijd en 600MB+ geheugen-overhead per pod.

User namespaces zitten in het gat tussen "UID-restricties afdwingen" en "een aparte kernel draaien." Geen prestatiekosten, volledige syscall-compatibiliteit, maar de host-kernel wordt wel gedeeld.

Wanneer user namespaces niet genoeg zijn

Dit is de sectie die ertoe doet bij security-architectuurbeslissingen.

Onderzoek van Edera toonde aan dat user namespaces het bereikbare kernel-aanvalsoppervlak vergroten vanuit onbevoegde containers. Zonder user namespaces kan een onbevoegde container 8 van 40 geteste kernel-subsystemen bereiken. Met user namespaces stijgt dat naar 27: een toename van 262%. De nieuw toegankelijke subsystemen zijn onder meer nftables (18 CVEs op het moment van het onderzoek, waaronder CVE-2024-1086 met een betrouwbare escape-rate van 99,4%) en overlayfs-mounting.

Het mechanisme: user namespaces verlenen in-namespace CAP_SYS_ADMIN, wat kernel-codepaden ontsluit die eerder achter volledige root-privileges zaten. De container kan die capabilities niet uitoefenen op de host, maar kan wel kernelcode triggeren die exploitbare kwetsbaarheden kan bevatten.

De juiste framing: user namespaces verkleinen de blast radius van een escape (de aanvaller komt onbevoegd terecht) terwijl ze de kans vergroten op het vinden van een exploitbare bug. Voor clusters met wederzijds wantrouwende tenants zijn user namespaces alleen niet voldoende. Kata Containers of gVisor bieden de benodigde kernel-isolatiegrens.

De praktische aanbeveling: schakel user namespaces in en pas seccomp-profielen toe (minimaal RuntimeDefault). Seccomp beperkt de extra syscalls die via user namespaces toegankelijk worden. Samen verminderen ze zowel de kans op een escape als de impact als er toch een optreedt.

Belangrijkste punten

  • User namespaces zijn stable in 1.36 en staan standaard aan sinds 1.33. De opt-in is spec.hostUsers: false in de pod-spec.
  • containerd 2.0 en Linux-kernel 6.3+ zijn harde vereisten. containerd 2.0 is ook een algemene Kubernetes 1.36-vereiste, los van user namespaces.
  • NFS-volumes zijn een blocker. Pods met NFS PVCs kunnen hostUsers: false niet gebruiken totdat de kernel NFS idmap-ondersteuning toevoegt.
  • User namespaces verkleinen de impact na een escape maar vergroten het bereikbare kernel-aanvalsoppervlak. Combineer ze altijd met seccomp-profielen voor defense in depth.
  • Voor strikte multi-tenant isolatie met wederzijds wantrouwende partijen blijven gVisor of Kata Containers nodig. User namespaces zijn een goedkope verbetering, geen complete isolatiegrens.

Terugkerende server- of deploymentproblemen?

Ik help teams productie betrouwbaar maken met CI/CD, Kubernetes en cloud—zodat fixes blijven en deploys geen stress meer zijn.

Bekijk DevOps consultancy

Doorzoek deze site

Begin met typen om te zoeken, of blader door de kennisbank en blog.