VPC 다시 배우기 : 서브넷과 Dual-Stack
서브넷은 격리 경계가 아니다, 그리고 Dual-Stack VPC와 E-IGW
2019년 AWS Architecture Blog에 올라온 One to Many: Evolving VPC Design을 다시 읽으면서 VPC를 처음부터 정리하고 있습니다. 꽤 오래된 글이지만 기본 개념은 지금도 그대로 유효합니다.
오히려 요즘 기능인 Dual-Stack VPC, IPv6-only 서브넷과 이어서 보니 ‘왜 이렇게 설계했는가’가 더 선명해졌습니다. 이번 글에서는 서브넷의 정체부터 Dual-Stack, 그리고 E-IGW까지 다뤄보겠습니다.
서브넷은 격리 경계가 아닙니다
VPC를 처음 배울 때 흔히 하는 오해가 ‘서브넷을 나누면 네트워크가 격리된다’는 생각입니다. 저도 한동안 그렇게 이해하고 있었습니다. 정확히는 이렇습니다.
- 서브넷 : 라우팅 정책을 담는 컨테이너입니다. CIDR 범위(
/16~/28)를 갖고, 하나의 AZ에 속하며, 반드시 하나의 라우트 테이블과 연결됩니다. - 격리 : Security Group(상태 저장 방화벽)이 인스턴스, 정확히는 ENI 단위로 담당합니다.
즉 서브넷 자체에는 격리 기능이 내장되어 있지 않습니다. 이전 글에서도 같은 이야기를 했었습니다.
사실 서브넷은 기본적으로 격리되어있지만, ‘인터넷 게이트웨이로 라우팅이 가능한가’에 따라 Public / Private 서브넷으로 나눠질 뿐입니다.
Public 서브넷 / Private 서브넷이라는 구분도 결국 그 서브넷의 라우트 테이블이 어디를 가리키는가의 문제입니다. AWS 콘솔 어디에도 ‘이 서브넷을 Private으로 만들기’ 같은 체크박스는 없습니다. 우리가 라우트 테이블을 그렇게 구성했기 때문에 그렇게 부르는 것뿐입니다.
그럼 격리는 누가 하나요
| Security Group | Network ACL | |
|---|---|---|
| 적용 단위 | 인스턴스(ENI) | 서브넷 |
| 상태 | 상태 저장(Stateful) | 상태 비저장(Stateless) |
| 규칙 | 허용(Allow)만 가능 | 허용 + 거부(Deny) |
| 평가 | 모든 규칙을 종합 | 번호 순서대로 |
정리하면 서브넷은 ‘어디로 보낼지’를 정하고, SG와 NACL은 ‘무엇을 통과시킬지’를 정합니다. 서로 하는 일이 다릅니다.
예약 주소도 서브넷 단위입니다
서브넷 CIDR 안에서 앞의 4개와 마지막 1개, 총 5개의 IPv4 주소는 AWS가 예약해 사용할 수 없습니다. /28 서브넷을 만들면 16개 중 11개만 쓸 수 있다는 뜻입니다.
IPv6 서브넷도 예약 주소가 있습니다. 다만 브로드캐스트 주소가 없기 때문에 앞의 4개만 예약됩니다.
Dual-Stack VPC : IPv4는 필수, IPv6는 선택
VPC를 만들면 IPv4 CIDR은 무조건 따라붙습니다. 그리고 이 기본 IPv4 CIDR은 제거할 수 없습니다. VPC를 삭제하는 방법밖에 없습니다.
IPv6는 원하면 추가로 붙이는 방식입니다. Amazon이 제공하는 /56 대역을 받거나, 보유한 대역을 BYOIP로 가져올 수 있습니다. 이렇게 IPv6를 추가한 VPC를 Dual-Stack VPC라고 부릅니다.
서브넷은 세 가지로 섞을 수 있습니다
흥미로운 건 서브넷 레벨입니다. Dual-Stack VPC 안에서는 서브넷을 세 가지로 자유롭게 조합할 수 있습니다.
| 서브넷 타입 | IPv4 | IPv6 | 설명 |
|---|---|---|---|
| IPv4-only | O | X | 기존 방식 |
| Dual-Stack | O | O | 둘 다 할당 |
| IPv6-only | X | O | IPv4 주소를 아예 할당받지 않음 |
IPv6-only 서브넷의 인스턴스는 ENI에 IPv4 주소가 전혀 없습니다. VPC는 IPv4를 갖고 있어도, 그 안의 특정 서브넷은 IPv4를 완전히 배제할 수 있다는 뜻입니다.
IPv6 서브넷의 제약
IPv4 서브넷과 달리 IPv6 서브넷 CIDR은 /64로 고정입니다. Prefix 길이를 마음대로 정할 수 없습니다. VPC가 받은 /56 대역을 /64 단위로 쪼개면 256개의 서브넷을 만들 수 있는 셈입니다.
그 외에 IPv6-only 서브넷을 쓸 때 미리 알아두면 좋은 것들입니다.
- Nitro 기반 인스턴스 타입에서만 지원됩니다.
- IPv4 전용 대상(외부 API 등)과 통신하려면 DNS64 + NAT64 조합이 필요합니다. Route 53 Resolver가 IPv4 주소를 IPv6로 합성해주면, NAT 게이트웨이가 실제 변환을 수행합니다.
- 일부 서비스는 여전히 IPv4 엔드포인트만 제공하므로, 적용 전에 사용 중인 서비스의 IPv6 지원 여부를 확인해야 합니다.
왜 지금 IPv6를 보는가
2024년 2월 1일부터 모든 퍼블릭 IPv4 주소에 시간당 요금이 부과되기 시작했습니다. 사용 중인 주소든 미사용 EIP든 예외가 없습니다. 인스턴스가 수백 대 규모가 되면 무시할 수 없는 금액이 됩니다.
그래서 IPv6-only 서브넷을 실무에서 검토하는 사례가 늘고 있습니다. 예전에는 ‘언젠가 해야 할 일’이었다면, 지금은 청구서에 바로 찍히는 문제가 되었습니다.
E-IGW : IPv6에 NAT가 필요 없는 이유
IPv6는 주소 공간이 방대해서 IPv4처럼 ‘부족한 공인 IP를 나눠 쓰기 위한 NAT’가 필요 없습니다. 인스턴스에 할당되는 IPv6 주소 자체가 이미 Global Unicast, 즉 공인 주소입니다.
그런데 여기서 문제가 하나 생깁니다.
그럼 Private 서브넷처럼 인바운드는 막고 아웃바운드만 허용하고 싶을 때는 뭘 쓰나요?
여기서 등장하는 것이 Egress-Only Internet Gateway(E-IGW) 입니다.
주소를 숨기는 게 아니라 방향을 통제합니다
핵심은 E-IGW가 NAT처럼 주소를 바꾸거나 숨기지 않는다는 점입니다. 인스턴스의 IPv6 주소는 그대로 노출된 채 나갑니다. E-IGW가 하는 일은 연결의 방향을 통제하는 것뿐입니다.
%%{
init: {
'theme': 'base',
'themeVariables': {
'primaryColor': '#2a3844',
'lineColor': '#fff',
'primaryTextColor': '#fff',
'primaryBorderColor': '#fff',
'tertiaryColor': '#fff'
}
}
}%%
flowchart LR
EC2A["EC2
Public Subnet"]
EC2B["EC2
Private Subnet"]
IGW["Internet
Gateway"]
EIGW["Egress-Only
Internet Gateway"]
NET(["Internet"])
EC2A <--> IGW
IGW <--> NET
EC2B -- "아웃바운드 개시" --> EIGW
EIGW -- "리턴 트래픽만" --> EC2B
EIGW <--> NET
> 그림 1. IGW는 양방향, E-IGW는 아웃바운드 개시만 허용
- 일반 IGW : 양방향 통신을 허용합니다. (Public 서브넷)
- E-IGW : 상태 저장(Stateful) 게이트웨이로, 아웃바운드로 나간 연결의 리턴 트래픽만 통과시킵니다. 인터넷 쪽에서 먼저 시작하는 연결은 통과하지 못합니다. (Private 서브넷)
그리고 하나의 서브넷에 연결된 라우트 테이블에서 ::/0 경로는 IGW든 E-IGW든 하나만 가리킬 수 있습니다. 어느 쪽을 쓸지는 그 서브넷을 Public으로 설계할지 Private으로 설계할지에 달려 있습니다.
그냥 IGW 쓰고 SG로 막으면 안 되나요?
기술적으로는 가능합니다. IGW를 연결한 뒤 SG에서 인바운드 규칙을 하나도 열지 않으면 결과적으로는 비슷해 보입니다. 하지만 이건 방어가 걸리는 계층이 다릅니다.
| IGW + SG/NACL | E-IGW | |
|---|---|---|
| 인바운드 연결 시도 | 인스턴스까지 도달 → SG/NACL이 평가 후 drop | 게이트웨이에서 차단, 애초에 들어올 경로가 없음 |
| 실패 시나리오 | SG 규칙 하나 잘못 열면 즉시 인바운드 노출 | SG를 열어도 경로가 없어 여전히 차단 |
| 방어 계층 | 인스턴스 레벨 | 라우팅 레벨 |
‘IGW + SG’는 인바운드 차단을 인스턴스 레벨 설정에 전적으로 의존하는 구조입니다. 누군가 실수로 SG에 ::/0 인바운드 규칙을 추가하는 순간 인터넷에 그대로 노출됩니다.
반면 E-IGW는 라우팅 레벨에서 원천적으로 경로를 없애는 구조입니다. IPv4의 Private 서브넷도 원래 ‘NAT 게이트웨이가 라우팅 레벨에서 인바운드를 막아주는’ 설계였다는 걸 생각하면, E-IGW는 그 설계 철학을 IPv6로 그대로 옮긴 것에 가깝습니다.
SG는 인스턴스 레벨, E-IGW는 라우팅 레벨. 서로 다른 계층에서 같은 목적(인바운드 차단)을 이중으로 보장하는 Defense in Depth 구조입니다.
라우트 테이블로 정리하기
지금까지의 이야기를 결국 라우트 테이블 한 장으로 정리하면 이렇게 됩니다. VPC CIDR이 10.0.0.0/16, IPv6 CIDR이 2001:db8:1a00::/56인 경우입니다.
Public 서브넷의 라우트 테이블
| Destination | Target |
|---|---|
| 10.0.0.0/16 | local |
| 2001:db8:1a00::/56 | local |
| 0.0.0.0/0 | igw-id |
| ::/0 | igw-id |
Private 서브넷의 라우트 테이블
| Destination | Target |
|---|---|
| 10.0.0.0/16 | local |
| 2001:db8:1a00::/56 | local |
| 0.0.0.0/0 | nat-gateway-id |
| ::/0 | eigw-id |
IPv4는 NAT 게이트웨이, IPv6는 E-IGW. 역할은 같지만 담당하는 프로토콜이 다릅니다. 이 표만 이해하면 Public / Private 서브넷의 정체는 사실상 끝입니다.
마무리
VPC를 다시 보면서 정리한 핵심은 다음과 같습니다.
- 서브넷은 격리 경계가 아니라 라우팅 컨테이너이며, 격리는 SG와 NACL의 역할입니다.
- VPC는 IPv4가 항상 필수이고, IPv6는 선택적으로 추가합니다. 이를 Dual-Stack VPC라 부릅니다.
- 서브넷 단위로는 IPv4-only / Dual-Stack / IPv6-only를 자유롭게 조합할 수 있습니다.
- IPv6에 NAT가 필요 없는 이유는 주소가 이미 공인 주소이기 때문입니다.
- E-IGW는 주소를 숨기는 게 아니라, 인바운드 연결 시작을 라우팅 레벨에서 차단하는 방향 제어 장치입니다.
다음 편에서는 Public 서브넷과 IGW를 조금 더 깊게 보고, Private 서브넷의 NAT 게이트웨이 HA 구성을 다뤄보겠습니다.
감사합니다! 😊