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

Tunel SSH przez wiele chmieli

Tunelowanie danych przez SSH jest dość proste:

ssh -D9999 username@example.com

ustawia port 9999 w swoim localhost jako tunel do example.com, ale mam bardziej konkretne potrzeby:

  • pracuję lokalnie nad localhost
  • host1 jest dostępny dla localhost
  • host2 akceptuje tylko połączenia z host1
  • muszę stworzyć tunel z localhost do host2

Skutecznie, chcę stworzyć “multi-hopowy” tunel SSH. Jak mogę to zrobić? Idealnie, chciałbym to zrobić bez potrzeby bycia superużytkownikiem na anach maszyn.

Odpowiedzi (15)

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

Zasadniczo masz trzy możliwości:

  1. Tunel od localhost do host1:

  2. Tunnel from localhost to host1 and from host1 to host2:

  3. Tunnel from localhost to host1 and from localhost to host2:

Normalnie, I’d go with option 1. Jeśli połączenie z host1 do host2 musi być zabezpieczone, przejdź do opcji 2. Opcja 3 jest przydatna głównie w celu uzyskania dostępu do usługi w host2, która jest dostępna tylko z samego host2.

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

There is an excellent answer explaining the use of the ProxyCommand configuration directive for SSH :

Add this to your ~/.ssh/config (see man 5 ssh_config for details):

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

Then ssh host2 will automatically tunnel through host1 (also works with X11 forwarding etc.). ).

This also works for an entire class of hosts e.g. identified by domain:

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

Update

OpenSSH 7.3 introduces a ProxyJump directive, simplifying the first example to

Host host2
  ProxyJump host1
35
35
35
2016-08-10 09:11:34 +0000

OpenSSH v7.3 dalej obsługuje przełącznik -J oraz opcję ProxyJump, która pozwala na jedno lub więcej oddzielonych przecinkami gospodarzy skoków, więc możesz po prostu zrobić to teraz:

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

Mamy jedną bramę ssh do naszej prywatnej sieci. Jeśli jestem na zewnątrz i chcę mieć zdalną powłokę na maszynie wewnątrz sieci prywatnej, będę musiał wpaść do bramki, a stamtąd do maszyny prywatnej.

Aby zautomatyzować tę procedurę, używam następującego skryptu:

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

Co się dzieje:

  1. Tworzenie tunelu dla protokołu ssh (port 22) do maszyny prywatnej.
  2. Tylko jeśli się to uda, ssh do maszyny prywatnej używającej tunelu. (zapewnia to &&operator).
  3. Po zamknięciu prywatnej sesji ssh, chcę, aby tunel ssh również został zamknięty. Odbywa się to za pomocą triku “sleep 10”. Zwykle pierwsza komenda ssh zamyka się po 10 sekundach, ale w tym czasie druga komenda ssh nawiązuje połączenie przy użyciu tunelu. W rezultacie, pierwsze polecenie ssh utrzymuje tunel otwarty do momentu spełnienia dwóch następujących warunków: sen 10 jest zakończony i tunel nie jest już używany.
18
18
18
2012-01-11 11:02:06 +0000

Po przeczytaniu powyższego i sklejeniu wszystkiego razem, stworzyłem następujący skrypt Perla (zapisz go jako mssh w /usr/bin i zrób go wykonywalnym):

#!/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($_);
}

Wykorzystanie:

Aby uzyskać dostęp do HOSTC przez HOSTA i HOSTB (ten sam użytkownik):

mssh HOSTA HOSTB HOSTC

Aby uzyskać dostęp do HOSTC przez HOSTA i HOSTB i korzystać z nieudanych numerów SSH i różnych użytkowników:

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

Aby uzyskać dostęp do HOSTC przez HOSTA i HOSTB i korzystać z przesyłu X:

mssh HOSTA HOSTB HOSTC -X

Aby uzyskać dostęp do portu 8080 w HOSTC przez HOSTA i HOSTB:

mssh HOSTA HOSTB -L8080:HOSTC:8080
8
8
8
2013-03-13 09:57:28 +0000

