Questão Um túnel SSH via múltiplos saltos


O tunelamento de dados por SSH é bastante direto:

ssh -D9999 username@example.com

configura a porta 9999 no seu localhost como um túnel para example.com, mas tenho uma necessidade mais específica:

  • Eu estou trabalhando localmente localhost
  • host1 está acessível para localhost
  • host2 aceita apenas conexões de host1
  • Eu preciso criar um túnel de localhost para host2

Efetivamente, quero criar um túnel SSH "multi-hop". Como posso fazer isso? Idealmente, eu gostaria de fazer isso sem precisar ser superusuário qualquer das máquinas.


287


origem


O que você usou para isso? Eu quero usá-lo para proxy de meias. será que vai dar certo? - prongs
Sim, você deve poder usar a conexão encapsulada como um proxy SOCKS, a menos que host2 nega encaminhamento - Mala
Eu estava pensando em criar um wrapper sobre SSH que configuraria isso usando múltiplos usos do ProxyCommand. - Pavel Šimerda
@prongs Você conseguiu usar isso para o proxy SOCKS (todos esses anos atrás)? - Drux


Respostas:


Você basicamente tem três possibilidades:

  1. Túnel de localhost para host1:

    ssh -L 9999:host2:1234 -N host1
    

    Como mencionado acima, a conexão de host1 para host2 não será garantido.

  2. Túnel de localhost para host1 e de host1 para host2:

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

    Isto irá abrir um túnel de localhost para host1 e outro túnel de host1 para host2. No entanto o porto 9999 para host2:1234 pode ser usado por qualquer pessoa host1. Isso pode ou não ser um problema.

  3. Túnel de localhost para host1 e de localhost para host2:

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

    Isto irá abrir um túnel de localhost para host1 através do qual o serviço SSH em host2 pode ser usado. Então um segundo túnel é aberto localhost para host2 através do primeiro túnel.

Normalmente, eu iria com a opção 1. Se a conexão de host1 para host2 precisa ser protegido, escolha a opção 2. A opção 3 é útil principalmente para acessar um serviço em host2 que só é acessível a partir de host2 em si.


272



