Pregunta Un túnel SSH a través de múltiples saltos


El túnel de datos a través de SSH es bastante directo:

ssh -D9999 username@example.com

configura el puerto 9999 en su localhost como un túnel para example.com, pero tengo una necesidad más específica:

  • Estoy trabajando localmente en localhost
  • host1 es accesible para localhost
  • host2 solo acepta conexiones de host1
  • Necesito crear un túnel desde localhost a host2

Efectivamente, quiero crear un túnel SSH "multi-hop". ¿Cómo puedo hacer esto? Idealmente, me gustaría hacer esto sin necesidad de ser superusuario en alguna de las máquinas.


287


origen


¿Para qué lo usaste? Quiero usarlo para calcetines proxy. ¿Funcionará? - prongs
Sí, debería poder usar la conexión de túnel como un proxy SOCKS, a menos que host2 niega el reenvío - Mala
Estaba pensando en crear un contenedor sobre SSH que configuraría ese uso múltiple de ProxyCommand. - Pavel Šimerda
@prongs ¿Ha logrado usar esto para el proxy SOCKS (hace tantos años)? - Drux


Respuestas:


Básicamente tienes tres posibilidades:

  1. Túnel de localhost a host1:

    ssh -L 9999:host2:1234 -N host1
    

    Como se señaló anteriormente, la conexión de host1 a host2 no será asegurado.

  2. Túnel de localhost a host1 y de host1 a host2:

    ssh -L 9999:localhost:9999 host1 ssh -L 9999:localhost:1234 -N host2
    

    Esto abrirá un túnel desde localhost a host1 y otro túnel de host1 a host2. Sin embargo, el puerto 9999 a host2:1234 puede ser utilizado por cualquier persona en host1. Esto puede o no ser un problema.

  3. Túnel de localhost a host1 y de localhost a host2:

    ssh -L 9998:host2:22 -N host1
    ssh -L 9999:localhost:1234 -N -p 9998 localhost
    

    Esto abrirá un túnel desde localhost a host1 a través del cual el servicio SSH en host2 puede ser usado. Luego se abre un segundo túnel desde localhost a host2 a través del primer túnel

Normalmente, iría con la opción 1. Si la conexión de host1 a host2 necesita ser asegurado, vaya con la opción 2. La opción 3 es principalmente útil para acceder a un servicio en host2 eso solo es accesible desde host2 sí mismo.


272



