Birden çok atlama aracılığıyla bir SSH tüneli


332

SSH üzerinden tünel oluşturma işlemi oldukça kolay:

ssh -D9999 username@example.com

localhosttüneli olarak 9999 numaralı bağlantı noktasını bir tünel olarak kurar example.com, ancak daha özel bir ihtiyacım var:

  • Üzerinde yerel olarak çalışıyorum localhost
  • host1 için erişilebilir localhost
  • host2 sadece gelen bağlantıları kabul eder host1
  • Ben bir tünel oluşturmak için gereken localhostetmekhost2

Etkili bir şekilde "çok sekmeli" SSH tüneli oluşturmak istiyorum. Bunu nasıl yapabilirim? İdeal olarak, herhangi bir makinede süper kullanıcı olmaya gerek kalmadan bunu yapmak istiyorum .


2
Ne için kullandın? Çorap vekili için kullanmak istiyorum. İşe yarayacak mı?
Çatalak

2
Evet, tüneli bağlamayı SOCKS proxy'si olarak kullanabilmelisiniz, aksi halde host2reddetmedikçe
Mala

ProxyCommand'ın çoklu kullanımını kullanarak ayarlayabilecek SSH üzerinde bir sarıcı oluşturmayı düşünüyordum.
Pavel Šimerda

@prongs Bunu, SOCKS vekili için (hepsi yıllar önce) kullanmayı başardınız mı?
Drux

Yanıtlar:


324

Temel olarak üç seçeneğiniz var:

  1. Tünel localhostiçin host1:

    ssh -L 9999:host2:1234 -N host1
    

    Yukarıda belirtildiği gibi, gelen bağlantı host1için host2güvenli olmayacaktır.

  2. Tünel localhostiçin host1ve gelen host1için host2:

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

    Bu bir tünel açılacak localhostiçin host1ve başka bir tünel host1için host2. Ancak liman 9999için host2:1234herkes tarafından kullanılabilir host1. Bu bir problem olabilir veya olmayabilir.

  3. Tünel localhostiçin host1ve gelen localhostiçin host2:

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

    Bu bir tünel açılacak localhostiçin host1SSH hizmetini içinden host2kullanılabilir. Daha sonra, bir ikinci tünel açıldığında localhostiçin host2birinci tünel üzerinden.

Normalde, gelen bağlantı varsa seçeneği 1. ile gitmek istiyorum host1için host2ihtiyaçları tespit edilecek şekilde üzerine, 2. Seçenek 3 bir hizmete erişmek için esas yararlıdır seçeneği ile gitmek host2o sadece ulaşılabilir host2kendisi.


17
seçenek 3 aradığım şeydi, teşekkürler!
Mala

