Watch at Ease세상을 읽고, 일상의 답을 찾다.

기술 · 실용 가이드

OpenSSH ControlMaster가 멈췄나요? 소켓을 지우기 전에 상태를 증명하세요

실제 ControlPath를 확인하고 마스터의 생존 여부를 물은 뒤, 오래된 경로·멈춘 전송·경로 실패를 분리해 증명된 경계만 복구합니다.

OpenSSH 유효 설정에서 ControlPath 검증, 마스터 확인, 안전한 조치까지 보여 주는 원본 결정도.
원본 일러스트: 실제 ControlPath를 해석하고 정확한 마스터에 질의한 뒤 관측된 경계만 조치합니다. Watch at Ease

ControlMaster 실패는 한 가지 문제가 아닙니다. 경로가 예상 밖 위치로 확장되거나 Unix 도메인 소켓 길이 제한을 넘거나, 소켓을 제대로 지원하지 않는 파일시스템에 있거나, 종료된 마스터를 가리키거나, 로컬 마스터는 살아 있어도 원격 전송이 멈췄을 수 있습니다. 먼저 경로를 지우면 증거가 사라지고 살아 있는 프로세스와 경쟁할 수 있습니다.

증거 순서로 진행합니다. ssh -G로 유효 설정을 고정하고 비공개 ControlPath와 길이를 검사한 다음 ssh -O check로 정확한 소켓에 묻습니다. 관측된 경계에 따라 exit, unlink, 경로 이동, keepalive 수정을 선택하고 두 번째 클라이언트가 새 마스터를 재사용하는지 증명합니다.

1. 별칭과 유효 설정 고정

실패한 때와 같은 별칭과 실행 환경에서 ssh -G alias를 실행하고 hostname, user, port, proxyjump, controlmaster, controlpath, controlpersist를 기록합니다. OpenSSH는 대개 명령행, 사용자 설정, 시스템 설정 순서에서 첫 값을 사용하므로 마지막 일치 블록만 보면 다른 소켓을 조사할 수 있습니다.

다른 별칭을 손으로 확장하지 마세요. %h, %p, %r, %C는 유효 연결에서 해석되므로 겉보기 같은 이름도 다른 마스터에 매핑될 수 있습니다. 전체 출력을 사고 증거로 보관합니다.

2. 생존 검사 전에 경로 검증

해석된 ControlPath가 SSH 사용자 소유이며 다른 사용자가 쓸 수 없는 디렉터리에 있는지 확인합니다. %h-%p-%r 또는 길이가 문제면 %C로 고유하게 만듭니다. 각 부모의 검색 권한과 최종 디렉터리 쓰기 권한을 확인하며, 누락·권한 부족은 오래된 소켓이 아니라 경로 실패입니다.

인코딩된 경로 길이를 측정합니다. Linux pathname socket의 sun_path는 108바이트지만 더 짧은 구현도 있으므로 여유를 둡니다. 짧은 비공개 런타임 디렉터리는 깊은 홈, 컨테이너, CI 경로를 피합니다.

3. 정확한 마스터에 질의

고정한 설정으로 ssh -O check alias를 실행합니다. 캡처한 경로를 직접 검사해야 한다면 같은 유효 호스트·사용자·포트로 ssh -S "$socket" -O check host를 사용합니다. 성공 응답은 실행 중 마스터와 보통 PID를 알려 주므로 변경 전에 저장합니다.

모든 OpenSSH 빌드에서 같은 오류 문자열을 기대하지 마세요. 경로가 없으면 확장·생성 단계로 돌아갑니다. 연결 거부는 오래된 후보지만 소유자, 파일 종류, 별칭, 열린 프로세스를 확인해야 합니다. 성공하면 삭제가 아니라 전송 건강을 조사합니다.

4. 오래된 경로와 멈춘 전송 분리

마스터가 응답하고 종료하려면 ssh -O exit alias를 쓰고 프로세스와 경로가 사라졌는지 확인합니다. 응답하는 경로를 unlink하면 기존 클라이언트는 남고 경쟁 마스터가 생길 수 있습니다. 무응답, 예상 소유자, 관련 프로세스·열린 소켓 없음이 확인될 때만 증거를 보관하고 그 경로만 삭제합니다.

제어 소켓 응답은 로컬 제어 채널만 증명합니다. ServerAliveInterval과 ServerAliveCountMax를 함께 설정하면 연결이 형성된 뒤에도 서버 무응답을 암호화된 프로토콜 메시지로 감지합니다. TCPKeepAlive와는 다른 경계입니다.

5. 경로와 파일시스템 배치 복구

overlay 또는 컨테이너 작업공간에서 생성이 실패하면 로컬 파일시스템의 짧은 비공개 런타임 디렉터리에서 한 번 재현합니다. ControlPath를 overlayfs 밖으로 옮겨 해결된 CI 사례는 배치 진단이지 모든 overlay의 일반 법칙이 아닙니다. %C 같은 대상 고유 토큰을 유지합니다.

적절한 $XDG_RUNTIME_DIR 하위처럼 사용자 소유 0700 디렉터리를 우선합니다. 제한된 시험에 /dev/shm을 쓰더라도 비공개 하위 디렉터리를 만들고 소유권과 모드를 확인합니다. 공유 쓰기 디렉터리에 예측 가능한 소켓을 직접 두지 말고 ControlPersist와 비정상 종료 후 정리도 기록합니다.

6. 복구 증명과 범위 제한

verbose 연결 하나를 시작해 다중화 설정 줄을 저장합니다. 두 번째 프로세스가 같은 별칭으로 재사용하는지 확인하고 ssh -O check를 다시 실행합니다. 전후 ssh -G를 비교해 비다중화 연결로 우연히 폴백한 것이 아님을 증명합니다.

비공개 경로 생성, 정확한 마스터 응답, 두 번째 클라이언트 재사용, 설계된 exit 또는 지속 동작, 원격 명령 성공이 모두 확인될 때만 수락합니다. pathname ControlMaster와 시험한 클라이언트가 범위이며 추상 소켓, 런처, 보안 모듈, 프록시, 공급자 패치는 추가 증거가 필요합니다.

클라이언트, 로컬 Unix 제어 소켓, SSH 마스터 프로세스, 원격 전송을 보여 주는 원본 수명주기 그림.
원본 일러스트: 로컬 제어 소켓과 원격 전송은 서로 다른 실패 경계입니다. Watch at Ease