Một đường hầm SSH thông qua nhiều bước nhảy


332

Dữ liệu đường hầm qua SSH khá đơn giản:

ssh -D9999 username@example.com

thiết lập cổng 9999 trên localhostđường hầm của bạn example.com, nhưng tôi có một nhu cầu cụ thể hơn:

  • Tôi đang làm việc tại địa phương localhost
  • host1 có thể truy cập để localhost
  • host2 chỉ chấp nhận kết nối từ host1
  • Tôi cần tạo một đường hầm từ localhostđếnhost2

Thực tế, tôi muốn tạo một đường hầm SSH "nhiều bước nhảy". Tôi có thể làm cái này như thế nào? Lý tưởng nhất, tôi muốn làm điều này mà không cần phải là siêu người dùng trên bất kỳ máy nào.


2
Bạn đã sử dụng nó để làm gì? Tôi muốn sử dụng nó cho vớ proxy. Nó sẽ làm việc chứ?
ngạnh

2
Có, bạn sẽ có thể sử dụng kết nối được tạo đường hầm làm proxy SOCKS, trừ khi host2từ chối chuyển tiếp
Mala

Tôi đã suy nghĩ về việc tạo một trình bao bọc qua SSH sẽ thiết lập việc sử dụng nhiều ProxyCommand.
Pavel imerda

@prongs Bạn đã quản lý để sử dụng điều này cho proxy SOCKS (tất cả những năm trước)?
Drux

Câu trả lời:


324

Về cơ bản bạn có ba khả năng:

  1. Đường hầm từ localhostđến host1:

    ssh -L 9999:host2:1234 -N host1
    

    Như đã lưu ý ở trên, kết nối từ host1đến host2sẽ không được bảo mật.

  2. Đường hầm từ localhostđến host1và từ host1đến host2:

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

    Điều này sẽ mở một đường hầm từ localhostđến host1và một đường hầm khác từ host1đến host2. Tuy nhiên các cổng 9999để host2:1234có thể được sử dụng bởi bất cứ ai trên host1. Điều này có thể hoặc không thể là một vấn đề.

  3. Đường hầm từ localhostđến host1và từ localhostđến host2:

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

    Điều này sẽ mở một đường hầm từ localhostđể host1qua đó vào dịch vụ SSH host2có thể được sử dụng. Sau đó, một đường hầm thứ hai được mở từ localhostđến host2qua đường hầm đầu tiên.

Thông thường, tôi muốn đi với tùy chọn 1. Nếu kết nối từ host1để host2cần phải được bảo đảm, đi với tùy chọn 2. Lựa chọn 3 chủ yếu là hữu ích để truy cập một dịch vụ trên host2đó là chỉ có thể truy cập từ host2chính nó.


17
lựa chọn 3 là những gì tôi đang tìm kiếm, cảm ơn!
Mala