Ta odpowiedź jest podobna do kynan, ponieważ wymaga użycia ProxyCommand. Ale to jest bardziej wygodne w użyciu IMO.

Jeśli masz netcat zainstalowany w maszynach hop można dodać ten snippet do swojego ~/.ssh/config:

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

Następnie

ssh -D9999 host1+host2 -l username

zrobi to, o co prosiłeś.

Przyszedłem tutaj szukając oryginalnego miejsca, gdzie czytam tę sztuczkę. Zamieszczę link, gdy go znajdę.

6
6
6
2017-11-21 11:06:21 +0000

Zrobiłem to, co ja think chciałeś zrobić z

ssh -D 9999 -J host1 host2

Jestem proszony o oba hasła, a następnie mogę użyć localhost:9999 dla SOCKS proxy do hosta2. To jest najbliżej mogę myśleć o przykładzie, który pokazałeś w pierwszej kolejności.

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

-L 9999:host2:80

Oznacza powiązanie z localhost:9999 i każdy pakiet wysłany do localhost:9999 przekaże go do hosta:80

-R 9999:localhost:9999

Oznacza każdy pakiet otrzymany przez hosta:9999 przekaże go z powrotem do localhost:9999.

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

powinieneś mieć możliwość korzystania z przekierowania portów, aby uzyskać dostęp do usługi w host2 z localhost. Dobry przewodnik znajduje się tutaj . Fragment:

Istnieją dwa rodzaje przekierowania portów: przekierowanie lokalne i zdalne. Są one również nazywane odpowiednio tunelami wychodzącymi i przychodzącymi. Przekierowanie na port lokalny przekierowuje ruch przychodzący na port lokalny na określony port zdalny.

Np. jeśli wydasz polecenie

ssh2 -L 1234:localhost:23 username@host

cały ruch przychodzący na port 1234 na kliencie zostanie przekierowany na port 23 na serwerze (hostie). Należy pamiętać, że lokalny host będzie rozwiązany przez sshdserver po nawiązaniu połączenia. W tym przypadku localhost odnosi się więc do samego serwera (hosta).

Remote port forwarding robi odwrotnie: przekazuje ruch przychodzący na zdalny port na określony port lokalny.

Na przykład, jeśli wydasz komendę

ssh2 -R 1234:localhost:23 username@host

cały ruch przychodzący na port 1234 na serwerze (hoście) zostanie przekierowany na port 23 na kliencie (hoście).

W swojej obsadzie zastąp localhost w przykładzie host2 i host w host1.

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

Moja odpowiedź jest naprawdę taka sama, jak wszystkie inne odpowiedzi tutaj, ale, chciałem wyjaśnić przydatność ~/.ssh/config i ProxyJump.

Powiedzmy, że muszę dostać się do miejsca przeznaczenia w 3 hop, a dla każdego hop, potrzebowałem konkretnej nazwy użytkownika, hosta, portu i tożsamości. Ze względu na kryteria tożsamości, można to zrobić tylko z plikiem konfiguracyjnym ~/.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

Z komputera można przetestować każdy skok indywidualnie, np.

$ 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

Kolejną fajną rzeczą w pliku ~/.ssh/config jest to, że umożliwi to również transfer plików sftp, np.

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

W tej odpowiedzi przejdę przez konkretny przykład. Wystarczy, że zastąpisz nazwy hostów komputerów, nazwy użytkowników i hasła swoimi.

Problematyka

Załóżmy, że mamy następującą topologię sieci:

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

Dla ścisłości, załóżmy, że mamy następujące nazwy hostów, nazwy użytkowników i hasła komputerów:

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

Cel: chcemy ustawić SOCKS proxy, który nasłuchuje na porcie 9991 z LocalPC tak, aby za każdym razem gdy połączenie na LocalPC jest inicjowane z portu 9991 przechodziło przez mit.edu następnie hec.edu.

