Capítulo 4. Control de acceso

Este trabajo se ha traducido utilizando IA. Agradecemos tus opiniones y comentarios: translation-feedback@oreilly.com

Tras el amplio alcance del capítulo anterior sobre todo lo relacionado con el shell y los scripts, ahora nos centraremos en un aspecto específico y crucial de la seguridad en Linux. En este capítulo, trataremos el tema de los usuarios y el control del acceso a los recursos en general y a los archivos en particular.

Una cuestión que surge inmediatamente en una configuración multiusuario de este tipo es la propiedad. Un usuario puede ser propietario, por ejemplo, de un archivo. Se le permite leer del archivo, escribir en él y también, digamos, borrarlo. Dado que también hay otros usuarios en el sistema, ¿qué pueden hacer esos usuarios y cómo se define y aplica? También hay actividades que no necesariamente se asocian a los archivos en primer lugar. Por ejemplo, un usuario puede (o no) estar autorizado a cambiar losajustes relacionados con la red.

Para dominar este tema, primero echaremos un vistazo a la relación fundamental entre usuarios, procesos y archivos, desde el punto de vista del acceso. También revisaremos los tipos de sandboxing y de control de acceso. A continuación, nos centraremos en la definición de un usuario de Linux, en lo que pueden hacer los usuarios y en cómo gestionarlos localmente o, alternativamente, desde un lugar central.

A continuación, pasaremos al tema de los permisos, donde veremos cómo controlar el acceso a los archivos y cómo se ven afectados los procesos por tales restricciones.

Terminaremos este capítulo cubriendo una serie de características avanzadas de Linux en el espacio del control de acceso, incluyendo capacidades, perfiles seccomp y ACL. Como colofón, ofreceremos algunas buenas prácticas de seguridad en torno a los permisos y elcontrol de acceso.

Con esto, vamos a entrar de lleno en el tema de los usuarios y la propiedad de los recursos, sentando las bases para el resto del capítulo.

Conceptos básicos

Antes de entrar en los mecanismos de control de acceso, retrocedamos un poco y veamos el tema a vista de pájaro. Esto nos ayudará a establecer cierta terminología y a aclarar las relaciones entre los conceptos principales.

Recursos y propiedad

Linux es un sistema operativo multiusuario y, como tal, ha heredado de UNIX el concepto de usuario (véase "Usuarios").Cada cuenta de usuario está asociada a un identificador de usuario al que se puede dar acceso a ejecutables, archivos, dispositivos y otros activos de Linux. Un usuario humano puede iniciar sesión con una cuenta de usuario, y un proceso puede ejecutarse como una cuenta de usuario. Luego están los recursos (a los que nos referiremos simplemente como archivos), que son cualquier componente de hardware o software a disposición del usuario. En el caso general, nos referiremos a los recursos como archivos, a menos que hablemos explícitamente del acceso a otros tipos de recursos, como con las llamadas al sistema. En la Figura 4-1y en el pasaje que sigue, puedes ver las relaciones de alto nivel entre usuarios, procesos y archivos en Linux.

lmlx 0401
Figura 4-1. Usuarios, procesos y archivos en Linux
Usuarios

Lanzar procesos y archivos propios. Un proceso es un programa (archivo ejecutable) que el núcleo ha cargado en la memoria principal y ejecuta.

Archivos

Tienen propietario; por defecto, el usuario que crea el archivo es su propietario.

Procesos

Utiliza archivos para la comunicación y la persistencia. Por supuesto, los usuarios también utilizan archivos indirectamente, pero deben hacerlo a través de procesos.

Esta representación de las relaciones entre usuarios, procesos y archivos es, por supuesto, una visión muy simplista, pero nos permite comprender a los actores y sus relaciones, y nos resultará útil más adelante, cuando tratemos con más detalle la interacción entre estos distintos actores.

Veamos primero el contexto de ejecución de un proceso, abordando la cuestión de cómo de restringido está el proceso. Un término con el que nos encontramos a menudo cuando hablamos del acceso a los recursos es sandboxing.

Sandboxing

Sandboxing es un término vagamente definido y puede referirse a una serie de métodos diferentes, desde jaulas a contenedores o máquinas virtuales, que pueden gestionarse en el núcleo o en el terreno del usuario. Normalmente hay algo que se ejecuta en la caja de arena -normalmente alguna aplicación- y el mecanismo supervisor impone un cierto grado de aislamiento entre el proceso en la caja de arena y el entorno anfitrión. Si todo esto suena bastante teórico, te pido un poco de paciencia. Veremos el sandboxing en acción más adelante en este capítulo, en "Perfiles seccomp", y de nuevo en el Capítulo 9, cuando hablemos de máquinas virtuales y contenedores.

