VPC / Subnet / Security Group
분류: Layer 3 - AWS 인프라 & 보안
이 문서는 네트워크 구조와 통신에 집중합니다. 보안 메커니즘(WAF, Shield, NACL 심화)은 network-security.mdx를 참고하세요.
1. 한 줄 정의
섹션 제목: “1. 한 줄 정의”VPC(Virtual Private Cloud)는 AWS 안에 만드는 격리된 가상 네트워크다. Subnet(서브넷)은 그 네트워크를 Availability Zone(AZ, 리전 안에서 전원·네트워크·건물 장애를 독립적으로 견디도록 분리된 장애 도메인)과 용도별로 나눈 작은 구역이고, Security Group(SG, 보안 그룹)은 EC2, ECS Task, RDS 같은 리소스에 붙는 stateful 방화벽 규칙이다.
첫 회독에서는 아래 네 문장만 붙잡으면 된다.
- VPC는 “어떤 IP 주소 범위를 우리 네트워크로 쓸 것인가”를 정한다.
- Subnet은 “그 주소 범위를 어느 AZ와 어느 용도에 나눠 둘 것인가”를 정한다.
- Route Table(라우팅 테이블)은 “이 Subnet에서 목적지별 트래픽을 어디로 보낼 것인가”를 정한다.
- Security Group은 “이 리소스가 누구와 어떤 포트로 통신해도 되는가”를 정한다.
2. 왜 중요한가
섹션 제목: “2. 왜 중요한가”AWS에서 네트워크 문제는 대개 애플리케이션 코드 밖에서 발생한다. 서버는 실행 중인데 DB 연결만 타임아웃되고, ECS Task는 RUNNING인데 이미지를 못 받아오며, 같은 VPC 안의 두 서비스도 서로 통신하지 못할 수 있다. 이때 원인은 보통 코드 버그가 아니라 주소 범위, 라우팅, 보안 규칙, 관측 로그 중 하나다.
VPC/Subnet/SG를 공부하는 이유는 모든 네트워크 장애를 외우기 위해서가 아니다. “패킷이 어디까지 갔고, 어디에서 막혔는가”를 순서대로 좁히는 사고방식을 얻기 위해서다.
2.5 선행 기술의 한계 — EC2-Classic에서 VPC로
섹션 제목: “2.5 선행 기술의 한계 — EC2-Classic에서 VPC로”VPC의 lineage는 EC2-Classic의 한계에서 시작한다. EC2-Classic은 초기 EC2의 네트워크 모델로, 고객별 가상 네트워크를 먼저 만들지 않고 리전 단위의 넓은 네트워크 평면에서 인스턴스를 실행했다. 이 방식은 단순했지만 서비스가 커질수록 세 가지 문제가 뚜렷해졌다.
| 깨진 지점 | EC2-Classic에서의 문제 | VPC가 제공한 해결책 |
|---|---|---|
| 주소 통제 | 사용자가 사설 IP 대역을 직접 설계하기 어렵고, 사내망 CIDR과 충돌하면 VPN 연결이 막힌다 | VPC 생성 시 CIDR(Classless Inter-Domain Routing) 범위를 직접 선택한다 |
| 격리 단위 | ”우리 서비스만 들어 있는 네트워크”라는 경계가 약하다 | 계정과 VPC 단위로 논리적 네트워크 평면을 분리한다 |
| 다계층 토폴로지 | 웹/API/DB를 서로 다른 네트워크 구역으로 나누기 어렵다 | Subnet과 Route Table로 Public, Private, DB 구역을 분리한다 |
| 보안 표현력 | 리소스별 SG 규칙에 많이 의존한다 | VPC 경계, Subnet 경로, SG, NACL을 조합해 여러 층에서 허용 범위를 좁힌다 |
EC2-Classic은 2023년 8월 15일 마지막 Classic 인스턴스 종료와 함께 역사적 모델이 되었다. 신규 인프라를 설계할 때는 “VPC를 쓸지 말지”가 아니라 “VPC 안에서 주소, 경로, 허용 규칙을 어떻게 나눌지”가 질문이다.
이 토픽이 사라지면 가장 기본적인 결정도 표현하기 어렵다. 예를 들어 “DB는 인터넷에서 직접 보이지 않게 하고, API 서버 SG에서만 5432 포트를 허용한다”는 결정은 VPC, Subnet, Route Table, SG가 함께 있어야 정확히 말할 수 있다.
출처: Farewell EC2-Classic — All Things Distributed (Werner Vogels), Amazon EC2 Update – Virtual Private Clouds for Everyone! (AWS News Blog), EC2-Classic Networking is Retiring (AWS News Blog)
3. VPC를 읽는 4층 모델
섹션 제목: “3. VPC를 읽는 4층 모델”VPC 문서를 읽을 때는 용어를 낱개로 외우기보다 네 층으로 나눠 보는 편이 낫다.
| 층 | 질문 | 대표 용어 |
|---|---|---|
| 주소 | 어떤 사설 IP 범위를 쓸 것인가 | CIDR, Primary CIDR, Secondary CIDR |
| 구역 | 주소 범위를 어느 AZ와 용도에 배치할 것인가 | Subnet, Public Subnet, Private Subnet, DB Subnet |
| 경로 | 목적지별 트래픽을 어디로 보낼 것인가 | Route Table, IGW(Internet Gateway), NAT Gateway, VPC Endpoint |
| 허용 규칙 | 누가 어떤 포트로 통신해도 되는가 | Security Group, NACL(Network ACL), SG-as-source |
| 관측 | 실제 패킷이 왔고 허용됐는가 | ENI(Elastic Network Interface), VPC Flow Logs, Reachability Analyzer |
ENI(Elastic Network Interface)는 리소스가 VPC 네트워크에 붙는 네트워크 카드라고 보면 된다. EC2 인스턴스는 ENI를 갖고, Fargate의 awsvpc 네트워크 모드에서는 ECS Task마다 ENI와 Private IP가 붙는다. 그래서 “Task 100개”는 단순히 컨테이너 100개가 아니라 Subnet IP 100개를 소비하는 사건이 된다.
NACL(Network ACL)은 Subnet 단위의 stateless 방화벽이다. SG가 리소스 단위이고 응답 트래픽을 자동 허용하는 반면, NACL은 인바운드와 아웃바운드를 각각 허용해야 한다. 처음 공부할 때는 SG를 먼저 보고, SG와 Route Table이 맞는데도 막히면 NACL을 확인한다.
요청 하나로 전체 모델 읽기
섹션 제목: “요청 하나로 전체 모델 읽기”아래 상황을 손으로 따라가면 각 용어가 왜 따로 존재하는지 보인다.
사용자 브라우저 -> Internet Gateway -> Public Subnet의 ALB -> Private Subnet의 ECS Task -> DB Subnet의 RDS -> 외부 결제 API 호출 시 NAT Gateway각 홉에서 확인하는 질문은 다르다.
| 구간 | 필요한 VPC 개념 | 통과 조건 |
|---|---|---|
| 인터넷 -> ALB | IGW, Public Subnet Route Table, ALB SG | ALB가 Public Subnet에 있고, 0.0.0.0/0 -> IGW 경로와 443 inbound가 있다 |
| ALB -> ECS Task | Private Subnet, ECS Task SG | ECS 수신 SG가 ALB SG를 source로 8080 또는 서비스 포트 inbound 허용한다 |
| ECS Task -> RDS | DB Subnet, RDS SG, SG-as-source | RDS SG가 ECS Task SG를 source로 5432 또는 3306 inbound 허용한다 |
| ECS Task -> 외부 결제 API | Private Route Table, NAT Gateway | Private Subnet Route Table에 0.0.0.0/0 -> NAT Gateway 경로가 있다 |
| ECS Task -> S3/ECR/Logs | VPC Endpoint 또는 NAT Gateway | Endpoint가 있으면 내부 경로, 없으면 NAT Gateway를 통해 AWS 서비스로 간다 |
이 예제에서 “Private Subnet의 ECS Task에 Public IP가 없다”는 사실만으로는 충분하지 않다. 외부 결제 API 호출에는 outbound 경로가 필요하고, RDS 접속에는 수신 SG 허용이 필요하며, ECR 이미지 pull에는 Endpoint나 NAT가 필요하다. 하나의 요청도 주소, 경로, 허용 규칙을 각각 통과해야 한다.
반대로 ALB가 Public Subnet에 있어도 ECS Task와 RDS는 Public Subnet에 둘 필요가 없다. 진입점만 공개하고 내부 컴퓨팅과 데이터 저장소는 Private/DB Subnet에 두는 것이 프로덕션 VPC의 기본 사고방식이다.
4. 주소 설계 — CIDR은 나중에 쉽게 고치기 어렵다
섹션 제목: “4. 주소 설계 — CIDR은 나중에 쉽게 고치기 어렵다”CIDR(Classless Inter-Domain Routing)은 IP 범위를 압축해 쓰는 표기법이다. 10.0.0.0/16은 앞 16비트가 네트워크 주소라는 뜻이고, 전체 주소 수는 2^(32-16) = 65,536개다. 10.0.1.0/24는 2^(32-24) = 256개다.
AWS는 각 Subnet에서 5개 IP를 예약한다. 그래서 /24 Subnet은 표기상 256개지만 실제 사용 가능한 IP는 251개다.
| CIDR 예시 | 총 IP 수 | AWS 예약 후 사용 가능 | 공부할 때의 감각 |
|---|---|---|---|
10.0.0.0/16 | 65,536 | VPC 전체 범위 | 여러 AZ, 서비스, 미래 확장을 담는 큰 주소 풀 |
10.0.1.0/24 | 256 | 251 | Public, Private, DB 같은 용도별 Subnet 기본 단위 |
10.0.1.0/27 | 32 | 27 | 실험용은 가능하지만 Fargate나 EKS에는 쉽게 부족함 |
/16 VPC와 /24 Subnet의 손계산
섹션 제목: “/16 VPC와 /24 Subnet의 손계산”10.0.0.0/16을 VPC로 잡으면 10.0.0.0부터 10.0.255.255까지 쓸 수 있다. 이 안에서 /24 Subnet을 만들면 세 번째 숫자를 용도별로 나누기 쉽다.
VPC: 10.0.0.0/16
Public Subnet A: 10.0.1.0/24 (ALB, NAT Gateway)Public Subnet B: 10.0.2.0/24 (ALB Multi-AZ)Private Subnet A: 10.0.11.0/24 (ECS Task, EC2)Private Subnet B: 10.0.12.0/24 (ECS Task, EC2 Multi-AZ)DB Subnet A: 10.0.21.0/24 (RDS Primary)DB Subnet B: 10.0.22.0/24 (RDS Standby)
미할당 예비:10.0.30.0/24 ~ 10.0.99.0/24 (신규 서비스, 추가 AZ)10.0.100.0/24 이상 (EKS 노드/Pod, Peering, 실험 환경)여기서 중요한 것은 “지금 필요한 IP 수”가 아니라 “나중에 어떤 단위로 나눌 수 있는가”다. VPC CIDR이 너무 작으면 Subnet을 쪼갤 자유도가 사라지고, 피어링이나 VPN 연결 시 겹치지 않는 대역을 찾기 어려워진다.
Fargate에서 작은 Subnet이 빨리 고갈되는 이유
섹션 제목: “Fargate에서 작은 Subnet이 빨리 고갈되는 이유”Fargate Task가 awsvpc 모드로 뜨면 Task마다 ENI와 Private IP를 하나씩 쓴다. Private Subnet이 /27이면 사용 가능 IP가 27개 정도이므로, 배포 중 rolling update로 기존 Task 20개와 신규 Task 20개가 잠깐 공존하는 순간 이미 부족하다. 반면 /24는 사용 가능 IP가 251개라 같은 상황을 훨씬 여유 있게 흡수한다.
실패 신호는 명확하다.
- ECS Service가 원하는 Task 수까지 올라가지 못한다.
- 이벤트에
RESOURCE:ENI,insufficient free addresses,IP address not available류 메시지가 보인다. - 특정 AZ의 Subnet만 IP가 고갈되어 Multi-AZ 배포가 한쪽으로 치우친다.
Secondary CIDR은 해결책이지만 만능은 아니다
섹션 제목: “Secondary CIDR은 해결책이지만 만능은 아니다”Primary CIDR은 VPC 생성 후 바꿀 수 없다. IP가 부족하면 Secondary CIDR을 추가할 수 있지만, 그때부터는 운영 비용이 붙는다. 새 CIDR에 Subnet을 만들고, Route Table을 연결하고, 보안 규칙과 배포 대상을 새 Subnet까지 확장해야 한다.
Secondary CIDR 제약은 처음 주소 설계가 중요한 이유를 보여준다.
| 제약 | 의미 |
|---|---|
| 크기 | IPv4 CIDR은 보통 /16부터 /28 범위 안에서 추가한다 |
| 중복 금지 | 기존 VPC CIDR, Peering된 VPC, VPN/Direct Connect 대상망과 겹치면 안 된다 |
| 개수 제한 | Primary 포함 연결 가능한 CIDR 개수는 Service Quotas로 관리된다. 무한히 덧붙일 수 없고, 설계 전에 현재 quota 숫자를 확인해야 한다 |
| RFC 1918 범위 혼합 제약 | Primary가 10.0.0.0/16이면 다른 RFC 1918 사설 범위를 마음대로 섞지 못하는 조건이 있다 |
실무에서 100.64.0.0/10 Shared Address Space를 Secondary CIDR로 쓰는 사례가 있는 이유도 여기에 있다. 기존 10.x.x.x 설계와 충돌을 피하면서 EKS Pod나 대규모 워크로드의 IP 풀을 늘리기 쉽기 때문이다. 다만 이 선택도 사내망, Peering, Transit Gateway 설계와 충돌하지 않는지 먼저 확인해야 한다.
짧은 반례로 보면 더 분명하다. Primary CIDR이 10.0.0.0/16이고 이미 VPN 경로 10.0.50.0/24 -> Virtual Private Gateway가 있다면, 같은 대역을 확장처럼 다시 쓰려는 시도는 기존 경로와 겹친다. 라우터는 더 구체적인 prefix를 우선하지만, 겹치는 CIDR 자체가 VPC 확장과 피어링/온프레미스 라우팅을 헷갈리게 만든다. Secondary CIDR을 고를 때는 “빈 IP가 있나”뿐 아니라 “기존 Route Table, VPN, Peering 경로와 겹치지 않나”를 같이 확인해야 한다.
출처: AWS VPC CIDR blocks, Add or remove a CIDR block from your VPC
5. Public과 Private의 경계는 Route Table에 있다
섹션 제목: “5. Public과 Private의 경계는 Route Table에 있다”Subnet 이름에 public이나 private이 들어간다고 해서 네트워크 성격이 정해지는 것은 아니다. 실제 경계는 Route Table이 만든다.
| Subnet 성격 | Route Table의 핵심 경로 | 외부에서 먼저 들어올 수 있나 | 내부에서 인터넷으로 나갈 수 있나 |
|---|---|---|---|
| Public Subnet | 0.0.0.0/0 -> IGW | 가능 | 가능 |
| Private Subnet | 0.0.0.0/0 -> NAT Gateway 또는 기본 경로 없음 | 불가 | NAT가 있으면 가능 |
| DB Subnet | 보통 인터넷 기본 경로 없음 | 불가 | 보통 불필요 |
IGW(Internet Gateway)는 VPC와 인터넷 사이의 관문이다. Public Subnet은 기본 경로 0.0.0.0/0을 IGW로 보내고, 리소스가 Public IP를 가지고 있어야 인터넷과 직접 통신할 수 있다.
NAT(Network Address Translation) Gateway는 Private Subnet의 리소스가 인터넷으로 나갈 때 출발지 IP를 NAT Gateway의 Elastic IP로 바꿔 주는 관리형 장치다. 밖에서 먼저 들어오는 연결은 매핑 정보가 없으므로 통과하지 않는다.
VPC Endpoint는 AWS 서비스로 향하는 트래픽을 인터넷 대신 AWS 내부 경로로 보내는 연결이다. S3/DynamoDB는 Gateway Endpoint가 Route Table에 경로를 추가하는 방식이고, ECR/CloudWatch Logs/Secrets Manager 같은 서비스는 Interface Endpoint가 ENI와 Private IP를 만들어 PrivateLink로 연결하는 방식이다.
AWS 문서에서 endpoint는 문맥에 따라 뜻이 달라진다. RDS endpoint는 애플리케이션이 DB에 붙기 위해 쓰는 DNS 접속 주소이고, VPC Endpoint는 AWS 서비스로 가는 private service path다. 둘 다 “접속 지점”이지만 하나는 주소 이름, 하나는 네트워크 경로에 가깝다.
NAT Gateway가 패킷을 바꾸는 순서
섹션 제목: “NAT Gateway가 패킷을 바꾸는 순서”sequenceDiagram participant Task as ECS Task participant Route as Private Route Table participant NAT as NAT Gateway participant IGW as Internet Gateway participant API as External API Task->>Route: 목적지 0.0.0.0/0 경로 조회 Route->>NAT: NAT Gateway로 전달 NAT->>IGW: Source IP를 NAT Elastic IP로 변환 IGW->>API: 인터넷으로 요청 전달 API-->>NAT: 응답 반환 NAT-->>Task: 원래 Private IP로 역변환
이 순서 때문에 NAT Gateway는 “Private 리소스가 밖으로 나가기 위한 장치”이지, “인터넷에서 Private 리소스로 들어오기 위한 장치”가 아니다. Private Subnet의 ECS Task가 외부 결제 API를 호출할 수 있어도, 외부 사용자가 그 Task로 직접 접속할 수는 없다.
Route Table로 보는 반례
섹션 제목: “Route Table로 보는 반례”가장 흔한 오해는 “Security Group에서 443을 열었으니 Public Subnet이다”라는 생각이다. 아니다. SG는 허용 규칙이고, Route Table은 경로다.
Case A: SG 443 허용 + Route Table에 IGW 없음=> 인터넷에서 들어올 경로가 없으므로 Public 리소스가 아니다.
Case B: Route Table에 IGW 있음 + SG 443 미허용=> 경로는 있지만 리소스가 트래픽을 거부한다.
Case C: Route Table에 NAT 있음 + SG outbound 443 허용=> Private 리소스가 외부 HTTPS API를 호출할 수 있다.6. Security Group — 리소스 단위의 stateful 허용 규칙
섹션 제목: “6. Security Group — 리소스 단위의 stateful 허용 규칙”Security Group은 ENI에 붙는 stateful 방화벽이다. “stateful”은 요청 트래픽이 허용되면 그 연결의 응답 트래픽은 별도 규칙 없이 자동 허용된다는 뜻이다.
예를 들어 RDS SG에 아래 인바운드 규칙이 있다면:
Type: PostgreSQLPort: 5432Source: sg-ecs-tasksg-ecs-task를 가진 ECS Task는 RDS의 5432 포트로 연결할 수 있다. RDS의 응답 패킷은 connection tracking 덕분에 아웃바운드 규칙을 따로 열지 않아도 돌아간다. 반대로 RDS SG가 10.0.11.0/24 같은 IP 대역만 허용하면 Task IP가 바뀔 때마다 규칙이 깨질 수 있다.
SG-as-source 패턴
섹션 제목: “SG-as-source 패턴”실무에서는 IP 주소보다 다른 Security Group ID를 source로 쓰는 편이 안전하다.
RDS Security Group inbound:- Port: 5432- Source: sg-ecs-task
ECS Task Security Group outbound:- Port: 5432- Destination: sg-rds이 패턴의 장점은 세 가지다.
- Task가 재배포되어 Private IP가 바뀌어도 규칙을 고칠 필요가 없다.
- “DB에 접근 가능한 워크로드”를 SG라는 이름 있는 집합으로 표현한다.
- 같은 VPC 안에서도 허용된 SG가 아니면 통신할 수 없다는 최소 권한 모델이 유지된다.
Stateful이 항상 마법처럼 해결해주지는 않는다
섹션 제목: “Stateful이 항상 마법처럼 해결해주지는 않는다”SG의 stateful 동작은 connection tracking에 의존한다. 첫 회독에서는 아래 실패 신호만 기억해도 충분하다.
작은 예로, 인바운드와 아웃바운드가 모두 0.0.0.0/0에 전체 포트 허용처럼 너무 넓으면 일부 흐름은 untracked flow로 처리될 수 있다. 이 상태에서 넓은 규칙을 갑자기 좁히면 기존 연결이 즉시 끊겨 “stateful인데 왜 세션이 유지되지 않지?”처럼 보인다. 또 Nitro v6 계열에서는 TCP established idle timeout 기본값을 350초로 보는 운영 사례가 있어, DB pool이나 HTTP keep-alive가 5분 넘게 놀면 다음 요청에서 끊김으로 드러날 수 있다. 그래서 첫 mental model은 “장기 idle 연결은 5분보다 짧은 keep-alive로 주기적으로 깨운다”에 가깝다. 정확한 값 조정은 인스턴스 세대, ENI 설정, 로드밸런서 timeout을 함께 보고 나중에 한다.
| 실패 신호 | 의미 | 먼저 볼 곳 |
|---|---|---|
RDS 연결이 Connection timed out으로 끝난다 | 수신 측 SG 인바운드에 발신 SG가 없거나 Route Table 경로가 없다 | RDS SG inbound, DB Subnet Route |
| 기존 SSH/HTTP 연결이 규칙 변경 직후 끊긴다 | 넓은 allow 규칙의 untracked flow였거나 tracking 상태가 사라졌다 | SG 규칙 변경 이력 |
| DB pool/keep-alive 연결이 몇 분 idle 후 다음 요청에서 실패한다 | connection tracking idle timeout 또는 중간 장비 timeout과 keep-alive 불일치 | ENI timeout, client keep-alive |
| CloudWatch ENA 지표에 conntrack drop이 보인다 | 추적 가능한 연결 수가 인스턴스/ENI 한도를 넘었다 | 연결 수, timeout, 워크로드 분산 |
이 절의 목적은 모든 timeout 값을 외우는 것이 아니다. “SG가 stateful이어도 연결 상태를 추적하는 테이블과 timeout이 있다”는 모델을 갖는 것이다. 긴 확인 명령은 선택 부록으로 뺐다.
출처: Amazon EC2 security group connection tracking (AWS Docs), Introducing configurable Idle timeout for Connection tracking (AWS Networking Blog)
7. VPC Endpoint vs NAT Gateway — 언제 무엇을 쓰나
섹션 제목: “7. VPC Endpoint vs NAT Gateway — 언제 무엇을 쓰나”NAT Gateway와 VPC Endpoint는 둘 다 “Private Subnet에서 밖으로 나가는 길”처럼 보이지만, 성격이 다르다.
| 질문 | NAT Gateway | VPC Endpoint |
|---|---|---|
| 목적지 | 인터넷 전체 | 특정 AWS 서비스 |
| 대표 사용 | GitHub, npm, 외부 결제 API, 외부 SaaS | S3, DynamoDB, ECR, CloudWatch Logs, Secrets Manager |
| 보안 경계 | 인터넷 경유 | AWS 내부 경로/PrivateLink |
| 비용 모델 | 시간당 고정비 + 처리 GB당 과금 | Endpoint 종류별 고정비/처리비, Gateway Endpoint는 무료 |
| 대체 가능성 | 외부 인터넷 목적지는 Endpoint로 대체 불가 | AWS 서비스 트래픽은 NAT 우회 가능 |
Fargate Task가 Private Subnet에서 ECR 이미지를 pull하고 CloudWatch Logs로 로그를 보내야 한다면, 선택지는 두 가지다.
- NAT Gateway로 인터넷 경유 경로를 열어 둔다.
- ECR, S3, CloudWatch Logs, Secrets Manager Endpoint를 만들어 AWS 서비스 트래픽을 내부 경로로 보낸다.
처음 설계에서는 NAT Gateway 하나로 단순하게 시작할 수 있다. 하지만 ECR 이미지 pull, S3 객체 읽기, CloudWatch Logs 전송처럼 AWS 서비스 트래픽이 크고 반복적이면 Endpoint가 비용과 보안 면에서 유리해진다.
비용 감각: 단가보다 “이미 NAT가 필요한가”가 먼저다
섹션 제목: “비용 감각: 단가보다 “이미 NAT가 필요한가”가 먼저다”아래 계산은 서울 리전 예시 단가를 학습용 모델로 정리한 것이다. 실제 설계 전에는 AWS Pricing 페이지에서 현재 리전 단가를 다시 확인해야 한다.
| 항목 | NAT Gateway 예시 | Interface Endpoint 예시 | Gateway Endpoint |
|---|---|---|---|
| 시간당 고정 요금 | $0.045/AZ | $0.01/AZ | 무료 |
| 데이터 처리 요금 | $0.045/GB | $0.01/GB | 무료 |
| 적용 대상 | 모든 인터넷 트래픽 | 특정 AWS 서비스 | S3, DynamoDB |
AZ 2개, 월 720시간, 월 100GB AWS 서비스 트래픽이라고 가정하면:
NAT Gateway만 사용:2 * 0.045 * 720 + 100 * 0.045 = 64.8 + 4.5 = $69.3
Interface Endpoint만으로 해당 서비스 트래픽 처리:2 * 0.01 * 720 + 100 * 0.01 = 14.4 + 1.0 = $15.4하지만 외부 API 호출 때문에 NAT Gateway를 어차피 유지해야 한다면 계산이 달라진다. 이때 Endpoint의 가치는 “NAT를 완전히 없애는 비용 절감”이 아니라 “NAT 데이터 처리비를 얼마나 우회하는가”다. 위 예시 단가라면 Interface Endpoint 추가 고정비 $14.4/월을 데이터 처리비 절감분 (0.045 - 0.01) = $0.035/GB로 회수해야 하므로, 단순 손익분기점은 약 411GB/월이다.
결정은 먼저 “NAT를 없애거나 회피할 수 있는가”로 나눈다.
- AWS 서비스 트래픽이 대부분이고 외부 인터넷 목적지가 없다면, S3 Gateway Endpoint와 필요한 Interface Endpoint를 두어 NAT Gateway를 아예 만들지 않거나 사용량을 크게 줄일 수 있다. 이 경우 Endpoint는 비용 절감과 인터넷 경유 축소를 동시에 만든다.
- 외부 결제 API, GitHub, npm, 외부 SaaS가 필요하면 NAT Gateway는 계속 남아야 한다. 이때 Endpoint의 역할은 NAT 제거가 아니라 ECR/S3/Logs 같은 AWS 서비스 트래픽만 NAT에서 분리해 데이터 처리비와 인터넷 노출면을 줄이는 것이다.
세부 기준은 다음처럼 잡는다.
- S3/DynamoDB: Gateway Endpoint가 무료이므로 보통 먼저 만든다.
- ECR/CloudWatch Logs/Secrets Manager: Fargate Task 수가 많거나 이미지/로그 트래픽이 크면 Interface Endpoint를 검토한다.
- GitHub, npm, 외부 SaaS: VPC Endpoint로 대체할 수 없으므로 NAT Gateway 또는 다른 egress 설계가 필요하다.
- 보안 요구가 강한 워크로드: 비용만 보지 말고 “인터넷 경유를 줄인다”는 보안 이득을 함께 본다.
8. Flow Logs — 패킷이 실제로 왔는지 확인하는 기록
섹션 제목: “8. Flow Logs — 패킷이 실제로 왔는지 확인하는 기록”VPC Flow Logs는 VPC, Subnet, ENI 수준에서 IP 트래픽 메타데이터를 기록한다. 본문에서 가장 중요한 필드는 srcaddr, dstaddr, srcport, dstport, action이다.
ACCEPT 예시:2 123456789012 eni-0abc1234 10.0.11.5 10.0.21.3 49152 5432 6 25 7500 ACCEPT OK
의미:- ENI eni-0abc1234에서 관측- 10.0.11.5:49152 -> 10.0.21.3:5432- SG/NACL 기준으로 허용되어 ACCEPTREJECT 예시:2 123456789012 eni-0abc1234 10.0.11.5 10.0.21.3 49152 5432 6 0 0 REJECT OK
의미:- 패킷은 해당 ENI까지 도착했다.- 하지만 SG 또는 NACL 규칙에서 거부됐다.- bytes/packets가 0이면 실제 payload 전달은 없었다.ACCEPT는 애플리케이션이 요청을 정상 처리했다는 뜻이 아니다. 네트워크 정책 기준으로 허용됐다는 뜻이다. DB가 다운되어 있거나 애플리케이션 포트가 닫혀 있으면 Flow Logs는 ACCEPT인데 클라이언트는 여전히 실패할 수 있다.
반대로 로그 자체가 없다면 패킷이 해당 ENI까지 오지 않았을 가능성이 크다. 이때는 SG보다 Route Table, DNS, 대상 IP, NAT/Endpoint 경로를 먼저 의심한다.
9. 통신 실패를 좁히는 첫 진단 순서
섹션 제목: “9. 통신 실패를 좁히는 첫 진단 순서”네트워크 장애를 볼 때는 “SG부터 아무거나 열기”가 아니라 패킷의 경로를 순서대로 좁힌다.
flowchart TD
A["통신 실패 발생"] --> B{"수신 리소스 SG가 발신 SG/CIDR과 포트를 허용하나?"}
B -->|아니오| C["수신 SG inbound에 source SG와 port를 추가"]
B -->|예| D{"Subnet Route Table에 목적지 경로가 있나?"}
D -->|아니오| E["IGW, NAT Gateway, VPC Endpoint, Peering 경로 확인"]
D -->|예| F{"VPC Flow Logs에 REJECT가 보이나?"}
F -->|예| G["SG 또는 NACL 차단 지점 확인"]
F -->|아니오| H{"Flow Logs 자체가 있나?"}
H -->|아니오| I["패킷 미도달: Route, DNS, 대상 IP 확인"]
H -->|예| J["애플리케이션 포트, health check, TLS, DB 상태 확인"] SG와 Route Table 중 어디가 문제인지 애매하면 Reachability Analyzer로 source ENI -> destination ENI 경로 분석을 한 번 돌린다. 이 도구는 실제 패킷을 보내는 것이 아니라 현재 VPC 설정을 기준으로 어느 홉에서 막히는지 모델링해 보여주므로, “규칙은 맞아 보이는데 왜 안 되지?” 상황에서 SG, NACL, Route Table을 다시 좁히는 데 유용하다.
대표 실패 신호
섹션 제목: “대표 실패 신호”| 증상 | 먼저 의심할 개념 | 판단 포인트 |
|---|---|---|
| ECS에서 RDS 연결 타임아웃 | RDS SG inbound, DB Subnet route | RDS SG source가 ECS Task SG인지, DB Subnet이 인터넷 경로를 갖지 않는지 |
| Private Subnet Task가 ECR 이미지를 못 받음 | NAT Gateway 또는 ECR/S3 Endpoint | CannotPullContainerError, ECR/S3/Logs Endpoint 누락 여부 |
| 같은 VPC 안 서비스끼리 통신 불가 | 수신 SG의 SG-as-source 규칙 | 같은 VPC여도 SG 허용 없이는 통신 불가 |
| NAT Gateway 비용 급증 | AWS 서비스 트래픽의 NAT 경유 | S3/ECR/Logs가 Endpoint 없이 NAT를 타는지 |
Flow Logs에 REJECT가 반복 | SG 또는 NACL | REJECT가 보이면 패킷은 도착했고 정책에서 막힌 것 |
| Flow Logs에 아무것도 없음 | Route Table, DNS, 목적지 주소 | 패킷이 대상 ENI까지 오지 못했을 가능성 |
시나리오
ECS에서 RDS 연결 타임아웃
Private Subnet의 ECS Task가 RUNNING이고 RDS 엔드포인트 DNS도 해석되지만, NestJS 시작 시 DB 연결만 타임아웃된다.
먼저 RDS SG inbound에 ECS Task SG가 source로 허용됐는지 확인한다. 그다음 DB Subnet Route Table과 NACL을 확인한다.Runbook은 짧게, 원리는 본문에
섹션 제목: “Runbook은 짧게, 원리는 본문에”실제 콘솔 절차는 환경마다 다르지만 판단 순서는 거의 같다.
- 수신 리소스의 SG inbound에서 source와 port를 본다.
- 발신 리소스가 있는 Subnet의 Route Table에서 목적지 경로를 본다.
- Private Subnet에서 AWS 서비스로 나간다면 Endpoint 또는 NAT 경로를 본다.
- Flow Logs로
ACCEPT,REJECT, 로그 부재를 구분한다. - 네트워크가 통과했으면 애플리케이션 포트, TLS, health check, DB 상태를 본다.
10. 자주 헷갈리는 비교
섹션 제목: “10. 자주 헷갈리는 비교”| 개념 A | 개념 B | 차이점 |
|---|---|---|
| Public Subnet | Private Subnet | 차이는 이름이 아니라 Route Table의 0.0.0.0/0 -> IGW 경로 여부다 |
| Security Group | NACL | SG는 리소스 단위 + stateful, NACL은 Subnet 단위 + stateless다 |
| IGW | NAT Gateway | IGW는 인터넷과 VPC의 직접 관문, NAT는 Private 리소스의 outbound 경로다 |
| NAT Gateway | VPC Endpoint | NAT는 인터넷 목적지, Endpoint는 특정 AWS 서비스 목적지에 맞다 |
CIDR /16 | CIDR /24 | /16은 65,536개, /24는 256개다. 숫자가 작을수록 범위가 넓다 |
| ACCEPT | REJECT | ACCEPT는 네트워크 정책 허용, REJECT는 SG/NACL 차단을 뜻한다 |
11. 네트워크 격리 원리의 전이 — VPC에서 Kubernetes로
섹션 제목: “11. 네트워크 격리 원리의 전이 — VPC에서 Kubernetes로”VPC를 공부하면 Kubernetes NetworkPolicy를 읽을 때도 도움이 된다. 둘 다 “격리할 대상을 고르고, 허용할 통신만 명시한다”는 사고방식을 쓴다. 다만 기본값은 다르다.
| 항목 | AWS Security Group | Kubernetes NetworkPolicy |
|---|---|---|
| 기본 상태 | inbound는 기본 차단 | Policy가 없으면 보통 Pod 간 통신 허용 |
| 적용 단위 | ENI 또는 리소스 | Pod label selector |
| 허용 명시 | port + source SG/CIDR | ingress/egress + podSelector/namespaceSelector |
| 응답 트래픽 | stateful하게 자동 허용 | CNI 구현과 policy 방향에 따라 별도 고려 필요 |
짧은 대응 관계만 기억하면 충분하다.
RDS SG inbound: port 5432, source sg-ecs-task
Kubernetes NetworkPolicy: postgres Pod ingress: from app=backend port 5432이 절은 Kubernetes를 자세히 배우기 위한 본문이 아니다. VPC의 “명시적 허용” 모델이 다른 플랫폼의 네트워크 격리로 전이된다는 감각만 가져가면 된다.
출처: Kubernetes NetworkPolicy 공식 문서, Amazon EKS Network Policy
12. 프로덕션 VPC 설계 기본형
섹션 제목: “12. 프로덕션 VPC 설계 기본형”아래 스케치는 처음 보는 인프라 다이어그램을 읽기 위한 기준점이다. 실제 운영에서는 계정 분리, Transit Gateway, PrivateLink, centralized egress, WAF, CloudFront 같은 요소가 추가될 수 있지만, 기본 뼈대는 크게 다르지 않다.
VPC 10.0.0.0/16
Public Subnet A 10.0.1.0/24 (ap-northeast-2a) - ALB - NAT Gateway A - Route: 0.0.0.0/0 -> IGW
Public Subnet B 10.0.2.0/24 (ap-northeast-2b) - ALB - NAT Gateway B - Route: 0.0.0.0/0 -> IGW
Private App Subnet A 10.0.11.0/24 - ECS Task / EC2 - Route: 0.0.0.0/0 -> NAT Gateway A - SG outbound: RDS SG 5432, HTTPS egress, 필요한 Endpoint
Private App Subnet B 10.0.12.0/24 - ECS Task / EC2 - Route: 0.0.0.0/0 -> NAT Gateway B
DB Subnet A 10.0.21.0/24 - RDS Primary - Route: local only 또는 제한된 내부 경로 - SG inbound: source = ECS Task SG, port = 5432
DB Subnet B 10.0.22.0/24 - RDS Standby - Multi-AZ failover 대비
VPC Endpoints - S3 Gateway Endpoint - ECR API / ECR DKR Interface Endpoints - CloudWatch Logs Interface Endpoint - Secrets Manager Interface Endpoint이 구조에서 Public Subnet에 있는 것은 “인터넷과 직접 맞닿아도 되는 진입점”이다. 애플리케이션 서버와 DB는 Private/DB Subnet에 두고, SG-as-source로 허용 관계를 좁힌다. Endpoint는 AWS 서비스 트래픽을 NAT에서 분리하고, Flow Logs는 네트워크 정책이 실제로 어떻게 적용됐는지 확인하는 관측 장치가 된다.
보안 하드닝 기능은 개별 SG 설계를 대체하지 않는다. VPC Block Public Access 같은 VPC/계정 단위 가드레일이나 GuardDuty 연동은 “실수했을 때 피해를 줄이는 상위 안전망”이고, 기본 모델은 여전히 CIDR, Route Table, SG, NACL, Flow Logs다.
13. 내가 직접 확인해볼 것
섹션 제목: “13. 내가 직접 확인해볼 것”- AWS 콘솔에서 팀 VPC의 Resource Map을 열고 Public/Private/DB Subnet이 어떤 Route Table을 쓰는지 확인한다. 예상 패턴: Public Subnet Route Table에는
0.0.0.0/0 -> igw-...경로가 있고, DB Subnet에는 보통 인터넷 기본 경로가 없다. - ECS Task 하나를 골라 Subnet ID, ENI ID, Security Group ID를 확인한다.
- RDS SG inbound에
0.0.0.0/0이 아니라 애플리케이션 SG가 source로 들어 있는지 확인한다. 예상 패턴:PostgreSQL 5432 source sg-app또는sg-ecs-task형태다. - Private Subnet Route Table에 NAT Gateway 경로가 있는지, S3 Gateway Endpoint 경로가 있는지 비교한다.
- Cost Explorer에서 NAT Gateway의
Bytes사용량을 보고, S3/ECR/CloudWatch Logs 트래픽이 Endpoint로 우회될 수 있는지 가설을 세운다. - Flow Logs가 켜져 있다면 RDS 포트(
5432또는3306)로ACCEPT와REJECT를 검색해 본다. - VPC CIDR에서 현재 할당된 Subnet과 미할당 예비 대역을 직접 그려 본다.
14. 체크리스트
섹션 제목: “14. 체크리스트”VPC/Subnet/SG 복습 체크
- VPC, CIDR, Subnet, ENI, Security Group의 관계를 설명할 수 있다
- Public Subnet과 Private Subnet의 차이가 Route Table에 있음을 설명할 수 있다
- Security Group의 stateful 동작과 SG-as-source 패턴을 설명할 수 있다
- NAT Gateway가 outbound용이고, VPC Endpoint가 특정 AWS 서비스용임을 구분할 수 있다
- Flow Logs의 ACCEPT, REJECT, 로그 부재가 각각 무엇을 뜻하는지 말할 수 있다
- CIDR 고갈 시 Secondary CIDR이 왜 가능하지만 번거로운 해결책인지 설명할 수 있다
15. 추가 학습 키워드
섹션 제목: “15. 추가 학습 키워드”Route Table, NACL(Network ACL), Peering, VPN, Transit Gateway, Elastic IP, PrivateLink, VPC Flow Logs, Reachability Analyzer, IPAM
추천 리소스
섹션 제목: “추천 리소스”- AWS VPC Security Groups 공식 문서 — Stateful 동작, 규칙 구성 요소, Security Group을 source로 사용하는 방법
- AWS VPC 예제: Private Subnet + NAT Gateway — Private Subnet에서 NAT Gateway로 outbound를 구성하는 공식 예시
- AWS VPC CIDR blocks — VPC CIDR과 Secondary CIDR 제약
- AWS VPC Pricing — NAT Gateway, VPC Endpoint 비용 확인
- AWS PrivateLink Pricing — Interface Endpoint 비용 확인
- AWS VPC Security Best Practices — VPC 보안 가드레일과 운영 권고
16. 5줄 요약
섹션 제목: “16. 5줄 요약”- VPC는 AWS 안의 격리된 네트워크이고, CIDR로 주소 범위를 정한다.
- Subnet은 VPC 주소를 AZ와 용도별로 나눈 구역이며, Public/Private 차이는 Route Table이 만든다.
- Security Group은 ENI에 붙는 stateful 방화벽이고, IP보다 SG를 source로 쓰는 패턴이 실무에서 안전하다.
- Private Subnet의 outbound는 NAT Gateway 또는 VPC Endpoint로 설계하며, Endpoint는 특정 AWS 서비스 트래픽을 NAT에서 분리한다.
- 통신 장애는 SG → Route Table → Flow Logs → NACL/앱 상태 순서로 좁히면 된다.
17. 출처와 공식 문서
섹션 제목: “17. 출처와 공식 문서”본문의 역사와 제약은 기존 공식 문서 링크를 기준으로 정리했다. 가격은 변동될 수 있으므로 실제 설계 전에는 리전별 최신 Pricing 페이지를 다시 확인한다.
- Farewell EC2-Classic — All Things Distributed
- Amazon EC2 Update – Virtual Private Clouds for Everyone!
- EC2-Classic Networking is Retiring
- AWS VPC Security Groups
- AWS VPC CIDR blocks
- AWS VPC Pricing
- AWS PrivateLink Pricing
선택 부록
섹션 제목: “선택 부록”긴 절차는 첫 회독의 핵심이 아니다. 아래는 실무에서 확인이 필요할 때만 펼쳐 본다.
VPC Flow Logs에서 REJECT 검색 예시
fields @timestamp, srcAddr, dstAddr, srcPort, dstPort, action| filter action = "REJECT"| filter dstAddr = "10.0.21.3"| sort @timestamp desc| limit 20해석:
REJECT가 보이면 패킷은 대상 ENI까지 도착했고 SG 또는 NACL에서 막힌 것이다.- 로그가 없으면 Route Table, DNS, 대상 IP, Peering/Endpoint 경로를 먼저 본다.
ACCEPT인데 앱이 실패하면 DB listener, TLS, health check, 인증, 애플리케이션 로그를 본다.
Secondary CIDR 추가 절차를 읽는 법
aws ec2 describe-vpcs --vpc-ids vpc-xxxxxxxxx \ --query 'Vpcs[0].CidrBlockAssociationSet'
aws ec2 associate-vpc-cidr-block \ --vpc-id vpc-xxxxxxxxx \ --cidr-block 100.64.0.0/16
aws ec2 create-subnet \ --vpc-id vpc-xxxxxxxxx \ --cidr-block 100.64.1.0/24 \ --availability-zone ap-northeast-2a절차보다 중요한 판단:
- 기존 VPC, Peering, VPN 대상망과 겹치지 않는가?
- 새 Subnet이 어떤 Route Table을 쓸 것인가?
- ECS, EKS, RDS 같은 리소스가 새 Subnet을 실제로 사용할 수 있게 배포 설정이 바뀌었는가?
- 보안 규칙이 CIDR 기반이면 새 CIDR까지 열어야 하는가?
Connection tracking 관련 확인 포인트
aws cloudwatch get-metric-statistics \ --namespace AWS/EC2 \ --metric-name conntrack_allowance_exceeded \ --dimensions Name=InstanceId,Value=i-xxxxxxxxx \ --start-time 2026-05-17T00:00:00Z \ --end-time 2026-05-18T00:00:00Z \ --period 300 \ --statistics Sum읽는 법:
Sum > 0이면 connection tracking 한도 초과로 패킷 드롭이 발생했을 수 있다.- 한도 초과가 아니라 idle 이후 실패라면 client keep-alive와 ENI idle timeout의 불일치를 의심한다.
- 운영 조정은 인스턴스 세대, 로드밸런서 timeout, DB pool 설정을 함께 보고 적용한다.