개발일지

[devlog] Private EC2에 프로젝트 수동 배포하기 - Bastion Host, SSH Agent Forwarding, NAT Gateway 본문

Infra, AWS, Linux

[devlog] Private EC2에 프로젝트 수동 배포하기 - Bastion Host, SSH Agent Forwarding, NAT Gateway

lyjin 2025. 4. 21.

목표

  • 로컬에서 Private 서브넷 EC2 안전하게 접속하기
  • Private EC2에 git clone 받아 프로젝트 수동 배포하기

 

현 인프라 구조 파악

현재 서버 구조는 다음과 같다. (이해를 위해 간소화했다.)

 

백엔드 서버는 Private Subnet에 존재하기때문에 외부에서의 접근이 불가능하다. 하지만 개발을 하다보면 해당 서버 내 로그 파일을 확인하거나 핫픽스 등 서버에 직접 접속해야하는 경우가 생긴다.

 

어떻게 접근할 수 있을까?

이럴 때는 단순 SSH만으로는 접근이 불가하다. 로컬 PC와 Private EC2 사이를 연결해줄 중개자가 필요하다.

 

현재 고려한 방안은 크게 두 가지이다.

  • Bastion Host
    • 구성이 간단하고 VSCode, Git과의 연동 편리
    • 보안 그룹 및 키 관리, 인스턴스 유지 등 관리 포인트 존재
  • AWS SSM Session Manager
    • 비교적 보안성 좋음 (IAM 기반, 22포트 오픈 필요X)
    • 추가 인프라 자원 불필요 → 비용 낮음
    • 로그 기능 제공 (CloudTrail)
    • 자동화 배포 시 추가 설정 필요

 

 

선택: Bastion Host

기존 프로젝트들의 인프라 구성이었던 Bastion Host 방식을 선택했다. 익숙하기도 하고 다른 프로젝트들의 구성이 Bastion Host 기반이었기때문에 운영의 편의성을 고려했다. 하지만 장기적으로 봤을 때는 보안, 비용, 관리 등 여러 측면에서 SSM이 효율적이라고 판단하고 있기 때문에 점진적으로 전환할 예정이다.

 

 


Bastion Host 서버와 SSH Agent Forwarding

 

Public 서브넷에 Bastion Host 서버를 두고, '로컬→Bastion→Private EC2'로 우회하여 접근할 수 있다. 이때 Bastion Host에서 서버에 접속하려면 Bastion 서버에 Private 서버에 대한 SSH 개인키가 있어야한다.

 

즉, 로컬 PC에 있는 Private 서버 private-key를 Bastion Host에서 사용하기 위한 설정이 필요하다.

  • Bastion Host에 키 직접 복사하기
    • 보안에 취약. Public 서브넷에 위치한 Bastion 서버에 private-key 존재
    • EC2 인스턴스를 재생성하거나 키페어가 변경될 때마다 다시 복사해줘야함
  • SSH Agent Forwarding 사용
    • 보안상 안전. Bastion 서버에는 실제 키가 존재하지않음
    • 키페어도 로컬 PC에서만 관리하면 되므로 유지보수에 용이

 

비교적 운영이 편리하고 보안상 안전SSH Agent Forwarding 방식을 선택했다.

 

 

SSH Agent Forwarding

 

 

로컬 PC에서 SSH Agent를 실행하고 Private 서버의 private-key를 agent에 등록해줬다.

# ssh agent 실행
$ eval "$(ssh-agent -s)"

# private key 등록
$ ssh-add <private-key path>

# ssh agent에 등록된 키 확인
$ ssh-add -l

# ssh 접속 (ssh-agent forwarding)
$ ssh -A <user@address>

# ProxyJump(-J)로 바로 bastion → ec2 우회 접속 가능
$ ssh -A -J <bastion-address> <private-ec2-address>

 

 

등록된 키 목록은 다음과 같다.

 

 

로컬→Bastion 서버로 SSH 접속할 때 -A 옵션으로 Agent Forwarding을 활성화 해야한다. 그래야 로컬에 있는 private-key를 Bastion 서버에 들고 갈 수 있다.

 

 

Bastion 서버에 접속한 후 ssh-add -l 해보면 로컬 SSH Agent에 등록된 키 목록이 확인된다.

 

 

Bastion 서버→Private 서버 원격 접속도 성공적으로 이루어졌다.

 

 

.ssh/config 설정

현재 VSCode Remote - SSH를 사용 중이기 때문에, 빠른 연동을 위해 config 파일 설정까지 해줬다.

Host bastion-host
    HostName <bastion-address>
    User <user>
    IdentityFile <bastion-private-key.pem>
    ForwardAgent yes
  
Host server
    HostName <private-ec2-address>
    User <user>
    IdentityFile <ec2-private-key.pem>
    ProxyJump bastion-host   # -J 옵션
    ForwardAgent yes         # -A 옵션

 

 

이렇게 하면 CLI에서도 별다른 옵션 없이도 간단히 접속 가능하다.

$ ssh server

 

 

 


Private EC2에서 Git 요청하기 (SSH, NAT Gateway)

마지막으로 Github에 올라가있는 프로젝트를 Private EC2에 clone 받아 배포해야한다. 보안을 위해 SSH 방식을 사용했고 앞서 설명한 SSH Agent Forwarding을 활용했다.

 

하지만 처음 Git 접속을 시도했을 때 실패했었다. 알고보니 키문제는 아니었고 NAT Gateway가 없었기 때문이었다. Private 서브넷에 있는 EC2가 외부 인터넷으로 요청하려면 Private 서브넷과 외부를 이어주는 NAT Gateway가 필요하다.

 

 

NAT Gateway 이해하기

 

  • 구성 조건
    1. NAT Gateway는 Public 서브넷에 위치해야한다. → 그래야 해당 서브넷이 연결된 IGW를 통해 외부 통신 가능
    2. Private 서브넷 라우팅테이블에 NAT Gateway 지정해줘야한다. → Private EC2가 외부로 보내려는 트래픽을 NAT Gateway로 전달.
  • 예시) git clone 동작 흐름
    1. Private 서버에서 git clone 요청
    2. 서버는 자신이 속한 Private 서브넷의 라우팅테이블 참조
    3. 라우팅 규칙(0.0.0.0/0 → NAT Gateway)에 따라 NAT Gateway로 전달
    4. NAT Gateway는 해당 요청을 자신의 public-ip로 변환한 뒤, IGW를 통해 Github에 전달
    5. 응답은 다시 NAT Gateway를 거쳐 Private 서버로 돌아옴

 

 

성공!

 

 


 

참고로 실제 운영 배포 환경에서는 NAT Gateway가 꼭 필요한 것은 아니다. 지금은 테스트를 위해 Private EC2 내에서 직접 git clone 했지만, 실제로는 Codedeploy+EC2 기반 자동화 배포를 사용할 예정이기 때문이다.

해당 방식은 코드를 Github에서 직접 clone 받는게 아니라, S3에 zip 파일로 업로드한 뒤 Codedeploy가 이 파일을 EC2에 전달하고 배포하는 구조이다. 따라서 Private EC2가 Github와 통신할 필요가 없으며, NAT Gateway 없이도 안정적인 배포가 가능하다.

 

 

기타 참고 자료)

Github Docs - Using SSH agent forwarding

http://www.unixwiz.net/techtips/ssh-agent-forwarding.html