Przykładowy przypadek użycia: hec.edu posiada serwer HTTP, który jest dostępny tylko na http://127.0.0.1:8001 , ze względów bezpieczeństwa. Chcielibyśmy móc odwiedzić http://127.0.0.1:8001 otwierając przeglądarkę internetową w LocalPC.

  • *

Configuration

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

Host HEC
    HostName hec.edu
    User john
    ProxyCommand ssh bob@mit.edu -W %h:%p

Then in the terminal of LocalPC, run:

ssh -D9991 HEC

It will ask you the password of bob on mit.edu, dylan123), następnie w terminalu z john zapyta Cię o hasło hec.edu on doe456 (tzn, 9991).

W tym momencie, SOCKS proxy działa na porcie LocalPC z LocalPC.

Na przykład, jeśli chcesz odwiedzić stronę internetową w ~/.ssh/config za pomocą SOCKS proxy, możesz zrobić to w Firefoksie:

Kilka uwag:

  • w HEC, -D9991 to nazwa połączenia: możesz zmienić ją na dowolną osobę.
  • ssh mówi 9991, aby ustawić SOCKS4 proxy na porcie &007.
0
0
0
2020-02-22 07:13:01 +0000

Tylko to pomogło mi na więcej niż dwóch hostach:

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

To zachęci cię trzema hasłami. Zainspirowany tą odpowiedzią

0
0
0
2018-07-26 05:24:38 +0000

W moim przypadku zrobiłem

localhost$ ssh -D 9999 host1
host1$ ssh -L 8890:localhost:8890 host2

gdzie host2:8890 działa na notebooku Jupyter.

Następnie skonfigurowałem Firefoksa, aby używał localhost:9999 jako hosta SOCKS.

Więc teraz mam notebooka działającego na host2 dostępnego przez Firefoksa na localhost:8890 na moim komputerze.

0
0
0
2017-10-05 08:43:30 +0000

Opcja 2 z najlepsza odpowiedź może być używana z innymi użytkownikami ssh niż obecny 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

Trzy opcje wymienione w zaakceptowanej odpowiedzi wcale mi się nie sprawdziły. Ponieważ nie mam zbyt wielu uprawnień nad obydwoma hostami i wydaje mi się, że nasz zespół DevOps ma dość surowe zasady, jeśli chodzi o uwierzytelnianie i zajmuje się MFA. W jakiś sposób powyższe komendy nie mogą dobrze współgrać z naszą autentykacją.

Kontekst jest jednak bardzo podobny do powyższych odpowiedzi: nie mogę wpaść bezpośrednio na serwer produkcyjny i muszę wykonać 1 skok za pomocą serwera skokowego.

Jeszcze jedno rozwiązanie - naiwne

Skończyło się na tym, że zrobiłem to w bardzo naiwny sposób: zamiast próbować uruchomić wszystkie komendy na moim laptopie, uruchamiam komendy na każdej z maszyn , jak poniżej:

  1. SSH do twojego serwera skoków, a następnie uruchamiam ssh -v -L 6969:localhost:2222 -N your-protected.dest.server. Jeśli zostaniesz poproszony o podanie dowolnego hasła, wpisz je.
  2. Teraz na swoim laptopie, uruchom ssh -v -L 6969:localhost:6969 -N your-jump-server.host.name. Spowoduje to przekazanie każdego żądania na porcie 6969 w laptopie, do serwera skoków. Następnie z kolei, ponieważ skonfigurowaliśmy w naszym poprzednim kroku, serwer skoków ponownie przekaże żądania z portu 6969 na port 2222 na chronionym serwerze docelowym.

Powinieneś zobaczyć polecenie “wisi” tam po wydrukowaniu jakiejś wiadomości - to znaczy, że działają! Jeden wyjątek - nie powinieneś widzieć komunikatu o błędzie takiego jak Could not request local forwarding., jeśli to widzisz, to znaczy, że nadal nie działa :(. Możesz teraz spróbować odpalić z laptopa żądanie na porcie 6969 i sprawdzić, czy działa.

Miejmy nadzieję, że jeśli jesteś kimś, kto zawiódł wszystkie powyższe metody, być może możesz spróbować.