상세 컨텐츠

본문 제목

[SSH] SSH 연결 자동화 설정 개념/config/문제해결

IT 이야기/IT 상식

by 리치윈드 - windFlex 2023. 1. 27. 17:56

본문

반응형

매번 SSH 연결.... 귀찮아~

 

Linux/Mac 및 Cloud 환경에서 개발을 하게 되면, 필연적으로 SSH 연결을 사용하게끔 된다. 

Windows 환경에서는 Putty, WinSCP 등을 사용하여 GUI 환경에서 연결하고, 자동화하는 수단이 다수 제공하고 있다. 

그러나, Linux or Mac 등에서는 이러한 자동화 혹은 GUI 툴이 부족한 편이다. 

그도 그럴것이, Terminal에서 기본적으로 OpneSSH Remote Login Client를 지원하기 때문에, 굳이 별도의 Application의 사용 필요성을 느끼지 못하는 부분도 있다. 그러나, 개발과 원격접속이 반복됨에 따라서 이러한 부분도 점점 귀찮아지는 상황이 발생하곤 한다. 

 

OpenSSH의 모든 기능을 이야기 하려면 끝도 없기 때문에, 이번 포스팅에서는 연결 자동화 하는 부분으로 한정하여 이야기 해 보려 한다. 

 

SSH (Secured Shell) 및 비대칭키 암호화, 자동화 설정하기

 

I. SSH 기본 연결

SSH의 가장 단순한 사용 형식은 다음과 같다. 

$ ssh <remote server address>

이후 프롬프트에서 Username / Password를 입력하고 로그인 할 수 있다. 그러나, 이러한 user/password 방식은 무작위대입공격(Brute-force Attack)등에 매우 취약하기 때문에 보안 강화 차원에서 Password 문구 대신에 Hash (RSA Private Key)로 이루어진 Key파일로 인증을 진행하는 것이 표준으로 자리 잡고 있다. 

SSH는 Secured Shell 의 약자로써, 여기에서 "Secured"는 암화화 연결을 의미한다. 반대로 암호화를 하지 않는 터미널 연결인 Telnet이 있는데, Telnet는 네트워크 상에 평문(텍스트)로 전송이 되기 때문에, Wireshark 등의 Packet Dump를 한다면, 패스워드를 포함한 모든 명령어가 노출될 수 있다. 이러한 단점 때문에, 접속하고자 하는 서버측에서는 암호화 채널을 생성하고, 이를 통하여 통신하도록 한다. 이 때 비대칭키 (Asymetric Key : Public/Private Key 쌍)을 사용하여 암호화 한다. 

이번 포스팅에서는 이러한 연결 Session을 암호화 할 때 사용하는 키를 거론하는 것은 아니다.  SSH 접속 시 세션 암호화에 대한 내용은 하단을 참조하도록 하자. 이번 포스팅에서 대상으로 하는 것은, 인증 (ex. 로그인)에 대한 키를 대상으로 한다. 간혹, SSH에서 키파일을 거론할 때 이러한 점이 혼동을 유발하기도 하기 때문에 거론한다. 잘 모르겠다면 넘어가도 좋다. 

 

 

II. SSH 키파일 로그인 

패스워드 입력 대신 "키파일"을 입력하는 방식으로 SSH를 접속한다면, 수정된 명령어 유형은 다음과 같다.  옵션 -i를 사용하여 키파일을 지정해 주면 된다. 또한, 원격서버를 지정할 때, 키파일을 사용하는 username을 지정해 줄 수 있다. 

$ ssh -i keyfilename username@<Remote Server Address>
옵션 -i : 키파일을 별도 지정한다. 일반적으로, 홈폴더(/Users/username) 하위에 .ssh/에 보관하는 것이 기본설정이다. 
더보기

[참조] URI 정의