Con una comprensión básica de los recursos, la propiedad y el acceso a dichos recursos en tu mente, hablemos brevemente de algunas formas conceptuales de abordar el control de acceso.

Tipos de control de acceso

Un aspecto del control de acceso es la naturaleza del acceso en sí. ¿Un usuario o proceso accede directamente a un recurso, tal vez de forma ilimitada? O tal vez exista un conjunto claro de normas sobre a qué tipo de recursos (archivos o llamadas al sistema) puede acceder un proceso y en qué circunstancias. O puede que incluso se registre el propio acceso.

Conceptualmente, existen distintos tipos de control de acceso. Los dos más importantes y relevantes para nuestro debate en el contexto de Linux son el control de accesodiscrecional y el obligatorio:

Control de acceso discrecional

Con el control de acceso discrecional (CAD), la idea es restringir el acceso a los recursos en función de la identidad del usuario. Es discrecional en el sentido de que un usuario con determinados permisos puede cederlos a otros usuarios.

Control de acceso obligatorio

El control de acceso obligatorio se basa en un modelo jerárquico que representa los niveles de seguridad. A los usuarios se les asigna un nivel de autorización, y a los recursos una etiqueta de seguridad. Los usuarios sólo pueden acceder a los recursos correspondientes a un nivel de autorización igual (o inferior) al suyo. En un modelo de control de acceso obligatorio, un administrador controla estricta y exclusivamente el acceso, estableciendo todos los permisos. En otras palabras, los usuarios no pueden establecer permisos por sí mismos, aunque sean propietarios del recurso.

Además, Linux tiene tradicionalmente una actitud de todo o nada, es decir, o eres un superusuario que tiene poder para cambiarlo todo o eres un usuario normal con acceso limitado. Al principio, no había una forma fácil y flexible de asignar a un usuario o proceso determinados privilegios. Por ejemplo, en el caso general, para permitir que "el proceso X pueda cambiar la configuración de red", tenías que darle acceso a root. Esto, naturalmente, tiene un impacto concreto en un sistema vulnerado: un atacante puede hacer mal uso de estos amplios privilegios fácilmente.

Nota

Para matizar un poco la "actitud de todo o nada" en Linux: los valores predeterminados en la mayoría de los sistemas Linux permiten el acceso de lectura a casi todos los archivos y ejecutables por parte de "otros", es decir, todos los usuarios del sistema. Por ejemplo, con SELinux activado, el control de acceso obligatorio restringe el acceso sólo a los activos a los que se da permiso explícitamente. Así, por ejemplo, un servidor web sólo puede utilizar los puertos 80 y 443, sólo puede compartir archivos y scripts de directorios específicos, sólo puede escribir registros en lugares específicos, etc.

Volveremos sobre este tema en "Gestión avanzada de permisos" y veremos cómo las funciones modernas de Linux pueden ayudar a superar esta visión binaria del mundo, permitiendo una gestión más detallada de los privilegios.

Probablemente, la implementación más conocida del control de acceso obligatorio para Linux seaSELinux. Se desarrolló para cumplir los elevados requisitos de seguridad de los organismos gubernamentales y suele utilizarse en estos entornos, ya que la usabilidad se resiente de lo estricto de las normas. Otra opción de control de acceso obligatorio, incluida en el núcleo Linux desde la versión 2.6.36 y bastante popular en la familia Ubuntu de distribuciones Linux, esAppArmor.

Pasemos ahora al tema de los usuarios y cómo gestionarlos en Linux.

Usuarios

En Linux solemos distinguir entre dos tipos de cuentas de usuario, desde el punto de vista de su finalidad o uso previsto:

Los llamados usuarios del sistema, o cuentas del sistema

Normalmente, los programas (a veces llamados demonios) utilizan este tipo de cuentas para ejecutar procesos en segundo plano. Los servicios que prestan estos programas pueden formar parte del sistema operativo, como las redes (sshd, por ejemplo), o de la capa de aplicación (por ejemplo, mysql, en el caso de una popular base de datos relacional).

Usuarios habituales

Por ejemplo, un usuario humano que utiliza Linux de forma interactiva a través del shell.

La distinción entre usuarios del sistema y normales no es tanto técnica como organizativa. Para entenderlo, primero tenemos que introducir el concepto de ID de usuario (UID), un valor numérico de 32 bits gestionado por Linux.

