SSH 서버는 여러가지 방법으로 클라이언트를 인증할 수 있다. 그 중 가장 기본적인 방법은 패스워드를 사용하는 것으로 사용하기 쉽지만 가장 안전한 인증방법은 아니다.
비록 패스워드는 암호화되어 서버로 보내지지만 꾸준하고 반복적인 해커의 공격에 안전할만큼 복잡하거나 길지 않은 경우가 거의 대부분이다. 컴퓨팅 파워가 비약적으로 발전했기 때문에 자동화 된 스크립트를 사용한 brute-force 공격에 취약할 수 밖에 없다. 다른 추가적인 보안박식들도 있지만 SSH key가 가장 안정적이고 안전한 검증된 인증방식이다.
SSH 키 페어는 두개의 암호키로 SSH 서버가 클라이언트를 인증하는데 사용될 수 있다. 각 키 페어는 public 키와 private 키로 이루어진다.
Private 키는 클라이언트가 가지고 있고, 이 키는 절대적인 비밀(누구에게도 복사해 주거나 공개하면 안됨)로 해야만 한다. 어떤 식으로건 private 키가 알려지는 순간 공격자는 그 쌍이 되는 public 키로 설정된 서버에 아무 추가적인 인증 없이 로그인이 가능해진다. 추가적인 예방조치로 private 키를 passphrase로 암호화 해서 디스크에 저장할 수 있다.
쌍이 되는 public 키는 아무 걱정 없이 자유롭게 누구에게든 공유할 수 있다. Public 키로 메시지를 암호화 할 수 있는데, 그 암호화 된 메시지는 그 쌍이 되는 private 키로만 해석할 수 있다. (암호화에 사용한 public 키로도 암호화 된 메시지를 해석할 수 없다) 이런 특성이 키 페어를 사용한 인증방식에 사용된다.
Public 키는 SSH로 로그인하길 원하는 원격 서버에 업로드된다. 이 키는 사용자 어카운트의 ~/.ssh/authorized_keys 라는 특별한 파일에 추가된다.
클라이언트가 SSH key를 사용해 인증하려고 시도하면, 서버는 클라이언트가 private 키를 가지고 있는지 여부를 테스트 할 수 있다. 클라이언트가 private 키를 가지고 있는걸 증명하면 쉘 세션이 생성되거나 요구된 명령을 실행한다.
이 전체적인 흐름은 다음과 같다.
1. 클라이언트가 서버에 SSH 연결을 요청한다.
2. 서버는 랜덤 챌린지(랜덤 데이터 스트링)를 생성해 클라이언트에게 보낸다.
3. 클라이언트는 서버로 부터 받은 챌린지(C)를 자신이 가지고 있는 private 키로 암호화해서 암호화 된 메시지를 서버로 보낸다.
4. 서버는 클라이언트에서 받은 암호화 된 메시지를 public 키로 해석한 후 그 결과를 2단계에서 자신이 클라이언트에게 보낸 랜덤 챌린지와 일치하는지 확인한다. (public 키로 해석할 수 있는 메시지는 그 쌍이 되는 private 키를 가진 사람만이 만들 수 있기 때문) 일치하면 클라이언트가 인증된 것이다.
SSH 키 만들기
서버가 SSH 키 인증을 사용하도록 설정하려면 가장 먼저 해야 하는 일은 클라이언트에서 키 페어를 만드는 것이다.
키 페어를 만들려면 OpenSSH에 포함되어 있는 ssh-keygen 유틸리티를 사용한다. 디폴트로 2048-bit RSA 키 페어를 만들게 되어 있는데, 대부분의 사용자에게 이 정도면 충분하다.
클라이언트에서 ssh-keygen을 실행해 SSH 키 페어를 만든다.
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/test/.ssh/id_rsa):
프로그램이 생성될 키를 저장할 위치를 선택하도록 물어본다. 디폴트로 ~/.ssh 디렉토리에 저장하게 되어 있다. Private 키는 id_rsa라는 이름이고 public 키는 id_rsa.pub라는 이름을 사용한다.
일반적으로 디폴트를 그대로 사용하는게 좋다. 별도 디렉토리를 사용하려면 원하는 위치를 입력하고, 그냥 디폴트를 사용하려면 엔터를 누르면 된다.
만일 이전에 만들어 놓은 SSH 키가 있다면 다음과 같은 내용을 보게 될 것이다.
/home/test/.ssh/id_rsa already exists.
Overwrite (y/n)?
덮어쓰기를 선택하면 이전 키를 사용하는 인증은 더 이상 사용할 수 없게 된다. 이 단계는 되돌릴 수 없으므로 yes를 선택하려면 매우 주의해야 한다.
Created directory '/home/test/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
다음으로 키에 대한 passphrase를 물어본다. Passphrase는 옵션으로 private 키를 디스크에 저장할 때 암호화 하는데 사용된다.
어짜피 passphrase를 입력해야 한다면 SSH 키를 사용하는 장점이 무엇인가 궁금할 수 있을 것이다. 몇가지 장점을 나열하자면...
* Private SSH키(passphrase로 보호되는 부분)는 네트웍 상에 절대로 노출되지 않는다. Passphrase는 로컬머신상에서 private 키를 해석하는데만 사용된다. 그러므로 passphrase에 대한 네트웍 기반의 brute-force 공격이 불가능해 진다.
* Private 키는 제한된 디렉토리내에서만 보관된다. SSH 클라이언트는 제한된 디렉토리에 보관되지 않는 private 키는 인식하지 않는다. 또한 키 자체는 제한된 퍼미션을 가져야만 한다. (owner만 rw가 가능) 즉 시스템의 다른 사용자가 볼 수 없다는걸 의미한다.
* Private SSH 키의 passphrase를 탈취하려는 해커는 이미 시스템을 억세스 할 수 있어야 한다. 즉 해커가 이미 시스템의 사용자 어카운트나 루트 어카운트에 억세스 할 수 있다는걸 의미한다. 이 경우 passphrase를 사용하면 해커가 즉각 다른 서버에 로그인 하는걸 막아줄 수 있다. 즉 새로운 SSH key 쌍을 만들고 이미 탈취당한 키는 삭제할 수 있는 시간을 벌어줄 수 있다.
Private 키는 절대 네트웍에 노출되지 않고 파일 퍼미션으로 보호되기 때문에 당신(과 루트유저) 이외에는 이 파일에 접근할 수 없다.
Passphrase는 옵션이기 때문에 입력해주면 이후에는 (SSH agent를 사용하지 않는 한) 이 키를 사용할 때 마다 passphrase를 입력해 줘야 한다. Passphrase를 사용하는걸 권장하지만, 원하지 않는다면 그냥 엔터를 눌러주면 된다.
Your identification has been saved in /home/username/.ssh/id_rsa.
Your public key has been saved in /home/username/.ssh/id_rsa.pub.
The key fingerprint is:
a9:49:2e:2a:5e:33:3e:a9:de:4e:77:11:58:b6:90:26 username@remote_host
The key's randomart image is:
+--[ RSA 2048]----+
| ..o |
| E o= . |
| o. o |
| .. |
| ..S |
| o o. |
| =o.+. |
|. =++.. |
|o=++. |
+-----------------+
이제 인증에 사용할 수 있는 private 키와 public 키 쌍을 만들었다. 다음 단계는 public키를 서버에 넣어줘 SSH key를 인증에 사용할 수 있게 해 주는 것이다.
서버에 public 키를 카피하기
- SSH-Copy-ID
서버에 public키를 복사하는 가장 쉬운 방법은 ssh-copy-id 라는 유틸리티를 사용하는 것이다. 간단하기 때문에 가능하다면 가장 권장하는 방법이다.
ssh-copy-id는 OpenSSH 패키지에 들어있기 때문에 로컬 시스템에 이미 설치되어 있을 가능성이 크다. 이 방식을 사용하려면 먼저 서버에 패스워드로 ssh 억세스가 가능해야만 한다.
이 유틸리티를 사용하려면 연결하려는 원격 호스트 이름과 유저 어카운트를 지정해 주면 된다.
$ ssh-copy-id test@foo.bar.com
명령을 입력하면 다음과 같은 메시지가 출력된다.
The authenticity of host 'foo.bar.com (111.111.11.111)' can't be established.
ECDSA key fingerprint is fd:fd:d4:f9:77:fe:73:84:e1:55:00:ad:d6:6d:22:fe.
Are you sure you want to continue connecting (yes/no)? yes
메시지의 내용은 로컬 컴퓨터가 원격 컴퓨터를 식별할 수 없다는 의미이다. 새 호스트에 처음으로 접속하는 경우 발생한다. 'yes'와 엔터를 눌러 계속 진행한다.
유틸리티가 로컬 어카운트의 기존에 만들어 놓은 id_rsa.pub 키를 찾는다. 키를 찾으면 원격 컴퓨터의 유저 어카운트 패스워드를 묻는다. (예에서는 foo.bar.com 서버의 test 어카운트의 암호)
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
test@foo.bar.com's password:
암호를 입력하고 엔터를 누르면 유틸리티는 입력한 암호를 사용해 원격 호스트의 어카운트에 연결한다. 그리고 로컬 어카운트에 있는 ~/.ssh/id_rsa.pub 키파일의 내용을 원격 호스트 어카운트의 ~/.ssh 디렉토리에 있는 authorized_keys 에 복사한다.
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'test@foo.bar.com'"
and check to make sure that only the key(s) you wanted were added.
이제 자신의 id_rsa.pub 파일이 서버에 업로드 된 것이다.
- 수동으로 복사
로컬 머신 어카운트의 id_rsa.pub 키 파일 내용을 SSH로 로그인하길 원하는 서버 어카운트의 ~/.ssh/authorized_keys 파일에 복사해 넣어주면 된다.
먼저 id_rsa.pub 키 파일 내용을 화면에 출력한다.
$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCqql6MzstZYh1TmWWv11q5O3pISj2ZFl9HgH1JLknLLx44+tXfJ7mIrKNxOOwxIxvcBF8PXSYvobFYEZjGIVCEAjrUzLiIxbyCoxVyle7Q+bqgZ8SeeM8wzytsY+dVGcBxF6N4JS+zVk5eMcV385gG3Y6ON3EG112n6d+SMXY0OEBIcO6x+PnUSGHrSgpBgX7Ks1r7xqFa7heJLLt2wWwkARptX7udSq05paBhcpB0pHtA1Rfz3K2B+ZVIpSDfki9UVKzT8JUmwW6NNzSgxUfQHGwnW7kj4jp4AT0VZk3ADw497M2G/12N0PPB5CnhHf7ovgy6nL1ikrygTKRFmNZISvAcywB9GVqNAVE+ZHDSCuURNsAInVzgYo9xgJDW8wUw2o8U77+xiFxgI5QSZX3Iq7YLMgeksaO4rBJEa54k8m5wEiEE1nUhLuJ0X/vh2xPff6SQ1BL/zkOhvJCACK6Vb15mDOeCSq54Cr7kvS46itMosi/uS66+PujOO+xt/2FWYepz6ZlN70bRly57Q06J+ZJoc9FfBCbCyYH7U/ASsmY095ywPsBo1XQ9PqhnN1/YOorJ068foQDNVpm146mUpILVxmq41Cj55YKHEazXGsdBIbXWhcrRf4G2fJLRcGUr9q8/lERo9oxRm5JFX6TCmj6kmiFqv+Ow9gI0x8GvaQ== test@localhost
원격 호스트에 로그인 한 다음 먼저 홈 디렉토리에 .ssh 디렉토리가 만들어 져 있는가 확인한다. 만일 없다면 다음 명령으로 만들어준다.
$ mkdir ~/.ssh
이제 .ssh 디렉토리 안에 authorized_key 파일이 없으면 만들고, 이미 존재하면 파일 내용에 추가해주면 된다.
$ echo [public_key_string] >> ~/.ssh/authorized_keys
위의 명령에서 빨간색 [public_key_string] 부분은 위의 cat 명령에서 출력된 결과로 바꿔줘야 한다. (위에서 노란색으로 칠해진 부분)
SSH 키를 사용해 서버에 로그인하기
서버에 public 키를 카피해 놓았다면 원격 호스트에 로그인 할 어카운트의 암호 없이 로그인이 가능하다. 로그인 절차는 완전 동일하다.
$ ssh test@foo.bar.com
만일 이 호스트에 SSH로 첫번째 접속하는 것이면 다음과 같은 메시지를 보게 될 것이다.
The authenticity of host 'foo.bar.com (111.111.11.111)' can't be established.
ECDSA key fingerprint is fd:fd:d4:f9:77:fe:73:84:e1:55:00:ad:d6:6d:22:fe.
Are you sure you want to continue connecting (yes/no)? yes
Private 키에 passphrase를 지정해 주지 않았다면 곧바로 로그인이 된다. 만일 키 쌍을 만들 때 private 키에 passphrase를 지정해 주었다면 passphrase를 물어본다. 인증이 성공되면 쉘 세션이 열리게 된다.
애초에 원격호스트의 정체를 확정할수 없어서 키를 사용하는건데 the authenticity of host can't be establiosehd. 라고 경고해주는데 그냥 yes 눌러서 쉘접속후에 내 개인 키를 업로드를 한다는게 이해가 안되네요....
답글삭제개인키를 업로드 하는것이 아니라 공개키를 업로드 하는것입니다. 원격호스트의 정체를 확정할수 없어서 키를 사용한다는 전제가 이해가 안가네요. 이 기능은 내가 지식기반의 인증(password)을 접속할때마다 수행하던것을 '내가 업로드시키는 공개키와 쌍이 맞는 개인키가 저장되어있는 컴퓨터가 접속하는 경우 패스워드 입력없이 인증을 성공시켜라' 라는 기능이니까요.
답글삭제안녕하세요. 저는 Window 10에서 Client로 Window 10 SSH Server에 암호없이 접속 테스트를 하려고 하는데요.. Client에서는 private key, public key를 rsa 명령어를 통해서 만들었고, 서버에는 user 폴더에 .ssh 폴더를 만들어서 authorized_keys 라는 파일을 만들어 그안에 Client의 public key 내용을 복사했습니다. 그리고 최종적으로 client에서 cmd로 ssh 서버 접속을 하는데 password 를 물어보네요... 접속 할때마다 password를 물어보는데 제가 뭘 놓친걸까요??
답글삭제감사합니다.
window에서는 해당키가 어느 서버의 키인지 모를겁니다. 연결시에 해당 키가 없다고 인식하니까요. 해당 부분을 해결하세요
삭제