la opción 3 era lo que estaba buscando, ¡gracias! - Mala
Quiero hacer navegar de esta manera. ¿Cuál es el mejor? Intenté primero uno pero no funcionó. Configuré un proxy de calcetines en mi navegador localhost: 1234 pero no tuve suerte. :( por favor ayuda.. - prongs
@prongs prueba la opción 3 - Mala
¿Hay alguna manera de reenviar mi clave pública de localhost, a través del túnel del host 1, a host2? - Noli
@Noli Si usa ssh-agent (que debería), puede reenviarlo a través de las conexiones utilizando -A opción para ssh. - Mika Fischer


Hay un excelente respuesta explicando el uso del ProxyCommand directiva de configuración para SSH:

Agrega esto a tu ~/.ssh/config (ver man 5 ssh_config para detalles):

Host host2
  ProxyCommand ssh host1 -W %h:%p

Entonces ssh host2 pasará automáticamente a través de túnel host1 (también funciona con el reenvío de X11, etc.).

Esto también funciona para una clase completa de hosts, p. identificado por dominio:

Host *.mycompany.com
  ProxyCommand ssh gateway.mycompany.com -W %h:%p

Actualizar

OpenSSH 7.3 presenta un ProxyJump directiva, simplificando el primer ejemplo para

Host host2
  ProxyJump host1

138



¿Hay alguna manera de hacer esto condicionalmente? Solo quiero hacer esto a veces. Además, esto es específicamente para comandos, pero estoy buscando algo para todos los puertos 22 (ssh, sftp, etc.). - Stephane
@Stephane, ¿a qué te refieres con específicamente para comandos? Su configuración SSH es utilizada por cualquier cosa que use ssh, incluyendo git, sftp etc. afaik. - kynan
@Stephane No conozco una forma de habilitar esto de forma condicional (por ejemplo, solo cuando estás fuera de la red del host de destino). Establecí esta opción para todos los hosts en cuestión en un bloque de configuración y luego (no) comento la línea según sea necesario. No es perfecto, pero funciona. - kynan
@Stephane seguro: ssh -F /path/to/altconfig. Cuidado, esto ignorará todo el sistema /etc/ssh/ssh_config. - kynan
Una manera fácil de hacer ajustes "condicional" es definir dos hosts diferentes en .ssh / config, que tienen el mismo nombre de host. Conéctese a host2-tunnel cuando desee el túnel, y host2 cuando no lo haga. - Steve Bennett


Tenemos una puerta de enlace ssh en nuestra red privada. Si estoy afuera y quiero un shell remoto en una máquina dentro de la red privada, tendría que ingresar al portal y desde allí a la máquina privada.

Para automatizar este procedimiento, utilizo el siguiente script:

#!/bin/bash
ssh -f -L some_port:private_machine:22 user@gateway "sleep 10" && ssh -p some_port private_user@localhost

Que esta pasando:

  1. Establezca un túnel para el protocolo ssh (puerto 22) a la máquina privada.
  2. Solo si esto tiene éxito, ssh en la máquina privada usando el túnel. (el operador && asegura esto).
  3. Después de cerrar la sesión privada de SSH, también quiero que el túnel ssh se cierre. Esto se hace a través del truco de "dormir 10". Usualmente, el primer comando ssh se cerraría después de 10 segundos, pero durante este tiempo, el segundo comando ssh habrá establecido una conexión usando el túnel. Como resultado, el primer comando ssh mantiene el túnel abierto hasta que se cumplan las dos condiciones siguientes: el modo reposo 10 finaliza y el túnel ya no se utiliza.

20



¡¡¡Muy inteligente!!! ¡QUIÉRALO! - Hendy Irawan


Después de leer todo lo anterior y pegar todo junto, he creado el siguiente script Perl (guárdelo como mssh en / usr / bin y hágalo ejecutable):

#!/usr/bin/perl

$iport = 13021;
$first = 1;

foreach (@ARGV) {
  if (/^-/) {
    $args .= " $_";
  }
  elsif (/^((.+)@)?([^:]+):?(\d+)?$/) {
    $user = $1;
    $host = $3;
    $port = $4 || 22;
    if ($first) {
      $cmd = "ssh ${user}${host} -p $port -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no";
      $args = '';
      $first = 0;
    }
    else {
      $cmd .= " -L $iport:$host:$port";
      push @cmds, "$cmd -f sleep 10 $args";
      $cmd = "ssh ${user}localhost -p $iport -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no";
      $args = '';
      $iport ++;
    }
  }
}
push @cmds, "$cmd $args";

foreach (@cmds) {
  print "$_\n";
  system($_);
}

Uso:

Para acceder a HOSTC a través de HOSTA y HOSTB (mismo usuario):

mssh HOSTA HOSTB HOSTC

Para acceder a HOSTC a través de HOSTA y HOSTB y usar números de puerto SSH no predeterminados y diferentes usuarios:

mssh user1@HOSTA:1234 user2@HOSTB:1222 user3@HOSTC:78231

Para acceder a HOSTC a través de HOSTA y HOSTB y usar X-reenvío:

mssh HOSTA HOSTB HOSTC -X

Para acceder al puerto 8080 en HOSTC a través de HOSTA y HOSTB:

mssh HOSTA HOSTB -L8080:HOSTC:8080

16



esto es asombroso - Mala
En serio, no puedo agradecerte lo suficiente, este guión me hace la vida más fácil a diario. Lo único que cambié fue agregar int (rand (1000)) a iport, para permitir que varias instancias se ejecuten al mismo tiempo. Definitivamente te debo una cerveza. - Mala
Esto funciona realmente bien. Una mejora adicional sería resolver HOSTB, HOSTC, etc. utilizando los servidores / etc / hosts de localhost y ~ / .ssh / config - Steve Bennett
También secundo el comentario de Mala. Sin el puerto aleatorizado, si intentas mssh HOSTA HOSTD en realidad terminarás en HOSTB (y quizás no te des cuenta ...) - Steve Bennett


OpenSSH v7.3 en adelante admite una -J cambiar y ProxyJump opción, que permite uno o más hosts de salto separados por comas, entonces, simplemente puede hacer esto ahora:

ssh -J jumpuser1@jumphost1,jumpuser2@jumphost2,...,jumpuserN@jumphostN user@host

16



ssh -J user1 @ host1 -YC4c arcfour, blowfish-cbc user2 @ host2 firefox -no-remote Esto acelerará la obtención de firefox desde host2 a localhost. - Jaur


Esta respuesta es similar a kynan, ya que implica el uso de ProxyCommand. Pero es más conveniente usar IMO.

Si tiene netcat instalado en sus máquinas de salto, puede agregar este fragmento a su ~ / .ssh / config:

Host *+*
    ProxyCommand ssh $(echo %h | sed 's/+[^+]*$//;s/\([^+%%]*\)%%\([^+]*\)$/\2 -l \1/;s/:/ -p /') nc $(echo %h | sed 's/^.*+//;/:/!s/$/ %p/;s/:/ /')

Entonces

ssh -D9999 host1+host2 -l username

hará lo que le pidas

Vine aquí buscando el lugar original donde leí este truco. Publicaré un enlace cuando lo encuentre.


8



Creo que este es el origen del truco: wiki.gentoo.org/wiki/SSH_jump_host - slm
@slm sí, eso es todo! ¡Gracias! - silviot


ssh -L 9999:host2:80 -R 9999:localhost:9999 host1

-L 9999: host2: 80

Medios que se unen a localhost: 9999 y cualquier paquete enviado a localhost: 9999 reenviarlo a host2: 80

-R 9999: localhost: 9999

Significa que cualquier paquete recibido por host1: 9999 lo reenvía a localhost: 9999


4



Brillante, la respuesta más simple para hacer un túnel para que pueda acceder a la aplicación en host2 directamente desde localhost: 9999 - dvtoever
Siguiendo esta respuesta, obtengo un channel 3: open failed: administratively prohibited: open failed  mensaje de error. - Franck Dernoncourt


deberías poder utilizar el reenvío de puertos para acceder a un servicio en host2 de localhost. Una buena guía se encuentra aquí. Extracto:

Hay dos tipos de reenvío de puertos: reenvío local y remoto. También se llaman túneles de entrada y salida, respectivamente. El reenvío de puerto local reenvía el tráfico que llega a un puerto local a un puerto remoto específico.

Por ejemplo, si emite el comando

ssh2 -L 1234:localhost:23 username@host

todo el tráfico que llega al puerto 1234 del cliente se reenviará al puerto 23 en el servidor (host). Tenga en cuenta que localhost será resuelto por sshdserver después de que se establezca la conexión. En este caso, localhost se refiere al servidor (host).

El reenvío de puertos remotos hace lo contrario: reenvía el tráfico que llega a un puerto remoto a un puerto local especificado.

Por ejemplo, si emite el comando

ssh2 -R 1234:localhost:23 username@host

todo el tráfico que llega al puerto 1234 en el servidor (host) se reenviará al puerto 23 en el cliente (localhost).

En tu elenco, reemplaza localhost en el ejemplo con host2 y host con host1.


2



según ese artículo, la conexión solo estará asegurada hasta la máquina del medio (host1). ¿Hay alguna forma de asegurarse de que todo permanezca seguro? - Mala
Nunca he intentado esto, pero si host1 y host2 son ambos servidores ssh, es posible que pueda configurar un túnel desde el host1 al host2, luego configure un túnel desde el host local al host1 para el mismo servicio (obteniendo su servidor local y remoto). puertos a la derecha). No sé si eso es posible en un comando de localhost. - fideli