A opção 3 foi o que eu estava procurando, obrigado! - Mala
Eu quero navegar dessa maneira. Qual é o melhor? Eu tentei primeiro um, mas não funcionou. Eu defino um proxy de meias no meu host localhost: 1234, mas sem sorte. :( por favor ajude.. - prongs
@prongs tentam a opção 3 - Mala
Existe uma maneira de encaminhar minha chave pública de localhost, através do túnel do host 1, para host2? - Noli
@Noli Se você usa ssh-agent (o que você deve), você pode encaminhá-lo através das conexões usando o -A opção para ssh. - Mika Fischer


Há um excelente resposta explicando o uso do ProxyCommand diretiva de configuração para SSH:

Adicione isto ao seu ~/.ssh/config (Vejo man 5 ssh_config para detalhes):

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

Então ssh host2 irá encapsular automaticamente host1 (também funciona com o encaminhamento do X11 etc.).

Isso também funciona para uma classe inteira de hosts, e. identificado por domínio:

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

Atualizar

OpenSSH 7.3 introduz uma ProxyJump directiva, simplificando o primeiro exemplo a

Host host2
  ProxyJump host1

138



Existe uma maneira de fazer isso condicionalmente? Eu só quero fazer isso às vezes. Além disso, isso é especificamente para comandos, mas estou procurando algo para toda a porta 22 (ssh, sftp, etc). - Stephane
@ Stephane o que você quer dizer com especificamente para comandos? Sua configuração SSH é usada por qualquer coisa usando ssh, Incluindo git, sftp afaik etc. - kynan
@Stephane Não estou ciente de uma maneira de ativar isso condicionalmente (por exemplo, somente quando você está fora da rede do host de destino). Eu defino essa opção para todos os hosts em questão em um bloco de configuração e, em seguida, (des) comento a linha conforme necessário. Não é perfeito, mas funciona. - kynan
@Stephane sure: ssh -F /path/to/altconfig. Cuidado, isso vai ignorar o sistema inteiro /etc/ssh/ssh_config. - kynan
Uma maneira fácil de tornar as configurações "condicionais" é definir dois hosts diferentes em .ssh / config, que possuem o mesmo HostName. Conecte-se ao host2-tunnel quando quiser o túnel e host2 quando não quiser. - Steve Bennett


Nós temos um gateway ssh em nossa rede privada. Se eu estou fora e quero um shell remoto em uma máquina dentro da rede privada, eu teria que ssh no gateway e de lá para a máquina privada.

Para automatizar esse procedimento, uso o seguinte script:

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

O que está acontecendo:

  1. Estabeleça um túnel para o protocolo ssh (porta 22) para a máquina privada.
  2. Somente se isso for bem-sucedido, ssh na máquina privada usando o túnel. (o operador && garante isso).
  3. Depois de fechar a sessão privada do ssh, eu quero que o túnel ssh feche também. Isso é feito através do truque "sleep 10". Normalmente, o primeiro comando ssh fecha após 10 segundos, mas durante esse tempo, o segundo comando ssh estabelecerá uma conexão usando o túnel. Como resultado, o primeiro comando ssh mantém o túnel aberto até que as duas condições a seguir sejam satisfeitas: o sleep 10 terminou e o túnel não é mais usado.

20



Muito esperto!!! ADORO! - Hendy Irawan


Depois de ler o acima e colar tudo junto, criei o seguinte script Perl (salve-o como mssh em / usr / bin e torne-o executável):

#!/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 acessar o HOSTC via HOSTA e HOSTB (mesmo usuário):

mssh HOSTA HOSTB HOSTC

Para acessar o HOSTC via HOSTA e HOSTB e usar números de porta SSH não padrão e usuários diferentes:

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

Para acessar o HOSTC via HOSTA e HOSTB e usar o X-forwarding:

mssh HOSTA HOSTB HOSTC -X

Para acessar a porta 8080 no HOSTC via HOSTA e HOSTB:

mssh HOSTA HOSTB -L8080:HOSTC:8080

16



isso é incrível - Mala
Eu sinceramente não posso agradecer o suficiente, esse roteiro facilita minha vida diariamente. A única coisa que mudei foi adicionar int (rand (1000)) ao iport, para permitir que várias instâncias sejam executadas ao mesmo tempo. Eu definitivamente te devo uma cerveja. - Mala
Isso funciona muito bem. Uma melhoria adicional seria resolver HOSTB, HOSTC etc usando o / etc / hosts do localhost e ~ / .ssh / config - Steve Bennett
Também faço o segundo comentário de Mala. Sem a porta randomizada, se você tentar mssh HOSTA HOSTD você vai acabar no HOSTB (e talvez não perceba ..) - Steve Bennett


O OpenSSH v7.3 em diante suporta -J interruptor e um ProxyJump opção, que permite um ou mais hosts de salto separados por vírgulas, portanto, você pode simplesmente fazer isso agora:

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

16



ssh -J usuário1 @ host1 -YC4c arcfour, blowfish-cbc usuário2 @ host2 firefox -no-remote Isso acelerará a obtenção do firefox de host2 para localhost. - Jaur


Esta resposta é semelhante ao kynan, pois envolve o uso do ProxyCommand. Mas é mais conveniente usar o IMO.

Se você tiver o netcat instalado em suas máquinas de salto, você pode adicionar este trecho ao seu arquivo ~ / .ssh / config:

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

Então

ssh -D9999 host1+host2 -l username

vai fazer o que você pediu.

Eu vim aqui procurando o lugar original onde eu li este truque. Vou postar um link quando o encontrar.


8



Eu acredito que esta é a origem do truque: wiki.gentoo.org/wiki/SSH_jump_host - slm
@slm sim, é isso! Obrigado! - silviot


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

-L 9999: host2: 80

Significa bind para localhost: 9999 e qualquer pacote enviado para localhost: 9999 encaminhar para host2: 80

-R 9999: localhost: 9999

Significa que qualquer pacote recebido pelo host1: 9999 o encaminha de volta para o localhost: 9999


4



Resposta brilhante e simples para criar um túnel para que você possa acessar o aplicativo no host2 diretamente do localhost: 9999 - dvtoever
Após esta resposta, recebo um channel 3: open failed: administratively prohibited: open failed  mensagem de erro. - Franck Dernoncourt


você deve ser capaz de usar o encaminhamento de porta para acessar um serviço em host2 a partir de localhost. Um bom guia está localizado Aqui. Excerto:

Existem dois tipos de encaminhamento de porta: encaminhamento local e remoto. Eles também são chamados de túneis de saída e de entrada, respectivamente. O encaminhamento de porta local encaminha o tráfego que chega a uma porta local para uma porta remota especificada.

Por exemplo, se você emitir o comando

ssh2 -L 1234:localhost:23 username@host

todo o tráfego que chega à porta 1234 no cliente será encaminhado para a porta 23 no servidor (host). Observe que o localhost será resolvido pelo sshdserver após a conexão ser estabelecida. Neste caso, localhost refere-se ao próprio servidor (host).

O encaminhamento de porta remota faz o oposto: encaminha o tráfego que chega a uma porta remota para uma porta local especificada.

Por exemplo, se você emitir o comando

ssh2 -R 1234:localhost:23 username@host

todo o tráfego que chega à porta 1234 no servidor (host) será encaminhado para a porta 23 no cliente (localhost).

No seu elenco, substitua localhost no exemplo com host2 e host com host1.


2



de acordo com esse artigo, a conexão só será assegurada até a máquina do meio (host1). Existe uma maneira de garantir que a coisa toda permaneça segura? - Mala
Eu nunca tentei isso, mas se host1 e host2 são ambos servidores ssh, você pode ser capaz de configurar um túnel de host1 para host2, em seguida, configurar um túnel de localhost para host1 para o mesmo serviço (obtendo seu local e remoto portas à direita). Eu não sei se isso é possível em um comando do localhost. - fideli