sshd 를 디버그 모드로 띄우면 호스트 키를 읽지 못한다고 나오고, 결국 기동에 실패한다.
debug1: sshd version OpenSSH_8.7, OpenSSL 3.2.2 4 Jun 2024
debug1: Unable to load host key: /etc/ssh/ssh_host_rsa_key
debug1: Unable to load host key: /etc/ssh/ssh_host_ecdsa_key
debug1: Unable to load host key: /etc/ssh/ssh_host_ed25519_key
sshd: no hostkeys available -- exiting.
호스트 키는 서버가 자기를 증명하는 키다. 클라이언트는 처음 접속할 때 이 키의 지문을 ~/.ssh/known_hosts 에 적어 두고, 다음부터 같은 키인지 대조한다. 중간자 공격을 막는 장치다.
사용자 키(~/.ssh/id_rsa)와는 전혀 다른 것이다. 사용자 키는 사용자를 증명하고, 호스트 키는 서버를 증명한다.
키가 없어지는 경우는 대개 다음이다.
/etc/ssh 를 통째로 복원하다 빠뜨렸다빠진 종류만 골라 한 번에 만든다. 이미 있는 키는 건드리지 않는다.
sudo ssh-keygen -A
이것이 정석이다. 그 배포판의 sshd 가 지원하는 종류를 알아서 만들고 파일 권한도 맞춰 준다.
특정 종류만 따로 만들려면 다음과 같다.
sudo ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' -C ''
sudo ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N '' -C ''
호스트 키에는 암호구(passphrase)를 걸지 않는다. -N '' 를 빼면 대화형으로 물어보고, 암호구를 걸면 sshd 가 부팅 시 키를 열지 못한다.
권한이 틀리면 sshd 가 키를 무시한다.
sudo chown root:root /etc/ssh/ssh_host_*
sudo chmod 600 /etc/ssh/ssh_host_*_key
sudo chmod 644 /etc/ssh/ssh_host_*_key.pub
SELinux 가 켜져 있고 키를 다른 곳에서 복사해 왔다면 컨텍스트를 되돌린다.
sudo restorecon -Rv /etc/ssh
설정 문법을 먼저 검사한다. 검사 없이 재기동하면 설정이 틀렸을 때 접속 경로가 통째로 막힌다.
sudo sshd -t && sudo systemctl restart sshd
만들어진 키의 지문을 확인한다.
for f in /etc/ssh/ssh_host_*_key.pub; do ssh-keygen -lf "$f"; done
호스트 키가 바뀌면 기존 클라이언트는 경고를 내고 접속을 거부한다.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
의도한 교체가 맞다면 옛 항목을 지운다.
ssh-keygen -R server.example.com
ssh-keygen -R 10.0.0.10
의도하지 않았다면 지우기 전에 서버에서 실제 지문을 확인해 대조한다. 경고를 습관적으로 지우고 넘어가면 이 장치가 있는 이유가 없어진다.
여러 대를 한꺼번에 갱신해야 한다면 서버에서 지문을 받아 배포한다.
ssh-keyscan -t rsa,ecdsa,ed25519 server.example.com >> ~/.ssh/known_hosts
ssh-keyscan 은 네트워크에서 받은 값을 그대로 믿는다. 신뢰할 수 있는 경로에서만 쓴다.
템플릿에서 복제한 VM 은 호스트 키까지 같다. 서로 다른 서버가 같은 신원을 주장하게 되므로 반드시 새로 만든다.
sudo rm -f /etc/ssh/ssh_host_*
sudo ssh-keygen -A
sudo systemctl restart sshd
cloud-init 을 쓰는 이미지는 첫 부팅에 알아서 다시 만든다. 템플릿을 봉인하기 전에 키를 지우고 cloud-init 상태를 초기화한다.