1
Bu şekilde tarama yapmak istiyorum. Hangisi en iyisi? Birincisini denedim ama işe yaramadı. Tarayıcımın yerel bilgisayarına çorap vekili ayarladım: 1234 ama şanssız. :( yardım lütfen ..
tırnaklar

1
@prongs seçenek 3'ü deneyin
Mala

6
@Noli Eğer ssh-agent kullanıyorsanız (kullanmanız gereken), -Assh seçeneğini kullanarak bağlantılardan geçirebilirsiniz .
Mika Fischer

2
@ musically_ut - bu doğru, 2. ssh komutu host1'de arka plana göre yazılmıştır, bu nedenle yerel olarak yeniden bağlanmak istiyorsanız, sadece ilk kısmı tekrar başlatmanız gerekir. Eğer eklerseniz -f, hemen plan lokal, böylece edecek ssh -f -L 9999:localhost:9999 host1ilk durumda ctrl-c basıldığında eğer yeniden bağlanır. Veya -fhemen her şeyi arka plana ilk kez çalıştırdığınızda orijinal double ssh komutuna ekleyin .
Mark Fisher

153

Bir yoktur kullanımını açıklayan mükemmel cevap ProxyCommandSSH için yapılandırma yönergesi :

Bunu kendinize ekleyin ~/.ssh/config( man 5 ssh_configayrıntılar için bakınız):

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

Ardından ssh host2otomatik olarak tünel açılacaktır host1(X11 iletme vb. İle de çalışır).

Bu aynı zamanda örneğin etki alanı tarafından tanımlanan bir ana bilgisayar sınıfı için de geçerlidir:

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

Güncelleme

OpenSSH 7.3ProxyJump ilk örneği basitleştiren bir yönerge sunar.

Host host2
  ProxyJump host1

3
Bunu şartlı yapmanın bir yolu var mı? Bunu sadece bazen yapmak istiyorum. Ayrıca, bu özellikle komutlar içindir, ancak 22 numaralı bağlantı noktasının (ssh, sftp, vb.) İçin bir şey arıyorum.
Stephane

1
@Stephane özellikle komutlar için neyi kastediyorsunuz ? SSH yapılandırmanız afaik , vb. sshDahil olmak üzere herhangi bir şey tarafından kullanılır . gitsftp
kynan

1
@Stephane Bunu şartlı sağlamanın bir yolunun farkında değilim (örneğin, yalnızca hedef ana bilgisayarın ağı dışındayken). Bu seçeneği, söz konusu tüm ana bilgisayarlar için bir yapılandırma bloğunda belirledim ve ardından (un) satırı gerektiği gibi yorumladım. Mükemmel değil, ama işe yarıyor.
kynan

2
Emin @Stephane: ssh -F /path/to/altconfig. Bunun sistemi tamamen görmezden geleceğine dikkat edin /etc/ssh/ssh_config.
kynan

19
Ayarları "koşullu" yapmanın kolay bir yolu, aynı HostName değerine sahip olan .ssh / config içinde iki farklı ana bilgisayar tanımlamaktır. Tüneli istediğiniz zaman host2-tüneline, istemediğinizde host2'ye bağlanın.
Steve Bennett

25

OpenSSH v7.3 , bir ya da daha fazla virgülle ayrılmış atlama ana bilgisayarına izin veren bir -Janahtarı ve bir ProxyJumpseçeneği desteklemektedir ;

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

ssh -J user1 @ host1 -YC4c arcfour, blowfish-cbc user2 @ host2 firefox -no-remote Bu hostfox'tan localhost'a firefox almayı hızlandıracak.
Jaur,

21

Özel ağımıza bir ssh ağ geçidimiz var. Dışarıda olsam ve özel ağ içindeki bir makinede uzak bir kabuk istiyorsam, ağ geçidine ve oradan özel makineye ssh gerekir.

Bu yordamı otomatikleştirmek için aşağıdaki komut dosyasını kullanıyorum:

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

Ne oluyor:

  1. Özel makineye ssh protokolü (22 numaralı bağlantı noktası) için bir tünel oluşturun.
  2. Ancak bu başarılı olursa, tüneli kullanarak özel makineye ssh. (&& operatörü bunu sağlar).
  3. Özel ssh oturumunu kapattıktan sonra, ssh tünelinin de kapanmasını istiyorum. Bu "uyku 10" numarasıyla yapılır. Genellikle, ilk ssh komutu 10 saniye sonra kapanır, ancak bu sırada ikinci ssh komutu tüneli kullanarak bir bağlantı kurar. Sonuç olarak, ilk ssh komutu aşağıdaki iki koşul yerine getirilinceye kadar tüneli açık tutar: uyku 10 bitmiştir ve tünel artık kullanılmamaktadır.

1
Çok zeki!!! SEVDİM!
Hendy Irawan

18

Yukarıdakileri okuduktan ve her şeyi bir arada yapıştırdıktan sonra, aşağıdaki Perl betiğini yarattım (/ usr / bin içine mssh olarak kaydedin ve çalıştırılabilir hale getirin):

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

Kullanımı:

HOSTC'ye HOSTA ve HOSTB üzerinden erişmek için (aynı kullanıcı):

mssh HOSTA HOSTB HOSTC

HOSTC'ye HOSTA ve HOSTB üzerinden erişmek ve varsayılan olmayan SSH portnumbers ve farklı kullanıcıları kullanmak için:

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

HOSTC'ye HOSTA ve HOSTB üzerinden erişmek ve X iletmeyi kullanmak için:

mssh HOSTA HOSTB HOSTC -X

HOSTC üzerindeki HOSTC ve HOSTB üzerinden 8080 numaralı bağlantı noktasına erişmek için:

mssh HOSTA HOSTB -L8080:HOSTC:8080

1
bu harika
Mala

1
Cidden yeterince teşekkür edemem, bu senaryo günlük hayatımı kolaylaştırıyor. Değiştirdiğim tek şey, aynı anda birden fazla örneğin çalışmasına izin vermek için, int'e (rand (1000)) eklemek. Sana kesinlikle bir bira borcum var.
Mala

Bu gerçekten iyi çalışıyor. Bir başka gelişme localhost / etc / host ve ~ / .ssh / config kullanılarak HostB, HOSTC vb çözmek olacak
Steve Bennett

Ayrıca Mala'nın yorumunu da ikincisiyim. Randomize port olmadan, o zaman denemeye çalışırsanız, mssh HOSTA HOSTDaslında HOSTB'ye (ve belki de fark etmeyeceksiniz ..)
Steve Bennett

8

Bu cevap, ProxyCommand kullanımını da içerdiği için kynan'a benzer. Ancak IMO'yu kullanmak daha uygun olur.

Eğer hop makinelerinizde netcat kurulu ise bu pasajı ~ / .ssh / config dosyasına ekleyebilirsiniz:

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

Sonra

ssh -D9999 host1+host2 -l username

ne istersen onu yapacağım.

Bu numarayı okuduğum orijinal yeri aramaya geldim. Bulduğumda bir link göndereceğim.


2
Bunun hilenin
slm

5

Yapmak istediğini düşündüğüm şeyi yaptım

ssh -D 9999 -J host1 host2

Her iki parola da istenir, o zaman localhost: 9999'u SOCKS proxy'si için host2'ye kullanabilirim. İlk başta gösterdiğin örneğe aklıma gelen en yakın şey.


Bu mükemmel çalıştı!
Arthur Silva

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

-L 9999: ana bilgisayar2: 80

Localhost'a bağlanan araçlar: 9999 ve localhost'a gönderilen herhangi bir paket: 9999 onu host2: 80'e iletir

-R 9999: yerel ana bilgisayar: 9999

Host1: 9999 tarafından alınan herhangi bir paketi, localhost: 9999'a geri götürmek anlamına gelir.


Bir tünel yapmak için mükemmel, en basit cevap böylece
host2'deki

Bu cevabın ardından bir channel 3: open failed: administratively prohibited: open failed hata mesajı alıyorum.
Franck Dernoncourt

2

Bir hizmeti üzerinde erişmek için bağlantı noktası iletme kullanmak gerekir host2dan localhost. İyi bir rehber burada bulunur . Alıntı:

İki tür port yönlendirme vardır: yerel ve uzaktan yönlendirme. Bunlara sırasıyla giden ve gelen tüneller de denir. Yerel bağlantı noktası iletme, yerel bir bağlantı noktasına gelen trafiği belirtilen bir uzak bağlantı noktasına iletir.

Örneğin, komutu verirseniz

ssh2 -L 1234:localhost:23 username@host

İstemcide 1234 numaralı bağlantı noktasına gelen tüm trafik, sunucudaki (ana bilgisayar) 23 numaralı bağlantı noktasına yönlendirilir. Localhost'un bağlantı kurulduktan sonra sshdserver tarafından çözüleceğini unutmayın. Bu durumda localhost bu nedenle sunucunun (ana bilgisayarın) kendisine atıfta bulunur.

Uzak bağlantı noktası iletme bunun tersini yapar: uzak bir bağlantı noktasına gelen trafiği belirtilen bir yerel bağlantı noktasına iletir.

Örneğin, komutu verirseniz

ssh2 -R 1234:localhost:23 username@host

Sunucu (ana bilgisayar) üzerindeki 1234 numaralı bağlantı noktasına gelen tüm trafik, istemcideki (yerel ana bilgisayar) 23 numaralı bağlantı noktasına iletilir.

Oyuncularınızda, localhostörnekte host2ve hostile değiştirin host1.


bu maddeye göre, bağlantı sadece ortadaki makineye kadar güvence altına alınacaktır (host1). Her şeyin güvenli olduğundan emin olmanın bir yolu var mı?
Mala

Bunu hiç denemedim, ancak host1 ve host2'nin her ikisi de ssh sunucusuysa, aynı hizmet için host1'den host2'ye bir tünel kurabilir ve aynı hizmet için localhost'tan host1'e bir tünel kurabilirsiniz (yerel ve uzaktan limanlar sağ). Localhost'tan bir komutta bunun mümkün olup olmadığını bilmiyorum.
fideli

1

Bu cevapta somut bir örnek üzerinden gideceğim. Yalnızca bilgisayarların ana bilgisayar adlarını, kullanıcı adlarını ve şifrelerini kendiniz girmeniz gerekir.

Sorun bildirimi

Aşağıdaki ağ topolojisine sahip olduğumuzu varsayalım:

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

Somutluk uğruna, aşağıdaki bilgisayarların ana bilgisayar adlarına, kullanıcı adlarına ve şifrelerine sahip olduğumuzu varsayalım:

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

Hedef: Biz bağlantı noktasını dinleyen bir SOCKS proxy kurmak istiyorum 9991ait LocalPCher seferinde bir bağlantı olacak şekilde LocalPCbaşlatılır limanından 9991o geçer mit.edusonra hec.edu.

Kullanım örneği: Güvenlik nedeniyle hec.edu, yalnızca http://127.0.0.1:8001 tarihinde erişilebilen bir HTTP sunucusuna sahiptir . Bir web tarayıcısını açarak http: //127.0.0.1.18001 tarihinde ziyaret edebilmek istiyoruz LocalPC.


Yapılandırma

İçinde LocalPC, ekle ~/.ssh/config:

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

Sonra terminalinde LocalPCçalıştırın:

ssh -D9991 HEC

Size bobon mit.edu(yani dylan123) şifresini soracak, sonra size johnon hec.edu( doe456) şifresini isteyecektir .

Bu noktada, SOCKS proxy şimdi noktası üzerinde çalıştığı 9991ait LocalPC.

Örneğin LocalPC, SOCKS proxy'sini kullanma hakkında bir web sayfasını ziyaret etmek istiyorsanız, Firefox'ta yapabilirsiniz:

görüntü tanımını buraya girin

Bazı açıklamalar:

  • içinde ~/.ssh/config, HECbağlantı adıdır: Eğer istediğiniz her şey için değişebilir.
  • Bağlantı noktasında bir SOCKS4 proxy kurmayı -D9991söyler .ssh9991

0

Her iki makineye de SSH ekleyebiliyorsanız, ssh'ın ProxyCommand yönergesine bakınız. Bu, doğrudan localhost'tan host2'ye gitmenize izin verecektir (eğer açık anahtarlar kullanıyorsanız, kolay bir komutla !!). O zaman host2 ile ne istersen yapabilirsin.

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


0

En iyi cevabın 2 seçeneği , şu anki aka olan farklı ssh kullanıcıları ile kullanılabilir: 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

Benim durumumda yaptım

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

nerede host2:8890bir Jupyter Notebook çalışıyor.

Sonra Firefox'u localhost:9999SOCKS sunucusu olarak kullanacak şekilde yapılandırdım .

Şimdi dizüstü bilgisayarımda host2Firefox tarafından erişilebilir durumda çalışıyor localhost:8890.


0

Kabul edilen cevapta belirtilen üç seçenek benim için hiç işe yaramadı. Her iki ana bilgisayarda da fazla izne sahip olmadığımdan ve DevOps ekibimizin kimlik doğrulaması ve MFA yaparken oldukça katı kurallara sahip oldukları için. Her nasılsa yukarıdaki komutlar bizim kimlik doğrulama işlemimizle iyi oynayamıyor.

Bağlam yukarıdaki cevaplara gerçekten benziyor: Doğrudan üretim sunucusuna ssh yapamıyorum ve bir atlama sunucusu kullanarak 1 atlama yapmak zorundayım.

Yine Başka Bir Çözüm - saf

Sonunda saf bir yolla bitirdim: dizüstü bilgisayarımdaki tüm komutları çalıştırmaya çalışmak yerine, komutları her makinede aşağıdaki gibi çalıştırıyorum:

  1. SSH’yi atlama sunucunuza ekleyin, sonra çalıştırın ssh -v -L 6969:localhost:2222 -N your-protected.dest.server. Parola girmeniz istenirse, yazın.
  2. Şimdi dizüstü bilgisayarınızda, çalıştırın ssh -v -L 6969:localhost:6969 -N your-jump-server.host.name. Bu, dizüstü bilgisayarınızda 6969 numaralı bağlantı noktasındaki isteğinizden herhangi birini atlama sunucusuna iletecektir. Ardından, sırayla, önceki adımımızda yapılandırdığımızdan, atlama sunucusu tekrar korumalı hedef sunucuda 6969 numaralı bağlantı noktasının taleplerini 2222 numaralı bağlantı noktasına iletir.

Bir mesaj bastıktan sonra orada "takılma" komutunu görmelisiniz - demek ki çalışıyorlar! Bir istisna - böyle bir hata mesajı görmemeniz gerekir Could not request local forwarding., eğer görürseniz, o zaman hala çalışmıyor :(. Artık dizüstü bilgisayarınızdan 6969 numaralı bağlantı noktasından istek göndermeyi deneyebilir ve çalışıp çalışmadığını görebilirsiniz.

Umarım, yukarıdaki tüm yöntemleri yerine getirmeyen biriyseniz, belki bunu deneyebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.