VPC / Subnet / Security Group
분류: Layer 3 - AWS 인프라 & 보안
이 문서는 네트워크 구조와 통신에 집중합니다. 보안 메커니즘(WAF, Shield, NACL 심화)은 network-security.md를 참고하세요.
1. 한 줄 정의
섹션 제목: “1. 한 줄 정의”VPC는 AWS 안에 만드는 나만의 가상 네트워크이고, Subnet은 그 네트워크를 나눈 구역, Security Group은 각 리소스의 방화벽 규칙이다.
2. 왜 중요한가
섹션 제목: “2. 왜 중요한가”모든 AWS 리소스(EC2, ECS, RDS 등)는 VPC 안에 존재한다. 네트워크 구성을 모르면 “왜 서버끼리 통신이 안 되는지”, “왜 외부에서 접속이 안 되는지” 원인을 찾을 수 없다. 보안 설정도 네트워크 레벨에서 시작된다.
2.5 왜 VPC가 등장했나 — EC2-Classic의 한계
섹션 제목: “2.5 왜 VPC가 등장했나 — EC2-Classic의 한계”VPC가 “기본 격리, 명시적 허용”이라는 사고방식의 출발점이라는 사실은, 그 이전 모델인 EC2-Classic의 한계를 보면 분명해진다.
EC2-Classic(2006~2023)의 구조와 깨진 지점
EC2-Classic은 리전 단위로 모든 AWS 고객의 인스턴스가 단일 flat network를 공유했다. 결과적으로 세 가지가 깨졌다:
- IP 주소 통제 불가: 인스턴스 시작 시 AWS가 임의 Public IP를 부여했고, 사설 IP 대역을 사용자가 직접 지정할 수 없었다 → 사내망 CIDR(
10.0.0.0/16등)과 충돌하면 VPN 연결 자체가 불가능했다. - 격리 단위 부재: “내 서비스만 모인 네트워크”라는 개념이 없어, 보안은 Security Group 단일 계층에만 의존했다. 같은 리전 내 다른 고객 인스턴스가 같은 L2 평면을 공유했다.
- Multi-tier 토폴로지 불가: Public/Private Subnet 구분이 없어 DB를 인터넷에서 물리적으로 분리할 수 없었다 — DB 인스턴스도 같은 flat 네트워크에서 SG 규칙으로만 막아야 했다.
VPC의 해결 메커니즘 (2009 출시)
AWS는 2009년 VPC를 출시하면서 위 세 가지를 동시에 해소했다:
- 자체 CIDR 지정 → 사내망과 일치하는 사설 대역을 골라 VPN/Direct Connect로 하이브리드 연결 가능 (본 문서 Section 3의 CIDR 설계 가이드가 이 위에서 성립)
- Subnet 계층 분리 → Route Table에 IGW를 둘지 말지로 Public/Private을 가르고, DB는 Private Subnet에 격리 (Section 3의 “Public/Private 차이는 Route Table에 있다” 명제가 여기서 유래)
- 계정별 논리적 격리 → 같은 리전이어도 다른 계정·VPC와 네트워크 평면이 분리됨
이 전환의 강제성은 일정에 박혀 있다 — 2013년 12월 4일 이후 신규 계정은 EC2-Classic을 제공받지 못했고, 2023년 8월 15일 AWS는 마지막 Classic 인스턴스를 종료했다. 즉 2026년 현재 모든 신규 인프라는 VPC 위에서만 동작하며, “VPC를 안 쓸 선택지”는 존재하지 않는다.
이 토픽이 사라지면 무엇이 깨지는가: VPC/Subnet/SG 모델 없이는 “DB를 인터넷에서 직접 보이지 않게” 같은 가장 기본적인 보안 결정조차 표현할 방법이 없다. 본 문서의 모든 트러블슈팅(Section 6.5)이 전제하는 “Public/Private 분리 + 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. 핵심 개념
섹션 제목: “3. 핵심 개념”VPC (Virtual Private Cloud)
AWS 안에 만드는 격리된 가상 네트워크. 하나의 VPC는 하나의 IP 주소 범위(CIDR)를 가진다. 예: 10.0.0.0/16 = 10.0.x.x 범위의 IP를 사용.
CIDR 설계 가이드 — 처음부터 여유 있게 잡아야 하는 이유
VPC CIDR은 생성 후 변경이 불가능하다(Secondary CIDR 추가는 가능하지만 번거롭다). 처음에 넉넉하게 설계하지 않으면 나중에 IP가 부족해 서비스 확장이 막힌다.
권장 설계 패턴:
- VPC: /16 (65,536개 IP) — 미래 확장을 고려해 충분히 크게.
10.0.0.0/16또는172.16.0.0/16 - Subnet: /24 (256개, 실제 사용 가능 251개) — 용도별로 나눠도 IP가 충분하고 Route Table 관리가 단순함
- 예비 대역 확보: 전체 CIDR의 50%는 미할당으로 남겨둔다. 새로운 AZ 추가, 신규 서비스 도입, VPC Peering 확장 등을 대비
[권장 설계 예시]VPC: 10.0.0.0/16 (65,536개 IP)
사용 중: Public Subnet A: 10.0.1.0/24 (251개 IP, ALB/NAT) Public Subnet B: 10.0.2.0/24 (251개 IP, ALB Multi-AZ) Private Subnet A: 10.0.11.0/24 (251개 IP, ECS Task) Private Subnet B: 10.0.12.0/24 (251개 IP, ECS Task Multi-AZ) DB Subnet A: 10.0.21.0/24 (251개 IP, RDS Primary) DB Subnet B: 10.0.22.0/24 (251개 IP, RDS Standby)
예비 대역 (미할당): 10.0.30.0/24 ~ 10.0.99.0/24 → 신규 서비스, 추가 AZ 대비 10.0.100.0/24 이상 → VPC Peering, EKS 노드 확장 대비ECS + Fargate 환경에서 주의할 점: awsvpc 모드에서는 Task마다 별도 ENI와 Private IP가 할당된다. Task 100개를 운영하면 Subnet에서 100개의 IP가 소비되므로, /24(251개)보다 작은 Subnet(/27 = 32개)으로는 충분하지 않다.
Subnet (서브넷)
VPC를 더 작은 네트워크로 분할한 것. 두 종류가 있다:
- Public Subnet: 인터넷과 직접 통신 가능. 웹 서버, 로드밸런서 등이 위치.
- Private Subnet: 인터넷에서 직접 접근 불가. DB, 내부 서비스 등이 위치.
Security Group (보안 그룹)
리소스별로 붙는 가상 방화벽.
예: 웹 서버의 Security Group- 인바운드: 80(HTTP), 443(HTTPS) 허용 — 모든 IP에서- 인바운드: 22(SSH) 허용 — 사무실 IP에서만- 아웃바운드: 전체 허용Security Group은 stateful이다. 인바운드를 허용하면 그 연결의 응답 트래픽은 아웃바운드 규칙에 관계없이 자동으로 허용된다. → 아웃바운드 전체 허용이 아니어도 요청/응답 쌍은 자동으로 통과한다.
stateful이 깨지는 조건 — untracked 흐름과 idle timeout silent drop
stateful 거동은 connection tracking 테이블에 항목이 있을 때만 성립한다. 두 가지 silent failure(에러 없이 잘못 동작)가 운영 중에 가장 자주 나타난다:
- Untracked flow의 갑작스러운 끊김: 인바운드/아웃바운드 모두
0.0.0.0/0+ 전체 포트(0-65535)면 그 흐름은 의도적으로 tracking에서 제외된다. 이 상태에서 인바운드 규칙을 좁히면 기존 SSH/HTTP 연결도 즉시 끊긴다. 반대로 좁은 규칙으로 시작해서 tracked 상태가 된 연결은 규칙을 제거해도 timeout 전까지 유지된다 → 운영 중 “왜 어떤 룰 변경은 즉시 세션을 끊고, 어떤 변경은 안 끊지?”의 직접 원인. - Nitro v6 인스턴스의 350초 idle timeout: M7i·C7i 등 Nitro v6 세대는 TCP established idle timeout 기본값이 350초로, 이전 세대 기본값(432,000초)보다 약 1,234배 짧다. DB 커넥션 풀·HTTP keep-alive 세션이 5분 넘게 idle이면 에러 로그 없이 silent drop되고, 다음 요청에서
ECONNRESET또는 hang으로 드러난다. 같은 코드가 Nitro v5(c6i 등)에서는 멀쩡히 돌다가 인스턴스 타입 업그레이드 직후 망가지는 패턴.
# 감지: 인스턴스의 conntrack 한도 초과 드롭을 CloudWatch ENA 지표로 확인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 이면 conntrack 한도 초과로 패킷이 드롭되고 있음# Sum = 0 이면 idle timeout 쪽을 의심 (drop이 아닌 timeout 만료)결정 기준과 복구 절차:
- 장기 idle 연결이 있는 워크로드(DB pool, persistent HTTP, 스트리밍): TCP keep-alive를 5분 미만으로 설정. Linux는
net.ipv4.tcp_keepalive_time=240, DB 클라이언트(pg-pool, mysql2)는idleTimeoutMillis < 240000. - conntrack 한도 초과가 보일 때: ENI에 더 짧은
TcpEstablishedTimeout을 설정해 stale 세션을 빨리 회수 (1번 시나리오 — exhaustion 회피가 우선). - conntrack 한도는 여유롭지만 idle drop이 보일 때: ENI
TcpEstablishedTimeout을 60~5400초 사이로 늘려 ALB·NLB 기본값(350초·90분)에 맞춤 (2번 시나리오 — 연결 유지가 우선). - 새 인스턴스 타입 도입 전: 반드시 Nitro v6에서 부하 시험. 코드가 Nitro v5에서 잘 돈다는 사실이 v6에서의 안전을 보장하지 않는다.
출처: Amazon EC2 security group connection tracking (AWS Docs), Introducing configurable Idle timeout for Connection tracking (AWS Networking Blog)
Security Group을 Source로 사용하는 패턴 — 실무의 핵심
IP 주소 대신 다른 Security Group ID를 소스로 지정할 수 있다. 이 방법이 실무에서 더 안전하고 유지보수가 쉽다.
예: RDS가 ECS Task에서만 접속되도록 설정
RDS Security Group 인바운드 규칙:- Port 5432 (PostgreSQL)- Source: sg-xxxxxxxx (ECS Task의 Security Group ID)이렇게 설정하면 ECS Task SG를 달고 있는 모든 컨테이너가 RDS에 접속 가능하고, IP가 바뀌어도 규칙 수정이 필요 없다.
📖 더 보기: AWS VPC Security Groups 공식 문서 — Stateful 동작 원리, 규칙 구성 요소, Security Group을 소스로 사용하는 방법 (입문)
Internet Gateway (IGW)
VPC가 인터넷과 통신하기 위한 관문.
NAT Gateway — 내부적으로 어떻게 동작하는가
비유: NAT Gateway는 “Private 구역의 직원이 외부 편의점에 가는 뒷문”이다. 직원(Private Subnet 리소스)은 나갈 수 있지만, 밖에서는 그 문을 열고 들어올 수 없다.
내부 동작:
- Private Subnet의 ECS Task → NAT Gateway(Public Subnet에 위치)로 패킷 전송
- NAT Gateway가 출발지 IP를 NAT Gateway의 Elastic IP로 교체(NAT = Network Address Translation)
- 외부 인터넷에는 NAT Gateway의 IP로 요청이 나감
- 응답 패킷이 돌아오면 NAT Gateway가 다시 원래 ECS Task IP로 변환해서 전달
- 외부에서 먼저 들어오려 해도 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를 Elastic IP로 변환 IGW->>API: 인터넷으로 요청 전달 API-->>NAT: 응답 반환 NAT-->>Task: 원래 Private IP로 역변환
Route Table (라우팅 테이블)
각 Subnet에 “트래픽을 어디로 보낼지” 경로 규칙을 정의한다.
- Public Subnet의 Route Table:
0.0.0.0/0 → IGW항목이 있음 → 인터넷 통신 가능 - Private Subnet의 Route Table: IGW 경로가 없음 → 인터넷 직접 통신 불가
- Private Subnet에서 외부 필요 시:
0.0.0.0/0 → NAT Gateway항목 추가
Public과 Private Subnet의 실제 차이는 Security Group이 아니라 Route Table에 있다.
VPC Endpoint — NAT Gateway 없이 AWS 서비스에 접근하는 방법
비유: VPC Endpoint는 “AWS 서비스로 향하는 전용 내부 통로”이다. ECR, S3, CloudWatch 등 AWS 서비스에 접근할 때, NAT Gateway를 거쳐 인터넷으로 나갔다 들어오는 대신, VPC 내부 네트워크를 통해 직접 연결한다.
실무에서 중요한 이유:
- Fargate Task가 Private Subnet에 있을 때 ECR 이미지 Pull에 필요
- NAT Gateway 비용 절감 (특히 ECR/S3 트래픽이 많을 때)
- 보안: 인터넷을 거치지 않으므로 더 안전
주요 VPC Endpoint:- com.amazonaws.ap-northeast-2.ecr.dkr (ECR 이미지 Pull)- com.amazonaws.ap-northeast-2.ecr.api (ECR API)- com.amazonaws.ap-northeast-2.s3 (S3 접근)- com.amazonaws.ap-northeast-2.logs (CloudWatch Logs)- com.amazonaws.ap-northeast-2.secretsmanager (Secrets Manager)VPC Flow Logs — 네트워크 트래픽 기록
VPC Flow Logs는 VPC를 통과하는 모든 IP 트래픽 정보를 기록한다. 네트워크 문제 디버깅 시 “실제로 패킷이 오고 있는가?”를 확인할 수 있는 유일한 방법이다.
활성화 경로: VPC → Flow Logs → Create flow log로그 대상: CloudWatch Logs 또는 S3
로그 항목 예시 (ACCEPT):2 123456789012 eni-0abc1234 10.0.1.5 10.0.2.3 49152 5432 6 25 7500 ACCEPT OK↑ 버전 ↑ 계정ID ↑ ENI ID ↑ 소스IP ↑ 목적IP ↑ 포트 ↑ 대상포트 ... ACCEPT
로그 항목 예시 (REJECT - Security Group 차단):2 123456789012 eni-0abc1234 10.0.1.5 10.0.2.3 49152 5432 6 0 0 REJECT OK→ REJECT가 보이면 Security Group 또는 NACL 규칙을 확인VPC 보안 하드닝 — 2025년 신기능 포함
-
VPC Block Public Access (2024년 11월 출시)
VPC 레벨에서 인터넷 인바운드/아웃바운드를 통째로 차단하는 기능이다. Security Group으로 개별 리소스를 관리하는 것과 달리, VPC 전체에 대해 인터넷 트래픽을 차단한다.
경로: VPC → Settings → Block Public AccessIngress-only 모드: 인터넷 → VPC 방향만 차단 (아웃바운드는 허용)→ 프로덕션 Private VPC에 권고하는 설정 -
GuardDuty VPC 위협 탐지
Flow Logs를 GuardDuty와 연동하면 비정상 트래픽 패턴(포트 스캔, 비정상적인 연결 시도)을 자동으로 탐지하고 알림을 보낸다.
경로: GuardDuty → Settings → Enable→ VPC Flow Logs를 자동으로 수집/분석하여 Findings 생성 -
최소 권한 Security Group 원칙
Security Group 아웃바운드 규칙을 “전체 허용(
0.0.0.0/0)“으로 두는 관행을 개선한다. 실제 필요한 포트와 대상만 허용한다.예: NestJS ECS Task의 아웃바운드 규칙 최소화- 5432 → RDS Security Group (PostgreSQL)- 443 → 0.0.0.0/0 (외부 HTTPS API 호출)- 그 외 포트는 기본 차단
비유로 이해하기
- VPC = 건물 전체
- Subnet = 건물 안의 층 (1층은 Public=로비, 지하는 Private=서버실)
- Security Group = 각 방의 잠금장치
- IGW = 건물 정문
- NAT Gateway = 서버실 직원이 편의점 가는 뒷문 (밖에서는 못 들어옴)
- Route Table = 층별 안내판 (어디로 가야 하는지 경로 표시)
- VPC Endpoint = 서버실에서 AWS 본사로 가는 전용 내부 통로
4. 실무에서 어디에 쓰이나
섹션 제목: “4. 실무에서 어디에 쓰이나”- 서비스 배포 시 어떤 Subnet에 배치할지 결정
- 보안 설정 (DB는 Private Subnet + 특정 SG만 허용)
- 네트워크 통신 문제 디버깅
- 새 서비스 추가 시 네트워크 설계
5. 현재 내 업무와 연결점
섹션 제목: “5. 현재 내 업무와 연결점”- 서비스 간 통신 안 될 때 Security Group 규칙 확인
- 배포 시 “어떤 서브넷에 배치됐는지” 이해
- RDS 접속 안 될 때 네트워크(Private Subnet + SG) 점검
- 팀 인프라 구조도를 읽을 때 VPC/Subnet 구조 이해 필요
6. 자주 헷갈리는 개념 비교
섹션 제목: “6. 자주 헷갈리는 개념 비교”| 개념 A | 개념 B | 차이점 |
|---|---|---|
| Public Subnet | Private Subnet | Public은 인터넷 직접 접근 가능, Private은 불가 |
| Security Group | NACL | SG는 리소스 단위 + stateful, NACL은 서브넷 단위 + stateless |
| IGW | NAT Gateway | IGW는 양방향(인터넷↔VPC), NAT는 단방향(VPC→인터넷만) |
| CIDR /16 | CIDR /24 | /16은 65,536개 IP, /24는 256개 IP. 숫자가 작을수록 범위가 넓다 |
| NAT Gateway | VPC Endpoint | NAT는 모든 인터넷 트래픽 허용, VPC Endpoint는 특정 AWS 서비스만 전용 연결 |
6.5 트러블슈팅
섹션 제목: “6.5 트러블슈팅”flowchart TD
A["통신 실패 발생"] --> B{"수신 SG가 발신 SG나 CIDR을 허용하나?"}
B -->|아니오| C["Inbound rule에 source SG와 port 추가"]
B -->|예| D{"Subnet Route Table에 목적지 경로가 있나?"}
D -->|아니오| E["IGW, NAT Gateway, VPC Endpoint 경로 확인"]
D -->|예| F{"VPC Flow Logs에 REJECT가 보이나?"}
F -->|예| G["SG 또는 NACL 차단 지점 확인"]
F -->|아니오| H["애플리케이션, DNS, health check 확인"] 🔧 ECS → RDS 통신 안 됨 — Security Group 미설정
섹션 제목: “🔧 ECS → RDS 통신 안 됨 — Security Group 미설정”증상: NestJS 서버 시작 시 DB 연결 타임아웃. ECONNREFUSED 또는 Connection timed out 에러
원인: RDS Security Group의 인바운드 규칙에 ECS Task가 사용하는 Security Group이 허용되어 있지 않음
해결:
- ECS Task의 Security Group ID 확인 (ECS → Task → Network → Security Groups)
- RDS Security Group → 인바운드 규칙 편집
- 아래 규칙 추가:
- 유형: PostgreSQL (또는 MySQL)
- 포트: 5432 (또는 3306)
- 소스: ECS Task의 Security Group ID (
sg-xxxxxxxxx)
- 저장 후 ECS Task 재시작
시나리오
ECS에서 RDS 연결 타임아웃
Private Subnet의 ECS Task가 RUNNING인데 NestJS 시작 시 DB 연결만 타임아웃된다. 같은 VPC이고 RDS 엔드포인트 DNS도 정상 해석된다.
먼저 RDS SG 인바운드에 ECS Task SG가 소스로 허용됐는지 확인하고, 그다음 DB Subnet 라우팅과 NACL을 확인한다.🔧 Private Subnet의 ECS가 ECR/외부 API에 접근 불가
섹션 제목: “🔧 Private Subnet의 ECS가 ECR/외부 API에 접근 불가”증상: ECS Task 시작 실패 (CannotPullContainerError) 또는 런타임에 외부 API 호출 실패. Private Subnet에 Task를 올린 직후부터 발생
원인: Private Subnet에 NAT Gateway 라우팅이 없어서 인터넷 아웃바운드 불가
해결:
- VPC → Route Tables → Private Subnet에 연결된 Route Table 확인
0.0.0.0/0→ NAT Gateway 경로가 있는지 확인- 없으면 Route 추가: Destination
0.0.0.0/0, Target = NAT Gateway ID - NAT Gateway가 없으면 Public Subnet에 NAT Gateway 생성 후 연결
- 비용 절감 대안: ECR/S3/CloudWatch용 VPC Endpoint 생성 (NAT 없이 AWS 서비스 접근 가능)
🔧 같은 VPC인데 서비스끼리 통신 불가
섹션 제목: “🔧 같은 VPC인데 서비스끼리 통신 불가”증상: ECS Service A → ECS Service B 또는 ECS → ElastiCache 등 같은 VPC 내 서비스 간 통신 실패. 외부 통신은 됨
원인: Security Group의 인바운드 규칙에 상대방 서비스의 SG가 허용되지 않음. 같은 VPC라도 SG 규칙이 없으면 통신 불가
해결:
- 수신 측 서비스의 Security Group → 인바운드 규칙 확인
- 발신 측 서비스의 Security Group ID를 소스로 해당 포트 허용
- VPC Reachability Analyzer로 경로 분석 가능:
경로: VPC → Reachability Analyzer → Create and analyze pathSource: 발신 서비스의 ENI, Destination: 수신 서비스의 ENI→ 차단 지점을 시각적으로 확인 가능
🔧 VPC Flow Logs로 보이지 않는 네트워크 문제 진단
섹션 제목: “🔧 VPC Flow Logs로 보이지 않는 네트워크 문제 진단”증상: SG 규칙을 다 확인했는데도 통신이 안 됨. 어디서 막히는지 감이 안 옴
원인: SG 외에 NACL, 라우팅 테이블, 또는 애플리케이션 자체 문제일 수 있음
해결:
# 1. VPC Flow Logs 활성화 (CloudWatch Logs로)# VPC → Flow Logs → Create flow log → CloudWatch Logs 선택
# 2. CloudWatch Logs에서 특정 IP/포트 로그 검색# Log Group: /vpc/flowlogs/<vpc-id># 필터 예시: REJECT 로그만 보기fields @timestamp, srcAddr, dstAddr, srcPort, dstPort, action| filter action = "REJECT"| filter dstAddr = "10.0.2.5" -- RDS IP| sort @timestamp desc| limit 20
# REJECT 로그가 보이면 → Security Group 또는 NACL 차단# 로그 자체가 없으면 → 패킷이 해당 ENI에 도달하지 못함 (라우팅 문제)🔧 NAT Gateway 비용이 예상보다 많이 나오는 경우
섹션 제목: “🔧 NAT Gateway 비용이 예상보다 많이 나오는 경우”증상: AWS Cost Explorer에서 NAT Gateway 항목이 월 수십만 원씩 나옴. 처리 데이터 양이 많을수록 비용이 급증
원인: NAT Gateway는 처리한 데이터 GB당 과금된다. ECR 이미지 Pull, S3 접근, 외부 API 호출이 모두 NAT Gateway를 거치면 비용이 빠르게 쌓임
해결:
1. AWS Cost Explorer → NAT Gateway 항목에서 데이터 처리량 확인 경로: Cost Explorer → Service: EC2-Other → Usage Type: NatGateway-Bytes
2. VPC Endpoint로 AWS 서비스 직접 연결 (NAT 우회) 설정 대상: - S3 Gateway Endpoint (무료) - ECR Interface Endpoint - CloudWatch Logs Endpoint → ECR과 S3 트래픽이 NAT를 우회하면 대부분의 경우 70% 이상 비용 절감
3. S3 Gateway Endpoint 생성 (무료이므로 우선 적용) 경로: VPC → Endpoints → Create Endpoint → Service: com.amazonaws.ap-northeast-2.s3 → Type: Gateway → 해당 Route Table에 자동으로 S3 라우팅 추가됨6.6 NAT Gateway vs VPC Endpoint 비용 정량 비교
섹션 제목: “6.6 NAT Gateway vs VPC Endpoint 비용 정량 비교”NAT Gateway와 VPC Endpoint 중 무엇을 써야 하는지는 트래픽 규모에 따른 비용 계산으로 결정된다.
기본 단가 (ap-northeast-2 서울 리전)
| 항목 | NAT Gateway | Interface Endpoint | Gateway Endpoint |
|---|---|---|---|
| 시간당 고정 요금 | $0.045/AZ | $0.01/AZ | 무료 |
| 데이터 처리 요금 | $0.045/GB | $0.01/GB | 무료 |
| 적용 대상 | 모든 인터넷 트래픽 | 특정 AWS 서비스 | S3, DynamoDB만 |
월 데이터 전송량 기준 비용 비교 (AZ 2개, S3/ECR 트래픽 가정)
| 월 트래픽 | NAT Gateway 비용 | Interface Endpoint 비용 | Gateway Endpoint 비용 |
|---|---|---|---|
| 10 GB | (2AZ × $0.045 × 720h) + (10 × $0.045) = $65.3 | (2AZ × $0.01 × 720h) + (10 × $0.01) = $14.5 | $0 |
| 100 GB | $64.8 (고정) + $4.5 = $69.3 | $14.4 (고정) + $1.0 = $15.4 | $0 |
| 1 TB | $64.8 (고정) + $46.1 = $110.9 | $14.4 (고정) + $10.2 = $24.6 | $0 |
손익분기점 분석
- S3·DynamoDB: Gateway Endpoint는 무료이므로 무조건 Endpoint가 유리. 라우팅 테이블에 자동 추가되며 별도 설정 비용 없음.
- ECR·CloudWatch Logs·Secrets Manager: Interface Endpoint 고정비($0.01/AZ/h × 2AZ × 720h = $14.4/월)가 발생하므로, 해당 서비스 트래픽이 월 약 200GB 이하면 NAT Gateway가 오히려 저렴할 수 있다. 트래픽이 많을수록 Interface Endpoint가 압도적으로 유리하다.
- 외부 인터넷(npm, GitHub 등): VPC Endpoint 적용 불가. NAT Gateway 필수.
실무 결정 패턴
1. S3 Gateway Endpoint → 무조건 생성 (무료, 즉시 비용 절감)2. ECR + CloudWatch Logs Endpoint → Fargate Task가 많을수록 효과적3. NAT Gateway → 외부 인터넷 트래픽용으로만 유지6.7 Secondary CIDR — CIDR 고갈 시 대응 절차
섹션 제목: “6.7 Secondary CIDR — CIDR 고갈 시 대응 절차”VPC CIDR을 처음부터 넉넉하게 잡아야 하는 이유는 Primary CIDR 변경이 불가능하기 때문이다. 이미 IP가 부족한 상황이라면 Secondary CIDR 추가가 유일한 해결책이다.
추가 절차 (CLI)
# 1. 현재 VPC CIDR 확인aws ec2 describe-vpcs --vpc-ids vpc-xxxxxxxxx \ --query 'Vpcs[0].CidrBlockAssociationSet'
# 2. Secondary CIDR 추가aws ec2 associate-vpc-cidr-block \ --vpc-id vpc-xxxxxxxxx \ --cidr-block 100.64.0.0/16
# 3. 추가된 CIDR로 새 Subnet 생성aws ec2 create-subnet \ --vpc-id vpc-xxxxxxxxx \ --cidr-block 100.64.1.0/24 \ --availability-zone ap-northeast-2a
# 4. 새 Subnet을 기존 Route Table에 연결 (Private이면 NAT GW 경로 포함)aws ec2 associate-route-table \ --route-table-id rtb-xxxxxxxxx \ --subnet-id subnet-xxxxxxxxx핵심 제약 조건
| 제약 | 내용 |
|---|---|
| RFC 1918 범위 혼합 금지 | Primary CIDR이 10.x.x.x이면 Secondary로 172.16.x.x나 192.168.x.x 추가 불가 |
| 최대 개수 | Secondary CIDR 최대 4개 (Primary 포함 5개) |
| 크기 | /16 ~ /28 사이만 허용, 생성 후 크기 변경 불가 |
| 중복 금지 | 기존 CIDR 또는 피어링된 VPC의 CIDR과 겹칠 수 없음 |
RFC 1918 혼합 금지 우회책: 100.64.0.0/10 (Shared Address Space, RFC 6598) 범위는 혼합 제한에서 자유롭다. IP 부족 시 100.64.0.0/16 대역을 Secondary CIDR로 추가하는 패턴이 실무에서 사용된다(EKS Pod CIDR 확장 시 자주 활용).
라우팅 테이블 주의사항
[문제 상황]Primary: 10.0.0.0/16VPN 게이트웨이 라우트: 10.0.50.0/24 → Virtual Private Gateway
Secondary CIDR로 10.0.50.0/24 이상을 추가하면 라우트 충돌 발생.→ 기존 라우트보다 더 좁은(/더 큰 prefix) 대역만 Secondary로 추가 가능.
[해결]Secondary CIDR을 기존 라우트와 겹치지 않는 완전히 다른 대역으로 선택.예: 100.64.0.0/16 (충돌 위험 없음)출처: AWS VPC CIDR blocks, Add or remove a CIDR block from your VPC
6.8 네트워크 격리 원리의 전이 — VPC → K8s → Docker
섹션 제목: “6.8 네트워크 격리 원리의 전이 — VPC → K8s → Docker”“격리가 기본값, 허용이 명시적” 원칙은 VPC Security Group에만 있는 개념이 아니다. Kubernetes NetworkPolicy, Docker 네트워크도 동일한 원리를 다른 형태로 구현한다.
플랫폼별 비교표
| 항목 | AWS Security Group | Kubernetes NetworkPolicy | Docker bridge/overlay |
|---|---|---|---|
| 기본 격리 정책 | Deny-all (인바운드 전체 차단) | Allow-all (기본은 모두 허용) | bridge: Allow-all, overlay: 네트워크 단위 격리 |
| 격리 활성화 방법 | SG 자체가 격리 단위 (생성 시 즉시 적용) | NetworkPolicy로 Pod를 선택하면 그 Pod만 격리됨 | --internal 플래그 또는 별도 네트워크 생성 |
| 허용 명시 방법 | Inbound Rule에 port + source SG 추가 | ingress.from 또는 egress.to 규칙 추가 | 같은 네트워크에 컨테이너 추가 |
| 적용 단위 | ENI(네트워크 인터페이스) | Pod 라벨 셀렉터 | 컨테이너/서비스 |
| Stateful 여부 | Yes (응답 자동 허용) | No (ingress/egress 각각 명시) | No |
K8s NetworkPolicy — deny-all + 허용 명시 패턴
K8s는 기본이 Allow-all이므로, 보안을 위해 먼저 deny-all Policy를 적용한 뒤 필요한 트래픽만 허용하는 것이 표준 패턴이다. 이는 VPC SG가 기본적으로 동작하는 방식과 동일한 결과를 의도적으로 구현하는 것이다.
# 1단계: 네임스페이스 전체 deny-all (VPC SG 기본 상태와 동일)apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: default-deny-all namespace: productionspec: podSelector: {} # 모든 Pod 선택 policyTypes: - Ingress - Egress
---# 2단계: 특정 트래픽만 허용 (VPC SG Inbound Rule과 동일한 역할)apiVersion: networking.k8s.io/v1kind: NetworkPolicymetadata: name: allow-backend-to-db namespace: productionspec: podSelector: matchLabels: app: postgres # 수신 Pod (RDS 역할) ingress: - from: - podSelector: matchLabels: app: backend # 송신 Pod (ECS Task 역할) ports: - port: 5432[AWS VPC SG와 1:1 대응]RDS SG Inbound: Port 5432, Source: ECS Task SG ↕ 동일한 의도K8s NetworkPolicy: postgres Pod Ingress, from: backend Pod, port: 5432결론: 플랫폼이 달라도 “격리가 기본값, 허용이 명시적”이라는 원칙은 동일하다. VPC SG 개념을 이해하면 K8s NetworkPolicy, Docker 네트워크 격리로 지식이 그대로 전이된다.
출처: Kubernetes NetworkPolicy 공식 문서, Amazon EKS Network Policy
7. 체크리스트
섹션 제목: “7. 체크리스트”VPC/Subnet/SG 복습 체크
- VPC, Subnet, Security Group의 관계를 설명할 수 있다
- Public Subnet과 Private Subnet의 차이가 Route Table에 있음을 설명할 수 있다
- Security Group의 인바운드와 아웃바운드 규칙을 읽을 수 있다
- 통신이 안 될 때 SG, Route Table, NACL, Flow Logs 중 무엇을 먼저 볼지 판단할 수 있다
- NAT Gateway와 VPC Endpoint의 차이와 선택 기준을 설명할 수 있다
8. 추가 학습 키워드
섹션 제목: “8. 추가 학습 키워드”Route Table, NACL(Network ACL), Peering, VPN, Transit Gateway, Elastic IP, PrivateLink, VPC Flow Logs
📚 추천 리소스
섹션 제목: “📚 추천 리소스”- 📖 AWS VPC Security Groups 공식 문서 — Stateful 동작, 규칙 구성 요소, Security Group을 소스로 사용하는 방법 (입문)
- 📖 AWS Networking - VPC, Subnets, NAT Gateway 개요 — VPC 전체 구성 요소를 그림과 함께 설명한 입문 가이드 (입문)
- 📖 Private Subnet + NAT Gateway 구성 예시 — AWS 공식 아키텍처 예시로 Private Subnet에서 NAT Gateway 연결하는 실제 설정 방법 (중급)
- 📖 AWS VPC 네트워크 트러블슈팅 10단계 — 통신 불가 상황에서 단계별 진단 방법 실전 가이드 (중급)
- 📖 AWS VPC 보안 베스트 프랙티스 2025 — VPC Block Public Access, GuardDuty 연동, 최소 권한 SG 설계 AWS 공식 가이드 (중급)
9. 내가 직접 확인해볼 것
섹션 제목: “9. 내가 직접 확인해볼 것”- AWS 콘솔에서 팀 VPC 구조 확인 (VPC > Subnets > Route Tables)
경로: VPC → Your VPCs → <팀 VPC> → Resource Map 탭확인: Public/Private Subnet 구분, Route Table에 IGW/NAT Gateway 연결 여부예상 화면: 왼쪽 Public Subnet에 IGW 연결, 오른쪽 Private Subnet에 NAT Gateway 연결
- 팀 서비스가 어떤 Subnet에 배치되어 있는지 확인
경로: ECS → Tasks → <Task> → Configuration 탭 → Networking 섹션확인: Subnet ID, Security Group ID
- Security Group 규칙을 열어보고 “무엇이 허용되어 있는지” 읽어보기
경로: EC2 → Security Groups → <SG 선택> → Inbound rules 탭예상 출력:Type Protocol Port SourcePostgreSQL TCP 5432 sg-0abc123def (ecs-task-sg)HTTPS TCP 443 0.0.0.0/0
- VPC 구조를 간단한 다이어그램으로 그려보기
10. 5줄 요약
섹션 제목: “10. 5줄 요약”- VPC(가상 네트워크) → Subnet(구역) → Security Group(방화벽) 3계층으로 AWS 네트워크가 구성된다 — 모든 AWS 리소스는 이 안에 존재한다
- Public Subnet = Route Table에 IGW 경로가 있는 것, Private Subnet = 없는 것 — 차이는 Security Group이 아닌 Route Table이다
- Security Group은 Stateful(요청 허용 시 응답 자동 허용)이며, IP 대신 다른 SG를 소스로 지정하는 것이 실무 표준이다
- 네트워크 문제 진단 순서: SG 규칙 → Route Table(NAT Gateway 경로) → VPC Flow Logs(REJECT 로그) → Reachability Analyzer
- NAT Gateway 비용이 크다면 S3/ECR/CloudWatch용 VPC Endpoint로 교체 — Gateway Endpoint(S3)는 무료이다
프론트엔드 → 플랫폼 브릿지
섹션 제목: “프론트엔드 → 플랫폼 브릿지”VPC 네트워크 격리 vs React 컴포넌트 Scope
React에서 컴포넌트는 명시적으로 props로 전달하지 않으면 다른 컴포넌트의 state에 접근할 수 없다. VPC 네트워크 격리도 동일한 원리다: 같은 VPC 안에 있어도 Security Group에서 명시적으로 허용하지 않으면 서로 통신할 수 없다.
[React 컴포넌트 scope]<ParentComponent state={userData}> <ChildA /> ← props 없으면 userData 접근 불가 <ChildB userProp={userData} /> ← 명시적 전달 시 접근 가능</ParentComponent>
[VPC Security Group]VPC (전체 네트워크) ├── ECS Task ─────────────────────┐ │ │ 명시적 SG 허용 없으면 통신 불가 └── RDS ←──── SG 인바운드 규칙 ───┘ "ECS Task SG에서 5432 허용" 명시 필요두 경우 모두 격리가 기본값, 허용이 명시적이다. 이 원칙을 “최소 권한 원칙”이라고 부른다.
프론트에서 갑자기 API 연결이 안 될 때 — 네트워크 레이어별 디버깅
배포 환경에서 API 연결이 안 될 때, 원인은 코드가 아니라 네트워크일 수 있다:
연결 실패 유형별 원인 추정:
CORS 에러 (브라우저 콘솔에 Access-Control 메시지): → 앱 코드 문제 (NestJS CORS 설정 누락)
Connection Refused / 타임아웃: → Security Group 문제 가능성 높음 → ECS Task SG의 인바운드에 ALB SG가 허용되어 있는지 확인
502 Bad Gateway: → ALB는 정상이나 Target (ECS Task)에 연결 실패 → ECS Task가 RUNNING 상태인지, Health Check 통과했는지 확인
503 Service Unavailable: → Target Group에 healthy 상태의 타겟이 없음 → ECS Service의 Task 수 확인실무 아키텍처 패턴 — 프로덕션 VPC 설계 기본형
섹션 제목: “실무 아키텍처 패턴 — 프로덕션 VPC 설계 기본형”VPC (10.0.0.0/16) ├─ Public Subnet A (10.0.1.0/24, ap-northeast-2a) │ └─ ALB, NAT Gateway ├─ Public Subnet B (10.0.2.0/24, ap-northeast-2b) │ └─ ALB (Multi-AZ 고가용성) ├─ Private Subnet A (10.0.11.0/24, ap-northeast-2a) │ └─ ECS Task, EC2 (Route Table → NAT GW) ├─ Private Subnet B (10.0.12.0/24, ap-northeast-2b) │ └─ ECS Task, EC2 (Multi-AZ 고가용성) └─ DB Subnet A/B (10.0.21.0/24, 10.0.22.0/24) └─ RDS Primary / Standby (Route Table: RDS만 허용, NAT 없음)
[VPC Endpoint 구성]- S3 Gateway Endpoint (무료, Route Table에 자동 추가)- ECR Interface Endpoint (ECR 이미지 Pull)- CloudWatch Logs Endpoint (컨테이너 로그)- Secrets Manager Endpoint (환경변수 주입)2025년 신기능 — VPC Encryption Controls: 2025년 11월 출시. VPC 내부 및 VPC 간 전송 트래픽에 하드웨어 기반 AES-256 암호화를 강제하는 기능이다. Fargate, NLB, ALB 간 트래픽에 적용되며, 먼저 모니터 모드로 평문 트래픽을 식별한 후 강제 모드로 전환하는 2단계 적용이 권장된다.
2025년 신기능 — CloudFront VPC Origins: CloudFront를 Private Subnet의 ALB에 직접 연결할 수 있게 됐다. 기존에는 ALB에 퍼블릭 IP가 필요했지만, 이제 ALB를 완전한 Private Subnet에 두고 CloudFront만 퍼블릭으로 노출할 수 있다 — 보안과 성능을 동시에 개선한다.