SSH 2 | ~/.ssh/known_hosts
2. ~/.ssh/known_hosts 파일
client가 server로 ssh 접속 시도를 합니다. server에는 퍼블릭 키와 프라이빗 키가 존재하는데, server의 퍼블릭 키가 client에게 전송됩니다. 처음에 ssh 접속을 시도할 때 fingerprint(지문)를 확인받는데, 이 때의 fingerprint가 server의 퍼블릭 키입니다. 지문을 검증받는 질문에 'yes'라고 답을 하게 되면, client측의 ~/.ssh/known_hosts 파일에 해당 퍼블릭 키가 등록됩니다. 그래서 특정 서버에 최초 접속할 때에만 지문을 물어보고, known_hosts 파일에 등록된 이후에는 ssh 접속을 할 때 먼저 known_hosts 파일에서 접속하려는 서버의 퍼블릭 키가 등록되어 있는지 확인합니다. 존재하면 다시 지문 확인을 하지 않습니다.
server가 VM인 경우 VM을 삭제했다가 다시 만들었을 때 server의 퍼블릭 키와 프라이빗 키는 바뀌게 됩니다. 하지만 server의 IP 주소는 동일합니다. (VM을 생성할 때 퍼블릭 키와 프라이빗 키가 자동으로 생성됩니다. 즉 모든 VM의 퍼블릭 키와 프라이빗 키는 다릅니다.) 문제는 여기서 발생합니다. 192.168.200.101이라는 IP 주소를 가진 VM server를 삭제했다가 다시 생성했을 때, server의 키 쌍은 이전과는 다른 값을 가지게 됩니다. 그런데 client는 그대로이기 때문에 ~/.ssh/known_hosts 파일에는 server의 예전 퍼블릭 키가 등록되어 있습니다. 그렇기 때문에 ssh 접속을 했을 때 키가 맞지 않다고 나오게 됩니다.
(vagrant로 배포한 ubuntu 이미지는 모든 시스템 노드에 vagrant라는 사용자가 기본적으로 존재하기 때문에 ssh 접속시 별도로 사용자를 지정하지 않았습니다.)
ssh 192.168.200.101
fingerprint를 확인하는 질문에 'no'라고 답하면 ~/.ssh/known_hosts 파일에 해당 서버의 퍼블릭 키가 등록되지 않습니다.
mgmt1 시스템의 /etc/ssh 디렉토리를 확인하면 ssh_host로 시작하는 파일들이 여럿 존재합니다. 이 중 이름이 같은 파일이 여럿 존재하는데 .pub이 붙은 파일이 퍼블릭 키이고, 아닌 파일이 프라이빗 파일입니다. 퍼블릭 키는 노출되어도 상관이 없지만 프라이빗 키는 절대 노출되어서는 안 됩니다. (공인인증서의 경우, 퍼블릭 키를 가지고 있습니다. 퍼블릭 키는 누구에게나 공개되어도 상관이 없기 때문입니다.)

파일들을 조금 더 살펴보면, 파일명이 ssh_host_암호화 알고리즘_key(.pub)로 구성됩니다. 즉 암호화 알고리즘은 dsa, ecdsa, rsa, ed25519이라는 4가지 알고리즘을 지원합니다. 이처럼 4가지 알고리즘을 이용하여 만들어져 있는 키 쌍이 server측의 /etc/ssh/ 디렉토리에 존재합니다. ssh 접속시 default로 사용하는 암호화 알고리즘은 ecdsa입니다.
이 key 파일이 client로 전송됩니다. 엄연히 말하면, 파일 자체라기보다는 key 파일의 fingerprint가 전송됩니다.

첫번째 필드는 암호화 알고리즘, 두번째 필드는 퍼블릭 키, 마지막 세번째 필드는 key를 만든 사람입니다. 두 번째 필드의 퍼블릭 키를 hash를 뜬 것이 fingerprint입니다. 다음의 명령어를 입력하면 퍼블릭 키의 fingerprint를 얻을 수 있습니다.
ssh-keygen -l -f ssh_host_ecdsa_key.pub