Linux identifica a los usuarios mediante un UID, y un usuario que pertenece a uno o varios grupos se identifica mediante un ID de grupo (GID). Hay un tipo especial de usuario con el UID 0, que suele llamarse root. A este "superusuario" se le permite hacer cualquier cosa, es decir, no se le aplica ninguna restricción. Normalmente, querrás evitar trabajar como el usuarioroot, porque es tener demasiado poder. Puedes destruir fácilmente un sistema si no tienes cuidado (créeme, yo lo he hecho). Volveremos sobre esto más adelante en el capítulo.

Las distintas distribuciones de Linux tienen sus propias formas de decidir cómo gestionar el rango UID. Por ejemplo, las distribuciones que utilizan systemd(ver "systemd"), tienen la siguiente convención(simplificada aquí):

UID 0

Es root

UID de 1 a 999

Están reservados a los usuarios del sistema

UID 65534

Es el usuario nobody-utilizado, por ejemplo, para asignar usuarios remotos a algún ID conocido, como es el caso de "Sistema de archivos de red"

UID de 1000 a 65533 y de 65536 a 4294967294

Son usuarios habituales

Para averiguar tus propios UID, puedes utilizar el comando (¡sorpresa!) id de la siguiente manera:

$ id -u
2016796723

Ahora que sabes lo básico sobre los usuarios de Linux, vamos a ver cómo puedes gestionar usuarios.

Gestionar usuarios localmente

La primera opción, y tradicionalmente la única disponible, es gestionar los usuarios localmente. Es decir, sólo se utiliza la información local de la máquina, y la información relacionada con el usuario no se comparte a través de una red de máquinas.

Para la gestión local de usuarios, Linux utiliza una sencilla interfaz basada en archivos con un esquema de nombres algo confuso que, por desgracia, es un artefacto histórico con el que tenemos que vivir. La Tabla 4-1 enumera los cuatro archivos que, juntos, implementan la gestión de usuarios.

Tabla 4-1. Referencia de los archivos locales de gestión de usuarios
Propósito Archivo

Base de datos de usuarios

/etc/passwd

Base de datos de grupos

/etc/grupo

Contraseñas de usuario

/etc/shadow

Contraseñas de grupo

/etc/gshadow

Piensa en /etc/passwd como una especie de minibase de datos de usuarios que mantiene un registro de nombres de usuario, UIDs, pertenencia a grupos y otros datos, como el directorio personal y el shell de inicio de sesión utilizado, para usuarios normales. Veamos un ejemplo concreto:

$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash 1
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin 2
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
syslog:x:104:110::/home/syslog:/usr/sbin/nologin
mh9:x:1000:1001::/home/mh9:/usr/bin/fish 3
1

El usuario root tiene UID 0.

2

Una cuenta del sistema (la nologin lo delata; ver más abajo).

3

Mi cuenta de usuario.

Echemos un vistazo más de cerca a una de las líneas de /etc/passwd para comprender en detalle la estructura de una entrada de usuario:

root:x:0:0:root:/root:/bin/bash
^    ^ ^ ^ ^    ^     ^
|    | | | |    |     └──  1
|    | | | |    └──  2
|    | | | └──  3
|    | | └── 4
|    | └──  5
|    └──  6
└──  7
1

El intérprete de comandos de inicio de sesión a utilizar. Para evitar inicios de sesión interactivos, utiliza /sbin/nologin.

2

El directorio personal del usuario; por defecto es /.

3

Información del usuario, como el nombre completo o datos de contacto como el número de teléfono. A menudo también se conoce como campo GECOS. Ten en cuenta que no se utiliza el formato GECOS, sino que el propio campo se utiliza normalmente para el nombre completo de la persona asociada a la cuenta.

4

El grupo principal del usuario (GID); consulta también /etc/group.

5

El UID. Ten en cuenta que Linux reserva los UID inferiores a 1000 para uso del sistema.

6

La contraseña del usuario, con el carácter x que significa que la contraseña (encriptada) se almacena en /etc/shadow, que es el valor por defecto actualmente.

7

El nombre de usuario, que debe tener 32 caracteres o menos.

Una cosa que notamos que está ausente en /etc/passwd es lo que esperaríamos encontrar allí, basándonos en su nombre: la contraseña. Las contraseñas se almacenan, por razones históricas, en un archivo llamado /etc/shadow. Aunque todos los usuarios pueden leer/etc/passwd, normalmente necesitas privilegios de root para leer /etc/shadow.

Para añadir un usuario, puedes utilizar el comando adduser como se indica a continuación:

