Skip to content

    Back to articles

    6 min read

    Kubernetes Pod user namespaces are worth piloting

    A different identity at the host boundary

    A process can be root inside a container without being root on the node. That distinction is the useful part of Pod user namespaces: Kubernetes maps the Pod’s users to different, unprivileged user IDs on the host. The Kubernetes user namespaces documentation describes this separation and explains that the process has privileges within its user namespace, but not outside it.

    Kubernetes 1.36 makes Pod user namespaces generally available. A Pod opts in with hostUsers: false:

    apiVersion: v1
    kind: Pod
    metadata:
      name: namespace-pilot
    spec:
      hostUsers: false
      containers:
        - name: app
          image: example/app:stable

    The relevant setting is on the Pod spec, so it belongs in the template for a Deployment or another workload controller as well. I would treat the setting as a change to the workload’s security boundary, not as a claim that the workload is now isolated from the host in every respect. The Kubernetes 1.36 announcement for user namespaces confirms the feature’s stable status and the hostUsers: false opt-in.

    The security gain is about what happens if a process crosses the container boundary. Without a user namespace, a process that runs as root in a container may have a more consequential identity on the host if another weakness lets it escape. With a user namespace, the host sees a mapped, unprivileged user instead. That can reduce the damage of a compromise; it does not stop the compromise itself, prevent every escape, or make the shared host kernel disappear. I would regard it as another layer between a compromised workload and the node, not as a substitute for deciding which workloads I trust to share a node.

    The flag is the easy part

    A Pod manifest does not tell me whether the node can actually run that Pod. User namespaces are Linux-specific and depend on support in the kernel, the CRI container runtime, its OCI runtime, and the filesystem used for the relevant mounts. The Kubernetes prerequisites and filesystem notes are the starting point for checking those dependencies.

    That dependency chain matters especially when I run Kubernetes on my own infrastructure. A cluster can have nodes with different kernels, runtime versions, runtime configuration, or storage layouts. A manifest accepted by the API is not proof that every eligible node can start it. I would verify the requirements against the actual node pools and storage paths, then test scheduling and startup on each class of node that could receive the workload.

    Storage deserves its own test rather than a checkbox in a platform spreadsheet. User namespaces rely on idmapped mounts, and support depends on the filesystem and kernel combination. The Kubernetes documentation, for example, notes that NFS volumes cannot currently be mounted by a user-namespace Pod because the Linux NFS client does not support idmapped mounts. I would test the real volume types, mount options, ownership expectations, and write paths used by the workload instead of assuming that a successful test with an ephemeral filesystem proves persistent storage will behave the same way.

    I would also inspect the image and its assumptions about file ownership. Container UIDs and GIDs are interpreted inside the namespace, while files and mounted volumes still have to work with the resulting mapping. An image that expects to write to a path owned by a particular numeric user, or a workload that depends on particular ownership when sharing files, may expose assumptions that were invisible before. The Kubernetes documentation on UID and GID mappings describes how IDs are mapped and the default range. I would check actual reads and writes, not infer compatibility from the fact that the process starts.

    What it does not replace

    User namespaces address the relationship between container users and host users. They do not replace a deliberate Pod security context, least-privilege capabilities, seccomp, or controls on which workloads may run together. Those controls answer different questions: what the process may do in its own environment, which kernel interfaces it may reach, and who is allowed to deploy it. My design would keep those controls and ask what additional risk the user namespace reduces.

    Nor should I assume that a Pod can use every host integration unchanged. The Kubernetes documentation lists restrictions for user-namespace Pods, including use of host namespaces and raw block devices. Workloads that depend on host-level process, IPC, or networking access—or on devices exposed through volumeDevices—need particular scrutiny. Some host-networking support is handled separately and has its own feature status and node requirements; the Kubernetes 1.36 security feature notes describe that distinction. I would not turn on the setting across a fleet before checking each workload’s actual Pod spec and dependencies.

    This is where the feature’s limits become an architectural question. If a workload needs host access that conflicts with the namespace boundary, I would make that exception explicit and consider whether the workload belongs in a separate node pool or needs a different isolation approach. I would not weaken the boundary for every Pod just to avoid examining one exceptional workload. Conversely, I would not force the setting onto a workload whose storage or device requirements make the feature incompatible and then treat the resulting operational friction as an implementation detail.

    What I would pilot before relying on it

    I would pick a workload that benefits from reducing host-side privilege but does not depend on host namespaces or unusual storage. Then I would test the failure paths as well as the happy path: scheduling onto each relevant node type, container startup, persistent volume mounts, file ownership, init containers, ephemeral debugging, and the operational workflows used to inspect or replace the Pod. Those are not claims that each workflow will fail; they are questions I would want answered before changing the default.

    I would observe startup errors and compare them with the platform’s existing signals. Kubernetes exposes kubelet metrics for user-namespaced Pod starts and errors, listed in the user namespaces documentation’s metrics section. I would use those alongside events and application-level checks. A Pod that starts is not necessarily a workload that behaves correctly, and a metric without a clear owner or response path does not make the rollout safer.

    I would also write down the boundary I expect the feature to improve and the boundaries it does not. If the goal is to reduce the host privileges of a process after a container escape, user namespaces are relevant. If the requirement is protection from a shared-kernel vulnerability, this feature alone does not provide a separate kernel. If the workload requires host access, I need to decide whether that access is essential and whether another isolation design fits better.

    My position is to pilot Pod user namespaces, not to assume that general availability makes them operationally universal. The feature gives me a useful layer: container root need not mean host root. I would rely on it only after validating the runtime, filesystem, workload compatibility, and node placement assumptions that make that layer real.

    Drafted with AI assistance, reviewed and edited by Ali.