여기 슈퍼유저에서 답변을 찾아봤지만 내 사용 사례에 대한 답변을 찾지 못했습니다.
터널을 통해 터널링할 수 있도록 사용하는 두 가지 명령을 연결하고 싶습니다.
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:10001
A로부터의 연결을 허용하지 않습니다. - 또는 무엇이든.
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
과 동등한 것은 입니다 . 무엇을 참조하십시오-S
ControlPath
man 5 ssh_config
그것에 대해 이렇게 말합니다:ControlPath
기회적 연결 공유에 사용되는 항목에는 최소한%h
,%p
및%r
(또는 대안으로%C
)이 포함되고 다른 사용자가 쓸 수 없는 디렉터리에 배치하는 것이 좋습니다 ./run/user/$UID
귀하의 OS가 이를 지원한다면 "다른 사용자가 쓸 수 없는 디렉토리"는 될 수 있습니다systemd
.