1
Tôi muốn làm theo cách này. Cái nào tốt nhất? Tôi đã thử đầu tiên nhưng nó không hoạt động. Tôi đặt proxy vớ trong trình duyệt localhost: 1234 nhưng không gặp may. :( vui lòng giúp đỡ ..
prongs

1
@prongs thử tùy chọn 3
Mala

6
@Noli Nếu bạn sử dụng ssh-agent (mà bạn nên), bạn có thể chuyển tiếp nó thông qua các kết nối bằng -Atùy chọn để ssh.
Mika Fischer

2
@musical_ut - không chính xác, lệnh ssh thứ 2 được đặt nền trên host1, vì vậy nếu bạn muốn kết nối lại cục bộ với nó, bạn chỉ cần chạy lại phần đầu tiên. Nếu bạn thêm -f, nó sẽ ngay lập tức nền cục bộ, do đó ssh -f -L 9999:localhost:9999 host1sẽ kết nối lại nếu bạn nhấn ctrl-c trong trường hợp đầu tiên. Hoặc thêm -fvào lệnh ssh đôi ban đầu khi lần đầu tiên chạy nó để làm nền mọi thứ ngay lập tức.
Mark Fisher

153

Có một câu trả lời tuyệt vời giải thích việc sử dụng ProxyCommandchỉ thị cấu hình cho SSH :

Thêm phần này vào của bạn ~/.ssh/config(xem man 5 ssh_configđể biết chi tiết):

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

Sau đó ssh host2sẽ tự động chuyển qua host1(cũng hoạt động với chuyển tiếp X11, v.v.).

Điều này cũng hoạt động cho toàn bộ lớp máy chủ, ví dụ như được xác định bởi tên miền:

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

Cập nhật

OpenSSH 7.3 giới thiệu một ProxyJumpchỉ thị, đơn giản hóa ví dụ đầu tiên để

Host host2
  ProxyJump host1

3
Có cách nào để làm điều này? Tôi chỉ muốn làm điều này đôi khi. Ngoài ra, điều này đặc biệt dành cho các lệnh, nhưng tôi đang tìm kiếm thứ gì đó cho tất cả cổng 22 (ssh, sftp, v.v.).
Stephane

1
@Stephane bạn có ý gì khi nói riêng về các lệnh ? Cấu hình SSH của bạn được sử dụng bởi mọi thứ bằng cách sử dụng ssh, bao gồm git, sftpvv afaik.
kynan

1
@Stephane Tôi không biết cách kích hoạt điều kiện này một cách có điều kiện (ví dụ: chỉ khi bạn ở ngoài mạng của máy chủ đích). Tôi đặt tùy chọn này cho tất cả các máy chủ được đề cập trong một khối cấu hình và sau đó (bỏ) nhận xét dòng nếu cần. Không hoàn hảo, nhưng nó hoạt động.
kynan

2
@Stephane chắc chắn : ssh -F /path/to/altconfig. Coi chừng điều này sẽ bỏ qua hệ thống rộng /etc/ssh/ssh_config.
kynan

19
Một cách dễ dàng để thực hiện cài đặt "có điều kiện" là xác định hai máy chủ khác nhau trong .ssh / config, có cùng Tên máy chủ. Kết nối với host2-đường hầm khi bạn muốn đường hầm và host2 khi bạn không.
Steve Bennett

25

OpenSSH v7.3 trở đi hỗ trợ một -Jcông tắc và một ProxyJumptùy chọn, cho phép một hoặc nhiều máy chủ nhảy được phân tách bằng dấu phẩy, vì vậy, bạn có thể chỉ cần làm điều này ngay bây giờ:

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

ssh -J user1 @ host1 -YC4c arcfour, blowfish-cbc user2 @ host2 firefox -no-remote Điều này sẽ tăng tốc độ nhận firefox từ host2 sang localhost.
Jaur

21

Chúng tôi có một cổng ssh vào mạng riêng của chúng tôi. Nếu tôi ở bên ngoài và muốn có một vỏ từ xa trên một máy bên trong mạng riêng, tôi sẽ phải ssh vào cổng và từ đó đến máy riêng.

Để tự động hóa thủ tục này, tôi sử dụng tập lệnh sau:

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

Chuyện gì đang xảy ra:

  1. Thiết lập một đường hầm cho giao thức ssh (cổng 22) đến máy riêng.
  2. Chỉ khi điều này thành công, ssh vào máy riêng bằng cách sử dụng đường hầm. (toán tử && đảm bảo điều này).
  3. Sau khi đóng phiên ssh riêng, tôi cũng muốn đường hầm ssh đóng lại. Điều này được thực hiện thông qua thủ thuật "ngủ 10". Thông thường, lệnh ssh đầu tiên sẽ đóng sau 10 giây, nhưng trong thời gian này, lệnh ssh thứ hai sẽ thiết lập kết nối bằng đường hầm. Kết quả là, lệnh ssh đầu tiên giữ cho đường hầm mở cho đến khi hai điều kiện sau được thỏa mãn: ngủ 10 kết thúc và đường hầm không còn được sử dụng.

1
Rất thông minh!!! YÊU NÓ!
Hendy I Girls

18

Sau khi đọc phần trên và dán mọi thứ lại với nhau, tôi đã tạo tập lệnh Perl sau (lưu nó dưới dạng mssh trong / usr / bin và làm cho nó có thể thực thi được):

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

Sử dụng:

Để truy cập HOSTC qua HOSTA và HOSTB (cùng một người dùng):

mssh HOSTA HOSTB HOSTC

Để truy cập HOSTC qua HOSTA và HOSTB và sử dụng các portnumbers không mặc định của SSH và những người dùng khác nhau:

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

Để truy cập HOSTC qua HOSTA và HOSTB và sử dụng chuyển tiếp X:

mssh HOSTA HOSTB HOSTC -X

Để truy cập cổng 8080 trên HOSTC qua HOSTA và HOSTB:

mssh HOSTA HOSTB -L8080:HOSTC:8080

1
điều này thật tuyệt vời
Mala

1
Tôi thực sự không thể cảm ơn bạn đủ, kịch bản này làm cho cuộc sống của tôi dễ dàng hơn trên cơ sở hàng ngày. Điều duy nhất tôi đã thay đổi là thêm int (rand (1000)) vào iport, để cho phép nhiều phiên bản chạy cùng một lúc. Tôi chắc chắn nợ bạn một ly bia.
Mala

Điều này hoạt động thực sự tốt. Một cải tiến nữa sẽ là giải quyết HOSTB, HOSTC, v.v ... bằng cách sử dụng / etc / hosts của localhost và ~ / .ssh / config
Steve Bennett

Ngoài ra tôi thứ hai bình luận của Mala. Nếu không có cổng ngẫu nhiên, nếu sau đó bạn cố gắng mssh HOSTA HOSTDthực sự kết thúc tại HOSTB (và có thể sẽ không nhận ra ..)
Steve Bennett

8

Câu trả lời này tương tự như kynan, vì nó liên quan đến việc sử dụng ProxyCommand. Nhưng nó thuận tiện hơn khi sử dụng IMO.

Nếu bạn đã cài đặt netcat trong các máy hop của mình, bạn có thể thêm đoạn mã này vào ~ / .ssh / config:

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

Sau đó

ssh -D9999 host1+host2 -l username

sẽ làm những gì bạn yêu cầu.

Tôi đến đây để tìm nơi ban đầu mà tôi đọc thủ thuật này. Tôi sẽ đăng một liên kết khi tôi tìm thấy nó.


2
Tôi tin rằng đây là nguồn gốc của mánh khóe: wiki.gentoo.org/wiki/SSH_jump_host
slm

5

Tôi đã làm những gì tôi nghĩ bạn muốn làm với

ssh -D 9999 -J host1 host2

Tôi được nhắc cho cả hai mật khẩu, sau đó tôi có thể sử dụng localhost: 9999 cho proxy SOCKS để lưu trữ2. Đó là lần gần nhất tôi có thể nghĩ đến ví dụ bạn đã chỉ ra ở nơi đầu tiên.


Điều này làm việc hoàn hảo!
Arthur Silva

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

-L 9999: máy chủ2: 80

Có nghĩa là liên kết với localhost: 9999 và bất kỳ gói nào được gửi đến localhost: 9999 chuyển tiếp nó đến host2: 80

-R 9999: localhost: 9999

Có nghĩa là bất kỳ gói tin nào được nhận bởi host1: 9999 chuyển tiếp nó trở lại localhost: 9999


Câu trả lời đơn giản, thú vị nhất để tạo một đường hầm để bạn có thể truy cập ứng dụng trên host2 trực tiếp từ localhost: 9999
dvtoever

Theo câu trả lời này, tôi nhận được một channel 3: open failed: administratively prohibited: open failed thông báo lỗi.
Franck Dernoncourt

2

bạn sẽ có thể sử dụng chuyển tiếp cổng để truy cập dịch vụ host2từ đó localhost. Một hướng dẫn tốt được đặt ở đây . Trích đoạn:

Có hai loại chuyển tiếp cổng: chuyển tiếp cục bộ và chuyển tiếp từ xa. Chúng cũng được gọi là các đường hầm đi và đến, tương ứng. Chuyển tiếp cổng cục bộ chuyển tiếp lưu lượng truy cập đến một cổng cục bộ đến một cổng từ xa được chỉ định.

Ví dụ: nếu bạn ban hành lệnh

ssh2 -L 1234:localhost:23 username@host

tất cả lưu lượng truy cập đến cổng 1234 trên máy khách sẽ được chuyển tiếp đến cổng 23 trên máy chủ (máy chủ). Lưu ý rằng localhost sẽ được giải quyết bởi sshdserver sau khi kết nối được thiết lập. Trong trường hợp này, localhost do đó đề cập đến chính máy chủ (máy chủ).

Chuyển tiếp cổng từ xa làm ngược lại: nó chuyển tiếp lưu lượng truy cập đến một cổng từ xa đến một cổng cục bộ được chỉ định.

Ví dụ: nếu bạn ban hành lệnh

ssh2 -R 1234:localhost:23 username@host

tất cả lưu lượng truy cập đến cổng 1234 trên máy chủ (máy chủ) sẽ được chuyển tiếp đến cổng 23 trên máy khách (localhost).

Trong dàn diễn viên của bạn, thay thế localhosttrong ví dụ bằng host2hostvới host1.


Theo bài báo đó, kết nối sẽ chỉ được bảo mật cho đến khi máy giữa (host1). Có cách nào để đảm bảo toàn bộ sự an toàn?
Mala

Tôi chưa bao giờ thử điều này, nhưng nếu host1 và host2 đều là máy chủ ssh, bạn có thể thiết lập một đường hầm từ host1 đến host2, sau đó thiết lập một đường hầm từ localhost đến host1 cho cùng một dịch vụ (nhận cục bộ và từ xa cổng bên phải). Tôi không biết nếu điều đó có thể trong một lệnh từ localhost.
fideli

1

Trong câu trả lời này tôi sẽ đi qua một ví dụ cụ thể. Bạn chỉ cần thay thế tên máy chủ, tên người dùng và mật khẩu của máy tính.

Báo cáo vấn đề

Giả sử chúng ta có cấu trúc liên kết mạng sau:

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

Để cụ thể hóa, hãy giả sử rằng chúng tôi có tên máy chủ, tên người dùng và mật khẩu của các máy tính sau:

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

Mục tiêu: chúng tôi muốn thiết lập một proxy SOCKS lắng nghe trên cổng 9991của LocalPCđể mỗi lần kết nối trên LocalPCđược bắt đầu từ cổng 9991nó đi qua mit.edurồi hec.edu.

Ví dụ về trường hợp sử dụng: hec.educó một máy chủ HTTP chỉ có thể truy cập vào http://127.0.0.1:8001 , vì lý do bảo mật. Chúng tôi muốn có thể truy cập http://127.0.0.1:8001 bằng cách mở trình duyệt web trên LocalPC.


Cấu hình

Trong LocalPC, thêm vào ~/.ssh/config:

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

Sau đó, trong thiết bị đầu cuối của LocalPC, chạy:

ssh -D9991 HEC

Nó sẽ hỏi bạn mật khẩu của bobon mit.edu(tức là dylan123), sau đó nó sẽ hỏi bạn mật khẩu của johnon hec.edu(tức là doe456).

Tại thời điểm đó, proxy SOCKS hiện đang chạy trên cổng 9991của LocalPC.

Ví dụ: nếu bạn muốn truy cập trang web LocalPCbằng proxy SOCKS, bạn có thể thực hiện trong Firefox:

nhập mô tả hình ảnh ở đây

Một số nhận xét:

  • trong ~/.ssh/config, HEClà tên kết nối: bạn có thể thay đổi nó thành bất cứ điều gì bạn muốn.
  • Các -D9991kể sshđể thiết lập một proxy SOCKS4 trên cổng 9991.

0

Nếu bạn có thể SSH vào cả hai máy, hãy xem chỉ thị ProxyCommand của ssh. Điều này sẽ cho phép bạn đi thẳng từ localhost vào host2 (trong một lệnh dễ dàng nếu bạn sử dụng khóa chung !!). Sau đó, bạn có thể làm bất cứ điều gì bạn muốn với host2.

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


0

Tùy chọn 2 của câu trả lời tốt nhất có thể được sử dụng với những người dùng ssh khác với câu hỏi hiện tại hay còn gọi là: 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

Trong trường hợp của tôi, tôi đã làm

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

nơi host2:8890đang chạy trên Notebook Jupyter.

Sau đó, tôi đã cấu hình Firefox để sử dụng localhost:9999làm máy chủ SOCKS.

Vì vậy, bây giờ tôi đã có máy tính xách tay chạy trên host2Firefox có thể truy cập localhost:8890trên máy của tôi.


0

Ba tùy chọn được đề cập trong câu trả lời được chấp nhận hoàn toàn không phù hợp với tôi. Vì tôi không có nhiều quyền đối với cả hai máy chủ và có vẻ như nhóm DevOps của chúng tôi có các quy tắc khá nghiêm ngặt khi xác thực và đang thực hiện MFA. Bằng cách nào đó các lệnh trên không thể chơi tốt với xác thực của chúng tôi.

Mặc dù bối cảnh thực sự giống với câu trả lời ở trên: Tôi không thể trực tiếp vào máy chủ sản xuất và phải thực hiện 1 bước nhảy bằng máy chủ nhảy.

Yet Another Solution - một điều ngây thơ

Tôi đã kết thúc việc đó bằng một cách rất ngây thơ: thay vì cố gắng chạy tất cả các lệnh trên máy tính xách tay của mình, tôi chạy các lệnh trên mỗi máy , như sau:

  1. SSH vào máy chủ nhảy của bạn, sau đó chạy ssh -v -L 6969:localhost:2222 -N your-protected.dest.server. Nếu bạn được nhắc với bất kỳ mật khẩu đầu vào, hãy nhập nó.
  2. Bây giờ trên máy tính xách tay của bạn, chạy ssh -v -L 6969:localhost:6969 -N your-jump-server.host.name. Điều này sẽ chuyển tiếp bất kỳ yêu cầu nào của bạn trên cổng 6969 trên máy tính xách tay của bạn, đến máy chủ nhảy. Sau đó, lần lượt, vì chúng tôi đã cấu hình ở bước trước, máy chủ nhảy sẽ lại chuyển tiếp các yêu cầu của cổng 6969 sang cổng 2222 trên máy chủ đích được bảo vệ.

Bạn sẽ thấy lệnh "treo" ở đó sau khi in một số tin nhắn - có nghĩa là chúng đang hoạt động! Một ngoại lệ - bạn không nên thấy thông báo lỗi như Could not request local forwarding., nếu bạn thấy vậy, thì nó vẫn không hoạt động :(. Bây giờ bạn có thể thử gửi yêu cầu trên cổng 6969 từ máy tính xách tay của mình và xem nó có hoạt động không.

Hy vọng nếu bạn là người thất bại trong tất cả các phương pháp trên, có lẽ bạn có thể thử điều này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.