Tengo 3 hosts:
- Mi computadora.
- Un Jump Host (también conocido como bastión) con una IP estática.
- 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.yml
necesito 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/config
el 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 -vvv
muestra 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=no
que 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 socat
parece un paso innecesario, donde estoy seguro de que debe haber una manera de obtener el ssh
comando 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 tunnel
cuenta (en Jump Host) está muy restringida (solo está ahí para establecer estas conexiones de túnel), necesito configurarla StreamLocalBindMask=0111
para 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, Match
las 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_tunnels
archivo.
#!/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/config
puede entonces utilizar Include ~/.ssh/config_tunnels
.
Tenga en cuenta que lo estoy usando sed
para 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).