
ssh-agent
백그라운드에서 에이전트를 실행하고 현재 셸 인스턴스에 적합한 환경 변수를 설정하기 위해 첫 번째 시작을 원하는 스크립트 하나를 작성했습니다 . 그러나 스크립트의 두 번째 부분에서는 내 서버에 연결하기 위해 개인 SSH 키도 추가하고 싶습니다.
현재 스크립트의 두 명령 모두 서로 작동하지 않습니다. 누군가 내가 뭘 잘못하고 있는지 제대로 이해하도록 도와줄 수 있나요?
#!/bin/bash
exec ssh-agent bash
sleep 5s
ssh-add /media/MyUSB/.ssh/id_00123 &
또한 에 내장된 디버거를 활용하는 동안 bash
스크립트의 첫 번째 섹션(예: exec ssh-agent bash
)만 작동하는 것을 볼 수 있습니다.
답변1
이렇게 작은 스크립트에 흥미로운 측면이 너무 많습니다.
이해ssh-agent
ssh-agent
무엇을 하도록 설계된 것부터 시작해 보겠습니다 . 거기에 앉아서 일부 소켓을 수신하는 프로세스를 원할 때 실행합니다 ssh-agent
(이것은 일종의 소켓입니다).파일양방향 프로세스 간 통신용) 소켓에 연결되거나 연결되는 ssh-add
프로그램 의 요청을 처리합니다. ssh
프로그램은 에이전트와 통신하여 개인 키를 저장, 조작 또는 사용합니다.
에이전트를 사용하려는 모든 프로그램은 에이전트가 수신하는 소켓의 경로를 알아야 합니다. 프로그램이 경로를 알고 있으면 소켓을 사용하여 에이전트와 통신할 수 있습니다.
일단 설계 결정이 내려졌습니다. 인증 에이전트의 소켓 경로를 알고자 하는 모든 프로그램은 SSH_AUTH_SOCK
자체 환경에서 변수를 확인해야 하며, 변수의 값은 경로입니다. 그것은 결정이었지만(즉, 프로그램이 매번 명령줄 인수를 통해 이 경로를 허용하도록 설계될 수 있다는 것과 같이 다른 방식으로 설계될 수 있음을 의미합니다), 매우 좋은 결정이었습니다.
환경이 기본적으로 상속되기 때문에 매우 좋은 결정이었습니다. 이는 하나의 프로세스(예: 쉘)에 대해 환경 변수를 설정해야 하며 SSH_AUTH_SOCK
모든 하위 프로세스가 이를 상속한다는 의미입니다(일부 프로세스가 의도적으로 환경을 변경하거나 변경된 환경을 가진 하위 프로세스를 생성하도록 선택하지 않는 한). 비교를 위해 에이전트와 통신해야 하는 작업을 실행하려고 할 때마다 경로를 명령줄 인수로 전달하려면 추가 입력이 필요합니다. 그리고 경로를 어딘가에 저장하고 싶을 것이므로 어쨌든 변수에 저장하는 것이 좋습니다. 자, 변수 이름이 표준화되어 있고 관심 있는 프로그램이 자동으로 이를 확인합니다.
또 다른 옵션은 경로를 고정된 위치의 텍스트 파일에 저장하거나 처음에 고정된 위치에 소켓을 만드는 것이었습니다. 그러나 때로는 일부 프로그램이 하나의 에이전트(소켓 하나)를 사용하고 일부 다른 프로그램이 다른 에이전트(다른 소켓)를 사용하기를 원하는 경우도 있습니다. 두 프로그램이 같은 위치에 있는 다른 파일을 볼 수 있게 만드는 것은 어렵습니다. 두 프로그램이 서로 다른 환경 변수를 볼 수 있게 만드는 것은 쉽습니다.
따라서 관심 있는 프로그램은 SSH_AUTH_SOCK
해당 환경을 확인해야 합니다. 프로세스 환경에서 이 변수를 올바른 값으로 어떻게 설정할 수 있습니까? 디버거가 없으면 두 가지 방법이 있습니다.
부모는 값을 알고 자식을 생성할 때 자식을 위한 환경에 올바른 값을 설정합니다 ( 부모로부터
SSH_AUTH_SOCK
변경되지 않은 상속 행위는 "부모가 아무것도 하지 않고 이를 설정"하는 것으로 해석될 수 있음).SSH_AUTH_SOCK
또는 프로세스가 다른 방식으로 값을 학습하고 자체 환경을 수정합니다.
따라서 ssh-agent
시작하는 두 가지 방법을 지원합니다.
-
ssh-agent command …
여기서는
ssh-agent
소켓을 생성하고 소켓에 연결되는 향후 프로그램을 제공할 준비를 합니다. 그러면 아이를 위한 환경에서 올바른 가치를 지닌command …
아이로 실행됩니다 .SSH_AUTH_SOCK
자식(또는 변수를 상속받은 모든 자손)은 소켓을 쉽게 찾을 수 있지만 다른 프로세스는 그렇게 쉽지 않습니다. 종료 되면command
종료됩니다ssh-agent
(손자가 있더라도). -
ssh-agent # but don't use it exactly this way
여기서는
ssh-agent
배경으로 분기됩니다. 즉, 자신의 하위 복사본을 생성하고 종료될 때까지 기다리지 않습니다. 자식은 부모의 표준 스트림과 터미널에서 분리되지만 자체적으로 종료되지는 않습니다. 아이는 남을 진짜 대리인이 될 것입니다. 부모는 스스로 종료되지만, 그 전에 쉘 코드가 인쇄됩니다. 쉘 코드는 쉘에 의해 평가될 때 쉘이 자체 환경을 수정하도록 하므로SSH_AUTH_SOCK
올바른 값이 거기에 배치됩니다.하지만 쉘은평가하다단지 실행이 아닌 출력ssh-agent
, 올바른 방법은 다음과 같습니다.eval "$(ssh-agent)"
그 후 실행되는 셸은
eval
해당 환경에 올바른 변수(사실: 변수)를 가지며 이제부터ssh-add
이 셸에서 실행되는 것과 같은 명령은 변수를 상속하므로 에이전트를 찾습니다. 셸을 종료해도 에이전트는 종료되지 않으므로 셸을 종료하기 전 특정 시점에 호출할 수 있습니다ssh-agent -k
(또는 변수 설정을 해제하려는 경우:eval "$(ssh-agent -k)"
). 올바른 값을 보유하는 프로세스가 없는 에이전트는SSH_AUTH_SOCK
사실상 쓸모가 없습니다.
스크립트에 어떤 문제가 있나요?
그리고 이제 – 마지막으로 – 스크립트로 이동하세요. 이것은 귀하의 스크립트입니다:
#!/bin/bash exec ssh-agent bash sleep 5s ssh-add /media/MyUSB/.ssh/id_00123 &
스크립트가 가장 먼저 하는 일은 exec ssh-agent bash
. exec
스크립트를 해석하는 쉘에게 명령인 으로 대체하도록 지시합니다 ssh-agent bash
. 쉘은 이를 수행하고 ssh-agent
새로운 것을 시작합니다 bash
(위의 방법 1입니다). 이는 bash
올바른 값을 보유하고 SSH_AUTH_SOCK
대화형이며 프롬프트를 인쇄하고 명령(이 필요한 명령 포함 SSH_AUTH_SOCK
)을 실행할 수 있도록 합니다. 원래 대화형 셸이 있었다면 bash
이제 별도의 bash
. 의 존재를 원래 쉘의 환경이 수정되었다는 SSH_AUTH_SOCK
확인으로 해석할 수 있습니다. ssh-agent
아니요, 아직 스크립트를 작성하는 중입니다.
글쎄요, 정확히 중간은 아닙니다. 이것을 종료하면 bash
스크립트 sleep
를 해석하는 쉘이 로 대체되었기 때문에 나머지는 실행되지 않습니다 ssh-agent
. 어떤 의미에서 당신은 exit
대본이 끝나기 전의 존재입니다.
./myscript
스크립트를 실행하는 방법이 와 같으면 exit
원래 셸로 다시 돌아갑니다. 당신의 방법이 다음과 같다면. ./myscript
또는source myscript
exit
원래 쉘은 스크립트를 해석하는 쉘이었고 현재 쉘에서 ssh-agent
곧 종료될 쉘로 대체되었기 때문에 원래 쉘을 종료한 것처럼 작동 합니다 . exit
이렇게 하면 원래 셸에 있었던(지금은 종료하고 있는) 느낌이 강화될 수 있습니다.
수정 사항
질문에서 귀하는 귀하의 목표를 명시적으로 밝혔습니다.
[...] 현재 쉘 인스턴스에 적합한 환경 변수. […]
현재 쉘의 환경을 수정하려면 스크립트는 위의 방법 2를 사용해야 합니다. 현재 쉘은 해석 쉘이어야 합니다. 즉, 스크립트는 소스여야 합니다. exec
쉘이 어떤 것으로 대체되는 것을 원하지 않기 때문에 쉘은 아무 것도 하지 않아야 합니다 . 수정 예시:
#!/usr/bin/false
[ -n "$SSH_AUTH_SOCK" ] || eval "$(ssh-agent)"
ssh-add /media/MyUSB/.ssh/id_00123
개선된 사항은 다음과 같습니다.
#!/usr/bin/false
shebang은 스크립트를 소싱하는 대신 (실수로) 실행하면 스크립트가 아무 작업도 수행하지 않고 실패하도록 보장합니다. 다른 전략은 다음과 같습니다.스크립트 실행을 잊어버리는 전략source
.셔뱅도 없이또는 를 가리키는 shebang이나 다른 호환 가능한 셸을 사용하면bash
실행sh
된 스크립트(소스가 아님)가 새 에이전트를 시작하고 여기에 키를 추가한 후 종료됩니다. 이 모든 것이 현재 셸의 환경에 영향을 주지 않으므로 에이전트는 거의 액세스할 수 없는 상태로 아무 의미도 없이 존재하게 됩니다. 이를 찾아 종료하는 데 약간의 노력을 기울이거나 소켓을 찾아SSH_AUTH_SOCK
쉘 환경에서 수동으로 설정하는 데 약간의 노력이 필요합니다. 아니면 그냥 놔둘 수도 있습니다.false
shebang은 이러한 불편한 상황을 방지하기 때문입니다.[ -n "$SSH_AUTH_SOCK" ]
$SSH_AUTH_SOCK
비어 있지 않은 문자열로 확장되는지 확인합니다 . 빈 문자열은 사용 가능한 에이전트가 없음을 나타내고, 비어 있지 않은 문자열은 에이전트가 있을 가능성이 있음을 나타냅니다. 스크립트는ssh-agent
문자열이 비어 있는 경우에만 새 스크립트를 시작합니다. 이는 (실수로) 스크립트를 두 번째로 소싱하고, 새 인증 에이전트를 생성하고, 쓸모 없게 계속 실행되는 이전 에이전트와 관련된 변수를 잃는 시나리오에 대한 기본적인 예방 조치입니다.그럴 필요는 없습니다
sleep
.ssh-agent
스크립트에서는 에이전트(즉, 백그라운드에 있는 해당 하위 에이전트)가 준비되면 종료됩니다.ssh-add
바로 가능합니다 .ssh-add
여기에는 동기 명령이 있습니다. 비동기식으로 실행하면(&
하려고 했던 것처럼) 아마도 많은 시간을 절약할 수 없을 것입니다. 당신은 시도 할 수 있습니다. 그러나 작업 제어가 활성화된 대화형 셸에서 스크립트를 소싱할 가능성이 높으며 따라서&
(만약 거기에 넣으면) 다음과 같은 메시지로 터미널을 오염시킬 것입니다[1]+ Done …
.