En la línea de comandos
ssh -J user@bastion user@target
your machine -> SSH to bastion -> TCP from bastion to target -> SSH from your machine to target, inside it
El jump host necesita una dirección alcanzable. El destino no. Su nombre lo resuelve el jump host, así que un nombre privado o una dirección privada como 10.0.0.5 funciona aunque tu máquina no pueda resolverla ni llegar a ella. Un puerto personalizado va tras dos puntos: -J user@bastion:2222.
scp y sftp aceptan la misma opción, y rsync se la pasa a ssh:
scp -J user@bastion file.txt user@target:/tmp/
sftp -J user@bastion user@target
rsync -av -e "ssh -J user@bastion" ./site/ user@target:/var/www/site/
En tu configuración de ssh
Host bastion
HostName 203.0.113.10
User user
IdentityFile ~/.ssh/id_ed25519
Host target
HostName 10.0.0.5
User user
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
Ahora basta con escribir ssh target, y scp, sftp y rsync funcionan igual. Para aplicarlo a toda una red:
Host 10.0.*
ProxyJump bastion
No escribas un patrón que coincida con el propio jump host. Para saltarte el salto en una conexión, usa ssh -o ProxyJump=none target.
Para más sobre bloques Host, patrones y Match, consulta ejemplos del archivo de configuración de ssh.
Varios saltos
Lista los jump hosts en orden, separados por comas:
ssh -J user@bastion,user@inner user@target
Host target
ProxyJump bastion,inner
Cada nombre de la lista después del primero se resuelve desde el salto anterior.
Las opciones de línea de comandos no llegan al jump host
Es la sorpresa más común. -i y -o se aplican solo al destino final, porque la conexión al jump host es un proceso ssh aparte que solo lee tu configuración. Lo probamos: con la clave indicada solo con -i, el inicio de sesión en el jump host falló, y el mensaje fue solo este:
Connection closed by UNKNOWN port 65535
Así que define el usuario, el puerto y la clave del jump host en un bloque Host de tu configuración. Para ver cada paso, usa ssh -v target. Imprime el comando implícito y muestra la autenticación en el jump host y luego en el destino.
Por qué es más seguro que el agent forwarding
La forma antigua era entrar en el jump host con ssh -A y ejecutar ssh de nuevo desde allí. Eso deja en el jump host un socket hacia tu agente mientras estás conectado. En nuestra prueba, un comando en el jump host podía listar las claves del agente del portátil:
ssh -A user@bastion 'ssh-add -l'
Cualquiera con root en ese jump host puede usar ese socket para entrar como tú, mientras estés conectado. No puede copiar la clave, pero no lo necesita.
Con ProxyJump, nada tuyo está en el jump host:
- Tu clave privada y tu agente se quedan en tu máquina, y el jump host nunca tiene acceso a ellos.
- Tu máquina hace el inicio de sesión en el destino y comprueba su clave de host contra tu propio
known_hosts. - El jump host ve bytes cifrados, y sabe a qué host y puerto te conectaste, y cuándo. No puede leer la sesión.
Un jump host comprometido aún puede bloquearte u observar ese patrón de tráfico, y puede atacar la red en la que está. Mantenlo pequeño y actualizado. Mira los riesgos del agent forwarding.
Versiones antiguas: ProxyCommand con -W
Para clientes anteriores a OpenSSH 7.3, usa ssh -W, que existe desde la versión 5.4:
Host target
HostName 10.0.0.5
ProxyCommand ssh -W %h:%p bastion
Usa una de las dos opciones para un host, no las dos. El manual dice que compiten, y la que aparece primero impide que la otra surta efecto. ProxyCommand también es útil cuando necesitas pasar tus propias opciones al ssh interior, como -i.
Qué debe permitir el jump host
Saltar usa un reenvío TCP en el jump host, así que necesita el reenvío activado. Con AllowTcpForwarding no ves:
stdio forwarding failed
Connection closed by UNKNOWN port 65535
Puedes no darles a los usuarios de salto nada más que esto. En la configuración de sshd del jump host:
Match User jump
PermitTTY no
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding local
PermitOpen 10.0.0.5:22 10.0.0.6:22
ForceCommand /usr/sbin/nologin
En nuestra prueba, un inicio de sesión con este usuario llegó al destino de la lista, un host que no estaba en ella falló con stdio forwarding failed, y un inicio de sesión normal imprimió This account is currently not available. PermitOpen compara el texto exactamente y no hace consultas, así que sus entradas deben coincidir con el nombre o la dirección que pide el cliente.
El firewall del destino debería aceptar SSH solo desde el jump host, o el salto aporta poca protección.
Preguntas
¿Qué diferencia hay entre ProxyJump y agent forwarding?
Con ProxyJump tu clave y tu agente se quedan en tu máquina y el jump host solo pasa bytes cifrados. El agent forwarding deja en el jump host un socket que root puede usar mientras estás conectado.
¿Puedo usar más de un jump host?
Sí. Escríbelos en orden, separados por comas: ssh -J user@bastion,user@inner user@target, o ProxyJump bastion,inner en la configuración.
¿Cómo uso scp o rsync a través de un jump host?
scp y sftp aceptan la misma opción: scp -J user@bastion file.txt user@target:/tmp/. Con rsync, pásala a ssh con -e "ssh -J user@bastion". Con ProxyJump en tu configuración, también basta un simple scp target:...
¿Por qué -i no sirve para el jump host?
Las opciones de la línea de comandos solo valen para el destino final. Define el usuario, el puerto y la clave del jump host en su propio bloque Host.
Fuentes
- ssh(1), manual de OpenBSD
- ssh_config(5), manual de OpenBSD
- Notas de la versión de OpenSSH 7.3, ProxyJump
- Notas de la versión de OpenSSH 5.4, ssh -W