VPC를 공부하면서 백엔드 서버를 public subnet에 둘지, private subnet에 둘지 혼란스러웠다. 보안을 고려하면 private이 맞는 것 같지만, 외부 API를 호출해야 하는 경우엔 통신이 어떻게 흘러가는지 궁금해졌다.
일단 private subnet은 NAT gateway를 통해 외부 인터넷 통신을 위한 아웃바운드가 가능하다. 또한 NAT gateway는 stateful한 성질을 가지고 있어서 요청에 대한 연결을 저장해두기 때문에, 외부API를 요청했을 때 그에 대한 응답도 NAT gateway로 받을 수 있다.
다만 걸리는 것은 NACL(Network Access Contol List)와 보안그룹에 의해 private subnet까지 이 응답이 도달하지 못할 거라고 생각했다. 그래서 즉, private subnet 내의 백엔드 서버는 외부 API 요청은 가능하지만, 2개의 필터에 의해 응답은 받지 못하는 상태라고 생각했다.
만약, 백엔드 서버가 private subnet에 위치해있는데, kakao API를 사용한다고 치자. 그러면 백엔드 서버는 private에서 kakao API를 요청하고 이는 NAT Gateway를 통과하여 public IP로 kakao API를 호출하게 될 것이다. 그러면 외부 API 서버(kakao 등)에서 응답을 NAT Gateway의 퍼블릭 IP로 되돌려주게 된다. NAT gateway는 앞서 언급한 것처럼, stateful하므로, 응답을 해당 EC2로 전달하게 될 것이다.
여기서 예기치 못한 이슈는 NACL을 제대로 설정하지 않는다면, NAT gateway를 통해 받은 응답(인바운드)이 EC2로 도달하지 못할 수 있다는 것이다.
NACL을 설정하여 통신
보안그룹 설정
- Outbound: TCP 443 → 0.0.0.0/0 (외부 API 호출용)
- Inbound: 없음 (stateful이므로 응답 자동 허용)
NACL을 잘 설정해줘야 하는 이유
NACL은 stateless하기 때문에, 인바운드 규칙만 허용한다고 아웃바운드 규칙도 허용되지 않는다. 즉, 독립적이다.
따라서, 인바운드 규칙에 고포트(1024-65535)를 허용해주어야 하며, 모든 외부 트래픽엔 deny해야 한다.
또한 아웃바운드 규칙에는 443포트(HTTPS)와 고포트(1024-65535)를 허용해주며, 이외 트래픽은 deny해야 한다.
고포트(Ephemeral Port)란?
클라이언트 측에서 외부 서버에 연결을 시도할 때 자동으로 열리는 임시 포트 번호
왜 고포트(Ephemeral Port)를 허용해줘야 하는가
- 백엔드 서버가 Kakao API (443 포트)에 요청 보냄
- 이때 백엔드는 자신이 임의의 포트 하나를 열고 요청을 보냄 (예: 10.0.2.15:52347 → kakao.com:443)
- 응답도 해당 고포트(52347)로 돌아옴
- 따라서 해당 포트가 인바운드로 열려 있어야 응답을 수신할 수 있음
AWS 공식 문서에서는 1024–65535 범위를 인바운드로 열어주는 것을 권장하고 있다.
따라서, 정리하자면 아래와 같다.
아웃바운드 트래픽 흐름 (요청)
- Private Subnet의 EC2 인스턴스가 Kakao API (https://api.kakao.com)에 요청을 보냄 (포트 443)
- 요청은 먼저 EC2에 설정된 보안그룹을 통과
- 이후 NACL (Network ACL)을 거쳐
- Route Table에 정의된 경로에 따라 NAT Gateway로 전달됨
- NAT Gateway는 요청을 보내는 EC2의 프라이빗 IP를 퍼블릭 IP로 변환(SNAT)
- 최종적으로 인터넷을 통해 Kakao API에 요청이 도달
인바운드 트래픽 흐름 (응답)
- Kakao API 서버는 NAT Gateway의 퍼블릭 IP로 응답을 전송
- NAT Gateway는 stateful이므로 이전 요청의 연결 상태를 기억하고 있음
- 응답을 요청을 보낸 EC2 인스턴스의 Ephemeral Port(고포트)로 전달
- 이 응답은 다시 NACL의 인바운드 규칙, 보안그룹의 인바운드 설정을 통과해야 EC2에 도달
Ref
물론 public subnet에 백엔드 서버를 두는 경우도 많다. 수많은 블로그와 미니 프로젝트들에서 종종 찾아볼 수 있다. 심지어 vpc를 적용하지 않는 경우도 허다하다. 퍼블릭 서브넷에 백엔드를 두는 경우는 개발용, 임시 서버, 테스트 환경 등에서만 활용해야한다.
실서비스에서는 보안상 이유로 반드시 퍼블릭 IP가 없는 프라이빗 서브넷에 백엔드 서버를 배치하고,
클라가 요청을 보내면 ALB 등을 통해서만 EC2(백엔드 서버)에 접근되도록 구성하는 것이 바람직하다.
보통은 아래와 같은 구성이 될 수 있는데,
[Client] → [EC2 직접 접근 via IGW]
이렇게 아무런 대책 없이 public subnet에 백엔드 서버를 두는 건 지양해야 한다.
- public IP 노출 위험성
- 외부에서 직접 호출 가능 -> 보안 위협
- 백도어 가능성 존재
하지만 아래 조건들을 충족한다면, public subnet에 백엔드 서버를 둬도 보안상 괜찮다고 할 수 있다.
- 백엔드 EC2가 퍼블릭 IP를 안 갖도록 설정 (Auto-assign public IP = false)
- 보안그룹으로 ALB만 접근 허용
- NACL로도 외부 접근 완전 차단
- ALB → 백엔드 통신만 허용되도록 제한
→ 이 경우엔 퍼블릭 서브넷에 있더라도 실질적으로는 외부에서 접근 못 한다.
하지만 설계상 실수 위험은 존재하므로 private server로 두는 게 맞다.)
이상적인 구성
[Client]
↓
[WAF + ALB] (Public Subnet)
↓
[Backend EC2] (Private Subnet)
요약
- 백엔드 서버는 보안상 private subnet에 두는 것이 원칙
- 외부 API 호출이 필요한 경우, NAT Gateway + Ephemeral Port 인바운드 허용으로 통신 가능
- NACL은 stateless이므로 인바운드/아웃바운드 규칙을 모두 명시해야 함
- public subnet에 백엔드를 둘 수도 있지만, 보안 설정 실수 위험이 있으므로 권장되지 않음