2010-01-16 05:58:48 +0000 2010-01-16 05:58:48 +0000
354
354

Un tunnel SSH attraverso più luppoli

I dati di tunneling su SSH sono piuttosto semplici:

ssh -D9999 username@example.com

imposta la porta 9999 sul vostro localhost come un tunnel verso example.com, ma ho un'esigenza più specifica:

  • Sto lavorando localmente su localhost
  • host1 è accessibile a localhost
  • host2 accetta solo connessioni da host1
  • Ho bisogno di creare un tunnel da localhost a host2

Effettivamente, voglio creare un tunnel SSH “multi-hop”. Come posso farlo? Idealmente, vorrei farlo senza dover essere superutente su qualsiasi delle macchine.

Risposte (15)

341
341
341
2010-01-17 21:31:56 +0000

Avete fondamentalmente tre possibilità:

    1. Tunnel da localhost a host1:
  1. Tunnel da localhost a host1:

  2. Tunnel da host1 a host2 e da localhost a host1:

  3. Tunnel da localhost a host2:

  4. Tunnel da host1 a host2 e da host2 a host2:

Normalmente, sceglierei l'opzione 1. Se la connessione da &007 a &007 deve essere assicurata, sceglierei l'opzione 2. L'opzione 3 è utile soprattutto per accedere a un servizio su &007 che è raggiungibile solo da &007 stesso.

158
158
158
2010-08-01 17:10:27 +0000

C'è una eccellente risposta che spiega l'uso della direttiva di configurazione ProxyCommand per SSH :

Aggiungetela al vostro ~/.ssh/config (vedi man 5 ssh_config per i dettagli):

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

Poi ssh host2 scaverà automaticamente un tunnel attraverso host1 (funziona anche con la spedizione X11 ecc. ).

Questo funziona anche per un'intera classe di host, ad esempio identificati per dominio:

Host *.mycompany.com
  ProxyCommand ssh gateway.mycompany.com -W %h:%p
``` ```
Host host2
  ProxyJump host1

Update

OpenSSH 7.3 introduce una direttiva ProxyJump, semplificando il primo esempio a

&001

35
35
35
2016-08-10 09:11:34 +0000

OpenSSH v7.3 onward supporta uno switch -J e un'opzione ProxyJump, che consentono uno o più host di salto separati da virgole, quindi, si può semplicemente fare questo ora:

ssh -J jumpuser1@jumphost1,jumpuser2@jumphost2,...,jumpuserN@jumphostN user@host
20
20
20
2010-01-24 18:47:37 +0000

Abbiamo un unico gateway ssh nella nostra rete privata. Se mi trovo all'esterno e voglio una shell remota su una macchina all'interno della rete privata, dovrei ssh nel gateway e da lì alla macchina privata.

Per automatizzare questa procedura, uso il seguente script:

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


Cosa sta succedendo: 

