---
title: Running pods in Linux user namespaces
---

# Running pods in Linux user namespaces {#nodes-pods-user-namespaces}

To enhance container security and prevent potential breakouts, you can isolate pod processes by using Linux user namespaces. By using this configuration, you can allow containers to run with administrative privileges inside the namespace, but remain unprivileged on the host system.

Linux user namespaces allow administrators to isolate the container user and group identifiers (UIDs and GIDs) so that a container can have a different set of permissions in the user namespace than on the host system where it is running. This allows containers to run processes with full privileges inside the user namespace, but the processes can be unprivileged for operations on the host machine.

By default, a container runs in the host user namespace. Running a container in the host user namespace can be useful when the container needs a feature that is available only in the host namespace. However, running pods in the host namespace introduces security concerns, such as the possibility of container breakouts, in which a process inside another container breaks out onto the host where the process can access or modify files on the host or in your containers.

Running containers in individual user namespaces can mitigate container breakouts and several other vulnerabilities that a compromised container can pose to other pods and the node itself.

When running a pod in an isolated user namespace, the UID/GID inside a pod container no longer matches the UID/GID on the host. In order for file system ownership to work correctly, the Linux kernel uses ID-mapped mounts, which translate user IDs between the container and the host at the virtual file system (VFS) layer.

> [!IMPORTANT]
> Not all file systems currently support ID-mapped mounts, such as Network File Systems (NFS) and other network/distributed file systems. Any pod that is using an NFS-backed persistent volume from a vendor that does not support ID-mapped mounts might experience access or permission issues when running in a user namespace. This behavior is not specific to OpenShift Container Platform. It applies to all Kubernetes distributions from Kubernetes v1.33 onward.