- -l : list
- -f : file
◆ ssh-keygen : ssh 키를 생성하는 것도 가능하지만 퍼블릭 키를 지정했을 때 지문을 확인할 수도 있습니다.
이 지문을 복사하여 client에서 비교를 해 봅시다. 서버 시스템(mgmt1)에 ssh 접속을 시도하니 fingerprint를 묻는데, 해당 fingerprint는 서버에서 확인한 /etc/ssh/ssh_host_ecdsa_key.pub의 hash와 동일한 값임을 확인할 수 있습니다.

생각해볼 문제가 또 있습니다. 지금이야 이미 VM이 만들어져 있는 경우지만 만약 퍼블릭 클라우드에서 인스턴스를 생성하여 접속할 때, 만들어져 있는 VM이 아닌데 해당되는 VM의 퍼블릭 키를 알 수 있을까요? 사실은 미리 알 수가 없습니다.
이 때는 ssh-keyscan 명령어를 사용할 수 있습니다. ssh-keyscan은 server의 퍼블릭 키를 얻는 데 사용하는 명령어 도구입니다. 이 도구는 kown_hosts 파일을 생성하고 검증하기 위한 목적으로 만들어졌습니다. 퍼블릭 클라우드 인스턴스처럼 미리 접속할 수 없는 시스템의 ssh 퍼블릭 키 fingerprint를 확인할 수 없을 때, ssh-keyscan으로 접속할 시스템의 퍼블릭 키를 미리 스캔할 수 있습니다.
[ ssh-keyscan 접속하려는 server IP] 를 입력하면 server의 퍼블릭 key가 출력됩니다.
ssh-keygen 192.168.200.101

이 키들을 server 측의 키와 비교해보면 동일한 키값임을 확인할 수 있습니다.
이를 redirection하여 a 파일로 만들어 두고, ssh-keygen을 사용하여 암호화하면 미리 ssh fingerprint를 알 수 있습니다. 따라서 시스템에 접속했을 때 fingerprint의 일치 여부를 검증하는 것이 가능해집니다.
ssh-keyscan 192.168.200.101 > a ssh-keygen -lf a

client(control)에서 server(mgmt1)로 ssh 접속 후 빠져나와 client 측의 ~/.ssh/known_hosts 파일을 확인해보면, server의 퍼블릭 키가 등록되어있습니다.
cat .ssh/known_hosts

이를 아주 간단하게 확인하는 방법도 있습니다. 실제로 ssh-keyscan을 이용하는 방식은 다음과 같습니다.
-t 옵션을 붙이면 암호화 타입을 지정할 수 있습니다. 원하는 암호화 타입을 지정하여 해당 퍼블릭 키를 ~/.ssh/known_hosts 파일에 append합니다.
rm .ssh/known_hosts ssh-keyscan -t ecdsa 192.168.200.101 >> .ssh/known_hosts
이미 server의 퍼블릭 키 fingerprint가 known_hosts 파일에 등록되었으므로, server에 접속시 fingerprint 검증을 묻지 않고 실행됩니다. 다시 말해 client 사용자가 직접 검증하지 않고 시스템이 검증하게 됩니다. 시스템이 검증한다는 것은, server가 전달해준 퍼블릭 키와 known_hosts 파일에 등록된 퍼블릭 키가 일치하는지를 판단하는 것입니다.