$ sudo adduser mh9
Adding user `mh9' ...
Adding new group `mh9' (1001) ...
Adding new user `mh9' (1000) with group `mh9' ...
Creating home directory `/home/mh9' ... 1
Copying files from `/etc/skel' ... 2
New password: 3
Retype new password:
passwd: password updated successfully
Changing the user information for mh9
Enter the new value, or press ENTER for the default 4
        Full Name []: Michael Hausenblas
        Room Number []:
        Work Phone []:
        Home Phone []:
        Other []:
Is the information correct? [Y/n] Y
1

El comando adduser crea un directorio personal.

2

También copia un montón de archivos de configuración por defecto en el directorio home.

3

Necesitas definir una contraseña.

4

Proporciona información GECOS opcional.

Si quieres crear una cuenta de sistema, pasa la opción -r. Esto desactivará la posibilidad de utilizar un intérprete de comandos de inicio de sesión y también evitará la creación del directorio personal. Para más detalles sobre la configuración, consulta también /etc/adduser.conf, incluyendo opciones como el rango UID/GID que debe utilizarse.

Además de los usuarios, Linux también tiene el concepto de grupos, que en cierto sentido no es más que una colección de uno o más usuarios. Cualquier usuario normal pertenece a un grupo por defecto, pero puede ser miembro de grupos adicionales. Puedes conocer los grupos y las asignaciones a través del archivo /etc/group:

$ cat /etc/group 1
root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:
adm:x:4:syslog
...
ssh:x:114:
landscape:x:115:
admin:x:116:
netdev:x:117:
lxd:x:118:
systemd-coredump:x:999:
mh9:x:1001: 2
1

Muestra el contenido del archivo de asignación de grupos.

2

Un ejemplo de grupo de mi usuario con el GID 1001. Ten en cuenta que puedes añadir una lista de nombres de usuario separados por comas después de los últimos dos puntos para permitir que varios usuarios tengan permiso para ese grupo.

Con este concepto básico de usuario y su gestión en nuestro haber, pasamos a una forma potencialmente mejor de gestionar usuarios en una configuración profesional, que permite la escala.

Gestión centralizada de usuarios

Si tienes más de una máquina o servidor para los que tienes que gestionar usuarios -por ejemplo, en una configuración profesional-, gestionar usuarios localmente se queda rápidamente anticuado. Quieres una forma centralizada de gestionar usuarios que puedas aplicar localmente, a una máquina concreta. Tienes a tu disposición unos cuantos métodos, en función de tus necesidades y de tu presupuesto (de tiempo):

Basado en directorios

El Protocolo Ligero de Acceso a Directorios (LDAP), un conjunto de protocolos con décadas de antigüedad ahora formalizado por el IETF, define cómo acceder y mantener un directorio distribuido a través del Protocolo de Internet (IP). Puedes ejecutar un servidor LDAP tú mismo -por ejemplo, utilizando proyectos como Keycloak- oexternalizarlo a un proveedor en la nube, como Azure Active Directory.

A través de una red

Los usuarios pueden autenticarse de esta manera con Kerberos. Veremos Kerberos en detalle en "Kerberos".

Utilizar sistemas de gestión de la configuración

Estos sistemas, que incluyen Ansible, Chef, Puppet o SaltStack, pueden utilizarse para crear usuarios de forma coherente en todas las máquinas.

La implementación real suele venir dictada por el entorno. Es decir, puede que una empresa ya esté utilizando LDAP y, por tanto, las opciones sean limitadas. Sin embargo, los detalles de los distintos enfoques y sus pros y contras quedan fuera del alcance de este libro.

Permisos

En esta sección, primero entramos en detalles sobre los permisos de archivos de Linux, que son fundamentales para el funcionamiento del control de acceso, y luego examinamos los permisos en torno a los procesos. Es decir, revisamos los permisos en tiempo de ejecución y cómo se derivan de los permisos de archivo.

Permisos de archivos

Los permisos de archivos son el núcleo del concepto de Linux de acceso a los recursos, ya que en Linux todo es un archivo, más o menos. Repasemos primero un poco de terminología y luego analicemos en detalle la representación de los metadatos en torno al acceso y los permisos de los archivos.

Existen tres tipos o ámbitos de permisos, de estrecho a amplio:

Usuario

El propietario del archivo

Grupo

Tiene uno o más miembros

Otros

La categoría para todos los demás

Además, hay tres tipos de acceso:

Leer (r)

Para un archivo normal, permite al usuario ver el contenido del archivo. Para un directorio, permite al usuario ver los nombres de los archivos del directorio.

Escribe (w)

Para un archivo normal, permite a un usuario modificar y eliminar el archivo. Para un directorio, permite a un usuario crear, renombrar y eliminar archivos en el directorio.

Ejecutar (x)

