Notice
Recent Posts
Recent Comments
Link
«   2025/08   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Archives
Today
Total
관리 메뉴

걍생

[9회차] ssh tunneling 본문

스터디

[9회차] ssh tunneling

apark 2025. 6. 22. 18:31

내가 만든 서버를 띄우거나, 다른 서버와 통신하거나, 사내 개발 서버에 붙어서 작업하거나 등

ssh는 IT 업계 종사자면 절대 모르면 안 되는 개념 중 하나이다.

 

대학생 시절 과 서버에 접속해 과제 할 때 처음으로 ssh를 접했는데, 당시에는 머신의 cmd를 쓰지 않고 putty로 접속했었다.

(그때만 해도 putty가 없으면 서버에 접속 못 하는 줄 알았음 ;;)

 

회사에 들어와 여러 업무를 하다 보니 단순히 서버에 접속하는 것뿐만 아니라

포트 포워딩 (virtualbox 게시글에서 살짝 언급하긴 했지만)이나 ssh tunneling 같은 작업이 필요하게 되었고,

꽤나 빈번하게 필요하게 되었는데 헷갈려서 이참에 잘 정리해 두기로 했다. 


 

먼저 SSH란, Secure Shell의 줄임말로 원격 호스트에 접속하기 위해 사용되는 보안 프로토콜이다.

원래는 텔넷(Telent)을 사용했다고 하는데 암호화를 제공하지 않아서 wireshark 같은 패킷 분석 프로그램으로 누구나 쉽게 데이터를 탈취할 수 있어서 이를 암호화는 ssh 기술이 등장, 현재는 원격 접속 보안을 위한 필수 요소가 되었다. 

(ssh의 자세한 작동 원리를 이해하기 위해서는 암호화에 대해 기본 지식이 있어야 하는데, 이건 나중에 다른 포스팅에서 다루도록 하겠다.)

 

그럼 ssh 터널링이란 무엇일까? (ssh 포트 포워딩이라고도 한다.)

단적으로 설명하자면 프록시라고도 할 수 있다. 그럼 대체 무엇을 위한 프록시인가? 

예를 들면 A 서버의 80번 port에서 기동 중인 서비스에 접근해야 하는데, 정작 A 서버의 방화벽이 ssh port 22번 port)만 열려 있다면 80번 port로는 서비스 접근이 어렵다.

 

이때 포트 포워딩을 사용하면 80번 port의 서비스에 접근이 가능하다.

80번 port와 22번 port를 매핑해서 ssh 터널링을 생성하고, 사용자가 서비스를 요청하면 해당 요청은 먼저 22번 port로 전송된 뒤 A 서버 내부에서 80번 port로 다시 포워딩되는 것이다.

 

 

 

그림처럼 ssh 터널링이 수립되고 나면

모든 request/response는 80번 port에 접근할 필요 없이 22번 port를 통해서 이루어지게 된다.

즉, ssh 서버가 터널링을 통해 데이터를 주고받을 수 있도록 해 주는 일종의 프록시 역할을 수행하게 되는 것이다.

ssh 터널은 ssh 연결 수립 뒤 외부로부터 데이터를 보호할 수 있는 일종의 연결 통로인 셈이다. 

물론 어떤 기술이든 악용하려면 한도 끝도 없기 때문에...... 보안 위험이 있겠지만 우선은 기술 설명에 집중하겠다.

 


그래서 어떻게 쓰는 것인가?

터널링에도 여러 방식이 있지만 우선은 내가 자주 쓰는 방식에 한정해서 기록을 해 두려고 한다. 

(당연하다... 이 글은 미래의 나를 위한 글임) 

 

내 업무 환경에서는 위 그림처럼 서비스가 기동되어 있는 서버에서 몇 개의 외부 포트만 제공하는 경우가 대부분이므로

해당 경우에 대해 설명하겠다.

 

기본적인 ssh 터널링 명령어는 다음과 같다.

ssh -L {여기서 사용할 port}:{접속할 서버 호스트 주소}:{접속할 서버 port} -N {remote_usr}@{remote+_host}

 

물론 이렇게만 보면 무슨 뜻인지 잘 모를 것이다. 

 

위의 그림으로 다시 설명해 보겠다.

내가 만약 A 서버에 떠 있는 서비스에 접속을 해야 하는데, 해당 서비스가 2025번 port에 떠 있다고 가정해 보자.

그리고 나는 현재 내 서버의 4080번 port를 사용해서 A 서버의 2025번 port와 통신하고 싶은 것이다.

 

그렇다면 다음과 같이 명령어를 작성하면 된다. 

ssh -N -L 4080:localhost:2025 root@123.456.78.9

 

그런데 이때, 만약 A 서버로 ssh 통신을 하기 위해 22번 port가 아니라 다른 port (예시에서는 10970라고 해 보겠음)를 사용해야 한다면 다음과 같이 구성하면 된다.

(간혹 외부 인스턴스를 대여해서 사용하게 되면 제공하는 ssh 명령어에 포트 번호 지정 명령어 `-p` 가 들어가 있는 경우가 그런 경우임) 

ssh -N -L 4080:localhost:2025 -p 10970 root@123.456.78.9

 

 

 

그런데 만약 port 번호 뿐만 아니라 ssh key (*.pem)까지 필요하다면?

ssh -i "server_key.pem" -N -L 4080:localhost:2025 -p 10970 root@123.456.78.9

 

위와 같이 ssh에서 쓰는 대로 `-i` 를 추가해 주면 된다.

하지만 이걸 하게 되면 터미널에 hang이 걸리기 때문에, 다음과 같이 nohup을 사용하는 방식도 있다.
(이 버전을 제일 많이 사용함)

nohup ssh -i "server_key.pem" -N -L 4080:localhost:2025 -p 10970 root@123.456.78.9 > nohup.out 2>& 1 &

 

 

물론 나는 autossh라는 툴을 제일 많이 사용한다. 

터널링이 끊기거나 일정 시간 이상 통신이 없어 ssh 접속이 끊길 경우 서비스에 문제가 생기기 때문이다.

autossh의 경우 ssh 연결이 중간에 끊어져도 자동으로 연결해 준다. 

 

ubuntu: 

sudo apt-get install autossh

 

RHEL 계열 OS (e.g. rocky):

sudo yum install autossh

 

 

그리고 기동 명령어는 다음과 같다.

autossh -f -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -i "server_key.pem" -N -L 4080:localhost:2025 -p 10970 root@123.456.78.9

내지는
autossh -N -f -L -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -i "server_key.pem" 4080:localhost:2025 -p 10970 root@123.456.78.9

 

간단히 arugment들을 설명하자면,

  • -M 0  : ssh 연결이 끊어졌는지 감지하기 위한 모니터링 포트. (built-in 포트 사용하라는 뜻)
  • -N     : "no command"라는 의미. ssh를 사용해서 원격 서버에 접속하지 않고 ssh 터널링만 만든다.
  • -f: 백그라운드 실행
  • -o "ServerAliveInteval 30" : keepalive 패킷을 30초마다 전송
  • -o "ServerAliveCountMax 3": keepalive 패킷 3개가 연속으로 전송 실패 시 ssh 연결을 다시 시도.

(여기서 잠깐, keepalive 패킷이란? ssh 클라이언트가 ssh 서버로 요청을 일정 시간동안 보내지 않으면 위에서 언급했듯이 ssh 연결이 끊어지는데, 이를 방지하기 위해 ssh 클라이언트가 일정 시간마다 keepalive 패킷을 보내서 연결을 유지하는 것이다.)