it-swarm-eu.dev

Un tunnel SSH tramite hop multipli

Il tunnelling dei dati su SSH è piuttosto diretto:

ssh -D9999 [email protected]

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

  • Sto lavorando localmente su localhost
  • Host1 è accessibile a localhost
  • Host2 accetta solo connessioni da Host1
  • Devo creare un tunnel da localhost a Host2

Effettivamente, voglio creare un tunnel SSH "multi-hop". Come posso fare questo? Idealmente, mi piacerebbe farlo senza dover essere superutente qualunque delle macchine.

319
Mala

In pratica hai tre possibilità:

  1. Tunnel da localhost a Host1:

    ssh -L 9999:Host2:1234 -N Host1
    

    Come notato sopra, la connessione da Host1 a Host2 non sarà protetta.

  2. Tunnel da localhost a Host1 e da Host1 a Host2:

    ssh -L 9999:localhost:9999 Host1 ssh -L 9999:localhost:1234 -N Host2
    

    Questo aprirà un tunnel da localhost a Host1 e un altro tunnel da Host1 a Host2. Tuttavia la porta 9999 a Host2:1234 può essere utilizzata da chiunque su Host1. Questo potrebbe o non potrebbe essere un problema.

  3. Tunnel da localhost a Host1 e da localhost a Host2:

    ssh -L 9998:Host2:22 -N Host1
    ssh -L 9999:localhost:1234 -N -p 9998 localhost
    

    Questo aprirà un tunnel da localhost a Host1 attraverso il quale è possibile utilizzare il servizio SSH su Host2. Quindi un secondo tunnel viene aperto da localhost a Host2 attraverso il primo tunnel.

Normalmente, opterei per l'opzione 1. Se la connessione da Host1 a Host2 deve essere protetta, andare con l'opzione 2. L'opzione 3 è principalmente utile per accedere a un servizio su Host2 che è raggiungibile solo da Host2 stesso.

306
Mika Fischer

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

Aggiungi questo al tuo ~/.ssh/config (vedi man 5 ssh_config per i dettagli):

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

