ACL: Access Control Lists y los permisos en GNU/Linux

Publicado por Diego Córdoba en

En esta oportunidad haremos una introducción al uso de las listas de control de acceso, o ACL (Access Control Lists) para añadir flexibilidad a la gestión de permisos y privilegios de usuarios y grupos sobre recursos del sistema de archivos.

Permisos en GNU/Linux

Si bien no es la intención profundizar sobre administración de permisos en GNU/Linux, sí haré una breve introducción para poder entender la motivación del uso de las ACL’s.

Los permisos se aplican sobre elementos del sistema de archivos, tales como archivos regulares, directorios, sockets Unix, enlaces simbólicos, nodos de dispositivos, etc. Los tipos de permisos que puede administrar GNU/Linux, o permisos POSIX, son tres (sí, existen los permisos especiales y los atributos, pero ese es otro tema 😛 ) :

  • Lectura (r: Read): la entidad asociada podrá leer el elemento.
  • Escritura (w: Write): la entidad asociada podrá escribir o modificar el elemento.
  • Ejecución (x: eXecution): la entidad asociada podrá ejecutar el elemento.

Las entidades sobre las que tienen vigencia estos permisos son:

  • Usuario dueño (u: User): usuario dueño del elemento en el sistema de archivos.
  • Grupo al que pertenece (g: Group): grupo al que pertenece el elemento.
  • Otros usuarios (o: Others): el resto de los usuarios del sistema que no son ni el dueño del elemento, ni pertenecen al grupo del elemento.

Así, por ejemplo, un elemento del sistema de archivos como un archivo podría tener permisos de lectura, escritura y ejecución para el usuario dueño (rwx), lectura y ejecución para el grupo (r-x) y solamente lectura para los otros usuarios del sistema (r--).

En el sistema de archivos permite ver los permisos de cada elemento a través de la salida del comando ls -l aplicado al directorio raíz /:

permisos nativos ls -l

Las líneas de esta salida tienen una estructura particular. De esta salida ahora nos interesa la primer columna, compuesta de 10 letras. En la captura mostrada se puede ver, en la primer columna, las letras que identifican los permisos de cada elemento. La primer letra de esta columna indica el tipo de elemento, y luego sí tenemos 9 letras que identifican los permisos de lectura, escritura y ejecución en tres ternas: usuario dueño, grupo, y los otros usuarios del sistema.

tipos de permisos

Cuando el permiso está presente, se verá la letra correspondiente, mientras que si el permiso no está activado en alguna terna, se verá un guion "-". Analicemos una de las líneas de esta salida:

drwxr-x---  35 root root  4096 Jun  7 20:45 root                                     

Esta línea corresponde con el directorio /root del sistema. Es un directorio puesto que la primer letra de esta línea es una «d«. Los permisos de este elemento son rwxr-x---, es decir, permisos totales (lectura, escritura y ejecución, rwx) para el dueño del elemento (el usuario root, columna 3 de la salida), permisos de lectura y ejecución (r-x) para el grupo de usuarios al cual pertenece el directorio (grupo root, columna 4 de la salida), y ningún permiso (---) para los usuarios del sistema que no son ni el dueño ni pertenecen al grupo del elemento.

Entre los comandos más comunes que un sysadmin puede emplear para gestionar estos permisos y propiedad de recursos se encuentran:

  • chown: permite cambiar el usuario dueño de un elemento del sistema de archivos.
  • chgrp: permite cambiar el grupo al que pertenece un elemento del sistema de archivos.
  • chmod: permite cambiar los permisos de un elemento del sistema de archivos.

Limitaciones de los permisos nativos

Estos permisos tienen algunas limitaciones. Consideremos el siguiente ejemplo:

drwxr-xr--  1 diego usuarios  916 Jun  7 20:51 miarchivo.sh

Aquí el usuario dueño, diego, tiene permisos de lectura, escritura y ejecución sobre el archivo miarchivo.sh, los usuarios que pertenecen al grupo usuarios pueden leer y ejecutar este archivo, y el resto de los usuarios del sistema solamente pueden leer dicho archivo.

