들어가며
ssh 연결이란 무엇일까? 간단하게 생각한다면 22번 포트로 원격 접속을 하는 것? 간단하게 클라우드 서비스를 사용할 때까지만 해도 22번 포트로 원격 접속을 하는구나 정도로 알고 있었지만 linux 환경에서 사용자에게 컴퓨팅 리소스를 제공하는 서비스를 하기 시작하면서 ssh에 대해 깊은 이해를 전달하고자 포스팅을 작성한다.
처음에 ssh 연결이 생각했던 것과는 다르게 동작하는 것을 보면서 호기심이 점점 생겼다. 지금 일하는 곳에서 linux를 굉장히 하드하게 쓰게 되다보니 ssh에 대해서 자세히 공부해야할 때가 있었는데, 관련해서 ssh가 뭔지 깊게 정리해서 포스팅하면 좋을 것 같아 글을 쓰게 되었다.
본론
SSH(Secure Shell)은 네트워크 연결을 통해서 다른 컴퓨터에 연결하거나 로그인하거나 명령을 실행하고 파일을 전송할 수 있는 암호화된 네트워크 프로토콜이다. SSH는 보안이 중요한 환경에서 널리 사용되며, 특히 원격 서버 관리 및 파일 전송에 많이 사용됩니다. SSH는 데이터 통신, 원격 명령어 실행, 원격 로그인, 그리고 다른 보안 네트워크 서비스들 사이의 데이터를 안전하게 암호화한다.
정의는 조금 어렵지만, 간단하게 설명하면 TCP 통신으로 컴퓨터의 22번 포트를 통해서 Shell로 원격 접속을 한다는 것이다. 그렇기 때문에 호스트의 22번 포트를 함부로 열어두는 것은 위험할 수 있다! 실제로 조직(회사, 학교 등)의 전산과 등에 요구할 때, 22번 포트를 열어달라고 하면 반려당하는 경우가 꽤나 있다. 예시를 먼저 살펴보면서 ssh가 뭔지 깊게 알아보자.
사례
ssh가 활용되는 사례로는 다음과 같다.
- 원격 로그인 : SSH를 통해 원격 서버에 로그인하고 명령어를 실행할 수 있다.
- 파일 전송 : SCP(Secure Copy)나 SFTP(Secure File Transfer Protocol)를 사용하여 파일을 안전하게 전송할 수 있다.
- 포트 포워딩 : ssh 명령어 중 -L 명령어를 통해 포트 포워딩을 수행할 수 있다.
- VPN 대체 : 프록시 서버에 ssh을 연결함으로써 vpn을 대체하는 일을 처리할 수 있다.
위와 같은 일들을 수행하는 것을 도와주는 것이 ssh이다. ssh 연결을 시도하는 경우에 어떻게 ssh 연결이 일어나는 지 그림으로 살펴보면 아래와 같다.
먼저 client에서 연결을 시도하면 server에서 public key를 넘겨준다. 해당 키를 검증하면 서버와 클라이언트는 세션 키를 교환하여 암호화된 터널을 열고, 클라이언트에서는 password나 private key를 넘겨주기 시작한다.
ssh의 기본적인 연결은 아래와 같다.
ssh username@192.168.0.10
이 내용은 말 그대로 192.168.0.10 IP를 가진 서버에 username을 들고서 연결하겠다는 뜻이 된다. 위 그림의 첫 번째 과정으로 22번 포트가 막혀있거나, 혹은 username이 틀렸다면 ssh 연결이 차단된다.
연결이 되어 서버에서 공개키를 받게 되면 session key 교환을 통해서 보다 안전하게 정보를 받는다. 이 때, password를 입력하거나 -i를 통해 붙인 private key를 서버와 주고받으며 안전하게 신원을 검증한다.
ssh username@192.168.0.10 -i .ssh/username.pem
위와 같이 ssh 연결에 -i(identity file) 파라미터를 통해서 인증서(.pem or .key) 등을 붙여주는 것을 통해 안전하게 서버에 접근할 수 있다. 원격 접속할 서버의 세팅에 따라 .pem 키를 필요로 하지 않는 경우도 있으며 보안을 위해서 일반적으로 .pem 키를 사용하는 것이 좋다.
이 외에 다른 연결 방법 예는 아래와 같다. 이 외에도 다양한 파라미터를 통해서 ssh 연결을 할 수 있다. 원격 접속 서버에서 GUI를 보기 위해서는 -X 파라미터를 쓰고, 서버에서 ssh 연결을 위해서 다른 포트를 사용한다고 하면 -p 파라미터도 있다.
- 로컬 포트 포워딩 :
ssh -L 8080:remote_host:80 username@hostname
- 원격 포트 포워딩 :
ssh -R 8080:local_host:80 username@hostname
.ssh 디렉토리
다음으로는 .ssh 디렉토리에 대해서 살펴보자. linux를 사용하는 유저라면 ~/.ssh/ 에 ssh 관련 파일들이 저장되어 있다. 일반적으로 존재하는 파일들의 목록과 역할은 아래와 같다. ( linux를 기반으로 설명한다 )
- id_rsa : 기본 RSA 개인 키 파일, 유출하면 안된다.
- id_rsa.pub : 기본 RSA 공개 키 파일(.public), ~/.ssh/authorized_keys 에 추가되어 클라이언트 인증에 사용된다.
- authorized_keys : 서버 측에서 클라이언트의 공개 키를 저장하는 파일, 여기에 있는 클라이언트만 서버에 접근 가능
- known_hosts : 접근한 적 있는 호스트의 공개 키를 저장하는 파일
기본적으로 이러한 것들이 있다. authorized_keys와 known_hosts의 차이는 전자는 공개키만 한 줄씩 저장하지만, 후자는 어떤 host, ip, algorithm, public key 등을 가지고 있는지 다 적혀있다.
또한, 맨 처음에 ssh 연결을 서버에 시도할 때 서버에서 공개키를 준다고 했는데, 그 공개키는 클라이언트의 ~/.ssh/known_hosts 에 기록되어 있다.
여기까지 이해가 되었고, 독자가 ssh 연결을 꽤나 해봤다면 몇 가지 의문점이 들 것이다. 일반적으로 cloud 서비스를 쓴다고 가정하면 귀찮은 적당한 사용자들은 username & password로 접근할 수 있게끔 AWS의 EC2나 GCP의 Compute Engine을 빌려서 쓸 것이다. 하지만 안전성을 생각해서 key를 발급받는다고 하면 .pem 확장자로 끝나는 key를 줄 것이다.
그렇다면 ssh 연결의 전반적인 내용은 이해했을 것이다. 여기서 궁금증이 끝나지 않는 사람이라면 우리(client)가 발급받은 .pem 키의 정체와 서버(server)에서 가지고 있는 id_rsa, id_rsa.pub의 관계가 궁금할 것이다. 대체 어떻게 key를 비교하기에 ssh 연결이 안정적으로 이루어지는 것일까?
이에 대해 이야기하기 앞서 전통적인 ssh 방식은 클라이언트와 서버 모두 공개키와 개인키를 가지고 있다. 하지만 우리가 사용하는 AWS 서비스와 같은 곳에서는 사용자는 .pem 확장자를 가진 암호화된 개인키 하나가 떨어지게 되는데, 이러한 케이스(클라이언트가 개인키만 가지고 있는 경우)에 대해서 설명할 것이다.
.pem 그리고 ssh의 암호화 방식
AWS나 기타 클라우드 사용에서 우리는 .pem 키를 달랑 하나 받는다. 그리고 소중하게 간직하라는 경고문을 하나 받는다. 아마도 private key니까 응당 그럴 것이다.
근데, 위에 포스팅 했던 내용을 리마인드 해보면 뭔가 이상하다. ssh 연결에는 서로 개인키와 공개키가 있어야 하는거 아닌가? 애초에 server의 ~/.ssh/authorized_keys에 클라이언트의 공개키를 저장하지 않는가? 그런데 어떻게 사용자는 개인키 하나만 가지고 ssh 연결을 시도하는가?
필자가 ssh에 대해 깊게 조사하게 된 이유가 위 이유이다. 이러한 이유를 두괄식으로 서술하면 Diffie–Hellman algorithm과 Challenge-Response Authentication을 사용하기 때문이다!
먼저 Diffie–Hellman algorithm을 통해서 임시의 키를 생성하여 서로 비교하는 과정을 거친다. 이 알고리즘은 암호키를 교환하는 하나의 방법으로, 두 사람이 암호화되지 않은 통신망을 통해 공통의 비밀 키를 공유할 수 있도록 하는 방법이다.
Challenge-Response Authentication은 아래와 같다. 그림으로 살펴보면 아까의 과정에 아래와 같은 로직이 하나 더 추가되어 있는 것이다.
접속을 시도하면 서버에서 challenge-response라고 불리는 난수 혹은 임의의 데이터를 보내준다. clinet는 이러한 데이터를 받으면 .pem 키를 통해 디지털 서명 및 복호화(ssh에서는 일반적으로 디지털 서명을 사용한다)하여 서버에게 제공한다.
그렇게 되면 서버에서는 client의 공개키를 가지고 있는데, 서명된 응답을 .ssh/autherize_keys에 있는 공개키를 통해서 검증한다. 이러한 검증을 성공적으로 마치면 다시 기존의 ssh 연결 방식처럼 안전한 세션을 열어 ssh 연결을 수행한다.
이러한 Challenge-response authentication에 대한 레퍼런스는 위키피디아에서 참고하였다.
마치며
ssh 연결하는 과정에서 가끔씩 ssh-key 관련 명령어를 묻는 경우도 있고, 다양한 에러들이 많이 발생하곤 했었는데, 이렇게 정리를 거치다 보니까 왜 그런 에러가 일어났는 지 알 것만 같다.
'CS > network' 카테고리의 다른 글
RESTful API 원칙에 대해서 (1) | 2024.04.16 |
---|---|
nginx를 통한 https 접속 및 포트포워딩 (SSL/TLS) (0) | 2023.11.21 |
microsoft remote desktop을 통한 window 원격 접속 (1) | 2023.09.01 |