SSH, através de um Jump Host, com um número de porta dinâmico

SSH, através de um Jump Host, com um número de porta dinâmico

Eu tenho 3 hosts:

  1. Meu computador.
  2. Um Jump Host (também conhecido como bastião) com um IP estático.
  3. Um servidor com IP dinâmico; atrás de um roteador/firewall NAT, sem portas de entrada abertas.

O servidor atualmente se conecta ao Jump Host e estabelece um túnel SSH via -R "0:localhost:22", de modo que a porta é alocada dinamicamente pelo Jump Host (isso tem sido muito confiável até agora).

Com algummagia de soquete, tenho o número da porta alocada dinamicamente registrado em um arquivo no Jump Host.

Com isso, posso usar SSH para o Jump Host e executarssh -p $(cat /path/to/port-file) localhost

Mas é possível pular esta etapa extra?


Isso seria útil para Ansible, onde inventory.ymlpreciso atualizar o número da porta:

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"

Talvez seja possível usar ProxyCommand:

Ele pode (mais ou menos) usar a substituição de comandos no ~/.ssh/configarquivo do meu computador:

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

Isso funciona (mesmo sem echo -n) onde a substituição parece acontecer no meu computador local.

E apesar da ineficiência de usar SSH para obter primeiro o número da porta, isso não funciona:

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

Isso resulta em:

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

E estranhamente, o servidor (no final da cadeia) anota isso em seus logs de autenticação:

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

O que implica que o número da porta está sendo retornado. Mas não tenho ideia de por que ele quebra neste momento.

E ssh -vvvmostra que identifica a chave do host no meu arquivo ~/.ssh/known_hosts.


Também tentei criar um arquivo "ssh_config" personalizado no Jump Host, usando ssh -F /path/to/ssh_config, com o conteúdo:

Host tunnel.server
  HostName localhost
  Port 34625

Mas acho que não posso usar isso com o ProxyCommand.


Eu também suspeito StrictHostKeyChecking=noque talvez seja necessário introduzi-lo em algum momento, quando o número da porta for alterado.

Responder1

Segunda solução parcial, inspirada em @anx...

Crie um arquivo de soquete

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

Então, para usar este soquete (do Jump Host), posso usar socat:

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

O uso de socatparece uma etapa desnecessária, onde tenho certeza de que deve haver uma maneira de fazer com que o sshcomando use o arquivo de soquete diretamente, mas ainda não consigo encontrá-lo.

Também não descobri como usar esse arquivo de soquete no meu computador (já que o ProxyCommand é executado no host local, não no JumpHost).

Devo também observar; como a tunnelconta (no Jump Host) é muito restrita (só existe para estabelecer essas conexões de túnel), preciso configurar StreamLocalBindMask=0111para que minha conta no Jump Host possa usar esse arquivo de soquete. Da mesma forma, o arquivo de soquete antigo deve ser removido se uma nova conexão for estabelecida, via StreamLocalBindUnlink=yes.

Ambas as opções precisam ser definidas no Jump Host, em "/etc/ssh/sshd_config":

Match User tunnel
  StreamLocalBindMask 0111
  StreamLocalBindUnlink yes

Infelizmente, Matchas regras são ignoradas em "/etc/ssh/sshd_config.d/tunnel.conf" antes do OpenSSH 8.4, lançado em 27 de setembro de 2020 (relatório de erro), e isso não está disponível atualmente no Ubuntu 20.04.1 LTS.

Responder2

Solução temporária, não ideal...

Adicione um cron job de hora em hora no meu computador, ele coleta os números das portas do Jump Host e cria um novo ~/.ssh/config_tunnelsarquivo.

#!/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}";

O arquivo principal ~/.ssh/configpode então usar Include ~/.ssh/config_tunnels.

Observe que estou usando sedpara ter certeza de que receberei um número de volta. Se meu Jump Host for comprometido, não quero que o arquivo de porta contenha alguma configuração SSH extra (malicioso).

informação relacionada