인터넷에서 리소스를 지칭하는 URI는 본래적인 의미로, 사용자이름(user)와 패스워드(password)를 포함할 수 있다. 그 예중 하나로, http://user:password@host_address/ 형태가 될 수 있다. 즉, 위 SSH의 예에서 "username@<remote Server Address>" 중 username을 포함하는 것 자체가 URI이다. 이러한 예는, Github를 사용할 때에도 자주 확인할 수 있다.  

 

더보기

클라우드 환경에서 User/Password 로그인 금지

최근 클라우드 환경 (AWS, Azure 등)에서는 User/Password 로그인을 금지하도록 SSH 서비스 설정을 하고 있다.

  • 설정파일 : /etc/ssh/ssh_config 또는 /etc/ssh/ssh_config.d/*.conf 
  • 설정값 :
    "PasswordAuthentication no"

 

 

III. SSH 키파일 로그인 자동화 

`SSH -i <키파일>`을 통해서 username/password 없이 원격접속이 가능한 것은 알겠다. 
몇가지 의문이 생긴다.
키파일은 어떻게 생성하거나 구하는가?
어떤 구조이길래 가능한가? --> 즉, 어떻게 설정해야 하는가?

 

그렇다. 키파일을 통한 로그인이 무작정 될리 없다. 해당하는 비대칭키-쌍도 등록을 해 주어야 할것이다. 아무 키파일이나 로그인이 되지는 않을것 아닌가? 

 

근본적인 원리는, 구어체로 쓰면 다음과 같다. 

비대칭키 (공개키, 개인키 각각 다른 키)를 생성하고,
원격서버에 공개키를 주고, 개인키는 내가 보관하고,
원격서버에 접속할 때, 로그인으로 인증해 줄 사용자에 키를 할당 해줌

좀 더 실제적으로는, 서버에 키-파일을 등록하고 로그인 자동화를 하기 위해서 일반적으로 다음과 같은 단계로 진행한다. (클라우드에 따라서는 key 등록 과정들이 생략될 수 있다.)

  1. SSH-Keygen으로 비대칭키쌍 (Public Key, Private Key)를 생성 : ex) ssh-keygen -t rsa
  2. Server에 인증가능한 대상으로 등록 : authorized_keys에 등록 (public key를 추가함)
  3. ssh -i 로 접속 --> 로그인 자동화
  4. 추가적인 설정 : ~/.ssh/config 설정

1) ssh-keygen으로 비대칭키-쌍 생성

키파일의 생성은 여러가지 비대칭키 생성기가 있지만, Linux/Mac 등 환경에 기본 제공하고 있는 `ssh-keygen`명령어를 사용하도록 하자. 

$ ssh-keygen 
or
$ ssh-keygen -t rsa
ssh-keygen 의 옵션 -t 를 통해서 암호화 알고리즘을 설정 할 수 있다. 기본적으로 로그인용 키파일은 RSA알고리즘을 많이 사용한다. SSH Session을 암호화하기 위해서 ecdsa 등을 사용하기도 한다.
옵션 설정은 다음과 같이 설정 할 수 있다.  [-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa]

ssh-keygen 실행 결과. 옵션 없이 실행하는 경우 기본값으로 RSA알고리즘을 사용한다. passphrase는 키파일에 사용할 패스워드이다. 그냥 엔터를 입력해도 좋고, 키파일에 패스워드를 추가할 때 입력해주면 된다.

ssh-keygen 명령어를 실행하면, RSA 공개키/개인키 쌍 (public/private pair)를 생성해 준다. 기본 설정은 각각 다음 파일에 공개키, 개인키를 저장하도록 하고 있다. 별도 파일을 지정하여 저장할 수 있다. 변경없이 진행한다면 그냥 엔터를 눌러주자. (위 실행 결과에서는 "test_key"와 "test_key.pub"에 각각 개인키와 공개키가 저장되었다. )

  • 개인키 : ~/.ssh/id_rsa
  • 공개키 : ~/.ssh/id_rsa.pub ==> 이후, 원격 서버 authorized_keys로 복사

이 때, Fingerprint가 같이 구해 진다. 출력된다. Fingerprint는 Key File을 검증하기 위해 사용된다. Fingerprint는 공개키의 해쉬값이다. (위 예에서는 SHA256, 알고리즘에 따라서 Salt가 추가 된다.). 이러한 Fingerprint는 ssh 연결에서 "known_hosts"에 사용된다. 또한 github 등의 deploy_key 등의 위변조를 확인 용도로 자주 접할 수 있다. 

`ssh-keygen -l -f <공개키 파일명>` 을 통해서 해당 키의 fingerprint를 다시 확인 할 수 있다. 

 

2) 공개키 원격서버에 등록

공개키/개인키를 확보했다면, 서버에 해당 유저가 사용할 키로 등록해 주어야 한다. 이 후 만약 해당 User로 접속할 경우, 패스워드 입력 대신에 Keyfile로 인증을 대체 하게 되는 것이다. 이러한 역할을 하는 파일이 `~/.ssh/authorized_keys`에 등록된다. 이미 등록되어 있는 authorized_keys 파일을 열어서 확인해 보면, 등록한 공개키(public key)와 동일하다. 즉, 인증받고자 하는 공개키를 `~/.ssh/authorized_keys`로 복사해 주면 된다. (기존에 authorized_keys가 존재한다면 다음 행에 공개키를 추가한다.)

원격 서버의 ~/.ssh/authorized_keys는 클라이언트의 공개키를 복사한 것이다. 이후, 개인키를 사용하여 원격서버에 인증을 요청하면, 권한이 부여된다.

즉, 패스워드 입력없이 SSH 접속을 하려면, 다음처럼 진행 하면 된다. 

  1. rsa 공개키/개인키 쌍을 생성한다. 
  2. rsa 공개키를 원격서버로 복사한다. 
  3. 복사한 공개키를 원격서버의 ~/.ssh/authorized_keys로 변경하거나, 추가 한다. 

2-2) 클라우드 환경 Authorized_keys

이 과정이 처음에는 어렵고 번거로울 수 있다. 그런데, 요즈음 클라우드 서버들은 이러한 과정은 GUI/Portal로 처리하고 있다. 다음은 Azure Portal에서 VM을 생성할 때, SSH 공개키를 등록하는 과정이다. (VM 생성 이후에더 암호변경 메뉴에서 사후 설정할 수 있다.)

Azure Cloud Portal에서 VM을 생성 시, 관리자 계정에 대한 SSH 공개키 방식으로 설정 ==> 해당 계정에 Authorized_keys에 등록해 준다. 여기에서 사용된 공개키는 새롭게 생성하거나, 기존 키를 사용할 수 있다. 생성된 키는 Key Service에서 별도 관리된다.

실제 설정 완료, Provisioning 이 완료된 후에 해당 서버에 접속하여 확인해 보면 해당 계정의 Authorized_keys에 공개키가 등록되어 있는 것을 확인할 수 있다. 

Azure Cloud에서는 Key Service를 VM에 연결할 수 있다.

Azure 및 AWS의 경우, Key Service를 별도록 제공한다.

 

 

3) SSH 접속 ( ssh -i )

이제 SSH를 접속하기 위해 shell에서 다음과 같이 입력할 수 있다.

$ ssh -i ~/.ssh/id_rsa 계정이름@<원격서버>
ex) ssh -i ~/.ssh/id_rsa user@testcloud.com

~/.ssh/id_rsa는 기본값이므로 파일명을 생략이 가능하다. 만약, 다른 파일에 개인키를 저장하고 있다면 이 파일을 명시해 주어야 할것이다. 

자.! 이제 패스워드 입력 환경 없이, SSH를 접속하는 환경이 세팅 되었다. 해당 명령어가 번거롭다면 스크립트 파일을 만들어서 단순화 할 수 도 있을 것이다. 또한, 다음장에서 소개하는 `.ssh/config`를 통해서 더욱 단순화 할 수 있다. 

 

4) 발생 가능한 이슈/문제점

키파일을 사용하여 SSH를 접속할 때, 빈번하게 발생하는 문제점중 하나는 아래와 같이 "UNPROTECTED PRIVATE KEY FILE!"이라는 경고가 출력되면서 접속이 되지 않는 현상이다.

이것은 최소한의 보안 장치이다.  보안적인 관점에서 다음과 같이 생각해 볼 수 있다. 

으음.. 이렇게 되면 private key 파일만 있으면 누구든지 서버에 접속할 수 있는거 아냐??
좀...... 위험한데?

이러한, 이유로 키파일은 좀더 타이트하게 관리되어야 한다. 따라서, 해당 소유자만 읽기(READ)을 가지며, 다른 모든 사용자는 권한을 제거하도록 강제하고 있다. 위 경고는 소유자 외에도 리드권한이 있기 때문에 키파일로써 허가하지 않는다는 의미이다. 만약, 개인PC가 아닌 다중사용자 환경 (서버 등)에서 644 권한을 가진 키파일이 사용된다면, 다른 권한없는 사용자들도 해당 서버에 SSH로 접속할 수 있게 될것이다. 이러한 이유로, 키파일 (개인키)는 600 혹은 400 (소유자만, 읽거나/쓰기 권한)으로 설정되어 있어야만 동작하도록 강제하고 있다. 

다음과 같이 수정해 주면 해결 할 수 있다. 

$ chmod 400 ~/.ssh/test_key

 

III. SSH Config

우리는 SSH 접속할 때 매번 패스워드 입력을 하는 작업을 단순화 하였다. 그러나, 원격 개발을 하는 과정에서 반복적으로 접속을 하거나 다수개의 터미널을 사용하여 처리하는 일이 빈번하다. 패스워드 입력 없이 SSH를 접속하더라도 매번 키파일을 지정하고, 기억 나지도 않는 IP 혹은 Domain 등을 입력하기도 번거로운 것이 사실이다.  Putty 등은 기존 접속이력을 보관하여 버튼 클릭 한번이면 재접속이 가능하기도 하다. (보안에 유의하자...!!!)

$ touch ~/.ssh/config
만약, 이미 config 파일이 존재한다면, 편집으로 추가 하면 된다. 

~/.ssh/config 에는 우리가 command line에 Argument로 입력할 사항을 미리 적어두면 된다. 다음은 하나의 예이다. 

Host remote-server
    HostName mytest-server.example.com
    User testuser
    IdentityFile ~/.ssh/test_key

첫째줄에 Host는 나중에 ssh 접속 시 사용할 별칭 (alias)가 된다. 둘째줄 부터 설정 값으로 각각, 접속할 원격서버의 IP/도메인네임, 접속할 사용자 계정, 마지막으로 개인키 파일을 지정한다. 설정이 완료된 경우, 앞으로 다음과 같은 명령만으로 SSH 접속을 단순화 할 수 있다. 

 

$ ssh remote-server

 

어떠한가? 정말 단순해 지지 않았는가?
복잡하게 도메인이름이나, IP를 기억하지 않아도 된다. 
각 서버마다 다른 키파일을 기억하거나 입력하지 않아도 된다. 

 

 

오늘도 삽질을 줄여보자.....

 

IV. 기타

[ known_hosts ]

~/.ssh 디렉토리를 살펴보면, `known_hosts`라는 파일이 있다. 이 파일의 용도는 무엇일까?

파일을 열어서 확인해 보면, 다음과 같이 도메인이름과 해시 값들이 열거되어 있다. 

$ cat ~/.ssh/known_hosts

known_hosts 파일 내용. 도메인-해시값이 나열되어 있다.

결론적으로, `known_hosts`파일은 fingerprint 값을 저장하고 있다. 앞서 잠깐거론 했듯이, fingerprint는 공개키의 해시값에 해당한다. 결국, 이 fingerprint라는 해시값은 해당 Client(접속하는 서버도 Client가 될 수 있다)에서 인지하고 있는 원격서버가 정확한지? 변조는 없었는지를 검증하는 용도이다. 

원격 서버가 SSH 데몬서비스를 오픈하면 기본적으로 세팅된 공개키가 존재한다. 이것은 SSH에서는 HostKey라고 한다. 또한, 이 HostKey는 SSH 데몬서비스인 sshd의 설정값에 따라서 다른 인코딩 알고리즘을 사용한다. 다음은 서버에 일반적으로 존재하는 지원하는 알고리즘별로 공개키를 fingerprint 해 둔 파일들이다. 

예를 들면, 위 예제의 서버에서는 ed25519 알고리즘을 HostKey로 사용하고 있다. 따라서, Client (위 예제 서버에 접속하는 Client)의 `known_host`에는 위에 표기된 `ssh_host_ed25519_key.pub`에 기록된 해시값이 입력되게 된다. 

 

그런데, 이러한 fingerprint는 왜......? 필요한건데..?
결론은 보안 때문이다. 

앞서 거론했듯이, 핑거프린팅(fingerprint)은 공개키를 검증하는데 사용하고 있다. 

우리가, 최초 ssh로 서버에 접속하게 되면, fingerprint를 known_host에 등록하겠냐는 질문을 받는다. (대부분 엔터를 입력하므로 등록된다.) 따라서, 우리는 `www.example.com`이라는 원격서버에 접속해서, 공개키를 기준으로 핑거프린트를 등록해 두었다. 이것은 다음과 같은 작업을 의미한다. 

 

www.example.com의 공개키는 "xxx"값이다. 이것을 빠르게 검증하기 위해 fingerprint 사용할께~

이런 상황에서 만약, 어떠한 이유에서 공개키가 변경될 수 있다.

  • 동일한 "ww.example.com"에서 hostkey가 변경된 경우 --> 이런 경우는 정상이므로 제외하도록 하자.  
  • "www.example.com"을 위장한 다른서버로의 접속
  • /etc/hosts 파일 변경 등으로 인한, 다른 서버 접속
  • 중간에 proxy 이 중간에 껴서 대상 서버가 달라지는 경우

특히, 마지막의 경우를 우리는 중간자공격 (MITM : Man In The Middle)이라고 하는데, fingerprint는 이러한 공격을 방지하고자 함이다. 내가 분명히 "www.example.com"으로 접속했을 때, 접속한 대상이 과거에 기록된 "www.example.com"의 HostKey와 동일함을 확인하는 것이다. 그렇지 않고, 위장서버 또는 중간에 가로채기 등이 존재하는 경우, HostKey가 변경될 것이고, 이 변경사항을 Fingerprint로 빠르게 확인 할 수 있다. 


[Visual Studio Code - Extension]

Visual Studio Code에서는 다양한 확장App을 제공한다. 이중에서 Remote-SSH를 제공하는데, Microsoft가 제공/유지 관리하여 상당히 신뢰성을 가지고 사용해 볼만 하다. "Remote-SSH 호스트에 연결" 명령어를 통하여 쉽게 서버에 접속하고, Visual Stuiod Code 환경으로 편집/개발을 할 수 있으며, Terminal도 오픈하여 사용할 수 있다. 굳이 Code를 작성하는 시점이 아니더라도, Terminal 사용 환경으로도 우수한 환경을 지원한다. 

그러나, 항상 Visual Studio Code를 사용할 수 있는 환경만 있는 것은 아니므로, 기본기는 갖추어야 할 것이다. 툴을 최대한 이용하되 툴에 종속되지는 말자....!!!

 

 

반응형

관련글 더보기

댓글 영역