# Aislar contenedores con un espacio de nombres de usuario


Los espacios de nombres de Linux proporcionan aislamiento para los procesos en ejecución, limitando su acceso a los recursos del sistema sin que el proceso en ejecución sea consciente de las limitaciones. Para obtener más información sobre los espacios de nombres de Linux, consulta [espacios de nombres de Linux](https://www.linux.com/news/understanding-and-securing-linux-namespaces).

La mejor manera de prevenir ataques de escalada de privilegios desde dentro de un contenedor es configurar las aplicaciones de tu contenedor para que se ejecuten como usuarios sin privilegios. Para los contenedores cuyos procesos deben ejecutarse como el usuario `root` dentro del contenedor, puedes remapear este usuario a un usuario con menos privilegios en el anfitrión de Docker. Al usuario mapeado se le asigna un rango de UID que funcionan dentro del espacio de nombres como UID normales del 0 al 65536, pero que no tienen privilegios en la propia máquina anfitriona.

> [!NOTE]
>
> Con `userns-remap`, el demonio de Docker todavía se ejecuta como root. Para ejecutar tanto el demonio como los contenedores sin privilegios de root, consulta el [modo Rootless](/engine/security/userns-remap/rootless/) en su lugar.

## Acerca de la reasignación (remapping) y los ID de usuarios y grupos subordinados

La reasignación en sí se gestiona mediante dos archivos: `/etc/subuid` y `/etc/subgid`. Ambos archivos funcionan igual, pero uno se encarga del rango de ID de usuario y el otro del rango de ID de grupo. Considera la siguiente entrada en `/etc/subuid`:

```text
testuser:231072:65536
```

Esto significa que a `testuser` se le asigna un rango de ID de usuario subordinado de `231072` y los siguientes 65536 enteros en secuencia. El UID `231072` se mapea dentro del espacio de nombres (dentro del contenedor, en este caso) como UID `0` (`root`). El UID `231073` se mapea como UID `1`, y así sucesivamente. Si un proceso intenta escalar privilegios fuera del espacio de nombres, el proceso se estará ejecutando como un UID de número alto sin privilegios en el anfitrión, el cual ni siquiera se mapea a un usuario real. Esto significa que el proceso no tiene ningún privilegio en el sistema anfitrión.

> [!NOTE]
>
> Es posible asignar múltiples rangos subordinados para un usuario o grupo determinado añadiendo múltiples mapeos que no se superpongan para el mismo usuario o grupo en el archivo `/etc/subuid` o `/etc/subgid`. En este caso, Docker utiliza únicamente los primeros cinco mapeos, de acuerdo con la limitación del kernel de solo cinco entradas en `/proc/self/uid_map` y `/proc/self/gid_map`.

Cuando configuras Docker para utilizar la característica `userns-remap`, puedes especificar opcionalmente un usuario y/o grupo existente, o puedes especificar `default`. Si especificas `default`, se crea y se utiliza un usuario y grupo `dockremap` para este propósito.

> [!WARNING]
>
> Algunas distribuciones no añaden automáticamente el nuevo grupo a los archivos `/etc/subuid` y `/etc/subgid`. Si ese es el caso, es posible que debas editar manualmente estos archivos y asignar rangos que no se superpongan. Este paso se detalla en [Requisitos previos](#prerequisites).

Es muy importante que los rangos no se superpongan, para que un proceso no pueda obtener acceso en un espacio de nombres diferente. En la mayoría de las distribuciones de Linux, las utilidades del sistema gestionan los rangos por ti cuando añades o eliminas usuarios.

Esta reasignación es transparente para el contenedor, pero introduce cierta complejidad de configuración en situaciones en las que el contenedor necesita acceder a recursos en el anfitrión de Docker, como montajes de tipo bind en áreas del sistema de archivos en las que el usuario del sistema no puede escribir. Desde el punto de vista de la seguridad, lo mejor es evitar estas situaciones.

## Requisitos previos

1.  Los rangos de UID y GID subordinados deben estar asociados con un usuario existente, aunque la asociación sea un detalle de implementación. El usuario es el propietario de los directorios de almacenamiento con espacio de nombres bajo `/var/lib/docker/`. Si no quieres utilizar un usuario existente, Docker puede crear uno por ti y usarlo. Si quieres utilizar un nombre de usuario o ID de usuario existente, este ya debe existir. Normalmente, esto significa que las entradas correspondientes deben estar en `/etc/passwd` y `/etc/group`, pero si utilizas un backend de autenticación diferente, este requisito puede traducirse de otra manera.

    Para verificar esto, utiliza el comando `id`:

    ```console
    $ id testuser

    uid=1001(testuser) gid=1001(testuser) groups=1001(testuser)
    ```

2.  La forma en que se gestiona la reasignación de espacios de nombres en el anfitrión es mediante el uso de dos archivos, `/etc/subuid` y `/etc/subgid`. Estos archivos normalmente se gestionan de forma automática cuando añades o eliminas usuarios o grupos, pero en algunas distribuciones, es posible que debas gestionar estos archivos manualmente.

    Cada archivo contiene tres campos: el nombre de usuario o el ID del usuario, seguido por un UID o GID inicial (que se trata como el UID o GID 0 dentro del espacio de nombres) y un número máximo de UID o GID disponibles para el usuario. Por ejemplo, dada la siguiente entrada:

    ```text
    testuser:231072:65536
    ```

    Esto significa que los procesos con espacio de nombres de usuario iniciados por `testuser` pertenecen al UID del anfitrión `231072` (que parece el UID `0` dentro del espacio de nombres) hasta el 296607 (231072 + 65536 - 1). Estos rangos no deben superponerse para garantizar que los procesos con espacio de nombres no puedan acceder a los espacios de nombres de los demás.

    Después de añadir tu usuario, comprueba `/etc/subuid` y `/etc/subgid` para ver si tu usuario tiene una entrada en cada uno. Si no es así, debes añadirla, teniendo cuidado de evitar superposiciones.

    Si quieres utilizar el usuario `dockremap` creado automáticamente por Docker, busca la entrada `dockremap` en estos archivos después de configurar y reiniciar Docker.

3.  Si hay alguna ubicación en el anfitrión de Docker en la que el usuario sin privilegios necesite escribir, ajusta los permisos de esas ubicaciones en consecuencia. Esto también se aplica si quieres utilizar el usuario `dockremap` creado automáticamente por Docker, pero no podrás modificar los permisos hasta después de configurar y reiniciar Docker.

4.  Habilitar `userns-remap` enmascara de manera efectiva las capas de imágenes y contenedores existentes, así como otros objetos de Docker dentro de `/var/lib/docker/`. Esto se debe a que Docker necesita ajustar la propiedad de estos recursos y en realidad los almacena en un subdirectorio dentro de `/var/lib/docker/`. Lo más recomendable es habilitar esta característica en una nueva instalación de Docker en lugar de una existente.

    En la misma línea, si deshabilitas `userns-remap`, no podrás acceder a ninguno de los recursos creados mientras estuvo habilitado.

5.  Revisa las [limitaciones](#user-namespace-known-limitations) de los espacios de nombres de usuario para asegurarte de que tu caso de uso sea posible.

## Habilitar userns-remap en el demonio

Puedes iniciar `dockerd` con la bandera `--userns-remap` o seguir este procedimiento para configurar el demonio utilizando el archivo de configuración `daemon.json`. Se recomienda el método de `daemon.json`. Si utilizas la bandera, usa el siguiente comando como modelo:

```console
$ dockerd --userns-remap="testuser:testuser"
```

1.  Edita `/etc/docker/daemon.json`. Asumiendo que el archivo estaba vacío previamente, la siguiente entrada habilita `userns-remap` utilizando el usuario y grupo llamado `testuser`. Puedes hacer referencia al usuario y grupo por su ID o nombre. Solo necesitas especificar el nombre o ID del grupo si es diferente del nombre o ID del usuario. Si proporcionas tanto el nombre o ID de usuario como de grupo, sepáralos por un carácter de dos puntos (`:`). Los siguientes formatos funcionan para el valor, asumiendo que el UID y GID de `testuser` son `1001`:

    - `testuser`
    - `testuser:testuser`
    - `1001`
    - `1001:1001`
    - `testuser:1001`
    - `1001:testuser`

    ```json
    {
      "userns-remap": "testuser"
    }
    ```

    > [!NOTE]
    >
    > Para utilizar el usuario `dockremap` y que Docker lo cree por ti, establece el valor en `default` en lugar de `testuser`.

    Guarda el archivo y reinicia Docker.

2.  Si utilizas el usuario `dockremap`, verifica que Docker lo haya creado utilizando el comando `id`.

    ```console
    $ id dockremap

    uid=112(dockremap) gid=116(dockremap) groups=116(dockremap)
    ```

    Verifica que la entrada se haya añadido a `/etc/subuid` y `/etc/subgid`:

    ```console
    $ grep dockremap /etc/subuid

    dockremap:231072:65536

    $ grep dockremap /etc/subgid

    dockremap:231072:65536
    ```

    If these entries are not present, edit the files as the `root` user and
    assign a starting UID and GID that is the highest-assigned one plus the
    offset (in this case, `65536`). Be careful not to allow any overlap in the
    ranges.

3.  Verifica que las imágenes anteriores no estén disponibles utilizando el comando `docker image ls`. La salida debería estar vacía.

4.  Inicia un contenedor desde la imagen `hello-world`.

    ```console
    $ docker run hello-world
    ```

5.  Verifica que exista un directorio con espacio de nombres dentro de `/var/lib/docker/` nombrado con el UID y GID del usuario con espacio de nombres, propiedad de ese UID y GID, y que no sea legible por el grupo ni por cualquiera. Algunos de los subdirectorios todavía pertenecen a `root` y tienen permisos diferentes.

    ```console
    $ sudo ls -ld /var/lib/docker/231072.231072/

    drwx------ 11 231072 231072 11 Jun 21 21:19 /var/lib/docker/231072.231072/

    $ sudo ls -l /var/lib/docker/231072.231072/

    total 14
    drwx------ 5 231072 231072 5 Jun 21 21:19 aufs
    drwx------ 3 231072 231072 3 Jun 21 21:21 containers
    drwx------ 3 root   root   3 Jun 21 21:19 image
    drwxr-x--- 3 root   root   3 Jun 21 21:19 network
    drwx------ 4 root   root   4 Jun 21 21:19 plugins
    drwx------ 2 root   root   2 Jun 21 21:19 swarm
    drwx------ 2 231072 231072 2 Jun 21 21:21 tmp
    drwx------ 2 root   root   2 Jun 21 21:19 trust
    drwx------ 2 231072 231072 3 Jun 21 21:19 volumes
    ```

    Tu listado de directorios puede tener algunas diferencias, especialmente si utilizas un controlador de almacenamiento de contenedores diferente a `aufs`.

    Los directorios que pertenecen al usuario remapeado se utilizan en lugar de los mismos directorios directamente debajo de `/var/lib/docker/` y las versiones no utilizadas (como `/var/lib/docker/tmp/` en este ejemplo) se pueden eliminar. Docker no los utiliza mientras `userns-remap` esté habilitado.

## Deshabilitar la reasignación de espacios de nombres para un contenedor

Si habilitas los espacios de nombres de usuario en el demonio, todos los contenedores se iniciarán con los espacios de nombres de usuario habilitados por defecto. En algunas situaciones, como contenedores privilegiados, es posible que debas deshabilitar los espacios de nombres de usuario para un contenedor específico. Consulta las [limitaciones conocidas de los espacios de nombres de usuario](#user-namespace-known-limitations) para conocer algunas de estas limitaciones.

Para deshabilitar los espacios de nombres de usuario para un contenedor específico, añade la bandera `--userns=host` al comando `docker container create`, `docker container run` o `docker container exec`.

Hay un efecto secundario al usar esta bandera: la reasignación de usuarios no se habilitará para ese contenedor pero, dado que las capas de solo lectura (imagen) se comparten entre los contenedores, la propiedad del sistema de archivos del contenedor seguirá remapeada.

Lo que esto significa es que todo el sistema de archivos del contenedor pertenecerá al usuario especificado en la configuración del demonio `--userns-remap` (`231072` en el ejemplo anterior). Esto puede provocar comportamientos inesperados de los programas dentro del contenedor. Por ejemplo, `sudo` (que comprueba que sus binarios pertenezcan al usuario `0`) o binarios con una bandera `setuid`.

## Limitaciones conocidas de los espacios de nombres de usuario

Las siguientes características estándar de Docker son incompatibles con la ejecución de un demonio de Docker con espacios de nombres de usuario habilitados:

- Compartir espacios de nombres PID o NET con el anfitrión (`--pid=host` o `--network=host`).
- Controladores externos (de volumen o almacenamiento) que no sean conscientes o no sean capaces de utilizar los mapeos de usuario del demonio.
- Utilizar la bandera de modo `--privileged` en `docker run` sin especificar también `--userns=host`.

Los espacios de nombres de usuario son una característica avanzada y requieren coordinación con otras capacidades. Por ejemplo, si se montan volúmenes desde el anfitrión, la propiedad de los archivos debe organizarse de antemano si necesitas acceso de lectura o escritura al contenido del volumen.

Aunque el usuario root dentro de un proceso de contenedor con espacio de nombres de usuario tiene muchos de los privilegios esperados del superusuario dentro del contenedor, el kernel de Linux impone restricciones basadas en el conocimiento interno de que se trata de un proceso con espacio de nombres de usuario. Una restricción notable es la imposibilidad de usar el comando `mknod`. Se deniega el permiso para la creación de dispositivos dentro del contenedor cuando es ejecutado por el usuario `root`.