To check user namespaces support for storage options, see [CSI drivers supported by OpenShift Container Platform](/openshift-docs-markdown/storage/container_storage_interface/persistent-storage-csi#csi-drivers-supported_persistent-storage-csi).

## Configuring Linux user namespace support {#nodes-pods-user-namespaces-configuring_nodes-pods-user-namespaces}

You can configure Linux user namespace by setting the `hostUsers` parameter to `false` in the pod spec, and a few other configurations. When you run workloads in user namespaces, the containers run with administrative privileges inside the namespace, but remain unprivileged on the host system.

Running workloads in user namespaces makes it safe to configure `RunAsAny` for Security Context Constraint (SCC) fields, such as `fsGroup`, `runAsGroup`, `runAsUser`, and `supplementalGroups`, as the UID or GID outside of the container is different from the one inside, which these fields express.

For extra security, you can use the `restricted-v3` or `nested-container` SCC, which are specifically designed for workloads in Linux user namespaces. The `userNamespaceLevel: RequirePodLevel` field in the SCC requires that the workloads run in user namespaces. For more information about SCCs, see "Managing security context constraints".

To require a specific SCC for a workload, you can add an SCC to a specific user or group by using the `oc adm policy add-scc-to-user` or `oc adm policy add-scc-to-group` command. For more information, see the "OpenShift CLI administrator command reference".

Also, you can optionally use the `procMount` parameter in a pod specification to configure the `/proc` file system in pods as `unmasked`. Setting `/proc` to `unmasked`, which is generally considered as safe, bypasses the default masking behavior of the container runtime, and should be used only with an SCC that sets `userNamespaceLevel` to `RequirePodLevel`.

**Prerequisites**

- Log into an OpenShift Container Platform cluster as a user configured with the `restricted-v3` or `nested-container` SCC, or as a user from a user group configured with either SCC. Alternatively, you can set the `restricted-v3` or `nested-container` SCC directly in the workload object.

**Procedure**

1. Edit the default user ID (UID) and group ID (GID) range of the OpenShift Container Platform namespace where your pod is deployed by running the following command:

   ```terminal
   $ oc edit ns/<namespace_name>
   ```

   ```yaml {title="Example namespace"}
   apiVersion: v1
   kind: Namespace
   metadata:
     annotations:
       openshift.io/description: ""
       openshift.io/display-name: ""
       openshift.io/requester: system:admin
       openshift.io/sa.scc.mcs: s0:c27,c24
       openshift.io/sa.scc.supplemental-groups: 1000/10000
       openshift.io/sa.scc.uid-range: 1000/10000
   # ...
     name: userns
   # ...
   ```

   where:

   `metadata.annotations.openshift.io/sa.scc.supplemental-groups`
   :   Specifies the default GID to require in the pod spec. The range for a Linux user namespace must be `65535` or lower. The default is `1000000000/10000`.

   `metadata.annotations.openshift.io/sa.scc.uid-range`
   :   Specifies the default UID to require in the pod spec. The range for a Linux user namespace must be `65535` or lower. The default is `1000000000/10000`.

   > [!NOTE]
   > The range 1000/10000 means 10,000 values starting with ID 1000, so it specifies the range of IDs from 1000 to 10,999.
2. Enable the use of Linux user namespaces by creating a workload configured to run with an appropriate SCC and the `hostUsers` parameter set to `false`.

   1. Create a YAML file similar to the following:

      ```yaml {title="Example pod specification"}
      apiVersion: v1
      kind: Pod
      metadata:
        name: userns-pod
      spec:
        securityContext:
          runAsNonRoot: true
          seccompProfile:
            type: RuntimeDefault
        hostUsers: false
        containers:
          name: userns-container
          image: registry.access.redhat.com/ubi9
          command: ["sleep", "1000"]
          securityContext:
            runAsUser: 1000
            runAsGroup: 1000
            runAsNonRoot: true
            procMount: Unmasked
            capabilities:
              add:
              - "SETGID"
              - "SETUID"
      # ...
      ```

      where:

      `spec.hostUsers`
      :   Specifies whether the pod is to be run in a user namespace. If `false`, the pod runs in a new user namespace that is created for the pod. If `true`, the pod runs in the host user namespace. The default is `true`.

      `spec.containers.securityContext.runAsUser`
      :   Specifies the user ID for processes that run inside of the container. This must fall in the range that you set in the `namespace` object.

      `spec.containers.securityContext.runAsGroup`
      :   Specifies the group ID for processes that run inside of the containers. This must fall in the range that you set in the `namespace` object.

      `spec.containers.securityContext.runAsNonRoot`
      :   Specifies that processes inside the container run with a user that has any UID other than 0.

      `spec.containers.securityContext.procMount`
      :   Specifies the type of proc mount to use for the containers. The `unmasked` value ensures that a container’s `/proc` file system is mounted as read/write by the container process. The default is `Default`. This value is optional.

      `spec.containers.securityContext.capabilities.add`
      :   Specifies Linux capabilities to set in the user namespace. This permits privileged actions without giving full root access. Technically, setting capabilities inside of a user namespace is safer than setting them outside, as the scope of the capabilities are limited by being inside user namespace, and can generally be considered to be safe. However, giving pods capabilities like `CAP_SYS_ADMIN` to any untrusted workload could increase the potential kernel surface area that a containerized process has access to and could find exploits in. Thus, capabilities inside of a user namespace are allowed at `baseline` level in pod security admission. This value is optional.
   2. Create the object by running the following command:

      ```
      $ oc create -f <file_name>.yaml
      ```

**Verification**

1. Check the user and group IDs being used by the container in the pod you created. The pod is inside the Linux user namespace.

   1. Start a shell session with the container in your pod:

      ```terminal
      $ oc rsh -c <container_name> pod/<pod_name>
      ```

      ```terminal {title="Example command"}
      $ oc rsh -c userns-container pod/userns-pod
      ```
   2. Display the user and group IDs being used inside the container:

      ```terminal
      sh-5.1$ id
      ```

      ```terminal {title="Example output"}
      uid=1000(1000) gid=1000(1000) groups=1000(1000)
      ```

      The UID and group for the container should be the same as you set in the pod specification.
   3. Display the user ID being used in the container user namespace:

      ```terminal
      sh-5.1$ lsns -t user
      ```

      ```terminal {title="Example output"}
              NS TYPE  NPROCS PID USER COMMAND
      4026532447 user       3   1 1000 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1000
      ```

      The UID for the process should be the same as you set in the pod spec.
   4. Exit the container shell session by using the following command:

      ```terminal
      sh-5.1$ exit
      ```
2. Check the UID being used by the node. The node is outside of the Linux user namespace. This user ID should be different from the UID being used in the container.

   1. Start a debug session for that node:

      ```terminal
      $ oc debug node/ci-ln-z5vppzb-72292-8zp2b-worker-c-q8sh9
      ```

      ```terminal {title="Example command"}
      $ oc debug node/ci-ln-z5vppzb-72292-8zp2b-worker-c-q8sh9
      ```
   2. Set `/host` as the root directory within the debug shell:

      ```terminal
      sh-5.1# chroot /host
      ```
   3. Display the UID being used by the node:

      ```terminal
      sh-5.1#  lsns -t user
      ```

      ```terminal {title="Example command"}
              NS TYPE  NPROCS   PID USER       COMMAND
      4026531837 user     233     1 root       /usr/lib/systemd/systemd --switched-root --system --deserialize 28
      4026532447 user       1  4767 2908816384 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1000
      ```

      The UID should be different from what you set in the pod specification.
   4. Exit the debug session by using the following commands:

      ```terminal
      sh-5.1#  exit
      ```

      ```terminal
      sh-5.1#  exit
      ```
3. Check that the `/proc` file system is mounted into container as `unmasked`, as indicated by read/write permission (`rw`) in the output of the following command:

   ```terminal
   $ oc exec <pod_name> -- mount | grep /proc
   ```

   ```terminal {title="Example output"}
   proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
   ```

**Additional resources**
{._additional-resources}

- [Managing security context constraints](/openshift-docs-markdown/authentication/managing-security-context-constraints#configuring-internal-oauth)
- [OpenShift CLI administrator command reference](/openshift-docs-markdown/cli_reference/openshift_cli/administrator-cli-commands#cli-administrator-commands)
