에러, 문제 해결

SSH 터널링

taehyuck 2026. 3. 2. 17:29
728x90

[삽질 일기] 온프레미스 서버에서 숨겨진 NCP Private DB 뚫기: 위대한 점프서버와 SSH 터널링

오늘도 평화롭게 코딩을 하고 있었다. 로컬 개발 환경에서는 잘 돌아가던 코드를 **온프레미스 서버(사내 물리 서버)**에 배포하는 순간, 평화는 깨졌다.

Connection timed out: connect...

빨간색 에러 로그가 화면을 가득 채웠다. 아... 서버가 DB를 못 찾는다. 알고 보니 내가 사용하려는 NCP(Naver Cloud Platform)의 데이터베이스가 Private Subnet에 숨어 있었던 것이다. 외부(온프레미스)에서는 당연히 접근 불가능한 '성역'에 있었던 셈.

오늘은 이 철벽같은 Private DB에 온프레미스 서버가 접속할 수 있도록 **점프서버(Bastion Host)**를 이용해 길을 뚫어준 과정을 기록으로 남긴다.


1. 문제 상황: 너는 닿을 수 없는 곳에

상황은 이랬다.

  • 내 서버: 회사 전산실에 있는 온프레미스 서버 (외부 인터넷망)
  • DB: NCP 클라우드 내부의 Private Subnet에 위치 (공인 IP 없음, 사설 IP만 존재)

Private DB는 보안상 외부 인터넷과 차단되어 있다. 내 온프레미스 서버가 아무리 문을 두드려도, NCP의 보안 그룹(ACG)과 네트워크 구조상 절대 닿을 수 없는 구조였다.

그림처럼 내 요청은 방화벽 앞에서 가로막혀 갈 곳을 잃고 타임아웃만 뱉고 있었다.


2. 해결책: 점프서버(Jump Server) 소환

이 문제를 해결하려면 **"다리"**가 필요하다. NCP 내부의 Public Subnet(외부와 통신 가능)에 있는 서버 하나를 섭외했다. 우리는 이걸 점프서버(Jump Server) 또는 **배스천 호스트(Bastion Host)**라고 부른다.

  • 점프서버는 **공인 IP(Public IP)**가 있어서 내 온프레미스 서버가 접속할 수 있다.
  • 점프서버는 같은 VPC 내부에 있어서 Private DB와 통신할 수 있다.

즉, "온프레미스 -> 점프서버 -> Private DB" 순서로 데이터를 토스해주면 된다. 이걸 기술적으로 구현하는 방법이 바로 **SSH 터널링(Tunneling)**이다.


3. 실전: SSH 터널링 뚫기 (따라해보자)

이제 온프레미스 서버의 터미널을 열고 터널을 뚫어보자. 원리는 간단하다. "내 서버의 특정 포트(예: 9999)로 들어오는 신호를 점프서버를 통해 저쪽 DB 포트(1433)로 보내줘!" 라고 명령하는 것이다.

준비물

  1. 점프서버 접속 정보: 공인 IP, 계정 ID, PEM 키 파일 (또는 비밀번호)
  2. 타겟 DB 정보: Private IP (사설 IP), 포트 번호 (MSSQL은 보통 1433)

SSH 터널링 명령어 (리눅스/맥 터미널)

온프레미스 서버에서 아래 명령어를 입력한다.

Bash
 
ssh -N -L [로컬포트]:[DB_Private_IP]:[DB_포트] -i [PEM키경로] [점프서버계정]@[점프서버_Public_IP]

예시 상황

  • 내 서버에서 사용할 포트: 9999 (아무거나 빈 거 쓰면 됨)
  • DB Private IP: 192.168.1.50
  • DB 포트: 1433 (MSSQL)
  • 점프서버 IP: 203.0.113.10
  • 점프서버 계정: root
  • 키 파일: key.pem

실제 명령어 입력

Bash
 
ssh -N -L 9999:192.168.1.50:1433 -i ./key.pem root@203.0.113.10

옵션 설명 (이게 중요함!)

  • -L (Local Port Forwarding): 가장 중요한 옵션. "로컬 포트를 리모트 호스트로 연결해라"라는 뜻.
    • 구조: 내_컴퓨터_포트:최종_목적지_IP:최종_목적지_포트
  • -N: "명령어 실행하지 마". 터널링만 연결하고 쉘 접속은 안 하겠다는 뜻이다. 이걸 안 쓰면 점프서버 터미널로 들어가져 버린다. (백그라운드에서 조용히 길만 열어둠)
  • -i: 접속에 필요한 인증 키 파일 경로.

4. 코드 수정: 이제 DB는 '로컬'에 있다

터널링이 성공했다면(에러 없이 커서가 깜빡이거나 멈춰있으면 성공), 이제 내 온프레미스 서버 입장에서 Private DB는 마치 내 컴퓨터의 9999번 포트에 있는 것과 같다.

따라서 애플리케이션(Java/Python 등)의 DB 설정 파일(application.yaml 등)을 수정해야 한다.

수정 전 (직접 접속 시도 - 실패)

YAML
 
spring:
  datasource:
    url: jdbc:sqlserver://192.168.1.50:1433;... # Private IP로 직접 가려니 실패

수정 후 (터널링 경유 - 성공)

YAML
 
spring:
  datasource:
    url: jdbc:sqlserver://localhost:9999;... # 내 서버의 9999로 보내면 터널 타고 DB로 감!

핵심 포인트: 호스트는 localhost(또는 127.0.0.1), 포트는 내가 -L 옵션 맨 앞에 적었던 9999를 써야 한다.


5. 오늘의 교훈

  1. 보안은 불편하다, 하지만 이유가 있다: DB를 Private Subnet에 두는 건 보안의 기본이다. 불편하다고 Public으로 열어버리면 해킹 맛집이 된다.
  2. SSH는 만능이다: 단순히 원격 접속 도구인 줄 알았는데, 네트워크 길을 뚫어주는 터널링 기능은 정말 강력하다.
  3. 점프서버 관리를 잘하자: 점프서버가 털리면 내부망이 다 털리는 거다. 점프서버 보안 그룹(ACG) 설정도 빡빡하게 해야 한다.

오늘의 삽질 끝! 다음엔 이 터널링을 매번 명령어로 치기 귀찮으니 AutoSSH로 서비스 등록하는 걸 해봐야겠다.

728x90