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

Een SSH-tunnel via meerdere hops

Tunneling data over SSH is vrij eenvoudig:

ssh -D9999 username@example.com

stelt poort 9999 op uw localhost in als een tunnel naar example.com, maar ik heb een meer specifieke behoefte:

  • Ik werk lokaal aan localhost
  • host1 is toegankelijk voor localhost
  • host2 accepteert alleen verbindingen van host1
  • Ik moet een tunnel maken van localhost naar host2

Effectief, ik wil een “multi-hop” SSH-tunnel maken. Hoe kan ik dit doen? Idealiter zou ik dit willen doen zonder superuser te hoeven zijn op een van de machines.

Antwoorden (15)

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

Je hebt in principe drie mogelijkheden:

    1. Tunnel van localhost naar host1:
  1. Tunnel van localhost naar host1. 2. Tunnel van host1 naar host2 en van localhost naar host1:

  2. Tunnel van localhost naar host2. 4. Tunnel van host1 naar host2 en van host2 naar host2:

  3. Tunnel van &007 naar &007 en van &007 naar &007:

  4. Tunnel van &007 naar &007 en van &007 naar &007:

  5. Tunnel van &007 naar &007 en van &007 naar &007:

  6. Tunnel van &007 naar &007:

  7. Tunnel van &007 naar &007:

  8. Tunnel van &007 naar &007:

  9. Tunnel van &007 naar &007: &007 naar &007:

  10. Normaal gesproken zou ik met optie 1 gaan. Als de verbinding van &007 naar &007 beveiligd moet worden, ga dan voor optie 2. Optie 3 is vooral handig om toegang te krijgen tot een dienst op &007 die alleen bereikbaar is vanuit &007 zelf.

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

Er is een uitstekend antwoord dat het gebruik van de ProxyCommand configuratierichtlijn voor SSH uitlegt:

Voeg dit toe aan uw ~/.ssh/config (zie man 5 ssh_config voor details):

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

Dan zal ssh host2 automatisch door host1 tunnelen (werkt ook met X11-forwarding etc.) ).

Dit werkt ook voor een hele klasse van hosts, bijv. geïdentificeerd per domein:

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

Update

OpenSSH 7.3 introduceert een ProxyJump richtlijn, waardoor het eerste voorbeeld van

Host host2
  ProxyJump host1
