Las opciones
| Opción | Qué hace | Qué ve el otro lado |
|---|---|---|
restrict | Sin reenvío de ningún tipo, sin terminal, sin ~/.ssh/rc | PTY allocation request failed on channel 0 |
command="..." | Ejecuta siempre este comando | La salida de ese comando |
from="..." | Solo desde estas direcciones o nombres | Permission denied |
permitopen="host:port" | Limita ssh -L y -W a este destino | stdio forwarding failed o open failed |
permitlisten="[host:]port" | Limita ssh -R a este puerto | remote port forwarding failed |
Empieza con restrict y añade solo lo que la clave necesita. Además cubre cualquier restricción que OpenSSH añada en el futuro, algo que una lista de no-pty,no-port-forwarding y similares no hace. Las opciones van en una sola línea, separadas por comas y sin espacios entre ellas.
Solo un comando
restrict,command="/usr/local/bin/backup" ssh-ed25519 AAAA... backup-job
Ahora tanto ssh user@server como ssh user@server rm -rf / ejecutan la copia de seguridad y nada más.
Unos pocos comandos permitidos, con SSH_ORIGINAL_COMMAND
Lo que pidió el cliente está en la variable SSH_ORIGINAL_COMMAND, y un script pequeño puede comprobarlo:
#!/bin/sh
# /usr/local/bin/ssh-allow
case "$SSH_ORIGINAL_COMMAND" in
"uptime"|"df -h")
exec $SSH_ORIGINAL_COMMAND
;;
*)
echo "Not allowed: $SSH_ORIGINAL_COMMAND" >&2
exit 1
;;
esac
restrict,command="/usr/local/bin/ssh-allow" ssh-ed25519 AAAA... monitoring
En nuestra prueba, ssh user@server uptime funcionó, y ssh user@server "uptime; id" respondió Not allowed: uptime; id. Compara cadenas completas, como arriba. Un patrón como uptime* deja pasar cualquier cosa que empiece por esa palabra, y nunca pases la variable a sh -c ni a eval.
Elige también con cuidado los comandos permitidos. Un comando que pueda escribir archivos o abrir un shell, como un editor, anula la restricción.
Limitar por dirección
from="203.0.113.10,198.51.100.0/24" ssh-ed25519 AAAA... office
Funcionan tanto los patrones como los rangos CIDR, y ! excluye una dirección. Usa direcciones IP en lugar de nombres de host, ya que un nombre de host depende del DNS inverso. Cuando la dirección no coincide, el cliente ve Permission denied y el registro del servidor lo explica:
Authentication tried for user with correct key but not from a permitted host (host=198.51.100.7, ip=198.51.100.7, required=203.0.113.10).
Una clave solo para un túnel
restrict,port-forwarding,permitopen="10.0.1.10:5432",command="/usr/sbin/nologin" ssh-ed25519 AAAA... db-tunnel
Esta clave puede llegar a la base de datos en esa dirección y ese puerto. Un reenvío a otro puerto falla, y un comando solo recibe This account is currently not available. Para usarla, añade -N para que ssh no pida ningún comando:
ssh -N -L 5432:10.0.1.10:5432 user@server
Un nombre de host en permitopen debe coincidir exactamente con lo que envía el cliente, sin ninguna resolución. localhost y 127.0.0.1 cuentan como distintos.
Ojo: esto sigue permitiendo ssh -R
port-forwarding activa ambas direcciones, y permitopen limita solo una. En nuestra prueba, la clave de arriba aún podía abrir un reenvío remoto con ssh -R. permitlisten="none" no es una salida, porque entonces la línea no es válida y la clave deja de funcionar por completo. Haz una de estas dos cosas:
- Pon en
permitlistenun único puerto que nada use, por ejemplopermitlisten="127.0.0.1:9". Comprobamos que un reenvío en cualquier otro puerto es rechazado. - Limita la cuenta en la configuración del servidor, lo que se aplica a todas sus claves:
# /etc/ssh/sshd_config.d/10-tunnel.conf
Match User tunnel
AllowTcpForwarding local
Para saber qué hacen -L, -R y -D, consulta túneles SSH locales, remotos y dinámicos.
Claves para transferir archivos
restrict por sí solo no impide la transferencia de archivos. En nuestra prueba, sftp seguía funcionando con él, porque SFTP no necesita terminal ni reenvío. Para permitir SFTP y nada más:
restrict,command="internal-sftp" ssh-ed25519 AAAA... files
Para permitir rsync en una sola carpeta, usa rrsync, que viene con rsync. En Debian está en /usr/bin/rrsync, y otros sistemas pueden variar. Con -ro permite solo lectura, y confirmamos que las subidas fallan:
restrict,command="/usr/bin/rrsync -ro /srv/backup" ssh-ed25519 AAAA... backup-read
Lo que estas opciones no hacen
- Solo atan a esa clave. Otra clave, o una contraseña, en la misma cuenta no tiene ninguno de estos límites. Da a cada tarea su propia cuenta cuando puedas, y desactiva las contraseñas.
- El usuario puede editar el archivo. Si la cuenta puede escribir en su propio
authorized_keys, un comando que escriba archivos puede quitar los límites. Para una frontera firme, deja el archivo como propiedad de root. Consulta authorized_keys explicado. - El orden de las líneas importa. Si la misma clave aparece también en una línea sin restricciones más arriba, gana esa línea.
Preguntas
¿command= en authorized_keys bloquea SFTP?
Sí, si command= apunta a algo distinto de internal-sftp, porque SFTP ejecuta entonces ese comando en su lugar. restrict por sí solo no bloquea SFTP.
¿Qué es SSH_ORIGINAL_COMMAND?
Una variable de entorno con el comando que pidió el cliente cuando se ejecuta un comando forzado. Un script puede comprobarla y permitir solo unos pocos comandos exactos.
¿Puedo usar un nombre de host en from=?
Sí, pero depende del DNS inverso, que la otra parte puede controlar. Las direcciones IP y los rangos CIDR son más seguros.