증상: 파워셸이나 파이썬 subprocess 로 ssh 를 부르면 UNPROTECTED PRIVATE KEY FILE 과 Permission denied (publickey) 가 나는데, 같은 키로 Git Bash 는 됩니다.
원인: 윈도우 OpenSSH 는 NTFS 권한을 검사해 Everyone 이나 Users 그룹이 읽을 수 있는 키를 거부합니다.
해결: icacls 로 상속을 끊고 본인 계정에만 읽기 권한을 남깁니다.
윈도우에서 SSH 자동화를 하다 보면 "손으로는 되는데 스크립트로는 안 되는" 일이 생깁니다. 이 경우는 키도 서버도 멀쩡했고, 문제는 키 파일의 윈도우 권한이었습니다.
Git Bash 는 되고 파워셸, 파이썬은 안 된다
서버 작업을 파이썬으로 자동화하려고 subprocess.run(['ssh', '-i', 키, ...]) 로 ssh 를 불렀더니 아래 두 줄이 나오며 접속이 거부됐습니다. 파워셸 창에서 ssh 를 직접 쳐도 같았습니다.
WARNING: UNPROTECTED PRIVATE KEY FILE!
Permission denied (publickey).
그런데 같은 키, 같은 서버로 Git Bash 에서 ssh 를 치면 아무 문제 없이 들어가졌습니다. 그래서 처음에는 서버 쪽 설정이나 키 형식을 의심하기 쉽습니다.
어떤 ssh 가 불리느냐에 따라 권한 검사가 다르다
| 호출하는 곳 | 실제로 불리는 ssh | 키 권한 검사 |
|---|---|---|
| Git Bash | Git 에 들어 있는 MSYS ssh | 권한을 자기 방식으로 변환해 통과 |
| 파워셸 | 윈도우 OpenSSH(ssh.exe) | NTFS 권한을 엄격하게 검사 |
| 파이썬 subprocess | 윈도우 OpenSSH(ssh.exe)를 직접 호출 | 위와 같음 |
윈도우 OpenSSH 는 개인 키 파일에 Everyone 이나 Users 그룹 권한이 남아 있으면 "다른 사람도 읽을 수 있는 키"로 보고 사용을 거부합니다. 키를 받은 폴더의 권한을 상속받은 파일은 대개 이런 상태입니다. Git Bash 의 ssh 는 이 검사를 통과시키기 때문에 둘의 결과가 갈렸습니다.
icacls 로 본인 읽기만 남기기
파워셸에서 한 번만 실행하면 됩니다. 키 파일 경로는 자기 것으로 바꿉니다.
$KEY = "C:\keys\server_key"
icacls $KEY /inheritance:r /grant:r "${env:USERNAME}:R"
/inheritance:r는 폴더에서 물려받은 권한을 끊고 지웁니다./grant:r "사용자:R"는 지금 로그인한 계정에만 읽기(R) 권한을 줍니다. 기존 권한을 덮어씁니다.
이렇게 하고 나면 파워셸과 파이썬 subprocess 양쪽에서 ssh 와 scp 가 정상으로 동작했습니다. 한 번 바꾸면 그 파일에는 계속 유지됩니다.
주의할 점은 새 키를 받을 때마다 같은 상태가 된다는 것입니다. 그래서 새 키를 받으면 이 명령을 먼저 돌리는 것을 표준 절차로 정해 두었습니다.
접속되는지 확인하는 법
먼저 권한이 의도대로 바뀌었는지 봅니다.
icacls $KEY
결과에 사용자이름:(R) 한 줄만 보이면 됩니다. Everyone, Users, Authenticated Users 같은 줄이 남아 있으면 상속이 끊기지 않은 것입니다.
그다음 실제로 문제가 났던 경로, 곧 파이썬에서 다시 불러 봅니다.
import subprocess
r = subprocess.run(
["ssh", "-i", r"C:\keys\server_key", "-o", "BatchMode=yes",
"[email protected]", "echo ok"],
capture_output=True, text=True)
print(r.returncode, r.stdout, r.stderr)
반환 코드 0 과 ok 가 나오고 stderr 에 경고가 없으면 해결된 것입니다. Git Bash 에서만 시험하면 문제가 원래 없던 것처럼 보이므로, 반드시 실패했던 쪽에서 확인합니다.
헷갈리기 쉬운 다른 원인과 구분
Permission denied (publickey) 한 줄만 보면 서버에 공개키가 등록되지 않은 경우와 똑같아 보입니다. 구분하는 단서는 바로 위에 함께 찍히는 UNPROTECTED PRIVATE KEY FILE 경고입니다. 이 경고가 있으면 ssh 가 키를 서버에 보내 보기도 전에 스스로 쓰지 않은 것이므로, 서버 설정을 볼 필요가 없습니다.
또 하나의 단서는 같은 키가 Git Bash 에서는 된다는 사실입니다. 키와 서버가 정상이라는 뜻이므로, 남는 차이는 어떤 ssh 프로그램이 불렸는가와 그 프로그램의 권한 검사뿐입니다. 이 두 단서를 먼저 보면 엉뚱한 곳을 고치는 시간을 줄일 수 있습니다.
확인한 환경
| 항목 | 내용 |
|---|---|
| 운영체제 | 윈도우 PC |
| 실패한 쪽 | 파워셸의 ssh.exe, 파이썬 subprocess 로 부른 ssh |
| 성공한 쪽 | Git Bash(MSYS) ssh |
| 확인한 날짜 | 2026년 5월 |
관련 글
이 글의 내용은 2026년 10월 5일에 마지막으로 확인했습니다. 틀린 곳을 발견하시면 연락처로 알려 주세요.