여러 홉을 통한 SSH 터널


332

SSH를 통한 데이터 터널링은 매우 간단합니다.

ssh -D9999 username@example.com

localhost에 터널로 포트 9999를 설정 example.com하지만 더 구체적인 요구 사항이 있습니다.

  • 나는 현지에서 일하고 있습니다. localhost
  • host1 ~에 접근 가능하다 localhost
  • host2 연결 만 허용 host1
  • 에서 localhost까지 터널을 만들어야합니다host2

효과적으로, "멀티 홉"SSH 터널을 만들고 싶습니다. 어떻게해야합니까? 이상적으로는 모든 컴퓨터 에서 수퍼 유저가 될 필요 없이이 작업을 수행하고 싶습니다 .


2
무엇을 위해 사용 했습니까? 양말 프록시에 사용하고 싶습니다. 작동합니까?
갈래

2
예, host2전달을 거부 하지 않는 한 터널링 된 연결을 SOCKS 프록시로 사용할 수 있어야합니다.
Mala

ProxyCommand를 여러 번 사용하여 SSH를 통해 래퍼를 만드는 것에 대해 생각하고있었습니다.
Pavel Šimerda

@prongs SOCKS 프록시에이 기능을 사용 했습니까 (몇 년 전)?
Drux

답변:


324

기본적으로 세 가지 가능성이 있습니다.

  1. 에서 터널 localhosthost1:

    ssh -L 9999:host2:1234 -N host1
    

    전술 한 바와 같이, 행 접속 host1에이 host2확보되지 않는다.

  2. 에서 터널 localhost까지 host1와에서 host1까지 host2:

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

    이것은에서 터널 열립니다 localhosthost1와에서 다른 터널 host1로를 host2. 그러나 포트가 9999하기 host2:1234에 누구나 사용할 수 있습니다 host1. 이것은 문제 일 수도 있고 아닐 수도 있습니다.

  3. 에서 터널 localhost까지 host1와에서 localhost까지 host2:

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

    이것은에서 터널을 엽니 다 localhosthost1SSH를 서비스에 어떤 통해 host2사용할 수 있습니다. 그런 다음 첫 번째 터널 localhosthost2통해 두 번째 터널이 열립니다 .

일반적으로, 나는에서 연결하는 경우 옵션 1로 가고 싶어 host1하는 host2요구가 확보되어야에, 2 옵션 3이 서비스에 액세스하는 데 유용하게 옵션으로 이동 host2즉 만 연결할 수 host2자체.


17
옵션 3은 내가 찾고 있던 것이 었습니다. 감사합니다!
Mala