Si quisiéramos que el usuario juan pueda modificar este archivo podríamos tomar varios cursos de acción, entre ellos:

  • Cambiar el dueño del archivo miarchivo.sh al usuario juan, con lo cual el usuario diego dejaría de tener permisos totales sobre el mismo.
  • Podríamos agregar al usuario juan al grupo usuarios, pero deberíamos darle permiso de escritura a este grupo, por lo que todos los demás usuarios del grupo también tendrían acceso de escritura, cosa que podría no ser conveniente.
  • Podríamos darle permisos de escritura a la terna de los otros usuarios del sistema, con lo cual juan podría escribir el archivo, pero cualquier usuario del sistema también podría.
  • Podríamos agregar permisos de escritura para el grupo, y cambiar el grupo por un grupo al cual pertenezca el usuario juan, como su grupo primario por ejemplo, pero los integrantes del grupo usuarios dejarían de tener acceso de lectura y ejecución.

La solución parece no ser sencilla. Lo mismo ocurriría si quisiéramos, por ejemplo, dar permisos de escritura a los usuarios del grupo sambausers, ya que no es el grupo al que pertenece el archivo, y nos ocasionaría problemas similares. Aquí es donde entran en juego las listas de control de acceso, o ACL (Access Control List), en la administración de privilegios en GNU/Linux.

¿Qué son las ACL?

Las ACL son representaciones de permisos para elementos del sistema de archivos, que extienden los permisos nativos POSIX.1 del sistema. De hecho, los permisos nativos también tienen su representación en ACL cuando éstas están activadas, es decir, los permisos nativos son representados por ACL’s, y además, podemos agregar ACL’s adicionales para otorgar permisos más granularizados a otras entidades del sistema de archivos.

Los tipos de entradas en una ACL y sus formatos específicos se resumen en la siguiente tabla.

Tipo de entradaEtiqueta de permisosForma en texto
Owner (dueño) *ACL_USER_OBJuser::rwx ó u::rwx
Named user (usuario nombrado)ACL_USERuser:name:rwx ó u:name:rwx
Owning group (grupo dueño) *ACL_GROUP_OBJgroup::rwx ó g::rwx
Named group (grupo nombrado)ACL_GROUPgroup:name:rwx ó g:name:rwx
Mask (máscara)ACL_MASKmask::rwx ó m::rwx
Others (otros) *ACL_OTHERother::rwx ó o::rwx
Tipos de entradas de ACL

Básicamente las ACL se conforman por un tipo (user, group, mask, other), una serie de calificadores (qué usuario, qué grupo, o ninguno), y los permisos en formato POSIX.1 estándar (mode). Los permisos de usuario dueño nativos mapean con la clase de permisos ACL_USER_OBJ. Los permisos de grupo dueño mapean con la clase ACL_GROUP_OBJ. Finalmente, los permisos de los otros usuarios mapean con la clase de permisos ACL_OTHER.

Cuando se activan las ACL en un sistema de archivos, pasan a utilizarse como mecanismo predeterminado de gestión de permisos. Las ternas de permisos nativos POSIX mapean directamente a ACL’s, lo que da la posibilidad de gestionar estos permisos mediante ACL’s. Las ACL equivalentes a los permisos nativos de POSIX se las denomina ACL’s mínimas, y están marcadas con un (*) en la tabla anterior, y son tres.

Las demás se denominan ACL’s extendidas. Estas ACL’s extendidas incluyen una máscara (mask) y cualquier cantidad de entradas de usuarios y grupos nombrados.

Los permisos definidos en las entradas owner (usuario dueño) y other (los otros usuarios) son siempre efectivos. Los demás, named user, named group, y owning group (grupo dueño) pueden ser efectivos o enmascarados por la entrada mask. Esto es porque los permisos dados por ACL’s, ya sean named user o named group, extienden los permisos nativos de grupo dueño, es decir, extienden la clase de permisos de grupo.

Para entender el funcionamiento analicemos las diferencias conceptuales entre los permisos nativos POSIX y los permisos asignados por ACL. Analicemos la siguiente imagen:

acl minimas

Cuando hablamos de las ACL mínimas (sin máscara), los permisos de las clases dueño, grupo y otros coinciden con los permisos nativos de usuario dueño, grupo y otros que vemos en la salida de comandos como ls -l.

Veamos ahora la siguiente imagen.

acl extendidas

