Administración de Linux
Usuarios, grupos y permisos en Linux: bits rwx, umask, ACL y sudo
Principiante11 min de lecturaActualizado
Esta página se tradujo del inglés con ayuda de IA y se cotejó con el original. Leer la versión en inglés
En una máquina Linux, toda decisión de acceso se reduce a un identificador numérico de usuario, un conjunto de identificadores de grupo y doce bits asociados a un archivo. Esta guía muestra dónde se guardan las cuentas, cómo evalúa el kernel una comprobación de permisos y cómo ampliar o restringir el acceso de forma segura con chmod, umask, las ACL y sudo. Termina con SSH basado en claves, el mecanismo de inicio de sesión que deberías usar en cualquier servidor expuesto a la red.
Lo que aprenderás
- Describir cómo se almacenan y crean las cuentas, los grupos primarios y los grupos secundarios
- Leer y establecer modos de archivo tanto en forma simbólica como octal, y predecir qué producirá umask
- Explicar qué hacen setuid, setgid y el sticky bit, y dónde tiene sentido usar cada uno
- Conceder una excepción a un usuario o grupo concreto con una ACL POSIX en lugar de relajar el modo
- Delegar comandos de administración con reglas de sudo e iniciar sesión con un par de claves SSH
Los permisos son lo primero que comprueba un sistema Linux y lo último que la mayoría aprende bien. El modelo es lo bastante pequeño como para tenerlo en la cabeza —un identificador numérico de usuario, una lista de identificadores de grupo y doce bits por archivo—, pero los detalles muerden: por qué un chmod 777 en un directorio web es a la vez un problema de seguridad y, normalmente, ni siquiera la solución; por qué añadirte al grupo docker no tiene efecto hasta que cierras la sesión; por qué una carpeta compartida no para de generar archivos que nadie más puede editar.
Esta guía empieza por las propias cuentas, recorre los bits rwx clásicos y los bits especiales que hay por encima, y después aborda los dos mecanismos a los que recurres cuando el modelo clásico se queda corto: las listas de control de acceso y sudo. Los ejemplos suponen un sistema Debian, Ubuntu o de la familia RHEL actual. Si el formato de salida de ls -l todavía no te resulta familiar, lee antes la guía del sistema de archivos.
Quién eres para el kernel
El kernel no conoce nombres de usuario. Conoce un identificador de usuario (UID) y un conjunto de identificadores de grupo (GID) asociados a cada proceso. Los nombres existen solo para que las personas puedan leer la salida; la traducción ocurre en espacio de usuario, a través de /etc/passwd, /etc/group y el servicio de directorio que la máquina tenga configurado.
$ id
uid=1000(alice) gid=1000(alice) groups=1000(alice),27(sudo),110(www-data)
/etc/passwd contiene una línea por cuenta con campos separados por dos puntos: nombre, un x donde antes estaba el hash de la contraseña, UID, GID primario, un campo de comentario libre, directorio personal y shell de inicio de sesión. Es legible por todo el mundo porque muchos programas necesitan traducir identificadores a nombres.
alice:x:1000:1000:Alice Martin:/home/alice:/bin/bash
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
Los hashes reales de las contraseñas están en /etc/shadow, legible solo por root, junto con la información de caducidad: cuándo se cambió la contraseña por última vez, vigencia mínima y máxima, periodo de aviso y fecha de expiración. Un ! o un * en el campo del hash significa que ninguna contraseña podrá coincidir nunca, y así es como se bloquean las cuentas de servicio. Esas cuentas reciben además /usr/sbin/nologin como shell, de modo que ni siquiera una autenticación correcta pueda abrir una sesión interactiva.
En la mayoría de las distribuciones, los UID por debajo de 1000 están reservados al sistema; los usuarios humanos empiezan en 1000. El UID 0 es especial en el propio kernel: es el superusuario, y para él la mayoría de las comprobaciones de permisos simplemente se omiten.
Crear y modificar cuentas
sudo useradd -m -s /bin/bash -c "Bob Chen" bob # -m creates and populates /home/bob
sudo passwd bob
sudo usermod -aG www-data,sudo bob # -a is essential: append, do not replace
sudo usermod -L bob # lock the password
sudo userdel -r bob # -r also removes the home directory
Debian y Ubuntu incluyen también adduser, un envoltorio interactivo que elige valores por defecto razonables y pide la contraseña. Uses el que uses, la opción más importante es -a en usermod -G: sin ella, la lista de grupos secundarios se sustituye, y más de un administrador se ha quedado sin acceso a sudo de esta manera.
Los directorios personales nuevos se rellenan a partir de /etc/skel, así que todo lo que pongas ahí —un .bashrc por defecto, una configuración del editor, un directorio .ssh con el modo correcto— se copia en cada cuenta que se cree después.
Grupos primarios y secundarios
Cada cuenta tiene exactamente un grupo primario, registrado en /etc/passwd y usado como grupo propietario de los archivos que crea. Además puede pertenecer a cualquier número de grupos secundarios, listados en /etc/group.
www-data:x:33:alice,bob
developers:x:1500:alice,bob,carol
La mayoría de las distribuciones crean un grupo privado por usuario (alice:alice), de modo que un modo por defecto 0644 no concede nada a nadie más aunque el archivo se mueva luego a una zona compartida. El acceso compartido se expresa entonces creando un grupo con un nombre que indique su propósito y añadiéndole miembros.
Como las credenciales se fijan al iniciar la sesión, id es la fuente de verdad sobre lo que pueden hacer tus procesos actuales, mientras que /etc/group muestra lo que obtendrá tu próximo inicio de sesión. Si no puedes cerrar la sesión, newgrp developers abre un subshell con la nueva pertenencia.
Los doce bits
Cada archivo tiene un UID propietario, un GID de grupo y un modo: tres conjuntos de tres bits, más tres bits especiales por encima.
| Bit | En un archivo normal | En un directorio |
|---|---|---|
r | leer el contenido | listar los nombres que contiene |
w | modificar el contenido | crear, renombrar y eliminar entradas |
x | ejecutarlo como programa | atravesarlo, es decir, resolver nombres a través de él |
El kernel evalúa en un orden estricto y se detiene en la primera coincidencia: si tu UID es el del propietario, se aplica el triplete de propietario y no se consulta nada más; si no, y alguno de tus GID coincide con el grupo del archivo, se aplica el triplete de grupo; en otro caso, el triplete de otros. Por eso ----rwxrwx se lo niega todo al propietario y se lo permite a todos los demás, un orden que sorprende a quien supone que los conjuntos se suman.
De la fila de directorios de la tabla se derivan dos consecuencias. Primero, borrar un archivo es una escritura en su directorio, no en el archivo, así que puedes eliminar un archivo de solo lectura de un directorio en el que puedes escribir. Segundo, x sin r en un directorio es un patrón útil: puedes abrir /srv/data/report.pdf si conoces el nombre, pero no puedes enumerar lo que hay dentro.
Modos octales
Cada triplete es un número de tres bits: r=4, w=2, x=1. Basta con sumarlos.
| Octal | Simbólico | Uso típico |
|---|---|---|
644 | rw-r--r-- | archivos de datos y de configuración corrientes |
600 | rw------- | claves privadas, credenciales, ~/.ssh/id_ed25519 |
755 | rwxr-xr-x | programas, scripts y la mayoría de los directorios |
750 | rwxr-x--- | un directorio compartido solo con un grupo |
775 | rwxrwxr-x | un directorio en el que un grupo puede escribir |
700 | rwx------ | un directorio privado como ~/.ssh |
chmod acepta ambas formas. La simbólica es relativa y a menudo más segura, porque solo cambia los bits que nombras:
chmod 640 /etc/myapp/secrets.env
chmod u+x deploy.sh # add execute for the owner only
chmod go-w,o-rx /srv/private # remove group write, and all "other" access
chmod -R u=rwX,g=rX,o= /srv/app # capital X: execute only where it is already set, or on directories
Conviene recordar esa X mayúscula: chmod -R 755 marca como ejecutables todos los archivos de datos, mientras que chmod -R u=rwX,go=rX arregla los directorios sin mentir sobre qué archivos son programas.
La propiedad se cambia con chown y chgrp, y solo root puede ceder un archivo a otro usuario:
sudo chown -R www-data:www-data /var/www/example.com
sudo chgrp developers /srv/shared
sudo chown --reference=/etc/nginx/nginx.conf /etc/nginx/conf.d/site.conf
umask: los permisos con los que nacen los archivos
Los programas piden un modo al crear un archivo: por convención, 0666 para datos y 0777 para directorios. El umask del proceso quita bits de esa petición antes de crear el archivo. Es una máscara de bits a borrar, no a conceder.
Con el valor por defecto habitual 022, un archivo nuevo obtiene 0666 & ~022 = 0644 y un directorio nuevo 0777 & ~022 = 0755. Con umask 027, el mismo archivo queda en 0640 y el directorio en 0750, invisibles para los usuarios de fuera del grupo. Usa umask 077 en una máquina donde no deba compartirse nada por defecto.
$ umask
0022
$ umask 027; touch a; mkdir b; ls -ld a b
-rw-r----- 1 alice alice 0 Sep 7 11:20 a
drwxr-x--- 2 alice alice 4096 Sep 7 11:20 b
Como umask es una propiedad del proceso, lo heredan los procesos hijos y hay que fijarlo donde arranca el proceso: en /etc/profile o ~/.profile para los shells de inicio de sesión, con una directiva UMask= en un servicio de systemd o en la configuración propia del demonio. Ten en cuenta que los archivos nunca reciben el bit de ejecución a partir de una petición 0666, y por eso un script extraído de un archivo comprimido necesita tan a menudo un chmod +x explícito.
setuid, setgid y el sticky bit
Por encima de los nueve bits de permisos hay tres más, que se muestran en las posiciones x de ls -l.
setuid (4000, una s en el triplete de propietario) hace que un ejecutable se ejecute con los privilegios de su propietario en lugar de los de quien lo llama. /usr/bin/passwd es el ejemplo canónico: un usuario sin privilegios tiene que poder reescribir una línea de /etc/shadow, y setuid root es la forma de conseguirlo. setuid es potente e históricamente ha sido la causa de muchas escaladas de privilegios locales, así que su sitio son los binarios de la distribución y prácticamente nada más. Buscar sorpresas cabe en una línea:
sudo find / -xdev -type f -perm -4000 -printf '%M %u %p\n' 2>/dev/null
setgid (2000) hace lo mismo con el grupo en un ejecutable, pero su forma más útil es sobre un directorio: los archivos creados dentro heredan el grupo del directorio en lugar del grupo primario de quien los crea, y los subdirectorios nuevos heredan también el bit setgid. Es la receta estándar para un espacio de proyecto compartido.
sudo install -d -o root -g developers -m 2775 /srv/projects
El sticky bit (1000, una t en el triplete de otros) hace que, en un directorio con escritura para todos, solo el propietario de cada archivo pueda borrarlo. /tmp es drwxrwxrwt justo por eso: cualquiera puede crear archivos ahí, pero nadie puede borrar los de otro.
chmod 2775 /srv/projects # setgid directory
chmod 1777 /srv/scratch # sticky, world-writable
chmod g+s,o-rwx /srv/team # symbolic equivalents
Los directorios setgid fijan el grupo, pero no el modo, así que un miembro que crea un archivo con umask 022 sigue produciendo rw-r--r--, que sus compañeros no pueden editar. Combina el bit setgid con umask 002 para los usuarios implicados o usa una ACL, que es la mejor respuesta.
ACL, cuando tres conjuntos no bastan
Una lista de control de acceso (ACL) POSIX asocia a un archivo entradas con nombre para usuarios y grupos, de modo que puedes dar acceso a una persona más sin inventarte un grupo ni relajar other. El sistema de archivos debe estar montado con soporte de ACL, que es lo predeterminado en ext4 y XFS con los kernels actuales.
$ setfacl -m u:jenkins:rx /srv/app/bin
$ setfacl -m g:auditors:r /var/log/app/audit.log
$ getfacl /srv/app/bin
# file: srv/app/bin
# owner: deploy
# group: deploy
user::rwx
user:jenkins:r-x
group::r-x
mask::r-x
other::---
ls -l marca con un + final los archivos que tienen una ACL. La entrada mask es un techo para todas las entradas con nombre y para la clase de grupo; en un archivo con ACL, chmod g= ajusta la máscara y no la entrada del grupo, lo que explica la confusión ocasional de «lo he concedido y sigue sin funcionar».
Las ACL por defecto de un directorio son el mecanismo de herencia que les falta a los bits clásicos. Se aplican a las entradas que se creen más adelante, de modo que un usuario de despliegue puede conservar acceso de escritura a todo lo que un build deje en un árbol:
sudo setfacl -R -m u:deploy:rwx -m d:u:deploy:rwx /var/www/example.com
sudo setfacl -x u:jenkins /srv/app/bin # remove one entry
sudo setfacl -b /srv/app/bin # remove the whole ACL
Usa las ACL de forma deliberada y documéntalas. En un ls -l normal no se ven más allá de ese +, y un enigma de permisos que nadie sabe explicar es peor que un grupo algo torpe.
Delegar privilegios con sudo
La práctica actual es desactivar el inicio de sesión directo como root y conceder privilegios concretos mediante sudo. La política vive en /etc/sudoers y, preferiblemente, en archivos dentro de /etc/sudoers.d/. Edítalos siempre con visudo, que valida la sintaxis antes de instalar el archivo.
# /etc/sudoers.d/deploy (mode 0440, edited with: sudo visudo -f /etc/sudoers.d/deploy)
Cmnd_Alias APPCTL = /usr/bin/systemctl restart app, /usr/bin/systemctl status app
%developers ALL=(ALL) APPCTL
deploy ALL=(www-data) NOPASSWD: /usr/bin/rsync
Lee una regla como quién host=(como quién) qué. La primera línea permite a los miembros del grupo developers reiniciar un servicio tras introducir su propia contraseña. La segunda permite a la cuenta deploy ejecutar rsync como www-data sin contraseña, que es lo que necesita un pipeline automatizado.
Dos hábitos mantienen sudo bajo control. Concede comandos, no shells: %developers ALL=(ALL) NOPASSWD: ALL es acceso root con pasos adicionales, y cualquier comando permitido que pueda lanzar un shell o editar un archivo arbitrario (vi, less, find, tar) equivale a root completo. Y conserva el registro: cada invocación queda anotada en el journal o en syslog, lo que convierte journalctl -t sudo en una pista de auditoría realmente útil, como se explica en logs y resolución de problemas.
Iniciar sesión con claves en lugar de contraseñas
La autenticación SSH por contraseña atrae ataques de fuerza bruta desde el momento en que una máquina tiene una dirección pública. Los pares de claves eliminan por completo el secreto adivinable.
ssh-keygen -t ed25519 -C "alice@laptop" # private key stays on your machine
ssh-copy-id [email protected] # appends the public key remotely
ssh -o PreferredAuthentications=publickey [email protected]
La clave privada debe tener modo 600 y el directorio ~/.ssh 700; sshd rechaza las claves legibles por el grupo o por todos, y rechaza authorized_keys si el propio directorio personal tiene escritura para el grupo. Cuando todas las cuentas que necesitan acceso tengan una clave, endurece el demonio en /etc/ssh/sshd_config.d/:
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
AllowGroups sshusers
Valida con sudo sshd -t y recarga en lugar de reiniciar, y —esta es la parte que la gente se salta— mantén abierta tu sesión actual mientras pruebas una nueva desde otro terminal. Una errata en sshd_config en una máquina remota es, en el mejor de los casos, un ticket de soporte.
Errores comunes
chmod 777 como paso de depuración. Da permiso de escritura a todos los usuarios de la máquina y rara vez arregla el problema real, que suele ser un propietario incorrecto o una x que falta en un directorio padre. Localiza el punto de fallo de la ruta con namei -l /var/www/example.com/index.php.
usermod -G sin -a. Elimina en silencio todos los demás grupos secundarios, incluidos sudo y wheel.
chmod recursivo con un modo numérico. chmod -R 755 vuelve ejecutables todos los archivos de configuración e imágenes. Usa u=rwX,go=rX, o find … -type d -exec chmod 755 y -type f -exec chmod 644.
Suponer que los permisos protegen el historial de un archivo. Endurecer un modo no sirve de nada para las copias que ya se hicieron, y un secreto que acabó en un commit de Git o dentro de una imagen de contenedor sigue ahí. En su lugar, rótalo.
Olvidar que root ignora los bits. Un modo de solo lectura no protege frente a un proceso root, y tampoco dentro de un contenedor que se ejecuta como root con la ruta montada mediante bind mount.
Cambios de grupo sin una sesión nueva. id refleja la sesión; compruébalo ahí antes de suponer que el grupo no ha tenido efecto.
Puntos clave
- El kernel autoriza por UID y GID; los nombres salen de
/etc/passwdy/etc/group, y los hashes y la caducidad, de/etc/shadow. - Las comprobaciones de permisos se detienen en la primera clase que coincide —propietario, luego grupo, luego otros—, así que los tripletes nunca se suman.
- En los directorios,
xsignifica atravesar ywsignifica crear o borrar, y por eso se puede borrar un archivo de solo lectura y unaxque falta rompe toda una ruta. umaskresta bits en el momento de la creación; fíjalo en el perfil de inicio de sesión o en una unidad de servicio, no a posteriori.- setgid en un directorio resuelve la herencia de grupo, el sticky bit protege los directorios con escritura para todos, y setuid es casi exclusivo de los binarios de la distribución.
- Recurre a una ACL POSIX, con una entrada por defecto para la herencia, cuando un usuario o grupo necesite una excepción; recurre a reglas de
sudolimitadas a comandos concretos cuando una persona necesite privilegios. - Sustituye las contraseñas de SSH por pares de claves, desactiva después
PasswordAuthenticationy verifica desde una segunda sesión antes de cerrar la primera.
Fuentes y lecturas recomendadas
Preguntas frecuentes
- ¿Por qué no puedo entrar en un directorio aunque sus archivos sean legibles?
- Los directorios usan el bit de ejecución de otra manera: x significa el derecho a atravesar el directorio, es decir, a resolver un nombre dentro de él. Sin x en cada directorio de la ruta, el kernel se detiene antes siquiera de mirar el archivo. Un directorio con r pero sin x te deja listar los nombres, pero no hacer stat ni abrir nada, y por eso 0644 en un directorio casi siempre es un error.
- Me he añadido a un grupo pero sigo recibiendo «permission denied». ¿Qué pasa?
- La pertenencia a grupos se copia en las credenciales del proceso al iniciar sesión. Tu shell actual arrancó antes del cambio, así que sigue teniendo la lista antigua. Cierra la sesión y vuelve a entrar, abre una sesión nueva o ejecuta newgrp nombregrupo en el shell en el que estás. Comprueba la lista efectiva con el comando id y no leyendo /etc/group, porque el kernel usa lo que se asignó a tu sesión.
- ¿Debo editar /etc/sudoers directamente?
- No. Usa visudo, que bloquea el archivo y se niega a instalar una versión que no pase la comprobación de sintaxis. Un archivo sudoers mal formado puede impedir que cualquier administrador escale privilegios en esa máquina. Mejor aún: coloca un archivo pequeño en /etc/sudoers.d/ y edítalo con visudo -f, para que las actualizaciones de paquetes nunca choquen con tus reglas y cada delegación viva en su propio archivo.
- ¿Qué diferencia hay entre su y sudo?
- su abre un shell como otro usuario y pide la contraseña de ese usuario, así que quien lo use necesita las credenciales de la cuenta de destino. sudo ejecuta un único comando según una política guardada en /etc/sudoers, autentica con la contraseña del propio usuario que lo invoca y registra cada ejecución. sudo permite delegar con precisión y auditar después, y por eso la mayoría de las distribuciones desactivan ya por completo el inicio de sesión directo como root.