1
이런 식으로 탐색하고 싶습니다. 어느 것이 가장 좋습니까? 첫 번째 시도했지만 작동하지 않았습니다. 브라우저 localhost : 1234에 양말 프록시를 설정했지만 운이 없습니다. :( 도와주세요 ..
갈래

1
@prongs 시도 옵션 3
말라

6
@Noli ssh-agent (필수)를 사용하는 경우 ssh -A옵션을 사용하여 연결을 통해 전달할 수 있습니다 .
Mika Fischer

2
@musically_ut-맞습니다. 두 번째 ssh 명령은 host1에 백그라운드로 있으므로 로컬로 다시 연결하려면 첫 번째 부분 만 다시 실행하면됩니다. 을 추가 -f하면 즉시 로컬로 백그라운드되므로 ssh -f -L 9999:localhost:9999 host1ctrl-c를 누르면 처음에 다시 연결됩니다. 또는 -f처음 실행할 때 원래 double ssh 명령에 추가 하여 모든 것을 즉시 배경으로 지정하십시오.
마크 피셔

153

SSH 에 대한 ProxyCommand구성 지시문 사용을 설명 하는 훌륭한 답변이 있습니다 .

이것에 추가하십시오 ~/.ssh/config(자세한 내용 man 5 ssh_config은 참조) :

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

그런 다음 ssh host2자동으로 터널을 통과합니다 host1(X11 전달 등에서도 작동).

이것은 또한 예를 들어 도메인으로 식별되는 전체 호스트 클래스에서 작동합니다.

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

최신 정보

OpenSSH 7.3ProxyJump지시문을 도입 하여 첫 번째 예를 단순화합니다.

Host host2
  ProxyJump host1

3
조건부로 이것을 수행하는 방법이 있습니까? 나는 때때로 이것을하고 싶다. 또한 이것은 명령에 대한 것이지만 모든 포트 22 (ssh, sftp 등)에 대한 것을 찾고 있습니다.
Stephane

1
@Stephane 명령에 대해 구체적으로 무엇을 의미 합니까? 귀하의 SSH의 설정을 사용하여 아무것도에 의해 사용되는 ssh포함 git, sftpAFAIK 등.
kynan

1
@Stephane 나는 이것을 조건부로 활성화하는 방법을 알지 못합니다 (예 : 대상 호스트의 네트워크 외부에있을 때만). 구성 블록에서 문제가되는 모든 호스트에 대해이 옵션을 설정 한 다음 필요에 따라 행의 주석을 해제하십시오. 완벽하지는 않지만 작동합니다.
kynan

2
@Stephane 확인 : ssh -F /path/to/altconfig. 이것은 시스템 전체를 무시한다는 것을 명심하십시오 /etc/ssh/ssh_config.
kynan

19
설정을 "조건부"로 만드는 쉬운 방법은 .ssh / config에서 동일한 HostName을 갖는 서로 다른 두 개의 호스트를 정의하는 것입니다. 터널을 원할 때는 host2 터널에 연결하고, 원치 않을 때는 host2 터널에 연결하십시오.
스티브 베넷

25

OpenSSH v7.3 이상은 하나 이상의 쉼표로 구분 된 점프 호스트를 허용 하는 -J스위치 및 ProxyJump옵션을 지원 하므로 다음과 같이하면됩니다.

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

ssh -J user1 @ host1 -YC4c arcfour, blowfish-cbc user2 @ host2 firefox -no-remote 파이어 폭스를 host2에서 localhost로 가져 오는 속도를 높입니다.
Jaur

21

개인 네트워크에 하나의 ssh 게이트웨이가 있습니다. 내가 외부에 있고 개인 네트워크 내부의 컴퓨터에서 원격 셸을 원한다면 게이트웨이로, 거기에서 개인 컴퓨터로 ssh해야합니다.

이 절차를 자동화하기 위해 다음 스크립트를 사용합니다.

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

일어나고있는 일 :

  1. ssh 프로토콜 (포트 22)에 대한 터널을 개인용 컴퓨터로 설정하십시오.
  2. 이것이 성공한 경우에만 터널을 사용하여 개인용 컴퓨터로 ssh하십시오. (&& 연산자가이를 보장합니다).
  3. 개인 ssh 세션을 닫은 후 ssh 터널도 닫고 싶습니다. 이것은 "sleep 10"트릭을 통해 수행됩니다. 일반적으로 첫 번째 ssh 명령은 10 초 후에 닫히지 만이 시간 동안 두 번째 ssh 명령은 터널을 사용하여 연결을 설정합니다. 결과적으로 첫 번째 ssh 명령은 다음 두 가지 조건이 충족 될 때까지 터널을 열린 상태로 유지합니다. 절전 10이 완료되고 터널이 더 이상 사용되지 않습니다.

1
매우 영리한!!! 그것을 사랑하십시오!
Hendy Irawan

18

위의 내용을 읽고 모든 것을 결합한 후 다음 Perl 스크립트를 작성했습니다 (/ usr / bin에 mssh로 저장하고 실행 가능하게 함).

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

용법:

HOSTA 및 HOSTB (동일한 사용자)를 통해 HOSTC에 액세스하려면 다음을 수행하십시오.

mssh HOSTA HOSTB HOSTC

HOSTA 및 HOSTB를 통해 HOSTC에 액세스하고 기본이 아닌 SSH 포트 번호 및 다른 사용자를 사용하려면 다음을 수행하십시오.

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

HOSTA 및 HOSTB를 통해 HOSTC에 액세스하고 X 전달을 사용하려면 다음을 수행하십시오.

mssh HOSTA HOSTB HOSTC -X

HOSTA 및 HOSTB를 통해 HOSTC의 포트 8080에 액세스하려면 다음을 수행하십시오.

mssh HOSTA HOSTB -L8080:HOSTC:8080

1
이것은 굉장하다
Mala

1
진심으로 감사하지 않습니다.이 스크립트는 일상 생활을 더 편하게 만들어줍니다. 내가 변경 한 유일한 것은 여러 인스턴스를 동시에 실행할 수 있도록 int (rand (1000))를 iport에 추가하는 것입니다. 나는 확실히 당신에게 맥주를 빚지고있다.
Mala

이것은 정말 잘 작동합니다. 또 개선은 로컬 호스트의 / etc / 호스트와 ~ / 스푸핑 / 설정하여 호스트 B, HOSTC 등을 해결하는 것입니다
스티브 베넷

또한 두 번째 Mala의 의견입니다. 당신이 다음에 시도 할 경우 무작위 포트없이, mssh HOSTA HOSTD실제로 호스트 B에 끝날 것이다 당신 (그리고 아마도 실현되지 않습니다 ..)
스티브 베넷

8

이 답변은 ProxyCommand를 사용하므로 kynan과 유사합니다. 그러나 IMO를 사용하는 것이 더 편리합니다.

홉 머신에 netcat을 설치 한 경우이 스 니펫을 ~ / .ssh / config에 추가 할 수 있습니다.

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

그때

ssh -D9999 host1+host2 -l username

당신이 요청한 것을 할 것입니다.

이 트릭을 읽은 원래 장소를 찾아 여기에 왔습니다. 링크를 찾으면 게시하겠습니다.


2
나는 이것이 트릭의 기원이라고 믿는다 : wiki.gentoo.org/wiki/SSH_jump_host
slm

5

내가 무엇을했다 생각 당신이하고 싶어

ssh -D 9999 -J host1 host2

두 암호를 입력하라는 메시지가 표시되면 SOCKS 프록시에 localhost : 9999를 사용하여 host2에 사용할 수 있습니다. 처음에 보여준 예에 가장 가깝습니다.


이것은 완벽하게 작동했습니다!
Arthur Silva

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

-L 9999 : 호스트 2:80

localhost : 9999에 바인딩되고 localhost : 9999에 전송 된 모든 패킷이 host2 : 80으로 전달됨을 의미합니다.

-R 9999 : 로컬 호스트 : 9999

host1 : 9999에 의해 수신 된 모든 패킷이 localhost : 9999로 다시 전달됨을 의미합니다.


localhost : 9999에서 직접 host2의 응용 프로그램에 액세스 할 수 있도록 터널을 만드는
훌륭하고

이 답변에 따라 channel 3: open failed: administratively prohibited: open failed 오류 메시지가 나타납니다.
Franck Dernoncourt

2

당신은 서비스에 액세스하기 위해 포트 포워딩을 사용할 수 있어야 host2에서 localhost. 좋은 가이드는 여기있습니다 . 발췌 :

포트 전달에는 로컬 및 원격 전달의 두 가지 종류가 있습니다. 또한 나가는 터널과 들어오는 터널이라고도합니다. 로컬 포트 ​​전달은 로컬 포트로 들어오는 트래픽을 지정된 원격 포트로 전달합니다.

예를 들어, 명령을 실행하면

ssh2 -L 1234:localhost:23 username@host

클라이언트의 포트 1234로 들어오는 모든 트래픽은 서버 (호스트)의 포트 23으로 전달됩니다. localhost는 연결이 설정된 후 sshdserver에 의해 해결됩니다. 이 경우 localhost는 서버 (호스트) 자체를 나타냅니다.

원격 포트 전달은 반대입니다. 원격 포트로 들어오는 트래픽을 지정된 로컬 포트로 전달합니다.

예를 들어, 명령을 실행하면

ssh2 -R 1234:localhost:23 username@host

서버 (호스트)의 포트 1234로 들어오는 모든 트래픽은 클라이언트 (localhost)의 포트 23으로 전달됩니다.

캐스트에서 교체 localhost와 예에서 host2hosthost1.


이 기사에 따르면 연결은 중간 시스템 (host1)까지만 보호됩니다. 모든 것이 안전하게 유지되도록하는 방법이 있습니까?
Mala

나는 이것을 시도한 적이 없지만 host1과 host2가 모두 ssh 서버 인 경우 host1에서 host2로 터널을 설정 한 다음 동일한 서비스에 대해 localhost에서 host1로 터널을 설정할 수 있습니다 (로컬 및 원격 가져 오기) 포트 오른쪽). localhost의 한 명령으로 가능한지 모르겠습니다.
fideli

