SSH como tecnología alternativa a `sudo`
(whynothugo.nl)sudoydoasdependen de binarios setuid y de la elevación de privilegios, por lo que esto es un experimento que delega la ejecución de comandos como root a unsshdlocal enlazado a un socket de dominio Unix- El objetivo es permitir que solo los usuarios autorizados ejecuten comandos como root sin dejar la capacidad de elevar privilegios disponible para toda la sesión del usuario
- La implementación se compone de un archivo de clave SSH exclusivo para root,
/run/sshd/sshd.sockcon acceso restringido y una instancia separada desshdcon las opcionesAuthorizedKeysFileyPermitRootLogin=yes - Como
sshno tiene una opción para pasarle directamente un socket ya existente, al principio se usaronProxyCommandysocat, y después ProxyUseFdpass junto con un pequeño script en Python para pasar el descriptor de archivo del socket - Este enfoque funciona y el manejo de seguridad depende principalmente de OpenSSH, pero para el uso diario conviene convertir
passfd.pyen un pequeño ejecutable y envolver todo el comandosshcon un wrapper
Las limitaciones estructurales de sudo y doas
sudoydoasdependen de binariossetuidy de la elevación de privilegios para ejecutar comandos como root- Este diseño tiene varias limitaciones
- Toda la sesión del usuario debe conservar la capacidad de realizar elevación de privilegios
- No funciona cuando toda la sesión del usuario se ejecuta dentro de un espacio de nombres de usuario restringido
- Los binarios
setuidimponen restricciones sobre la configuración de seguridad de todo el sistema
s6-sudodes una alternativa que divide el programa entre un servidor con privilegios y un cliente sin privilegios
Objetivo del experimento
- Usar
sshlocalmente para cumplir el mismo papel quesudo, pero sin exponer esa instancia desshda la red - Hay dos condiciones clave
- Solo los usuarios autorizados pueden ejecutar comandos como root
- No se usa elevación de privilegios
Configuración de sshd para inicio de sesión local como root
- Se crea una clave SSH dedicada para usarla solo en la autenticación de root y se guarda en
/root/.ssh/local_keysen lugar deauthorized_keysnormal - Se enlaza una instancia separada de
sshda un socket de dominio Unix y se restringen los permisos de/run/sshd/para que los usuarios no autorizados no puedan acceder al socket - El ejemplo de ejecución usa
s6-ipcserverpara crear/run/sshd/sshd.socky pasar estas opciones asshdAuthorizedKeysFile=/root/.ssh/local_keysPermitRootLogin=yes
- No se modifica
/etc/ssh/sshd_config- Porque no se quiere permitir el inicio de sesión de root en el
sshdexistente enlazado a la red - En la configuración existente se mantiene
PermitRootLogin no
- Porque no se quiere permitir el inicio de sesión de root en el
Bloqueo de la cuenta root y manejo del inicio de sesión por contraseña
- La cuenta root estaba bloqueada para impedir cualquier tipo de inicio de sesión, usando para ello un prefijo
!delante del hash de la contraseña sshdinterpreta ese prefijo!como bloqueo de cuenta y por eso no permite el inicio de sesión de root- Se cambia el valor de la contraseña de root en
/etc/passwdpara reemplazar!por*sshdno interpreta*como un valor especial de bloqueo- Como
*no coincide con ningún hash de contraseña, el inicio de sesión por contraseña sigue desactivado en la práctica
- Además, en
sshd_configse establecePasswordAuthentication no, y es más seguro desactivar la autenticación basada en contraseña ensshd
Conectarse a un socket Unix con ssh
sshdtiene una opción-ipara pasarle un socket existente, perosshno tiene una opción equivalente- Al principio se usó
socatconProxyCommandpara conectarse a/run/sshd/sshd.sock - El comando de conexión se compone de estos elementos
ProxyCommand='socat STDIO UNIX-CONNECT:/run/sshd/sshd.sock'- La clave root dedicada se especifica con
-i .ssh/root-key.pub - Se conecta a
root@root - Luego cambia al directorio actual y ejecuta un shell de inicio de sesión
- La clave SSH usada era una clave ligada a hardware, así que había que tocar físicamente el dispositivo para aprobar la conexión
- También podría servir como alternativa un
ssh-agentque solo publique la clave después de una aprobación explícita, comohissh-agent
La sobrecarga de socat y ProxyUseFdpass
socatlee toda la entrada desshy luego la escribe en el socket, así que la sobrecarga de conexión en la práctica se duplicaProxyUseFdpasshace que el comando envíe el descriptor de archivo del socket assha través destdout, y quesshuse ese socket para conectarse- A partir de un ejemplo de uso de OpenSSH ProxyUseFdpass de 2016, se escribió el script en Python
passfd.py- Se conecta al socket de dominio Unix
/run/sshd/sshd.sock - Pasa el descriptor de archivo con
sendmsgySCM_RIGHTS
- Se conecta al socket de dominio Unix
- Después, el comando de conexión pasa a usar
passfd.pyenProxyCommandy agregaProxyUseFdpass=yes nc -FU /run/sshd/sshd.socktambién parece posible, pero el manual indica explícitamente que-Fno puede usarse junto con-U
Conclusión y forma de uso real
- Esta técnica funciona y delega principalmente en OpenSSH el manejo sensible de la seguridad
- OpenSSH tiene un buen historial y permite usar varios métodos de autenticación, incluidas las claves SSH basadas en hardware
- El proceso de configuración en un host nuevo no tiene pasos complejos, y el comando
ipcserverpuede ejecutarse mediante el gestor de servicios del sistema passfd.pyse parece más a un hack rápido para llevar a cabo el experimento- Para el uso diario, es más adecuado crear un pequeño ejecutable que cumpla el mismo papel y dejarlo en
/usr/local/bin, además de envolver también todo el comandosshcon un pequeño wrapper
1 comentarios
Opiniones de Hacker News
La principal razón para oponerse a este enfoque es el aumento de complejidad. En lugar de un único binario
suidque lee un archivo de configuración y llama aexec(), ahora hay un binario que se ejecuta como root y escucha en un socket UNIX, y otro binario que habla con ese socket, y ambos además tienen que manejar criptografía asimétrica.Si el argumento central contra sudo/doas es “hay un binario
suidaccesible para todos los usuarios y, si tiene un bug, puede explotarse para elevar privilegios”, entonces se puede hacer algo como esto:chgrp wheel /usr/bin/sudochmod o-rwx /usr/bin/sudoSi pones a los usuarios de sudo en el grupo
wheel, solo los usuarios que pueden usar sudo podrán leer los bytes del archivo desde el disco y ejecutarlo. En términos de control de acceso, la seguridad es casi la misma que con el enfoque de sshd, donde solo los usuarios dewheelpueden acceder al socket UNIX, pero la complejidad es mucho menor.Además, el enfoque con sshd no puede limitar el acceso root a comandos específicos como sudo, así que aunque hubiera un bug que permitiera eludir las restricciones de comandos de sudo, no otorgaría más privilegios que el enfoque con sshd.
Si te preocupa que el gestor de paquetes arruine los permisos de
/usr/bin/sudo, puedes hacer que cron los corrija periódicamente, o eliminar sudo por completo e instalarlo manualmente desde el código fuente en otra ubicación. Claro que entonces también tendrás que encargarte tú del mantenimiento y las actualizaciones./etc. Ya sea una instalación/actualización de software o un cambio hecho por una persona, queda registrado; y al actualizar a una nueva versión también resulta útil porque puedes crear un parche con los cambios locales, aplicarlo sobre una instalación limpia y luego revisar los conflictos con una fusión de 3 vías.https://etckeeper.branchable.com/
wheelpara que solo quienes puedan usar sudo puedan leer y ejecutar el archivo suena bastante razonable. Me pregunto por qué no es la configuración predeterminada en todas partes./usr/bin/sudosea immutable? Parece que eso ayudaría a impedir que el gestor de paquetes lo toque.¿No es esto lo que hace ahora systemd run0? systemd tiene una nueva herramienta llamada
run0, aunque en realidad no es una herramienta completamente nueva: si invocas el viejosystemd-runmediante un enlace simbólico llamadorun0, se comporta como un reemplazo de sudo.La diferencia clave es que en realidad no es
SUID. Le pide al administrador de servicios que ejecute un comando o shell con el UID del usuario de destino, asigna una nueva PTY y luego pasa datos entre la TTY original y esta PTY.En otras palabras, el comando de destino no hereda el contexto del cliente, sino que se ejecuta en un contexto de ejecución aislado recién bifurcado desde PID 1. Se pasa
$TERM, pero eso es una excepción explícita, es decir, algo más parecido a una lista de permitidos que a una lista de bloqueados.En muchos sentidos,
run0se puede considerar más cercano al comportamiento desshque al desudo.https://mastodon.social/@pid_eins/112353324518585654
¿Me estoy perdiendo de algo? No veo cómo iniciar sesión por ssh como root sea más seguro que usar sudo. Siempre me enseñaron a no permitirlo, así que tampoco sé qué tan peligroso es en la práctica.
Aquí parece que hubo consideraciones para bloquear usuarios remotos, así que no me refiero a ese aspecto de seguridad.
Tal vez tenga que ver con la limitación 3 de sudo, pero al menos frente a la 1 no veo ninguna ventaja.
Entiendo que es un experimento, pero me parece que sería más vulnerable que sudo, no menos. Un proxy de socket abierto parece vulnerable a ataques de intermediario.
Aun así, aprendí algunas técnicas que se pueden hacer con herramientas antiguas, y estuvo bien que mostrara algo nuevo.
sudoes suid root y, al ser un binario con privilegios, queda expuesto directamente a usuarios no confiables. Si algo sale mal dentro de sudo, todo el entorno del usuario se convierte en superficie de ataque y puede explotarse.El enfoque con ssh no expone un binario
suidy usa la capa de red de ssh. Por lo tanto, no es menos seguro que acceder a ssh por la red, lo cual se considera bastante seguro.sudo bash, puedes ejecutar comandos individuales con sudo y así mejorar la auditabilidad.Ese daemon también puede tener errores de configuración o vulnerabilidades, y reduce varias capas de autorización basadas en usuarios a un único nivel root.
Aun así, parece que se lo considera más seguro. Desde una perspectiva de seguridad razonable, no puede considerarse más seguro; simplemente es un enfoque distinto.
En realidad, iniciar sesión por SSH directamente como root es estrictamente más seguro que iniciar sesión como usuario por SSH remoto y luego usar
sudo.Si
user@homehace ssh aroot@server,root@serverqueda comprometido solo siuser@homees comprometido.En cambio, si
user@homehace ssh auser@servery luego se convierte enroot@servercon sudo, basta con que se comprometauser@homeouser@serverpara que root quede comprometido. En particular, enuser@serversuelen ejecutarse otros programas, como daemons o tareas cron.No hay que regalarle a alguien que logró infectar por esa vía una elevación gratuita a root, y además movimiento lateral, algo frecuente por la reutilización de contraseñas.
Por supuesto, esto no aplica si sudo se usa en modo exclusivo de lista de comandos permitidos y no recibe contraseñas ni credenciales totalmente accesibles desde el host remoto.
¿Qué pasa si ssh no se inicia al arrancar? Recuerdo que, en una configuración común, se inicia dependiendo de la red. Entonces tampoco se podría iniciar sesión desde la consola failsafe
No sé qué se obtiene realmente en comparación con sudo o su. En vez de evitar un binario setuid, se termina ejecutando un servicio de red como root, aunque solo se conecte a un socket
¿Qué pasa si muere el SSD? Tampoco en ese caso podría iniciar sesión en la consola failsafe
En 30 años usando Linux, me han fallado discos duros muchísimas más veces que veces en que el daemon sshd no arrancó; en proporción, es como dividir entre cero
Si el daemon sshd del sistema operativo no arranca al azar, lo tomaría como señal de que es hora de pasarme a un sistema operativo más estable
Lo que se gana frente a sudo o su es que los exploits de escalamiento de privilegios locales se vuelven mucho más difíciles
ttyS*de puertos seriales e IPMI SoL, no usan sudo ni suEsas consolas usan programas como
gettyo un gestor de ventanas, que son programas no suid iniciados como rootLo correcto es dejar configurada una contraseña de root para iniciar sesión en la consola
kubectlen vez de sshSi alguien puede iniciar sesión, dejo que pueda hacer setuid a root. Si es una caja de k8s, eso corresponde al equipo de infraestructura de plataforma, y el acceso a los servicios encima de eso pasa por el proveedor de permisos de k8s
Desde el punto de vista del equipo de infraestructura de plataforma, si solo necesitan métricas y logs, ya están fuera de la caja; y si necesitan disparar algún trabajo o workflow, pueden usar un pipeline
Aun así, si alguien inicia sesión y hace tareas como root, quiero que quede un log de auditoría
No se me ocurre ninguna caja mía en la que alguien con permiso de login no tenga privilegios completos de root
Por supuesto entiendo los casos en que un servicio hace setuid, pero en servicios normalmente systemd hace setuid para bajar privilegios, no para elevarlos
systems.unit=emergency.target,init=/bin/bash,rd.break=pre-pivoto arrancar en un entorno live CD. Todas las opciones comunes de recuperación de emergencia siguen funcionandoY en una emergencia menos grave, tampoco veo por qué esta instancia de sshd tendría que estar ligada a la red
Es una pena que no incluya todas las desventajas de este enfoque. sudo permite controlar qué grupos pueden ejecutar qué comandos, qué argumentos pueden recibir esos comandos, si se permite crear subshells, etc.
Con este método se pierde mucho de ese control granular, y se depende de claves de confianza que son más difíciles de administrar que editar el archivo sudoers
Para ver las cosas sorprendentes que puede hacer sudo, de verdad recomiendo el libro Sudo Mastery
Esto es una idea similar a run0 de systemd: https://news.itsfoss.com/systemd-run0/
Uno de los problemas de ssh es que la creación de procesos no forma parte del protocolo. Y, al ser un protocolo remoto, no puede pasar recursos locales al proceso hijo
Por eso no se puede pasar un arreglo de argumentos separado por null, ni descriptores de archivo adicionales, ni especificar el ejecutable
En su lugar, se pasa una sola cadena al shell configurado en el servidor. Entonces se necesita escape de shell, y además hay que saber qué shell corre del lado del servidor
Para usar SSH como un reemplazo adecuado de sudo, haría falta una extensión con algo cercano a
posix_spawnhttps://bugzilla.mindrot.org/show_bug.cgi?id=2283
Totalmente de acuerdo. Yo hago algo parecido y también lo expliqué alguna vez en un comentario de HN
Mi método es un poco distinto. Uso una máquina dedicada como consola SSH física, y esa máquina está en una LAN privada separada de las demás máquinas de mi casa. No es un switch administrable, sino un switch común; uso cables Ethernet y no hay trunks
Solo se puede iniciar sesión por SSH, y le conecté una Yubikey
La PC de escritorio tiene su propio firewall y solo permite tráfico SSH proveniente de la dirección IP/MAC de esa consola SSH. Eso solo en la LAN privada que comparten; en otra LAN física, la desktop puede acceder a Internet
El daemon sshd solo permite login con clave pública/privada y tiene deshabilitado el login con contraseña
Cuando necesito root, arranco la “consola SSH”. Como es una máquina con casi nada, enciende muy rápido. Inicio sesión, recupero con la flecha arriba la línea
ssh root@..., presiono Enter y toco la YubikeyEsa consola SSH y el teclado están sobre el escritorio, siempre al alcance de la mano
Que iptables/nftables + sshd en una LAN privada, además físicamente separada de otra LAN privada, sea más o menos seguro que el binario sudo o su, que cada quien lo juzgue
Si me preguntan “por qué”, respondería “porque puedo”. Lo configuré hace tanto que ni recuerdo cuándo fue. Probablemente empecé a jugar con esta idea hace unos 2 años, y la he usado desde entonces. No he tenido ningún problema
Es una solución elegante para este problema. No hace falta tratar a los usuarios como niños, pero al mismo tiempo hay que evitar posibles errores con valores predeterminados razonables
Si necesitas root, puedes iniciar sesión como root desde la consola, así que creo que ni siquiera hace falta
su. Este método se acerca lo máximo posible a iniciar sesión como root en una tty de consolaPrimero, a diferencia de sudo, todos los usuarios tienen que conocer la contraseña de root
Segundo, si todos simplemente inician sesión como root, no hay forma de auditar quién inició sesión realmente ni qué hizo
Hace 10 años probé algo parecido. No tenía la parte de sockets UNIX; levanté un
sshdaparte que escuchaba solo en localhost, y tampoco tuve que lidiar conSCM_RIGHTSNo hubo resultados particularmente buenos ni malos; simplemente perdí el interés y no trasladé la configuración a la siguiente máquina