Cómo usar ProxyJump y un jump host en SSH

Ejecuta ssh -J user@bastion user@target para llegar a un servidor privado a través de un jump host. En ~/.ssh/config, pon ProxyJump bastion en el bloque Host del destino. Tu sesión SSH queda cifrada desde tu máquina hasta el destino, tu clave privada se queda en tu máquina y el jump host solo reenvía bytes. Necesita OpenSSH 7.3 o posterior en el cliente.

Actualizada el . Ejecutado con OpenSSH 10.3 en macOS a través de jump hosts OpenSSH 10.0 en Debian 13, hacia destinos privados sin puerto publicado: -J, ProxyJump, dos saltos, ProxyCommand, el usuario de salto restringido, AllowTcpForwarding no y el listado de claves reenviadas con ssh-add -l. scp -J, sftp -J y rsync a través de un jump host se ejecutaron con OpenSSH 10.0 en Debian 13.

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

Más en Túneles y jump hosts

Todas las guías