Cuando hablamos de ACL extendidas (con máscara), las clases de permisos de usuario dueño y otros coinciden con los que vemos en la salida de ls -l, pero la clase de permisos de grupo puede contener entradas de usuarios o grupos nombrados adicionales. Cuando se incorporan ACL’s extendidas los permisos de la clase grupo se mapean ahora con la máscara (mask), dejando intáctos los permisos POSIX del grupo dueño.

Este enfoque garantiza la interacción con aplicaciones que no tengan soporte para ACL, es decir, las aplicaciones que no entiendan sobre ACL gestionarán los permisos nativos POSIX. La máscara representa el límite superior de todos los «ajustes finos» realizados mediante ACL’s extendidas.

Los permisos que un usuario o grupo requieran para acceder a un elemento debe estar configurado explícitamente en una ACL extendida, y deben estar presentes también en la máscara.

Más abajo, luego de entender mejor el funcionamiento de las ACL’s extendidas, volveremos a hablar de la máscara.

ACL: requisitos

Para poder utilizar las listas de control de acceso en los sistemas de archivos en Linux se requieren tres cosas:

  • Que las ACL’s estén soportadas en los módulos de sistemas de archivos en el kernel Linux.
  • Que el sistema de archivos sobre el que se vayan a implementar tenga activada la opción acl.
  • Que se encuentren instaladas las utilidades para gestionar las ACL’s.

Soporte de ACL en el núcleo Linux

Para verificar si las ACL están soportadas por nuestro kernel tenemos dos formas. Si existe el archivo de configuración que se utilizó para compilar el núcleo en nuestra distribución, en general se encontrará dentro de /boot, y su nombre será config-<version del nucleo Linux activo>. En definitiva podríamos utilizar el siguiente comando para verificarlo:

grep ACL  /boot/config-$(uname -r)

Cuya salida debería ser algo similar a la siguiente, donde se ve que las ACL están activas para todos los sistemas de archivos soportados por el núcleo.

acl config kernel

Si no disponemos de este archivo de configuración, podríamos verificar si existe el archivo /proc/config.gz. Este archivo contiene las configuraciones utilizadas por el kernel que está en ejecución en este momento. Podríamos utilizar el siguiente comando para verificar el soporte de ACL’s:

zcat /proc/config.gz | grep ACL
# o alternativas más elegantes como:
zgrep ACL /proc/config.gz
acl config kernel proc

Opción de montaje con ACL

El sistema de archivos donde vayamos a aplicar las listas de control de acceso debe haber sido montado utilizando la opción acl. Supongamos que el punto de montaje que monta, valga la redundancia, el sistema de archivos donde se van a aplicar las ACL es /media/disco. Podríamos activar de manera temporal las ACL en dicho sistema de archivos remontándolo de la siguiente manera (se debe considerar agregar las opciones necesarias):

sudo mount -o remount,defaults,acl /media/disco

Para lograrlo de manera permanente bastará añadir la opción acl en la línea de montaje dentro del archivo /etc/fstab. Por ejemplo:

UUID=43a17673-c811-4c47-9d1b-556205f13a79 /media/disco ext4 defaults,noatime,nodiratime,commit=60,user,exec,acl 0 2

Con esto deberíamos reiniciar el ordenador, o desmontar y re-montar el dispositivo en cuestión para que tome los cambios.

También, como dato adicional, podríamos verificar la salida del comando tune2fs (si el sistema de archivos es ext4 por ejemplo) para verificar las opciones de montaje por defecto. Veamos mi disco, /dev/sdb1:

diego@cryptos:~$ sudo tune2fs -l /dev/sdb1 | grep options
Default mount options:    user_xattr acl

Instalación de las utilidades

Si ya verificamos que el kernel tiene soporte para ACL, no quedará más que instalar las utilidades necesarias, en general, incluidas en el paquete acl del repositorio de la distribución:

# Debian:
sudo apt install acl

# Arch Linux
sudo pacman -S acl

Esto nos dará los dos comandos más importantes para gestionar las ACL en el sistema de archivos:

  • getfacl: permite obtener las ACL de los elementos.
  • setfacl: permite configurar permisos utilizando las ACL’s.

Al fin! Configurando ACL’s