Para un archivo normal, esto permite a un usuario ejecutar el archivo si también tiene permisos de lectura sobre él. Para un directorio, permite a un usuario acceder a la información del archivo en el directorio, permitiéndole cambiar a él (cd) o listar su contenido (ls).

Veamos los permisos de archivo en acción (ten en cuenta que los espacios que ves aquí en la salida del comandols se han expandido para facilitar la lectura):

$ ls -al
total 0
-rw-r--r--  1  mh9  devs  9  Apr 12 11:42  test
^           ^  ^    ^     ^  ^             ^
|           |  |    |     |  |             └──  1
|           |  |    |     |  └──  2
|           |  |    |     └──  3
|           |  |    └── 4
|           |  └──  5
|           └──  6
└──  7
1

Nombre del archivo

2

Fecha de la última modificación

3

Tamaño del archivo en bytes

4

Grupo al que pertenece el archivo

5

Propietario del archivo

6

Número de enlaces duros

7

Modo archivo

Al hacer zoom sobre el modo de archivo -esdecir, el tipo de archivo y los permisos mencionados como 7 en el fragmento anterior- tenemos campos con el siguiente significado:

. rwx rwx rwx
^ ^   ^   ^
| |   |   └──  1
| |   └──  2
| └──  3
└── 4
1

Permisos para otros

2

Permisos para el grupo

3

Permisos para el propietario del archivo

4

El tipo de archivo(Tabla 4-2)

El primer campo del modo archivo representa el tipo de archivo; consulta la Tabla 4-2para más detalles. El resto del modo archivo codifica los permisos establecidos para varios objetivos, desde propietario a todos, como se indica en la Tabla 4-3.

Tabla 4-2. Tipos de archivo utilizados en el modo
Símbolo Semántica

-

Un archivo normal (como cuando haces touch abc)

b

Archivo especial de bloque

c

Archivo especial de caracteres

C

Fichero de alto rendimiento (datos contiguos)

d

Un directorio

l

Un enlace simbólico

p

Una tubería con nombre (creada con mkfifo)

s

Un enchufe

?

Algún otro tipo de archivo (desconocido)

Hay algunos otros caracteres (más antiguos u obsoletos) como M oP utilizados en la posición 0, que en general puedes ignorar. Si te interesa saber qué significan, ejecuta info ls -n "What information is listed".

En combinación, estos permisos en el modo archivo definen lo que está permitido para cada elemento del conjunto de destino (usuario, grupo, todos los demás), como se muestra enla Tabla 4-3, comprobado y aplicado mediante elacceso.

Tabla 4-3. Permisos de archivo
Patrón Permiso efectivo Representación decimal

---

Ninguno

0

--x

Ejecuta

1

-w-

Escribe

2

-wx

Escribe y ejecuta

3

r--

Leer

4

r-x

Leer y ejecutar

5

rw-

Leer y escribir

6

rwx

Leer, escribir, ejecutar

7

Veamos algunos ejemplos:

755

Acceso total para su propietario; lectura y ejecución para todos los demás

700

Acceso total para su propietario; ninguno para los demás

664

Acceso de lectura/escritura para el propietario y el grupo; sólo lectura para los demás

644

Lectura/escritura para el propietario; sólo lectura para todos los demás

400

Sólo lectura por su propietario

El 664 tiene un significado especial en mi sistema. Cuando creo un archivo, ése es el permiso por defecto que se le asigna. Puedes comprobarlo con elcomandoumask , que en mi caso me da 0002.

Los permisos de setuid se utilizan para indicar al sistema que ejecute un ejecutable como propietario, con los permisos del propietario. Si un archivo es propiedad de root, eso puede causar problemas.

Puedes cambiar los permisos de un archivo utilizando chmod. O bien especificas explícitamente la configuración de permisos deseada (como 644) o bien utilizas accesos directos (por ejemplo, +x para hacerlo ejecutable). Pero, ¿cómo se ve esto en la práctica?

Hagamos un archivo ejecutable con chmod:

$ ls -al /tmp/masktest
-rw-r--r-- 1 mh9 dev 0 Aug 28 13:07 /tmp/masktest 1

$ chmod +x /tmp/masktest 2

$ ls -al /tmp/masktest
-rwxr-xr-x 1 mh9 dev 0 Aug 28 13:07 /tmp/masktest 3
1

Inicialmente, los permisos de los archivos son r/w para el propietario y sólo lectura para todos los demás, es decir, 644.

2

Haz que el archivo sea ejecutable.

3

Ahora los permisos del archivo son r/w/x para el propietario y r/x para todos los demás, también conocido como 755.

