문제 상황
클라우드 환경에서 흔한 구성이 있다. 보안을 위해 내부 서버(DB, 앱 서버 등)는 외부에서 직접 접속할 수 없고, Bastion 서버(점프 서버)를 통해서만 접근할 수 있는 구조다.
[내 PC] → [Bastion 서버] → [내부 서버]
(공인 IP) (사설 IP)
이런 구조에서 내부 서버에 접속하려면 보통 두 단계를 거친다:
# 1단계: Bastion 서버에 접속
ssh user@bastion-host
# 2단계: Bastion에서 내부 서버에 접속
ssh user@internal-host
매번 두 번 SSH를 치는 건 번거롭고, 파일 전송(scp)은 더 복잡해진다. SSH ProxyJump를 사용하면 이 과정을 한 줄로 줄일 수 있다.
ProxyJump란?
OpenSSH 7.3(2016년)부터 추가된 기능으로, SSH 접속 시 중간 서버를 점프 호스트로 지정할 수 있다. 중간 서버에 셸을 열지 않고, TCP 포워딩만 수행한다.
핵심 포인트:
- Bastion 서버에 로그인하지 않고 통과만 한다
- 최종 목적지까지 암호화가 유지된다 (Bastion에서 트래픽을 볼 수 없다)
- 파일 전송(scp, rsync)도 동일하게 동작한다
기본 사용법: -J 플래그
ssh -J user@bastion-host user@internal-host
이 한 줄로 Bastion을 거쳐 내부 서버에 바로 접속한다.
예시
# Bastion(203.0.113.10)을 거쳐 내부 DB 서버(10.0.1.50)에 접속
ssh -J admin@203.0.113.10 dbadmin@10.0.1.50
포트가 다른 경우
# Bastion이 2222 포트를 사용하는 경우
ssh -J admin@203.0.113.10:2222 dbadmin@10.0.1.50
SSH Config로 영구 설정
매번 -J 플래그를 타이핑하는 건 여전히 번거롭다. ~/.ssh/config에 설정해두면 ssh internal-db만으로 접속할 수 있다.
# Bastion 서버
Host bastion
HostName 203.0.113.10
User admin
IdentityFile ~/.ssh/id_ed25519
# 내부 DB 서버 (Bastion 경유)
Host internal-db
HostName 10.0.1.50
User dbadmin
ProxyJump bastion
IdentityFile ~/.ssh/id_ed25519
이제 이렇게 접속한다:
ssh internal-db
파일 전송도 자연스럽게 동작한다:
# 내부 서버로 파일 복사
scp backup.sql internal-db:/tmp/
# 내부 서버에서 파일 가져오기
scp internal-db:/var/log/app.log ./
# rsync도 동일
rsync -avz ./deploy/ internal-db:/var/www/app/
다중 점프 (Multi-hop)
Bastion이 여러 단계인 경우도 지원한다.
[내 PC] → [Bastion 1] → [Bastion 2] → [최종 서버]
-J 플래그 방식
ssh -J user@bastion1,user@bastion2 user@final-host
쉼표로 구분하면 순서대로 점프한다.
SSH Config 방식
Host bastion1
HostName 203.0.113.10
User admin
Host bastion2
HostName 10.0.1.1
User admin
ProxyJump bastion1
Host final-server
HostName 10.0.2.50
User deploy
ProxyJump bastion2
체인처럼 연결된다: final-server → bastion2 → bastion1 → 인터넷.
ProxyJump vs ProxyCommand
SSH Config에서 비슷한 역할을 하는 ProxyCommand가 있다. 차이점:
# ProxyJump (간단)
Host internal
ProxyJump bastion
# ProxyCommand (구버전 호환)
Host internal
ProxyCommand ssh -W %h:%p bastion
| ProxyJump | ProxyCommand | |
|---|---|---|
| 도입 | OpenSSH 7.3+ | OpenSSH 5.4+ |
| 문법 | 간단 | 복잡 |
| 다중 점프 | 쉼표로 구분 | 중첩 필요 |
| 커맨드라인 | -J 플래그 | -o ProxyCommand=... |
OpenSSH 7.3 이상이면 ProxyJump를 쓰는 게 낫다. 더 간단하고 다중 점프도 깔끔하다.
OpenSSH 버전 확인:
ssh -V
실전 팁
1. Bastion 서버에 에이전트 포워딩
내부 서버 접속 시 로컬의 SSH 키를 사용하려면 에이전트 포워딩을 활성화한다:
Host bastion
HostName 203.0.113.10
User admin
ForwardAgent yes
보안 주의:
ForwardAgent는 Bastion 서버의 root가 에이전트 소켓에 접근할 수 있으므로, 신뢰할 수 있는 서버에서만 사용해야 한다.
2. 접속 끊김 방지 (KeepAlive)
점프 호스트를 거치면 타임아웃이 발생하기 쉽다:
Host *
ServerAliveInterval 60
ServerAliveCountMax 3
60초마다 keepalive 패킷을 보내서 연결을 유지한다.
3. 포트 포워딩과 함께 사용
Bastion을 거쳐 내부 DB 포트를 로컬로 포워딩할 수도 있다:
# 내부 PostgreSQL(5432)을 로컬 15432로 포워딩
ssh -J bastion -L 15432:10.0.1.50:5432 admin@10.0.1.50 -N
이제 localhost:15432로 내부 DB에 접속할 수 있다:
psql -h localhost -p 15432 -U postgres
SSH Config로 설정하면 더 깔끔하다:
Host db-tunnel
HostName 10.0.1.50
User dbadmin
ProxyJump bastion
LocalForward 15432 localhost:5432
ssh -N db-tunnel
# 다른 터미널에서: psql -h localhost -p 15432 -U postgres
정리
| 상황 | 명령어 |
|---|---|
| 단일 점프 | ssh -J bastion internal |
| 다중 점프 | ssh -J bastion1,bastion2 final |
| 파일 전송 | scp -J bastion file internal:/path |
| 포트 포워딩 | ssh -J bastion -L 15432:db:5432 db-host -N |
SSH ProxyJump는 Bastion 서버 환경에서 필수적인 기능이다. SSH Config에 한 번 설정해두면, 내부 서버도 직접 연결된 것처럼 쓸 수 있다.