Antes que nada aprendamos a ver las ACL’s de los elementos del sistema de archivos. Se preguntarán ¿por qué ver las acl’s si no hemos configurado ninguna? Pues bien, a partir de habilitar las ACL’s en el sistema, todos los permisos nativos mapean directamente como ACL’s, tal y como comentamos arriba.

La siguiente imagen muestra los permisos de un archivo llamado archivo.txt (la creatividad primero eh! 😀 ), y luego las ACL’s del mismo. Se puede ver que el archivo pertenece al usuario diego, grupo users, y tiene los permisos rw-r--r-- (lectura y escritura para el dueño, y lectura solamente para los usuarios del grupo y para el resto de los usuarios del sistema).

getfacl

Las primeras líneas de la salida de getfacl muestran el nombre del archivo, el dueño y el grupo, y luego los permisos para dueño (user), grupo (group) y el resto de los usuarios (other), tal y como se ve en la salida del ls -l arriba.

Otorgando permisos a usuarios y grupos

Supongamos que el usuario uaa necesita acceso de lectura y escritura al archivo archivo.txt. Como comentamos arriba, no podríamos darle estos permisos al usuario sin asignarlo como dueño, o cambiar el grupo del archivo. Con ACL podríamos otorgar estos permisos utilizando setfacl y el modificador -m o --modify de esta manera:

setfacl -m u:uaa:rw- archivo.txt

El dueño del archivo (o el root) podrán setear estos permisos. Ahora la ACL del archivo se verá como la siguiente imagen, y el usuario uaa podrá modificarlo. Se aprecia también una entrada para la máscara, o mask.

setfacl

Lo mismo podría aplicarse a un directorio.

La sintaxis de setfacl especifica los permisos para usuarios o grupos utilizando la siguiente nomenclatura:

u:named_user:permission
g:named_group:permission

Y se pueden otorgar varios permisos en la misma línea separando los mismos por coma, por ejemplo:
(los guiones - pueden omitirse, yo los uso para mantener la claridad de los permisos otorgados).

setfacl -m u:usuario1:rw-,u:usuario2:r--,g:grupo1:r-- archivo.txt

En el caso de que el destino sea un directorio y quisiéramos aplicar la ACL a todos los elementos interiores de manera recursiva, podemos utilizar el modificador -R:

setfacl -Rm u:usuario1:rw- directorio/

Eliminando ACL’s

Para eliminar una ACL creada por error podemos utilizar el modificador -x o --remove. Por ejemplo, si la ACL creada para el usuario uaa fue creada por error, podemos eliminarla con el siguiente comando:

setfacl -x u:uaa archivo.txt

Dicho sea de paso, podemos eliminar todas las ACL’s creadas para un archivo o directorio utilizando el modificador -b (o --remove-all) de esta forma:

setfacl -b archivo.txt

ACL’s por defecto para archivos y directorios

Muchas veces es necesario que todos los elementos, archivos o directorios, que sean creados dentro de un directorio, obtengan las mismas ACL’s que el directorio padre. Esto puede lograrse con el modificador -d o --default de setfacl. La siguiente captura muestra cómo he cargado una ACL para el usuario andy en el directorio directorio/, y cómo, mediante la opción -d, se ha heredado la ACL a un archivo creado dentro del directorio luego.

setfacl -dm u:andy:r directorio/
setfacl acl default

En este punto es importante notar que los subdirectorios de directorio/ creados antes de setear la ACL por default no la tendrán de manera predeterminada. Para que tanto el directorio directorio/ como todos sus subdirectorios incorporen dicha ACL de manera predeterminada, deberíamos haber incorporado la opción -R en el comando:

setfacl -Rdm u:andy:r directorio/

Usuarios y grupos

Supongamos que limpiamos las ACL’s de archivo.txt, y le damos privilegios de lectura al grupo users:

setfacl -b archivo.txt
setfacl -m g:users:r