En la Figura 4-2 puedes ver lo que ocurre bajo el capó. Ten en cuenta que quizá no quieras dar a todo el mundo el derecho a ejecutar el archivo, por lo que un chmod 744 podría haber sido mejor en este caso, dando sólo al propietario los permisos correctos y no cambiándolos para el resto. Trataremos este tema con más detalle en "Buenas prácticas".

lmlx 0402
Figura 4-2. Hacer ejecutable un archivo y cómo cambian con ello los permisos del archivo

También puedes cambiar la propiedad utilizando chown (y chgrp para el grupo):

$ touch myfile
$ ls -al myfile
-rw-rw-r-- 1 mh9 mh9 0 Sep 4 09:26 myfile 1

$ sudo chown root myfile 2
-rw-rw-r-- 1 root mh9 0 Sep 4 09:26 myfile
1

El archivo miarchivo, que he creado y del que soy propietario.

2

Después de chown, root es el propietario de ese archivo.

Habiendo hablado de la gestión básica de permisos, veamos algunas técnicas más avanzadas en este ámbito.

Permisos de proceso

Hasta ahora nos hemos centrado en cómo acceden los usuarios humanos a los archivos y cuáles son los respectivos permisos en juego. Ahora nos centraremos en los procesos. En "Recursos y propiedad", hablamos de cómo los usuarios poseen los archivos y de cómo los procesos los utilizan. Esto plantea la pregunta: ¿cuáles son los permisos relevantes, desde el punto de vista de los procesos?

Como se documenta en la página del manualcredentials(7) , hay diferentes ID de usuario relevantes en el contexto de los permisos de ejecución:

UID real

El UID real es el UID del usuario que lanzó el proceso. Representa la propiedad del proceso en términos de usuario humano. El propio proceso puede obtener su UID real mediantegetuid(2)y puede consultarlo a través del shell utilizando stat -c "%u %g" /proc/$pid/.

UID efectivo

El núcleo Linux utiliza el UID efectivo para determinar los permisos que tiene el proceso cuando accede a recursos compartidos, como las colas de mensajes. En los sistemas UNIX tradicionales, también se utilizan para el acceso a archivos. Sin embargo, Linux utilizaba anteriormente un UID dedicado al sistema de archivos (ver la siguiente discusión) para los permisos de acceso a archivos, lo que aún se admite por razones de compatibilidad. Un proceso puede obtener su UID efectivo mediante geteuid(2).

Guardado set-user-ID

Los set-user-ID guardados se utilizan en suid casos en los que un proceso puede asumir privilegios cambiando su UID efectivo entre el UID real y el set-user-ID guardado. Por ejemplo, para que un proceso pueda utilizar determinados puertos de red (ver "Puertos"), necesita privilegios elevados, como ser ejecutado como root. Un proceso puede obtener sus set-user-ID guardados mediante getresuid(2).

UID del sistema de archivos

Estos identificadores específicos de Linux se utilizan para determinar los permisos de acceso a los archivos. Este UID se introdujo inicialmente para dar soporte a casos de uso en los que un servidor de archivos actuara en nombre de un usuario normal, a la vez que aislaba el proceso de las señales de dicho usuario. Los programas no suelen manipular directamente este UID. El núcleo realiza un seguimiento de cuándo se cambia el UID efectivo y cambia automáticamente el UID del sistema de archivos con él. Esto significa que, por lo general, el UID del sistema de archivos es el mismo que el UID efectivo, pero puede cambiarse mediante el comandosetfsuid(2). Ten en cuenta que, técnicamente, este UID ya no es necesario desde la versión 2.0 del núcleo, pero sigue siendocompatible.

Inicialmente, cuando se crea un proceso hijo a través de fork(2), hereda copias de los UID de sus padres, y durante una llamada al sistema execve(2), el UID real del proceso se conserva, mientras que el UID efectivo y el set-user-ID guardado pueden cambiar.

Por ejemplo, cuando ejecutas el comando passwd, tu UID efectivo es tu UID, digamos 1000. Ahora bien, passwd tiene activado suid, lo que significa que cuando lo ejecutas, tu UID efectivo es 0 (también conocido como root). También hay otras formas de influir en el UID efectivo, por ejemplo, utilizando chroot y otras técnicas de sandboxing.

Nota

Los hilos POSIX requieren que las credenciales sean compartidas por todos los hilos de un proceso. Sin embargo, a nivel del núcleo, Linux mantiene credenciales de usuario y de grupo separadas para cada hebra.

