두 개의 SSH 포트포워드 연결

두 개의 SSH 포트포워드 연결

여기 슈퍼유저에서 답변을 찾아봤지만 내 사용 사례에 대한 답변을 찾지 못했습니다.

터널을 통해 터널링할 수 있도록 사용하는 두 가지 명령을 연결하고 싶습니다.

ssh -L 22:hostB:22 user@hostA

그리고

ssh -L 10002:localhost:10001 user@localhost

지금 내가 하는 일은 첫 번째 명령을 입력하고 다른 터미널을 열고 두 번째 명령을 입력하는 것입니다. 내가 뭔가를하면

ssh … && ssh …

두 번째 명령은 첫 번째 연결을 "종료"한 후에만 실행됩니다.

Jumphost와 같은 고급 SSH 옵션은 HostA의 서버 구성으로 인해 작동하지 않으므로 이것이 이와 같이 10001 포트에 액세스할 수 있는 유일한 옵션이라고 확신합니다.

두 명령을 하나의 별칭으로 묶는 방법이 있나요? 아니면 시간 제한 등이 있는 간단한 bash 스크립트를 사용할 수 있나요?

답변1

나는 당신이 단지 ssh -L 10002:hostB:10001 user@hostA때문에 할 수 없다고 가정합니다

  • B의 수신 대기가 10001로컬 인터페이스에만 바인딩되거나,
  • 또는 B의 방화벽이 hostB:10001A로부터의 연결을 허용하지 않습니다.
  • 또는 무엇이든.

ssh … && ssh …

두 번째 명령은 첫 번째 연결을 "종료"한 후에만 실행됩니다.

예, 이는 정상입니다. 이전 부분은 &&다음 명령이 실행되기 전에 종료되고 종료 상태를 반환해야 합니다(또는 상태에 따라 실행되지 않음).

두 번째는 거의 즉시 실행되지만 ssh결함이 있습니다.

( ssh ... & ) && ssh ...

ssh첫 번째가 두 번째에 영향을 미치지 않기 때문에 결함이 있습니다 . 두 번째 것은 아마도 첫 번째 것이 터널을 구축하기 전에 실행될 것입니다. 비밀번호를 묻는 것도 문제가 될 수 있습니다.

이 사용 사례에는 옵션이 ssh있습니다 -f. 에서man 1 ssh:

-f
ssh명령 실행 직전에 백그라운드로 이동하도록 요청합니다 . […]

따라서 기본 명령은 다음과 같습니다.

ssh -fNL 22:hostB:22 user@hostA && ssh -NL 10002:localhost:10001 user@localhost

-N두 번째와 함께 사용할지 여부는 귀하에게 달려 있습니다 ssh. 이제 트릭은 ssh암호를 요청한 후(해당하는 경우) 첫 번째 터널을 설정한 후 백그라운드로 첫 번째 포크를 수행하므로 일시적으로 두 개의 "첫 번째" ssh프로세스가 있습니다. 배경에 있는 사람이 터널을 처리하기 시작합니다. 전경에 있는 것이 종료되면 &&작동할 수 있습니다.

당신은 아마 원할 것입니다 -o ExitOnForwardFailure=yes. 첫 번째 터널을 설정할 수 없으면 첫 번째 터널이 ssh성공적으로 종료되지 않고 두 번째 터널이 실행되지 않습니다. 향상된 명령은 다음과 같습니다.

ssh -fNL 22:hostB:22 \
    -o ExitOnForwardFailure=yes \
    user@hostA &&
ssh -NL 10002:localhost:10001 user@localhost

두 번째 ssh종료 시 첫 번째(백그라운드)가 남아 있다는 점에 유의하세요. 장점은 나중에 단독 2초를 실행할 수 있다는 것입니다 ssh. 단점은 첫 번째 항목을 유지하지 않으려면 수동으로 종료해야 한다는 것입니다. 이를 염두에 두고 다음 접근 방식을 고려하십시오.

ssh -fNL 22:hostB:22 \
    -o ExitOnForwardFailure=yes \
    user@hostA
ssh -NL 10002:localhost:10001 user@localhost

가 없습니다 &&. 이제 이전 첫 번째 항목이 ssh아직 실행 중인 경우 새 항목은 포트에 바인딩할 수 없기 때문에 실패하게 됩니다. 두 번째는 ssh관계없이 실행되며 첫 번째 터널을 사용하며 터널이 얼마나 오래되었는지는 중요하지 않습니다.

어떤 이유로 든 오래된 것이 없고 ssh첫 번째가 실패하는 일이 발생할 수 있습니다. ssh그렇다면 두 번째 것이 실행되고 포트에서 수신 대기 중인 항목이 없기 때문에 아마도 실패할 것입니다(연결이 거부됨) 22.

여전히 "유휴" 프로세스를 종료하고 싶지 않을 수도 있고 , 두 번째 종료 ssh후 자동으로 종료하기를 원할 수도 있습니다 . ssh분명히 killall ssh부수적인 피해를 입힐 수도 있습니다. 좀 더 미묘한 것을 찾아 보겠습니다.

-M
ssh연결 공유를 위해 클라이언트를 "마스터" 모드로 전환합니다 . […]

[…]

-O ctl_cmd
활성 연결 다중화 마스터 프로세스를 제어합니다. […]

[…]

-S ctl_path
연결 공유를 위한 제어 소켓의 위치를 ​​지정합니다. [...]

#!/bin/sh

socket=/tmp/hostA.socket

ssh -fNL 22:hostB:22 \
    -o ExitOnForwardFailure=yes \
    -MS "$socket"
    user@hostA &&
{
ssh -NL 10002:localhost:10001 user@localhost
ssh -S "$socket" -O exit dummy
}

두 번째가 ssh종료된 후 세 번째는 첫 번째에게 종료하라고 지시합니다. 세 번째 명령에서 ssh중요한 것은 호스트 이름이 아니라 소켓입니다. 여전히 호스트 이름을 제공해야 하므로 dummy. 첫 번째는 ssh종료하기 전에 소켓을 제거하므로 쓰레기가 남아 있지 않아야 합니다.

여전히 우려할 점은 거의 없습니다.

  • 스크립트가 중단되면 첫 번째 스크립트가 ssh그대로 유지됩니다. 만약을 대비해 맨 처음부터 삭제 &&하거나 보내십시오 -O exit(0번째가 됩니다 ssh).
  • 첫 번째가 ssh갑자기 죽으면 소켓이 남을 수 있습니다. 그것은 새로운 첫 번째 ssh실패를 만들 것입니다. 좋은 아이디어는 ssh다음과 같이 0을 확장하는 것입니다.

    ssh -S "$socket" -O exit dummy || rm "$socket"
    
  • /tmp/hostA.socket소켓에 가장 적합한 위치가 아닐 수도 있습니다. 명령줄 옵션 ssh_config과 동등한 것은 입니다 . 무엇을 참조하십시오-SControlPathman 5 ssh_config그것에 대해 이렇게 말합니다:

    ControlPath기회적 연결 공유에 사용되는 항목에는 최소한 %h, %p%r(또는 대안으로 %C)이 포함되고 다른 사용자가 쓸 수 없는 디렉터리에 배치하는 것이 좋습니다 .

    /run/user/$UID귀하의 OS가 이를 지원한다면 "다른 사용자가 쓸 수 없는 디렉토리"는 될 수 있습니다 systemd.

관련 정보