El usuario uaa pertenece al grupo users, por lo que tiene permisos de lectura sobre el archivo (incluso si no perteneciera al grupo igualmente tendría permisos porque la terna other también le da permiso de lectura.

No obstante, si independientemente del grupo, al usuario uaa le damos privilegios de lectura y escritura al archivo, éstos prevalecerán por sobre los del grupo, y el usuario uaa podrá modificar el archivo:

setfacl -m u:uaa:rw archivo.txt

Mask: ¿qué es eso?

Como habrán notado en la captura anterior, al momento de crear la ACL se pudo observar que el usuario dispone de los nuevos permisos, y además se agregó una nueva línea de permisos: mask.

Hay que recordar primero que las ACL no son más que una extensión de los permisos nativos del sistema. Además, todos los permisos de ACL, ya sea para usuarios o grupos nombrados, son asignados a la clase de permisos de grupo, es decir, las ACL extienden los permisos tradicionales de la terna de grupo. En otras palabras, al agregar ACL’s a la administración de permisos, los permisos de grupo POSIX se ven extendidos con nuevas clases de permisos, por lo que se redefine el significado de los permisos de grupo, tal y como se mencionó arriba.

Ahora bien, con esta perspectiva, las ACL’s de usuarios o grupos nombrados podrían requerir mayor acceso al recurso, de los propuestos por los permisos nativos POSIX para el grupo dueño. Es decir, supongamos que tenemos un archivo.txt con los siguientes permisos:

-rw-r--r-- 1 diego users

En este caso el usuario diego tendrá permisos rw-, mientras que los usuarios pertenecientes al grupo users solamente tendrán permisos de lectura. Ahora, supongamos que un usuario no perteneciente a users, como el usuario andy, requiriere permisos de lectura y escritura.

El límite superior de permisos de la clase grupo (permisos nativos de grupo y permisos de ACL de usuarios y grupos nombrados) es rw-, para abarcar los permisos nativos y los permisos del usuario nombrado andy. Este límite superior debe quedar escrito en algún lado. Si modificamos los permisos nativos de grupo para abarcar rw-, los usuarios del grupo users ahora empezarían a tener permisos de escritura, por lo que no es conveniente.

Como no pueden usarse los permisos nativos de grupo como límite superior de permisos de la clase grupo, se utiliza la máscara o mask. Veamos un ejemplo. Si añadimos permisos de rw al usuario andy mediante ACL extendida:

setfacl -m u:andy:rw- archivo.txt

Los permisos ahora se verán así en la salida de ls -l:

-rw-rw-r--+ 1 diego users

Si bien aparece que la terna de permisos de grupo es rw- para el grupo users, también se ve un signo "+" al final de los permisos, lo que indica el uso de ACL’s extendidas. Si vemos las ACL’s de este archivo tenemos esto:

# file: archivo.txt
# owner: diego
# group: users
user::rw-
user:andy:rw-
group::r--
mask::rw-
other::r--

El usuario andy ahora puede leer y escribir el archivo, pero los usuarios del grupo users siguen manteniendo su permiso de sólo lectura. Los permisos de grupo que se ven en la salida del ls -l representan los de la clase grupo, ahora asignados a la máscara mask.

A partir de la implementación de ACL’s extendidas en el archivo, la máscara marcará el límite máximo de permisos de la clase grupo actualmente configurados, y se actualizará cada vez que carguemos una nueva ACL. Por ejemplo, si al usuario uaa le damos permiso de ejecución (no presente en la máscara), ahora la máscara pasará a ser rwx para abarcar también este permiso.

# file: archivo.txt
# owner: diego
# group: users
user::rw-
user:andy:rw-
user:uaa:--x
group::r--
mask::rwx
other::r--

Otro dato interesante. Como sabemos, el comando chmod permite modificar los bits de permisos nativos POSIX de los archivos y directorios. Los cambios que efectuemos sobre los permisos de user y other se verán reflejados directamente sobre sus respectivas ACL’s (user y other).

Asimismo, podríamos modificar estos bits utilizando setfacl para user omitiendo el usuario nombrado. Así, este comando:

chmod u+rwx archivo.txt

Equivale a:

setfacl -m u::rwx archivo.txt

Y lo mismo ocurre con los permisos de la terna other sustituyendo la letra «u» por «o«. Por supuesto, debemos recordar que la sintaxis mostrada de chmod depende de los permisos que actualmente posea el archivo, mientras que la sintaxis de setfacl especifica permisos absolutos.

Si hacemos lo mismo con la terna de grupo, cambiando «u» u «o» por «g«, veremos lo siguiente:

setfacl -m g::rwx archivo.txt

Luego de aplicar esta modificación a los permisos de grupo, la lista de ACL’s se verá algo así:

# file: archivo.txt
# owner: diego
# group: users
user::rw-
user:andy:rw-   
group::rwx
mask::rwx 
other::r--

Como era de esperarse, la ACL de permisos nativos de grupo, «group«, pasó a tener los permisos rwx, y la máscara mask también. Esto es obvio puesto que, como dijimos, la máscara se recalcula especificando el límite superior de los permisos otorgados a la clase grupo, y particularmente en este caso, los permisos nativos POSIX para el grupo también son un permiso incluido en la clase grupo.

Ahora, si quitamos el permiso de escritura de la ACL group con este comando:

setfacl -m g::r archivo.txt

El resultado será el siguiente:

# file: archivo.txt
# owner: diego
# group: users
user::rw-
user:andy:rw-   
group::r--      
mask::rw- 
other::r--

Los permisos nativos de grupo, group, se vieron modificados, y la ACL mask re recalculó para coincidir con el límite superior de permisos otorgados a la clase grupo.

Modificando la máscara

La máscara mask se puede manipular como un tipo de permiso más dentro de las ACL’s. Veamos un ejemplo. Supongamos tenemos un archivo con esta configuración de ACL’s:

# file: archivo.txt
# owner: diego
# group: users
user::rw-
user:andy:rw-   
group::r--      
mask::rw- 
other::r--

Si cambiamos la máscara con setfacl, por ejemplo, a sólo lectura «r--«, ¿qué pasará con los permisos de la clase grupo?

setfacl -m m::r archivo.txt

Como se ve, se usa el identificador «m» para modificar la máscara. Veamos ahora cómo quedó la ACL:

# file: archivo.txt
# owner: diego
# group: users
user::rw-
user:andy:rw-   #effective:r--
group::r--      
mask::r-- 
other::r--

Como se ve, primero la máscara mask quedó con permiso r--. Anteriormente era rw- puesto que el usuario andy tenía permisos en ACL como usuario nombrado, por lo que la máscara se había recalculado. Ahora, como «redujimos» los permisos de la máscara, se modificó el límite superior de permisos otorgados a todas las entidades de la clase grupo.

Particularmente en este caso, el usuario andy, si bien mantiene sus permisos de rw-, el permiso de escritura dejó de ser efectivo ya que está limitado por la máscara. Esto es indicado mediante la leyenda effective:r--.

Conclusiones: ¿Se usan las ACL?

En general no suelo usar ACL’s para administrar los privilegios de acceso a los archivos y directorios del sistema, casi siempre los permisos nativos son lo suficientemente flexibles para resolver muchas políticas de acceso a elementos del sistema de archivos.

Igualmente, como se vio, las ACL’s permiten extender y añadir flexibilidad en la gestión de permisos sobre elementos del sistema de archivos, por lo que resulta muy útil conocerlas y entenderlas.

Los permisos de ACL quedan aplicados a nivel de sistema de archivos, por lo que depende del tipo de sistema de archivos el soporte para ACL. Los ejemplos mostrados fueron realizados sobre ext4, pero en general los módulos del kernel que habilitan diferentes sistemas de archivos suelen dar soporte para ACL, por lo que las implementaciones de filesystems como CIFS suelen soportar ACL’s.

Particularmente NFSv4 incorpora un manejo de ACL propio, manteniendo mayormente la misma sintaxis de las ACL’s de Linux, por lo que antes de pensar en incorporar ACL’s en un sistema de archivos no está de mas investigar qué soporte provee.

Para quien quiera ampliar esta información, les comparto algunos enlaces de interés, que he utilizado como fuente (además de mis propios experimentos).

Espero que les guste y les resulte interesante! Cualquier comentario o sugerencia ya saben que pueden hacerlo en el grupo de Telegram de JuncoTIC!

Hasta la próxima!

Fuentes:

¿Preguntas? ¿Comentarios?

Si tenés dudas, o querés dejarnos tus comentarios y consultas, sumate al grupo de Telegram de la comunidad JuncoTIC!
¡Te esperamos!

Categorías: Linux

Diego Córdoba

- Ingeniero en Informática - Mg. Teleinformática - Tesis pendiente - Docente universitario - Investigador