I Installed the Key, So Why Is It Asking for a Password
한국어 원문으로 표시합니다.
한 줄 요약
공개키 인증이 실패하는 원인의 대부분은 암호학이 아니라 파일 권한이다. sshd 는 권한이 느슨하면 키를 조용히 거부한다.
왜 이게 필요했나
ssh-copy-id 로 키를 넣었는데 여전히 비밀번호를 묻는다. 클라이언트 로그(ssh -vvv)를 보면 키를 제시(Offering public key)했는데 서버가 받아 주지 않는다. 서버 로그에도 뚜렷한 이유가 없다.
원인은 대개 이것이다.
chmod 755 ~ # 홈이 그룹 쓰기 가능이면 거부된다
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
sshd 가 이렇게 까다로운 이유가 있다. authorized_keys 를 다른 사용자가 쓸 수 있으면, 그 사용자가 자기 키를 한 줄 추가해 남의 계정으로 로그인할 수 있다. 권한이 곧 인증 정책인 셈이다.
RHEL 계열에는 함정이 하나 더 있다. 홈 디렉터리를 손으로 만들었거나 파일을 다른 경로에서 복사하면 SELinux 컨텍스트가 틀려 키가 거부된다. 로그에 권한 문제로 명확히 찍히지 않아 시간을 많이 잡아먹는다. restorecon -Rv ~/.ssh 가 표준 해법이다.
어떻게 동작하나
키는 두 조각이다. 개인 키는 내 손에만 있고, 공개키는 서버의 authorized_keys 에 한 줄로 들어간다. 인증은 서버가 낸 문제를 개인 키로 서명해 보내는 방식이라 개인 키가 네트워크로 나가지 않는다.
키 종류는 사실상 둘로 좁혀졌다.
ssh-keygen -t ed25519 -C 'youngju@laptop-2026' -f ~/.ssh/id_ed25519
ssh-keygen -t rsa -b 4096 -C 'youngju@laptop-2026' -f ~/.ssh/id_rsa
ssh-keygen -t ed25519-sk -f ~/.ssh/id_ed25519_sk # FIDO2 하드웨어 키
Ed25519 가 기본이고, FIPS 같은 조직 정책이 요구할 때만 RSA 4096 을 쓴다. -sk 는 개인 키가 하드웨어를 벗어나지 않는다.
-C 주석에 사람과 기기를 적는 습관이 중요하다. authorized_keys 에 20줄이 쌓였을 때 어느 줄이 누구 것인지 알 수 있는 유일한 단서다.
authorized_keys 의 각 줄에는 제약을 걸 수 있다.
restrict,from="10.0.0.0/8",command="/usr/local/bin/deploy-only" ssh-ed25519 AAAAC3Nza... deploy@ci
restrict는 모든 기능을 끄는 안전한 기본값이다. 이후 필요한 것만 다시 켠다.from=은 접속 출발지를 제한한다.command=은 클라이언트가 무엇을 요청하든 지정한 명령만 실행한다. 배포용 키에 특히 유용하다.
클라이언트 쪽 설정도 파일에 적어 두는 편이 낫다.
Host bastion
HostName bastion.example.com
User youngju
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
ServerAliveInterval 30
Host prod-*
User deploy
ProxyJump bastion
IdentitiesOnly yes
IdentitiesOnly yes 가 특히 중요하다. 없으면 에이전트에 올라간 모든 키를 차례로 시도하다가 서버의 MaxAuthTries(기본 6)에 걸려 인증이 실패한다. 키가 여러 개인 사람이 겪는 대표적인 문제다.
현장에서 만나는 모습
키 회수는 파일에서 줄을 지우는 것으로 끝나지 않는다. 이미 열려 있는 세션은 그대로 살아 있다. 완전한 회수는 줄 삭제 → who 로 세션 확인 → 해당 사용자의 sshd 세션 종료 순서다. 마지막 단계는 본인 세션까지 끊을 수 있으니 대상 계정을 반드시 확인한다.
호스트 키 경고를 습관적으로 무시하는 것. 서버를 재설치할 때마다 뜨니까 그렇게 된다. 그 습관이 중간자 공격의 유일한 방어선을 무력화한다. 규모가 커지면 SSH 인증서(호스트 키를 CA 로 서명)로 옮기는 것이 정답이다.
키가 있는데 로그인이 안 될 때
Permission denied (publickey) 는 원인이 여럿인데, 확인 순서를 정해 두면 대개
1분 안에 끝난다.
먼저 클라이언트가 어느 키를 보내는지 본다.
ssh -v user@host 2>&1 | grep -E "Offering|Authentications|Server accepts"
키를 여러 개 갖고 있으면 ssh 는 순서대로 시도하는데, 서버의
MaxAuthTries(기본 6)에 먼저 걸려 정작 맞는 키를 보내기 전에 끊긴다.
그때는 쓸 키를 명시한다.
Host prod
IdentityFile ~/.ssh/id_prod
IdentitiesOnly yes # 다른 키는 아예 시도하지 않는다
권한이 조금만 헐거워도 sshd 는 거절한다. 이것이 가장 흔한 원인이다.
| 대상 | 권한 |
|---|---|
~ |
그룹·기타에 쓰기 없음(755 이하) |
~/.ssh |
700 |
~/.ssh/authorized_keys |
600 |
| 개인 키 | 600 |
서버 쪽 로그(journalctl -u sshd)에 Authentication refused: bad ownership or modes 가 남으므로, 접근할 수 있다면 그것이 가장 빠른 답이다.
서버 설정이 그 방식을 막고 있을 수 있다. PubkeyAuthentication,
AuthorizedKeysFile, AllowUsers/AllowGroups, 그리고 PermitRootLogin 을
본다. 최근 배포판은 낡은 키 형식(ssh-rsa with SHA-1)을 기본으로 거절하므로,
오래된 키가 갑자기 안 되는 일이 있다. 그때는 키를 새로 만드는 것이 맞고,
급하면 PubkeyAcceptedAlgorithms 에 임시로 더한다.
에이전트는 잊고 살기 쉽다. ssh-add -l 이 비어 있으면 암호로 잠긴 키를 못
쓴다. 에이전트 포워딩(-A)은 편하지만, 그 서버의 루트가 내 에이전트를 그대로
쓸 수 있다. 점프가 목적이라면 ProxyJump 를 쓴다 — 키가 중간 서버에 노출되지
않는다.
Host prod
ProxyJump bastion
다음 실습에서 할 것
키를 만들고, 권한을 맞추고, authorized_keys 에 등록해 실제로 127.0.0.1:2222 에 접속한다. ~/.ssh/config 로 별칭을 만들고, command= 제약을 건 키가 정말 그 명령만 실행하는지 확인한다.