SSH, a través de un Jump Host, con un número de puerto dinámico

SSH, a través de un Jump Host, con un número de puerto dinámico

Tengo 3 hosts:

  1. Mi computadora.
  2. Un Jump Host (también conocido como bastión) con una IP estática.
  3. Un servidor con una IP dinámica; detrás de un enrutador/firewall NAT, sin puertos de entrada abiertos.

El servidor actualmente se conecta al Jump Host y establece un túnel SSH a través de -R "0:localhost:22", por lo que el Jump Host asigna dinámicamente el puerto (esto ha sido muy confiable hasta ahora).

Con algomagia de enchufe, Tengo el número de puerto asignado dinámicamente registrado en un archivo en Jump Host.

Con esto, puedo conectarme mediante SSH al Jump Host y ejecutarssh -p $(cat /path/to/port-file) localhost

¿Pero es posible saltarse este paso extra?


Esto sería útil para Ansible, donde inventory.ymlnecesito tener actualizado el número de puerto:

server:
  # /usr/bin/ssh jh cat /path/to/port-file
  ansible_port: "34625"
  ansible_host: "localhost"
  ansible_ssh_common_args: "-o ProxyCommand='ssh -q -W %h:%p jh' -o StrictHostKeyChecking=no"

Podría ser posible utilizar ProxyCommand:

Puede (más o menos) usar la sustitución de comandos en ~/.ssh/configel archivo de mi computadora:

Host server
  ProxyCommand ssh -q -W localhost:$(echo "34625") jh

Esto funciona (incluso sin echo -n) donde la sustitución parece ocurrir en mi computadora local.

Y a pesar de la ineficiencia de usar SSH para obtener primero el número de puerto, esto no funciona:

Host server
  ProxyCommand ssh -q -W localhost:$(ssh jh cat /path/to/port-file) jh

En resultado de:

Bad packet length 1349676916.
ssh_dispatch_run_fatal: Connection to UNKNOWN port 65535: message authentication code incorrect

Y, curiosamente, el servidor (al final de la cadena) anota esto en sus registros de autenticación:

sshd[5558]: Bad protocol version identification '' from ::1 port 36048

Lo que implica que se está devolviendo el número de puerto. Pero no tengo idea de por qué se rompe en este momento.

Y ssh -vvvmuestra que identifica la clave de host en mi archivo ~/.ssh/known_hosts.


También intenté crear un archivo "ssh_config" personalizado en Jump Host, usando ssh -F /path/to/ssh_config, con el contenido:

Host tunnel.server
  HostName localhost
  Port 34625

Pero no creo que pueda usar esto con ProxyCommand.


También sospecho StrictHostKeyChecking=noque podría ser necesario introducirlo en algún momento, cuando cambie el número de puerto.

Respuesta1

Segunda solución parcial, inspirada en @anx...

Crear un archivo de socket

ssh -R '/path/to/socket-file:localhost:22' tunnel@jh

Luego, para usar este socket (desde Jump Host), puedo usar socat:

ssh -o "ProxyCommand socat - UNIX-CLIENT:/path/to/socket-file" localhost

El uso de socatparece un paso innecesario, donde estoy seguro de que debe haber una manera de obtener el sshcomando para usar el archivo socket directamente, pero no puedo encontrarlo todavía.

Tampoco encontré cómo usar este archivo de socket desde mi computadora (ya que ProxyCommand se ejecuta en localhost, no en JumpHost).

También debo señalar; Como la tunnelcuenta (en Jump Host) está muy restringida (solo está ahí para establecer estas conexiones de túnel), necesito configurarla StreamLocalBindMask=0111para que mi cuenta en Jump Host pueda usar este archivo de socket. Del mismo modo, el archivo de socket antiguo debe eliminarse si se establece una nueva conexión a través de StreamLocalBindUnlink=yes.

Ambas opciones deben configurarse en Jump Host, en "/etc/ssh/sshd_config":

Match User tunnel
  StreamLocalBindMask 0111
  StreamLocalBindUnlink yes

Desafortunadamente, Matchlas reglas se ignoran en "/etc/ssh/sshd_config.d/tunnel.conf" antes de OpenSSH 8.4, lanzado el 27 de septiembre de 2020 (informe de error), y esto no está disponible actualmente en Ubuntu 20.04.1 LTS.

Respuesta2

Solución temporal, no ideal...

Agregue un trabajo cron cada hora en mi computadora, recopila los números de puerto del Jump Host y crea un nuevo ~/.ssh/config_tunnelsarchivo.

#!/bin/bash

set -u;

config_path="${HOME}/.ssh/config_tunnels";

port=$(/bin/ssh jh /bin/cat /path/to/port-file 2> /dev/null | /bin/sed 's/[^0-9]//g');
if [[ "${port}" -lt 1024 ]]; then
  exit; # Probably a blank/zero value (e.g. connection issue).
fi
    
{
  echo "";
  echo "Host server";
  echo "  ProxyCommand ssh -q -W localhost:${port} jh";
  echo "";
} > "${config_path}";

chown user:group "${config_path}";
chmod 600 "${config_path}";

El archivo principal ~/.ssh/configpuede entonces utilizar Include ~/.ssh/config_tunnels.

Tenga en cuenta que lo estoy usando sedpara asegurarme de recuperar un número. Si mi Jump Host se viera comprometido, no quiero que el archivo de puerto contenga alguna configuración SSH adicional (maliciosa).

información relacionada