1

이 답변에서는 구체적인 예를 살펴 보겠습니다. 당신은 당신의 컴퓨터 호스트 이름, 사용자 이름 및 암호를 교체해야합니다.

문제 설명

다음과 같은 네트워크 토폴로지가 있다고 가정 해 봅시다.

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

구체적으로하기 위해 다음과 같은 컴퓨터의 호스트 이름, 사용자 이름 및 암호가 있다고 가정합니다.

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

목표 : 우리가 포트에서 수신 SOCKS 프록시 설정할 9991의를 LocalPC마다에 연결하도록 LocalPC시작 포트에서 9991그것을 통과 mit.eduhec.edu.

사용 사례의 예 : 보안상의 이유로 http://127.0.0.1:8001hec.edu 에만 액세스 할 수있는 HTTP 서버가 있습니다 . 에서 웹 브라우저를 열어 http://127.0.0.1:8001 을 방문하고 싶습니다 .LocalPC


구성

LocalPC에 추가 ~/.ssh/config:

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

그런 다음의 터미널에서 다음을 LocalPC실행하십시오.

ssh -D9991 HEC

그것은 당신의 암호를 묻습니다 bob에서을 mit.edu(즉, dylan123), 그것은 당신의 암호를 묻습니다 johnhec.edu(즉, doe456).