정리하면, 원칙은 다음과 같습니다. 이렇게 하면 안전을 담보할 수 있습니다.
ssh-keyscan -t ecdsa 192.168.200.102 >> .ssh/known_hosts ssh 192.168.200.102
이 방식은 자기 자신에게 접속할 때도 유효합니다.
ssh-keyscan -t ecdsa 192.168.200.100 >> .ssh/known_hosts ssh 192.168.200.100
- ~/.ssh/known_hosts 파일의 용도 : ssh 최초 접속시 server의 퍼블릭 키를 저장
또다른 방식도 있습니다. 하지만 이 방식은 매우 위험합니다.
-o 옵션을 사용하여 StrictHostKeyChecking=no를 전달하면 fingerprint 검증 없이 실행됩니다. 해당 옵션은 지문을 검증하지 말라는 의미입니다.
rm .ssh/known_hosts ssh -o StrictHostKeyChecking=no 192.168.200.101

fingerprint 검증 없이 이미 known_hosts 파일에 등록되었습니다.

ssh-keyscan을 모르는 많은 블로그에 해당 방식에 대한 내용이 소개되어 있으나, 보안상 매우 위험한 방식이므로 절대로 사용해서는 안 되는 방식입니다. ssh-keyscan을 사용하여 접속하는 것이 가장 바람직한 방법입니다.
현재 mgmt1은 ssh 접속이 가능한 상태입니다. 그러나 호스트 시스템에서 mgmt1을 삭제 후 다시 생성해보겠습니다. 이렇게 되면 mgmt1의 키 페어 값이 달라지게 됩니다.
vagrant destroy mgmt1 vagrant up mgmt1
◆ /etc/ssh/ssh_host_* 키 파일들을 당연히 이미지 내에 저장시켜 놓지는 않습니다. 만약 이미지 내에 키페어 파일을 미리 만들어 놓는다면, 이 이미지를 사용하는 전세계 사람들의 키가 다 같아지게 됩니다..; 클라우드든, vm이든 이미지 자체에는 키가 저장되어 있지 않고, 최초에 vm이 만들어질 때 키 파일이 생성됩니다.
생성된 mgmt1에 접속하여 /etc/ssh/ 밑의 파일을 살펴보면, ssh_host_* 키페어 파일들이 존재합니다. VM이 생성될 때 키페어 파일도 같이 생성됩니다. (해당 파일들은 15시 45분에 만들어졌는데, 이는 현재 시스템 시각이 UTC 타임으로 설정되어 있기 때문입니다.)

다시 control 노드로 돌아와서, known_hosts 파일에 등록되어 있는 키와, ssh-keyscan을 통해 새롭게 생성된 키를 확인해 봅시다. known_hosts 파일에 등록되어 있는 키는 mgmt1이 삭제되기 전의 퍼블릭 키이므로, 새로운 키로 등록해주지 않는 이상 mgmt1으로 ssh 접속이 불가능합니다. (REMOTE HOST IDENTIFICATION HAS CHANGED! 원격 호스트의 식별 정보가 변경됨)
~/.ssh/known_hosts에 저장되어 있는 공개키와 실제 서버측에서 받아온 공개키와 일치하지 않으면 man-in-the-middle attack일 가능성이 있다는 다음과 같은 오류 메세지가 발생합니다. 이는 시스템의 IP나 호스트네임이 동일한 시스템이기 때문입니다.

정상적으로 접속을 하기 위해서는 known_hosts 파일을 수정하여 접속하려는 서버의 퍼블릭 키를 지워주어야 합니다. 이 때 knwon_hosts 파일 자체를 지워서는 안 됩니다. 접속하려는 서버의 키만 들어 있는 것이 아닐 수 있기 때문입니다. 위 에러 메세지에서 offending ECDSA key가 존재하는 라인 넘버를 알려주므로 이 정보를 참고하여 파일을 수정해줍니다. 또는 아래서 세번째 줄에 나오는 ssh-keygen -f 명령어를 입력할 수도 있습니다.
접속하기 전에 새로 생성된 mgmt1의 sshd 설정파일에서 패스워드 인증 방식을 허용해주어야 합니다.
vi /etc/ssh/sshd_config -> PasswordAuthentication yes systemctl restart ssh

◆ 서버가 바뀌지 않았는데 접속 오류가 뜬다면 정말 MITM 공격을 의심해볼만 합니다.