Encadenar dos reenvíos de puertos ssh

Encadenar dos reenvíos de puertos ssh

He estado buscando respuestas aquí en superusuario, sin embargo, ninguna respuesta que encontré aborda mi caso de uso.

Quiero encadenar dos comandos que uso y que me permiten atravesar un túnel:

ssh -L 22:hostB:22 user@hostA

y

ssh -L 10002:localhost:10001 user@localhost

Ahora mismo lo que hago es ingresar el primer comando, abrir otra terminal e ingresar el segundo. Si hago algo como

ssh … && ssh …

el segundo comando se ejecuta sólo después de que "salgo" de la primera conexión.

Las opciones ssh más avanzadas como jumphost no funcionan debido a la configuración del servidor en el hostA, así que estoy bastante seguro de que esta es la única opción para tener acceso al puerto 10001 de esta manera.

¿Hay alguna manera de encadenar esos dos comandos en un alias o usar algún script bash simple con tiempos de espera, etc.?

Respuesta1

Supongo que no puedes hacerlo sólo ssh -L 10002:hostB:10001 user@hostAporque

  • o cualquier cosa que escuche en B 10001se une solo a la interfaz local,
  • o el firewall en B no permite la conexión hostB:10001desde A,
  • o lo que sea.

ssh … && ssh …

el segundo comando se ejecuta sólo después de que "salgo" de la primera conexión.

Sí, esto es normal. La parte anterior &&debe terminar y devolver el estado de salida antes de que se ejecute el siguiente comando (o no, según el estado).

Esto ejecutará el segundo sshcasi inmediatamente pero tiene errores:

(ssh…&) && ssh…

Es defectuoso porque el primero sshno tiene impacto sobre el segundo. El segundo probablemente correrá mucho antes que el primero establezca el túnel. Pedir contraseñas también puede resultar problemático.

Para este caso de uso sshtiene -fla opción. Deman 1 ssh:

-f
Solicita sshpasar a segundo plano justo antes de la ejecución del comando. […]

Entonces el comando básico puede ser:

ssh -fNL 22:hostB:22 user@hostA && ssh -NL 10002:localhost:10001 user@localhost

Depende de usted si desea utilizar -Nel segundo ssho no. Ahora el truco son las primeras sshbifurcaciones en segundo plano después de solicitar la contraseña (si corresponde) y después de establecer el primer túnel, por lo que temporalmente hay dos "primeros" sshprocesos. El que está al fondo comienza a manejar el túnel; el que está en primer plano sale, esto permite &&trabajar.

Probablemente quieras -o ExitOnForwardFailure=yes. Si no se puede establecer el primer túnel, el primero sshsaldrá sin éxito y el segundo no funcionará. El comando mejorado es:

ssh -fNL 22:hostB:22 \
    -o ExitOnForwardFailure=yes \
    user@hostA &&
ssh -NL 10002:localhost:10001 user@localhost

Tenga en cuenta que cuando el segundo sshsale, el primero (en segundo plano) permanece. La ventaja es que puedes ejecutar el único segundo sshdespués. La desventaja es que tendrás que eliminar el primero manualmente si no quieres que permanezca. Teniendo esto en cuenta, considere el siguiente enfoque:

ssh -fNL 22:hostB:22 \
    -o ExitOnForwardFailure=yes \
    user@hostA
ssh -NL 10002:localhost:10001 user@localhost

Tenga en cuenta que no hay &&. Ahora bien, si el antiguo primero sshtodavía se está ejecutando, el nuevo fallará porque no podrá conectarse al puerto. El segundo sshfuncionará independientemente, utilizará el primer túnel y no importa la antigüedad del túnel.

Puede pasar que no haya ningún viejo sshy el primero sshfalle por los motivos que sean. Si es así, el segundo se ejecutará y probablemente fallará (conexión rechazada) porque no hay nada escuchando en el puerto 22.

Aun así, es posible que no quieras dejar un sshproceso "inactivo", sino que quieras finalizarlo automáticamente después de que sshsalga el segundo. Evidentemente killall sshpuede provocar daños colaterales. Busquemos algo más sutil:

-M
Coloca al sshcliente en modo "maestro" para compartir la conexión. […]

[…]

-O ctl_cmd
Controlar un proceso maestro de multiplexación de conexión activa. […]

[…]

-S ctl_path
Especifica la ubicación de un zócalo de control para compartir conexión […]

#!/bin/sh

socket=/tmp/hostA.socket

ssh -fNL 22:hostB:22 \
    -o ExitOnForwardFailure=yes \
    -MS "$socket"
    user@hostA &&
{
ssh -NL 10002:localhost:10001 user@localhost
ssh -S "$socket" -O exit dummy
}

Después de que termine el segundo ssh, el tercero le dirá al primero que salga. En el tercer sshcomando lo que importa es el socket, no el nombre del host; aún así necesitas proporcionar algún nombre de host, por lo tanto dummy. El primero sshquitará el enchufe antes de salir, no debe quedar basura.

Todavía hay algunas preocupaciones:

  • Si se interrumpe el guión, sshquedará el primero. O suelte &&o envíe -O exitdesde el principio por si acaso (sería el cero ssh).
  • Si el primero sshmuere abruptamente, el encaje puede permanecer. Hará que cualquier nuevo primer sshfracaso. Una buena idea puede ser expandir el cero sshde esta manera:

    ssh -S "$socket" -O exit dummy || rm "$socket"
    
  • /tmp/hostA.socketPuede que no sea la mejor ubicación para el enchufe. En ssh_configel equivalente de -Sla opción de línea de comando es ControlPath. Mira quéman 5 ssh_configdice al respecto:

    Se recomienda que cualquier ControlPathuso para compartir conexiones oportunistas incluya al menos %h, %py %r(o alternativamente %C) y se coloque en un directorio en el que otros usuarios no puedan escribir.

    Un "directorio en el que otros usuarios no pueden escribir" puede ser /run/user/$UID, si su sistema operativo lo admite (creo que es systemdcosa de ).

información relacionada