Quindi ssh Host2 eseguirà automaticamente il tunneling attraverso Host1 (funziona anche con l'inoltro X11, ecc.).

Questo funziona anche per un'intera classe di host, ad es. identificato dal dominio:

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

Aggiornare

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

Host host2
  ProxyJump Host1
149
kynan

OpenSSH v7.3 in poi supporta uno switch -J e un'opzione ProxyJump, che consente uno o più host di salto separati da virgole, quindi puoi semplicemente farlo ora:

ssh -J [email protected],[email protected],...,[email protected] [email protected]
21
nikolay

Abbiamo un gateway SSH nella nostra rete privata. Se sono fuori 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, utilizzo il seguente script:

#!/bin/bash
ssh -f -L some_port:private_machine:22 [email protected] "sleep 10" && ssh -p some_port [email protected]

Che cosa sta succedendo:

  1. Stabilire un tunnel per il protocollo ssh (porta 22) sulla macchina privata.
  2. Solo se questo ha successo, ssh nella macchina privata usando il tunnel. (l'operatore && lo garantisce).
  3. Dopo aver chiuso la sessione ssh privata, voglio chiudere anche il tunnel ssh. Questo viene fatto tramite 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 aperto il tunnel fino a quando non sono soddisfatte le seguenti due condizioni: il sonno 10 è terminato e il tunnel non viene più utilizzato.
21
Bernhard Kausler

Dopo aver letto quanto sopra e 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 a HOSTC tramite HOSTA e HOSTB (stesso utente):

mssh HOSTA HOSTB HOSTC

Per accedere a HOSTC tramite HOSTA e HOSTB e utilizzare numeri di porta SSH non predefiniti e utenti diversi:

mssh [email protected]:1234 [email protected]:1222 [email protected]:78231

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

mssh HOSTA HOSTB HOSTC -X

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

mssh HOSTA HOSTB -L8080:HOSTC:8080
18
Bob Muller

Questa risposta è simile a kynan, poiché implica l'uso di ProxyCommand. Ma è più comodo usare IMO.

Se hai installato netcat nelle tue macchine hop puoi aggiungere questo snippet al tuo ~/.ssh/config:

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

Poi

ssh -D9999 Host1+Host2 -l username

farà quello che hai chiesto.

Sono venuto qui cercando il posto originale dove ho letto questo trucco. Pubblicherò un link quando lo trovo.

8
silviot
ssh -L 9999:Host2:80 -R 9999:localhost:9999 Host1

-L 9999: Host2: 80

Significa collegarsi a localhost: 9999 e qualsiasi pacchetto inviato a localhost: 9999 inoltrarlo a Host2: 80

-R 9999: localhost: 9999

Indica qualsiasi pacchetto ricevuto da Host1: 9999 lo inoltra all'host locale: 9999

4
chinmaya

Ho fatto quello che io penso tu volevi fare con

ssh -D 9999 -J Host1 Host2

Sono richiesto per entrambe le password, quindi posso usare localhost: 9999 per un proxy SOCKS su Host2. È il più vicino che riesco a pensare all'esempio che hai mostrato in primo luogo.

3
Cheryl

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

Esistono due tipi di port forwarding: local e remote forwarding. Vengono anche chiamati rispettivamente tunnel in uscita e in entrata. L'inoltro porta locale inoltra il traffico proveniente da una porta locale a una porta remota specificata.

Ad esempio, se si emette il comando

ssh2 -L 1234:localhost:23 [email protected]

tutto il traffico proveniente dalla porta 1234 sul client verrà inoltrato alla porta 23 sul server (Host). Si noti che localhost verrà risolto da sshdserver dopo aver stabilito la connessione. In questo caso, localhost si riferisce quindi al server (Host) stesso.

Il port forwarding remoto fa il contrario: inoltra il traffico proveniente da una porta remota a una porta locale specificata.

Ad esempio, se si emette il comando

ssh2 -R 1234:localhost:23 [email protected]

tutto il traffico che arriva alla porta 1234 sul server (Host) verrà inoltrato alla porta 23 sul client (localhost).

Nel cast, sostituire localhost nell'esempio con Host2 e Host con Host1.

2
fideli

In questa risposta darò un esempio concreto. Hai solo bisogno di sostituire i nomi host, i nomi utente e le password dei tuoi computer.

Dichiarazione problema

Supponiamo di avere la seguente topologia di rete:

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

Per ragioni di concretezza, supponiamo di avere i nomi host, i nomi utente e le password dei seguenti computer:

LocalPC            <--->  hostname: mit.edu         <---> hec.edu
                          username: bob                   username: john 
                          password: dylan123              password: doe456

Obiettivo: vogliamo impostare un proxy SOCKS che ascolti sulla porta 9991 di LocalPC in modo che ogni volta che una connessione su LocalPC sia avviata da port 9991, passa mit.edu quindi hec.edu.

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


Configurazione

In LocalPC, aggiungi ~/.ssh/config:

Host HEC
    HostName hec.edu
    User john
    ProxyCommand ssh [email protected] -W %h:%p

Quindi nel terminale di LocalPC, esegui:

ssh -D9991 HEC

Ti chiederà la password di bob su mit.edu (cioè, dylan123), quindi ti chiederà la password di john su hec.edu (cioè, doe456).

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

Ad esempio, se vuoi visitare una pagina web su LocalPC usando il proxy SOCKS, puoi farlo in Firefox:

 enter image description here

Alcune osservazioni:

  • in ~/.ssh/config, HEC è il nome della connessione: puoi cambiarlo in qualsiasi cosa tu voglia.
  • -D9991 indica a ssh di impostare un proxy SOCKS4 sulla porta 9991.
1

Se è possibile eseguire SSH su entrambe le macchine, dare un'occhiata alla direttiva ProxyCommand di ssh. Questo ti permetterà di andare direttamente da localhost a Host2 (con un semplice comando se usi le chiavi pubbliche !!). Quindi puoi fare tutto ciò che vuoi con Host2.

http://www.statusq.org/archives/2008/07/03/1916/

0
Andrew

Nel mio caso l'ho fatto

localhost$ ssh -D 9999 Host1
Host1$ ssh -L 8890:localhost:8890 Host2

dove Host2:8890 è in esecuzione su un Jupyter Notebook.

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

Così ora ho il notebook in esecuzione su Host2 accessibile da Firefox a localhost:8890 sulla mia macchina.

0
amarion

L'opzione 2 della miglior risposta potrebbe essere utilizzata con diversi utenti ssh rispetto a quella corrente alias: 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 [email protected]$Host1 \
    ssh -tt -L $Host1_port:localhost:$Host2_port [email protected]$Host2
0
Yordan Georgiev