``` wordt vereenvoudigd.
35
35
35
2016-08-10 09:11:34 +0000

OpenSSH v7.3 ondersteunt een -J switch en een ProxyJump optie, die een of meer door komma’s gescheiden jump hosts mogelijk maken, dus, je kunt dit nu gewoon doen:

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

We hebben één ssh-gateway in ons privé-netwerk. Als ik buiten ben en een remote shell wil op een machine binnen het private netwerk, dan zou ik in de gateway moeten sshen en vandaar naar de private machine.

Om deze procedure te automatiseren, gebruik ik het volgende script:

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

Wat gebeurt er:

  1. 1. Stel een tunnel in voor het ssh-protocol (poort 22) naar de privé-machine.
  2. 3. Alleen als dit succesvol is, ssh in de privé machine met behulp van de tunnel. (de && operater zorgt hiervoor).
  3. 3. Na het afsluiten van de privé ssh-sessie wil ik ook de ssh-tunnel afsluiten. Dit gebeurt via de “slaap 10” truc. Normaal gesproken zou het eerste ssh commando na 10 seconden sluiten, maar gedurende deze tijd zal het tweede ssh commando een verbinding tot stand hebben gebracht met behulp van de tunnel. Als gevolg hiervan houdt het eerste ssh commando de tunnel open totdat aan de volgende twee voorwaarden is voldaan: slaap 10 is klaar en de tunnel wordt niet meer gebruikt.
18
18
18
2012-01-11 11:02:06 +0000

Na het lezen van het bovenstaande en het aan elkaar lijmen van alles, heb ik het volgende Perl script gemaakt (sla het op als mssh in /usr/bin en maak het uitvoerbaar):

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

Gebruik:

Om toegang te krijgen tot HOSTC via HOSTA en HOSTB (dezelfde gebruiker):

mssh HOSTA HOSTB HOSTC

Toegang tot HOSTC via HOSTA en HOSTB en gebruik van niet-standaard SSH-portnummers en verschillende gebruikers:

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

Toegang tot HOSTC via HOSTA en HOSTB en gebruik van X-forwarding:

mssh HOSTA HOSTB HOSTC -X

Toegang tot poort 8080 op HOSTC via HOSTA en HOSTB:

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

Dit antwoord is vergelijkbaar met kynan, aangezien er gebruik wordt gemaakt van ProxyCommand. Maar het is handiger om IMO.

te gebruiken Als je netcat hebt geïnstalleerd in je hopmachines kun je dit snippet toevoegen aan je ~/.ssh/config:

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

dan zal

ssh -D9999 host1+host2 -l username

doen wat je vraagt.

Ik kwam hier op zoek naar de originele plaats waar ik deze truc heb gelezen. Ik zal een link plaatsen als ik hem vind.

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

Ik heb gedaan wat ik denk je wilde doen met

ssh -D 9999 -J host1 host2

Ik word gevraagd voor beide wachtwoorden, dan kan ik localhost:9999 gebruiken voor een SOCKS proxy om te hosten2. Het is het dichtstbijzijnde voorbeeld dat ik kan bedenken dat je in de eerste plaats liet zien.

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

-L 9999:host2:80

Bindt aan localhost:9999 en elk pakket dat naar localhost wordt gestuurd:9999 stuurt het door naar host2:80

-R 9999:localhost:9999

Betekent dat elk pakket dat door host1:9999 wordt ontvangen het terugstuurt naar localhost:9999

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

u moet in staat zijn om gebruik te maken van port forwarding om toegang te krijgen tot een service op host2 van localhost. Een goede gids is hier te vinden . Uittreksel:

Er zijn twee soorten port forwarding: lokale en remote forwarding. Ze worden ook wel respectievelijk uitgaande en inkomende tunnels genoemd. Lokale poort forwarding stuurt het verkeer dat naar een lokale poort komt door naar een bepaalde remote poort.

ssh2 -L 1234:localhost:23 username@host

al het verkeer dat naar poort 1234 op de client komt, wordt doorgestuurd naar poort 23 op de server (host). Merk op dat localhost wordt opgelost door de sshdserver nadat de verbinding tot stand is gebracht. In dit geval verwijst localhost dus naar de server (host) zelf.

Remote port forwarding doet het tegenovergestelde: het stuurt verkeer dat naar een remote poort komt door naar een gespecificeerde lokale poort.

al het verkeer dat naar poort 1234 op de server (host) komt wordt doorgestuurd naar poort 23 op de client (localhost).

In je cast vervang je localhost in het voorbeeld door host2 en host door host1.

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

Mijn antwoord is eigenlijk hetzelfde als alle andere antwoorden hier, maar, ik wilde het nut van ~/.ssh/config en ProxyJump verduidelijken.

Laat ik zeggen dat ik een bestemming in 3 hops moet bereiken, en voor elke hop had ik een specifieke gebruikersnaam, host, poort en identiteit nodig. Vanwege de identiteitscriteria kan dit alleen gedaan worden met het ~/.ssh/config configuratiebestand:

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

Vanaf uw computer kunt u elke sprong individueel testen, d.w.z.

$ 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

. Een ander cool ding van het ~/.ssh/config bestand is dat dit ook sftp bestandsoverdrachten mogelijk maakt, bijv.

$ 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)
1
1
1
2017-03-18 20:13:02 +0000

In dit antwoord zal ik een concreet voorbeeld geven. U hoeft alleen maar de hostnamen, gebruikersnamen en wachtwoorden van computers te vervangen door die van u.

Probleemstelling

Laten we aannemen dat we de volgende netwerktopologie hebben:

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

Voor de concretisering, laten we aannemen dat we de volgende computernamen, gebruikersnamen en wachtwoorden hebben:

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

Doel: we willen een SOCKS proxy opzetten die luistert op poort 9991 van LocalPC zodat elke keer dat een verbinding op LocalPC wordt geïnitieerd vanuit poort 9991 deze via mit.edu dan hec.edu gaat.

Voorbeeld van een use case: hec.edu heeft een HTTP-server die alleen toegankelijk is op http://127.0.0.1:8001 , om veiligheidsredenen. We willen graag http://127.0.0.1:8001 kunnen bezoeken door een webbrowser te openen op LocalPC.

  • *

Configuratie

In LocalPC, voeg in ~/.ssh/config toe:

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

Dan in de terminal van LocalPC, voer:

ssh -D9991 HEC

uit Het vraagt u het wachtwoord van bob op mit.edu (dat wil zeggen, dylan123), dan vraagt het u het wachtwoord van john op hec.edu (d.w.z, doe456).

Op dat moment draait de SOCKS proxy nu op poort 9991 van LocalPC.

Bijvoorbeeld, als u een webpagina op LocalPC wilt bezoeken met behulp van de SOCKS proxy, kunt u in Firefox:

Enkele opmerkingen:

  • in ~/.ssh/config, HEC is de naam van de verbinding: u mag deze wijzigen in alles wat u wilt.
  • De -D9991 vertelt ssh om een SOCKS4 proxy op poort 9991 in te stellen.
0
0
0
2020-02-22 07:13:01 +0000

Alleen dit hielp me op meer dan twee hosts:

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

Het zal u vragen met drie wachtwoorden. Geïnspireerd door dit antwoord

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

In mijn geval deed ik

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

waarbij host2:8890 op een Jupyter Notebook draait.

Toen heb ik Firefox geconfigureerd om localhost:9999 als SOCKS host te gebruiken.

Dus nu heb ik het notebook draaiend op host2 toegankelijk voor Firefox op localhost:8890 op mijn machine.

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

De optie 2 van de beste antwoord kan worden gebruikt met andere ssh-gebruikers dan de huidige 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

De drie opties die in het geaccepteerde antwoord worden genoemd, werkten voor mij helemaal niet. Aangezien ik niet veel toestemming heb over beide hosts, en het lijkt erop dat ons DevOps team vrij strikte regels heeft als het gaat om authenticatie en het doen van MFA. Op de een of andere manier kunnen de bovenstaande commando’s niet goed spelen met onze authenticatie.

De context is echter vergelijkbaar met de antwoorden hierboven: ik kan niet direct naar de productieserver gaan, en moet 1 hop doen met behulp van een jump server.

Nog een andere oplossing - een naïeve

Ik deed het op een zeer naïeve manier: in plaats van te proberen alle commando’s op mijn laptop uit te voeren, voer ik de commando’s ** op elk van de machines** uit, zoals hieronder:

  1. 1. SSH in je jump server, en dan ssh -v -L 6969:localhost:2222 -N your-protected.dest.server. Als je gevraagd wordt om een wachtwoord in te voeren, typ dan
  2. 3. Nu op je laptop, voer ssh -v -L 6969:localhost:6969 -N your-jump-server.host.name uit. Dit zal uw verzoek op poort 6969 van uw laptop doorsturen naar de jump server. Dan om de beurt, aangezien we in onze vorige stap hebben geconfigureerd, zal de jump server opnieuw verzoeken van poort 6969 doorsturen naar poort 2222 op de beveiligde bestemmingsserver.

Je zou daar het commando “hangt” moeten zien na het afdrukken van een of ander bericht - het betekent dat ze werken! Een uitzondering - je zou geen foutmelding moeten zien zoals Could not request local forwarding., als je dat ziet, dan werkt het nog steeds niet :(. Je kunt nu proberen om een verzoek op poort 6969 van je laptop af te vuren, en kijken of het werkt.

Hopelijk kun je dit proberen als je iemand bent die alle bovenstaande methodes heeft gefaald.