Además de los permisos de acceso a los archivos, el núcleo utiliza los UID de los procesos para otras cosas, entre las que se incluyen las siguientes:

  • Establecer permisos para enviar señales; por ejemplo, para determinar qué ocurre cuando haces un kill -9 para un ID de proceso determinado. Volveremos sobre esto en el Capítulo 6.

  • Gestión de permisos para la programación y las prioridades (por ejemplo, nice).

  • Comprobación de los límites de recursos, que trataremos en detalle en el contexto de los contenedores en el capítulo 9.

Aunque puede ser sencillo razonar con una UID efectiva en el contexto de suid, una vez que entran en juego las capacidades puede ser más difícil.

Gestión avanzada de permisos

Aunque hasta ahora nos hemos centrado en mecanismos ampliamente utilizados, los temas de esta sección son en cierto sentido avanzados y no necesariamente algo que considerarías en una configuración casual o de aficionado. Para un uso profesional, es decir, casos de uso en producción en los que se implementan cargas de trabajo críticas para la empresa, deberías conocer al menos los siguientes enfoques avanzados de gestión de permisos.

Capacidades

En Linux, como ocurre tradicionalmente en los sistemas UNIX, el usuario root no tiene restricciones a la hora de ejecutar procesos. En otras palabras, el núcleo sólo distingue entre dos casos:

  • Procesos privilegiados, que eluden las comprobaciones de permisos del núcleo, con un UID efectivo de 0 (también conocido como root)

  • Procesos sin privilegios, con un UID efectivo distinto de cero, para los que el núcleo realiza comprobaciones de permisos, como se explica en "Permisos de proceso"

Con la introducción de lallamada al sistema de capacidades en el kernel v2.2, esta visión binaria del mundo ha cambiado: los privilegios tradicionalmente asociados a root se dividen ahora en unidades distintas que pueden asignarse independientemente a nivel de cada hilo.

En la práctica, la idea es que un proceso normal tenga cero capacidades, controladas por los permisos comentados en la sección anterior. Puedes asignar capacidades a los ejecutables (binarios y shell scripts), así como a los procesos, para añadir gradualmente los privilegios necesarios para llevar a cabo una tarea (consulta la discusión en "Buenas prácticas").

Ahora, una advertencia: las capacidades suelen ser relevantes sólo para las tareas a nivel de sistema. En otras palabras: la mayoría de las veces no dependerás necesariamente de ellas.

En la Tabla 4-4 puedes ver algunas de las capacidades más utilizadas.

Tabla 4-4. Ejemplos de capacidades útiles
Capacidad Semántica

CAP_CHOWN

Permite al usuario realizar cambios arbitrarios en los UID/GID de los archivos

CAP_KILL

Permite enviar señales a procesos pertenecientes a otros usuarios

CAP_SETUID

Permite cambiar el UID

CAP_SETPCAP

Permite establecer las capacidades de un proceso en ejecución

CAP_NET_ADMIN

Permite realizar varias acciones relacionadas con la red, como configurar la interfaz

CAP_NET_RAW

Permite utilizar sockets RAW y PACKET

CAP_SYS_CHROOT

Permite llamar a chroot

CAP_SYS_ADMIN

Permite realizar operaciones de administración del sistema, incluido montar sistemas de archivos

CAP_SYS_PTRACE

Permite utilizar strace para depurar procesos

CAP_SYS_MODULE

Permite cargar módulos del núcleo

Veamos ahora las capacidades en acción. Para empezar, para ver las capacidades, puedes utilizar comandos como los que se muestran a continuación (salida editada para ajustarse):

$ capsh --print 1
Current: =
Bounding set =cap_chown,cap_dac_override,cap_dac_read_search,
cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,
...

$ grep Cap /proc/$$/status 2
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 000001ffffffffff
CapAmb: 0000000000000000
1

Visión general de todas las capacidades del sistema

2

Capacidades del proceso actual (el shell)

Puedes gestionar las capacidades de forma detallada -es decir, por archivo- congetcap ysetcap (los detalles y las buenas prácticas quedan fuera del alcance de este capítulo).

Las capacidades ayudan a pasar de un enfoque de todo o nada a privilegios más finos en función de los archivos. Pasemos ahora a otro tema de control de acceso avanzado: la técnica de sandboxing de seccomp.

Perfiles seccomp

El modo de computación segura (seccomp)es una función del núcleo de Linux disponible desde 2005. La idea básica de esta técnica de sandboxing es que, mediante una llamada al sistema dedicada llamada seccomp(2), puedes restringir las llamadas al sistema que puede utilizar un proceso.