1. 2. Stabilire un tunnel per il protocollo ssh (porta 22) verso la macchina privata. 2. Solo se questo ha successo, ssh nella macchina privata che usa il tunnel. (l'operatore && operater assicura questo). 
3. Dopo aver chiuso la sessione privata ssh, voglio che anche il tunnel ssh si chiuda. Questo avviene con il trucco "sleep 10". Di solito, il primo comando ssh si chiude dopo 10 secondi, ma durante questo tempo, il secondo comando ssh avrà stabilito una connessione usando il tunnel. Di conseguenza, il primo comando ssh mantiene il tunnel aperto fino a quando non vengono soddisfatte le due seguenti condizioni: sleep 10 è terminato e il tunnel non viene più utilizzato.
18
18
18
2012-01-11 11:02:06 +0000

Dopo aver letto quanto sopra e aver incollato tutto insieme, ho creato il seguente script Perl (salvarlo come mssh in /usr/bin e renderlo eseguibile):

#!/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:

Per accedere ad HOSTC via HOSTA e HOSTB (stesso utente):

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

Per accedere a HOSTC via HOSTA e HOSTB e utilizzare i numeri di porte SSH non difettose e diversi utenti:

mssh HOSTA HOSTB HOSTC -X
``` ```
mssh HOSTA HOSTB -L8080:HOSTC:8080

Per accedere a HOSTC via HOSTA e HOSTB e utilizzare l'inoltro X:

&001

Per accedere alla porta 8080 su HOSTC via HOSTA e HOSTB:

&001

8
8
8
2013-03-13 09:57:28 +0000

Questa risposta è simile a kynan, in quanto prevede l'uso di ProxyCommand. Ma è più conveniente usare IMO.

Se avete installato netcat nelle vostre macchine per il luppolo potete aggiungere questo frammento al vostro ~/.ssh/config:

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

Allora

ssh -D9999 host1+host2 -l username
``` &001 

farà quello che avete chiesto. 


Sono venuto qui cercando il luogo originale dove ho letto questo trucco. Quando lo troverò, pubblicherò un link.
6
6
6
2017-11-21 11:06:21 +0000

Ho fatto quello che penso che volevate fare con

ssh -D 9999 -J host1 host2

Mi vengono richieste entrambe le password, poi posso usare localhost:9999 per un proxy SOCKS a host2. È il più vicino che mi viene in mente all'esempio che avete mostrato in primo luogo.

4
4
4
2010-01-19 02:03:35 +0000
ssh -L 9999:host2:80 -R 9999:localhost:9999 host1

-L 9999:host2:80

Significa legarsi a localhost:9999 e qualsiasi pacchetto inviato a localhost:9999 inoltrarlo a host2:80

-R 9999:localhost:9999

Significa qualsiasi pacchetto ricevuto da host1:9999 inoltrarlo di nuovo a localhost:9999

2
2
2
2010-01-16 06:34:17 +0000

dovreste essere in grado di utilizzare il port forwarding per accedere ad un servizio su host2 da localhost. Una buona guida si trova qui . Estratto:

Ci sono due tipi di port forwarding: locale e remoto. Sono anche chiamati rispettivamente tunnel in uscita e in entrata. Il port forwarding locale inoltra il traffico proveniente da una porta locale verso una porta remota specificata.

Per esempio, se si emette il comando

ssh2 -L 1234:localhost:23 username@host

tutto il traffico che arriva alla porta 1234 sul client sarà inoltrato alla porta 23 sul server (host). Si noti che localhost sarà risolto dal sshdserver dopo che la connessione è stata stabilita. In questo caso localhost si riferisce quindi al server (host) stesso.

Remote port forwarding fa il contrario: inoltra il traffico proveniente da una porta remota verso una determinata porta locale.

Ad esempio, se si emette il comando

ssh2 -R 1234:localhost:23 username@host

tutto il traffico che arriva alla porta 1234 del server (host) viene inoltrato alla porta 23 del client (localhost).

Nel cast, sostituire localhost nell'esempio con host2 e host con host1.

1
1
1
2019-12-18 04:08:37 +0000

La mia risposta è davvero la stessa di tutte le altre risposte qui, ma, volevo chiarire l'utilità di ~/.ssh/config e ProxyJump.

Diciamo che ho bisogno di arrivare a una destinazione in 3 salti, e, per ogni salto, avevo bisogno di un nome utente specifico, host, porta e identità. A causa dei criteri di identità, questo può essere fatto solo con il file di configurazione ~/.ssh/config:

Host hop1
    User user1
    HostName host1
    Port 22
    IdentityFile ~/.ssh/pem/identity1.pem

Host hop2
    User user2
    HostName host2
    Port 22
    IdentityFile ~/.ssh/pem/identity2.pem
    ProxyJump hop1

Host hop3
    User user3
    HostName host3
    Port 22
    IdentityFile ~/.ssh/pem/identity3.pem
    ProxyJump hop2
``` ```
$ ssh hop1 # will go from your PC to the host1 in a single step
$ ssh hop2 # will go from your PC to host1, then from host1 to host2, i.e. in two steps
$ ssh hop3 # will go from your PC to host1, then to host2, then to host3, i.e. in three steps

Dal vostro computer, potete testare ogni salto individualmente, cioè

$ sftp hop1 # will connect your PC to host1 (i.e. file transfer between your PC and host1)
$ sftp hop2 # will connect your PC to host1 to host2 (i.e. file transfer between your PC and host2)
$ sftp hop3 # will connect your PC to host1 to host2 to host3 (i.e. file transfer between your PC and host3)

Un'altra cosa interessante del file ~/.ssh/config è che questo abiliterà anche i trasferimenti di file sftp, ad esempio

&001

1
1
1
2017-03-18 20:13:02 +0000

In questa risposta affronterò un esempio concreto. Basta sostituire i nomi host, i nomi utente e le password dei computer con i vostri.

Dichiarazione del problema

Supponiamo di avere la seguente topologia di rete:

our local computer <---> server 1 <---> server 2

Per motivi di concretezza, supponiamo di avere i seguenti hostname, nomi utente e password dei computer:

LocalPC <---> hostname: mit.edu <---> hec.edu
                          username: bob username: john 
                          password: dylan123 password: doe456
``` ```
Host HEC
    HostName hec.edu
    User john
    ProxyCommand ssh bob@mit.edu -W %h:%p

Obiettivo: vogliamo impostare un proxy SOCKS che ascolti sulla porta 9991 di LocalPC in modo che ogni volta che una connessione su LocalPC viene avviata dalla porta 9991 passi attraverso mit.edu e poi hec.edu.

Esempio di caso d'uso: hec.edu ha un server HTTP accessibile solo su http://127.0.0.1:8001 , per ragioni di sicurezza. Vorremmo poter visitare http://127.0.0.1:8001 aprendo un browser web su LocalPC.


Configurazione

In LocalPC, aggiungere in ~/.ssh/config:

ssh -D9991 HEC
``` &001 


Poi nel terminale di `LocalPC`, eseguire: 


&001 



Vi chiederà la password di `bob` su `mit.edu` (cioè, `dylan123`), poi vi chiederà la password di `john` su `hec.edu` (cioè `doe456`). 


A quel punto, il proxy SOCKS è ora in esecuzione sulla porta `9991` di `LocalPC`. 


Per esempio, se volete visitare una pagina web su `LocalPC` usando il proxy SOCKS, potete farlo in Firefox: 


[![enter image description here](https://i.stack.imgur.com/xQsky.png)](https://i.stack.imgur.com/xQsky.png) 


Alcune osservazioni: 

- in `~/.ssh/config`, `HEC` è il nome della connessione: potete cambiarlo con qualsiasi cosa vogliate. 
- Il `-D9991` dice a `ssh` di impostare un proxy SOCKS4 sulla porta `9991`.
0
0
0
2020-02-22 07:13:01 +0000

Solo questo mi ha aiutato su più di due host:

ssh -L 6010:localhost:6010 user1@host1 \
-t ssh -L 6010:localhost:6010 user2@host2 \
-t ssh -L 6010:localhost:6010 user3@host3
``` &001 


Vi chiederà tre password. 
[ Ispirato da questa risposta ](https://serverfault.com/a/791997/494014)
0
0
0
2018-07-26 05:24:38 +0000

Nel mio caso ho fatto

localhost$ ssh -D 9999 host1
host1$ ssh -L 8890:localhost:8890 host2
``` &001 


dove `host2:8890` gira su un Notebook Jupyter. 


Poi ho configurato Firefox per usare `localhost:9999` come host SOCKS. 


Quindi ora ho il notebook che gira su `host2` accessibile da Firefox a `localhost:8890` sulla mia macchina.
0
0
0
2017-10-05 08:43:30 +0000

L'opzione 2 della best answer potrebbe essere usata con diversi utenti ssh rispetto a quella attuale aka : user@host

export local_host_port=30000
    export host1_user=xyz
    export host1=mac-host
    export host1_port=30000
    export host2=192.168.56.115
    export host2_user=ysg
    export host2_port=13306

    # Tunnel from localhost to host1 and from host1 to host2
    # you could chain those as well to host3 ... hostn
    ssh -tt -L $local_host_port:localhost:$host1_port $host1_user@$host1 \
    ssh -tt -L $host1_port:localhost:$host2_port $host2_user@$host2
0
0
0
2019-08-20 19:09:55 +0000

Le tre opzioni menzionate nella risposta accettata non hanno funzionato affatto per me. Dal momento che non ho molti permessi su entrambi i padroni di casa, e sembra che il nostro team di DevOps abbia regole piuttosto rigide quando si tratta di autenticazione e stanno facendo MFA. In qualche modo i comandi di cui sopra non possono giocare bene con la nostra autenticazione.

Il contesto è molto simile alle risposte di cui sopra, però: non posso entrare direttamente nel server di produzione e devo fare 1 hop usando un server di salto.

Yet Another Solution - a naive one

Ho finito per farlo in un modo molto ingenuo: invece di cercare di eseguire tutti i comandi sul mio portatile, eseguo i comandi su ciascuna delle macchine , come di seguito:

  1. SSH nel vostro server di salto, poi eseguo ssh -v -L 6969:localhost:2222 -N your-protected.dest.server. Se vi viene richiesto di inserire una password, digitatela.
  2. 2. Ora sul vostro portatile, eseguite ssh -v -L 6969:localhost:6969 -N your-jump-server.host.name. Questo inoltrerà qualsiasi vostra richiesta sulla porta 6969 del vostro portatile, al server di salto. Poi a turno, dato che abbiamo configurato nel nostro passo precedente, il server di salto inoltrerà di nuovo le richieste della porta 6969 alla porta 2222 sul server di destinazione protetto.

Dovreste vedere il comando “si blocca” lì dopo aver stampato qualche messaggio - significa che stanno funzionando! Un'eccezione - non dovreste vedere un messaggio di errore come Could not request local forwarding., se lo vedete, allora non funziona ancora :(. Ora potete provare a lanciare la richiesta sulla porta 6969 dal vostro portatile, e vedere se funziona.

Speriamo che se siete qualcuno che ha fallito tutti i metodi di cui sopra, forse potete provare questo.