여러 홉을 통한 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. 에서 터널 localhost에 host1:

    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
    

    이것은에서 터널 열립니다 localhost로 host1와에서 다른 터널 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
    

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

일반적으로, 나는에서 연결하는 경우 옵션 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.3 은 ProxyJump지시문을 도입 하여 첫 번째 예를 단순화합니다.

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와 예에서 host2와 host와 host1.


이 기사에 따르면 연결은 중간 시스템 (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.edu후 hec.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), 그것은 당신의 암호를 묻습니다 john에 hec.edu(즉, doe456).

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

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

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

일부 비고 :

  • 에 ~/.ssh/config, HEC연결 이름 : 당신은 당신이 원하는 무엇이든 그것을 변경할 수 있습니다.
  • 는 -D9991알 ssh포트에서 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.