Aunque te resulte incómodo gestionar tú mismo seccomp directamente, hay formas de utilizarlo sin demasiadas complicaciones. Por ejemplo, en el contexto de los contenedores (ver "Contenedores"), tantoDocker comoKubernetes admiten seccomp.

Veamos ahora una extensión del permiso de archivos tradicional y granular.

Listas de control de acceso

Con las listas de control de acceso (ACL), disponemos en Linux de un mecanismo de permisos flexible que puedes utilizar además de los permisos más "tradicionales", de los que hablamos en "Permisos de archivos". Las ACL solucionan una deficiencia de los permisos tradicionales, ya que te permiten conceder permisos a un usuario o grupo que no esté en la lista de grupos de un usuario.

Para comprobar si tu distribución admite ACL, puedes utilizargrep -i acl /boot/config*, donde esperarías encontrar un POSIX_ACL=Y en algún lugar de la salida para confirmarlo. Para utilizar ACL en un sistema de archivos, debe activarse en el momento del montaje, utilizando la opción acl. La referencia docs sobreacl tiene muchos detalles útiles.

No entraremos aquí en más detalles sobre las ACL, ya que están un poco fuera del alcance de este libro; sin embargo, conocerlas y saber por dónde empezar puede ser beneficioso, en caso de que te encuentres con ellas en la naturaleza.

Dicho esto, repasemos algunas buenas prácticas para el control de acceso.

Buenas prácticas

He aquí algunas "buenas prácticas" de seguridad en el contexto más amplio del control de accesos. Aunque algunas de ellas pueden ser más aplicables en entornos profesionales, todo el mundo debería al menos conocerlas.

Menos privilegios

El principio de los mínimos privilegios dice, en pocas palabras, que una persona o proceso sólo debe tener los permisos necesarios para realizar una tarea determinada. Por ejemplo, si una aplicación no escribe en un archivo, entonces sólo necesita acceso de lectura. En el contexto del control de acceso, puedes poner en práctica los mínimos privilegios de dos formas:

  • En "Permisos de archivos", vimos lo que ocurre al utilizar chmod +x. Además de los permisos que pretendías, también asigna algunos permisos adicionales a otros usuarios. Utilizar permisos explícitos mediante el modo numérico es mejor que el modo simbólico. En otras palabras: aunque este último es más cómodo, es menos estricto.

  • Evita ejecutar como root tanto como puedas. Por ejemplo, cuando necesites instalar algo, deberías utilizar sudo en lugar de iniciar sesión comoroot.

Ten en cuenta que, si estás escribiendo una aplicación, puedes utilizar una política SELinux para restringir el acceso sólo a determinados archivos, directorios y otras funciones. En cambio, el modelo Linux por defecto podría potencialmente dar acceso a la aplicación a cualquier archivo que quede abierto en el sistema.

Evitar setuid

Aprovecha las capacidades en lugar de confiar en setuid, que es como un mazo y ofrece a los atacantes una forma estupenda de apoderarse de tu sistema.

Auditoría

La auditoría es la idea de que registras acciones (junto con quién las llevó a cabo) de forma que el registro resultante no pueda ser manipulado. Luego puedes utilizar este registro de sólo lectura para verificar quién hizo qué y cuándo. Profundizaremos en este tema en el Capítulo 8.

Conclusión

Ahora que sabes cómo gestiona Linux los usuarios, los archivos y el acceso a los recursos, tienes todo a tu disposición para llevar a cabo las tareas rutinarias de forma segura.

Para cualquier trabajo práctico con Linux, recuerda la relación entre usuarios, procesos y archivos. Esto es crucial, en el contexto del sistema operativo multiusuario que es Linux, para un funcionamiento seguro y para evitar daños.

Repasamos los tipos de control de acceso, definimos qué son los usuarios en Linux, qué pueden hacer y cómo gestionarlos tanto local como centralmente. El tema de los permisos de archivos y cómo gestionarlos puede ser peliagudo, y dominarlo es sobre todo cuestión de práctica.

Las técnicas avanzadas de permisos, incluidas las capacidades y los perfiles seccomp, son muy relevantes en el contexto de los contenedores.

En la última sección, hablamos de buenas prácticas en torno a la seguridad relacionada con el control de acceso, especialmente aplicando los mínimos privilegios.

Si quieres profundizar en los temas tratados en este capítulo, aquí tienes algunos recursos:

General
Capacidades
seccomp
Listas de control de acceso

Recuerda que la seguridad es un proceso continuo, por lo que debes asegurarte de vigilar a los usuarios y los archivos, algo en lo que profundizaremos en los Capítulos 8 y 9, pero por ahora pasemos al tema de los sistemas de archivos.

Get Aprender Linux moderno now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.