Running Kubernetes Node Components Without Root Privileges
By default, all Kubernetes node components — the kubelet, the container runtime (such as containerd or CRI-O), OCI runtimes (such as runc), CNI plugins, and kube-proxy — run as root on the host. When a container escape vulnerability exists in any of these components, an attacker who exploits it gains full root privileges on the node, with access to every pod's filesystem and every mounted secret on that host.
The KubeletInUserNamespace feature gate addresses this by running all node components inside a Linux user namespace, so the processes that would otherwise be host root are mapped to an unprivileged host user instead. The feature graduated to Beta (enabled by default) in Kubernetes v1.37.
What KubeletInUserNamespace Does
When the KubeletInUserNamespace feature gate is active, all of the node components — kubelet, CRI and OCI runtimes, CNI plugins, and kube-proxy — run as a non-root user on the host, inside a Linux user namespace.
Before (default without rootless mode): A container escape in the container runtime or kubelet grants the attacker root privileges on the host node. The attacker can read secrets mounted on the node, modify host files, and pivot to other pods.
After (rootless mode enabled): A container escape in the same runtime or kubelet lands the attacker as an unprivileged host user. The attacker cannot modify host-level files or escalate privileges to root on the host.
This does not eliminate container escape vulnerabilities — it reduces the blast radius of vulnerabilities in the node components themselves.
Distinguishing KubeletInUserNamespace from Pod User Namespaces
These are two separate features that address different layers of isolation.
| Feature | What runs in a user namespace | Feature gate | GA status |
|---|---|---|---|
hostUsers: false (User Namespace Pods) | The pod's workload processes | UserNamespacesSupport | Stable (v1.36) |
KubeletInUserNamespace (Rootless Node) | The kubelet, CRI runtime, CNI plugins, kube-proxy | KubeletInUserNamespace | Beta (v1.37) |
Setting hostUsers: false on a pod puts the pod's containers into a user namespace, but still runs all node components as root on the host. KubeletInUserNamespace does the opposite — it puts the node components into a user namespace while the setting of hostUsers on individual pods remains independent.
The two features are complementary. Using both provides isolation at both the node-component layer and the workload layer.
For details on hostUsers: false, see User Namespaces in Kubernetes.
Requirements
Before enabling rootless node operation, confirm the following prerequisites are met:
- Kubernetes v1.22 or later. The
KubeletInUserNamespacefeature gate was introduced in v1.22 (Alpha) and graduated to Beta (default: true) in v1.37. - Cgroup v2. Cgroup v1 is not supported. Verify with
stat -fc %T /sys/fs/cgroup/— the output must becgroup2fs. - systemd with user session support. Required for the delegated cgroup tree that allows unprivileged processes to manage their own cgroup hierarchy.
- Entries in
/etc/subuidand/etc/subgidfor the unprivileged user that will run the node components. These files define the UID and GID ranges that the user namespace maps to host IDs.
Managed Kubernetes services (EKS, GKE, AKS) do not expose these node-level configuration options. Rootless node operation is currently applicable to self-managed clusters and selected Kubernetes distributions that explicitly support it (see Deployment Methods below).
Feature Gate and Version History
| Kubernetes version range | Stage | Default |
|---|---|---|
| v1.22 – v1.36 | Alpha | false |
| v1.37+ | Beta | true |
Kubernetes v1.37 and later (Beta, default on): No explicit feature gate configuration is required. The kubelet and API server already have KubeletInUserNamespace enabled. The node still requires the prerequisites above (Cgroup v2, systemd user session, subuid/subgid entries) — enabling the feature gate without meeting those prerequisites will result in the node failing to start.
Kubernetes v1.22 – v1.36 (Alpha, default off): Enable the feature gate explicitly on the kubelet by adding --feature-gates=KubeletInUserNamespace=true to the kubelet's startup flags, or by adding it to the kubelet's configuration file:
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
featureGates:
KubeletInUserNamespace: true
Deployment Methods
The KubeletInUserNamespace feature gate works in combination with a user namespace for the host process. There are four established ways to set this up:
1. Inside Rootless Docker, Podman, or nerdctl
Tools like kind and minikube can create cluster nodes as rootless Docker or Podman containers. Node components inside those containers run inside the rootless daemon's user namespace, which is itself unprivileged on the host. The KubeletInUserNamespace gate must be enabled on the in-container kubelet.
2. Inside Kubernetes (User Namespace Pods — Kubernetes-in-Kubernetes)
Usernetes supports a Kubernetes-in-Kubernetes topology where inner cluster nodes run as pods with hostUsers: false. The node components in the inner cluster run inside the pod's user namespace and are therefore unprivileged on the outer host.
3. Inside Unprivileged Containers via Sysbox
Sysbox is a container runtime that enables system containers — containers that run full system software stacks, including Kubernetes nodes, without requiring root. Sysbox does not require Cgroup v2 or the KubeletInUserNamespace feature gate and uses its own isolation mechanism. It is an alternative deployment path for rootless nodes, not an additional layer on top of the feature gate.
4. Directly on Host
K3s includes an experimental rootless mode that runs all K3s components (including its embedded containerd and flannel CNI) as unprivileged processes on the host. This path uses unshare(1) or RootlessKit to create the user namespace before starting the node components.
Verification
After deploying with rootless mode enabled, confirm that the kubelet process is running as a non-root user on the host:
ps aux | grep kubelet | grep -v grep
The user column for the kubelet process should show the unprivileged user, not root. To inspect the UID mapping from within the user namespace:
cat /proc/$(pgrep -x kubelet)/status | grep -E '^Uid:|^Gid:'
On a correctly configured rootless node, the Uid line shows the unprivileged host UID (a value greater than 0), not 0 0 0 0.
For Kubernetes-level verification, the node should still register and become Ready normally:
kubectl get nodes
Pod scheduling, service account token projection, and network policies continue to function identically to a standard (rooted) node. The rootless configuration is transparent to workloads.
What This Feature Does Not Cover
- Pods on the node are not automatically placed into user namespaces. The rootless node protects against escapes through the node components. Escapes through container runtimes that land inside the node's user namespace (rather than the host root namespace) are still constrained by the node's user namespace, but pod-level user namespace isolation still requires
hostUsers: falseon each pod spec. - Not all Kubernetes features have been validated in rootless mode. Some advanced features that rely on direct host interaction (certain CSI drivers, eBPF-based CNI plugins, device plugins) may require additional configuration or may not be supported.
- The
/etc/subuidand/etc/subgidUID range allocation is not managed by Kubernetes. Cluster administrators are responsible for provisioning adequate UID/GID ranges on each node. An insufficient range will cause the node to fail to start.

References
This article is based on information from the following official sources:
- Running Kubernetes Node Components as a Non-root User - Kubernetes Documentation
- Feature Gates — KubeletInUserNamespace - Kubernetes Reference Documentation