이 시점에서 SOCKS 프록시는 현재 포트 9991에서 실행 중 LocalPC입니다.

예를 들어, LocalPCSOCKS 프록시 사용에 대한 웹 페이지를 방문하려는 경우 Firefox에서 수행 할 수 있습니다.

여기에 이미지 설명을 입력하십시오

일부 비고 :

  • ~/.ssh/config, HEC연결 이름 : 당신은 당신이 원하는 무엇이든 그것을 변경할 수 있습니다.
  • -D9991ssh포트에서 SOCKS4 프록시를 설정합니다 9991.

0

두 시스템에 SSH를 연결할 수 있으면 ssh의 ProxyCommand 지시문을 살펴보십시오. 이를 통해 localhost에서 host2로 바로 이동할 수 있습니다 (공개 키를 사용하는 경우 하나의 쉬운 명령으로 !!). 그런 다음 host2로 원하는 것을 할 수 있습니다.

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


0

최상의 답변 의 옵션 2 는 현재의 일명과 다른 ssh 사용자와 함께 사용할 수 있습니다 : 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

내 경우에는

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

어디 host2:8890Jupyter 노트북에서 실행되고 있습니다.

그런 다음 localhost:9999SOCKS 호스트 로 사용하도록 Firefox를 구성했습니다 .

이제 내 컴퓨터의 host2Firefox에서 노트북에 액세스 할 수 있습니다 localhost:8890.


0

허용 된 답변에 언급 된 세 가지 옵션이 전혀 효과가 없었습니다. 두 호스트 모두에 대해 많은 권한이 없으므로 DevOps 팀이 인증과 관련하여 MFA를 수행 할 때 매우 엄격한 규칙을 가지고있는 것처럼 보입니다. 어쨌든 위의 명령은 인증과 잘 어울리지 않습니다.

컨텍스트는 위의 답변과 실제로 비슷합니다. 프로덕션 서버에 직접 ssh 할 수 없으며 점프 서버를 사용하여 1 홉을 수행해야합니다.

또 다른 해결책-순진한 해결책

나는 매우 순진한 방법으로 그것을 끝내 었습니다. 노트북에서 모든 명령을 실행하려고하는 대신 다음과 같이 각 컴퓨터 에서 명령 실행합니다 .

  1. 점프 서버에 SSH를 연결 한 다음를 실행하십시오 ssh -v -L 6969:localhost:2222 -N your-protected.dest.server. 비밀번호를 입력하라는 메시지가 표시되면 입력하십시오.
  2. 이제 랩톱에서을 실행하십시오 ssh -v -L 6969:localhost:6969 -N your-jump-server.host.name. 그러면 랩톱의 포트 6969에 대한 요청이 점프 서버로 전달됩니다. 그런 다음 이전 단계에서 구성 했으므로 점프 서버는 다시 포트 6969의 요청을 보호 대상 서버의 포트 2222로 전달합니다.

메시지를 인쇄 한 후 "hangs"명령이 표시됩니다. 작동한다는 의미입니다. 한 가지 예외-와 같은 오류 메시지가 표시되지 않아야합니다 Could not request local forwarding..이 경우 여전히 작동하지 않습니다. (. 이제 랩톱에서 포트 6969에서 요청을 실행하고 작동하는지 확인할 수 있습니다.

위의 모든 방법을 실패한 사람이라면 이것을 시도해 볼 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.