infra
Platform

모듈 맵

[Network] 서브넷, 라우팅 테이블, 인터넷 게이트웨이 설계 가이드

0 / 35 완료

펼치기
0 / 35 완료0%

Networking · 31 / 35

[Network] 서브넷, 라우팅 테이블, 인터넷 게이트웨이 설계 가이드

온프레미스 네트워크 개념이 AWS VPC/Subnet/Security Group으로 어떻게 매핑되는지 이해합니다

🚨INCIDENT ALERT
HIGH

온프레미스에서 잘 알던 서브넷과 방화벽 개념이 AWS로 오자 VPC, Route Table, Security Group이라는 이름으로 바뀌었습니다. 새 서비스가 프라이빗 서브넷에 배포됐는데 인터넷 업데이트가 안 되고, 어디를 봐야 할지 막힙니다.

클라우드 네트워크는 이름만 다를 뿐 패킷의 길을 그리는 일입니다. 매핑 관계를 알면 장애 지점을 빠르게 찾을 수 있습니다.

클라우드 네트워크 아키텍처 (AWS VPC)

AWS에 EC2를 띄우고 배포까지 마쳤는데 브라우저에서 아무것도 열리지 않았다. 보안 그룹도 열었고 서비스도 돌고 있는데 — 결국 팀장이 VPC 콘솔을 열어서 한 마디 했다. "인터넷 게이트웨이가 없잖아." 그날 처음 알았다, AWS에서는 그냥 서버를 만든다고 인터넷이 연결되는 게 아니라는 걸. VPC, 서브넷, 라우트 테이블, 인터넷 게이트웨이 — 이 개념들이 서로 어떻게 연결돼야 트래픽이 흐르는지 모르면 AWS 배포는 운에 맡기는 작업이 된다. 온프레미스에서 배운 네트워크 지식이 쓸모없어지는 게 아니다 — VPC의 모든 구성 요소는 스위치, 라우터, 방화벽의 소프트웨어 구현이다. 이 챕터에서 그 매핑을 정확히 짚으면, 다음 배포에서 같은 실수는 반복하지 않는다.


이번 챕터에서 배울 것
  • 1온프레미스 네트워크 개념(VLAN, 라우터, 방화벽)과 AWS VPC 구성 요소 매핑
  • 2VPC CIDR 설계 및 Public/Private Subnet 분리 구조
  • 3Internet Gateway, Route Table, NAT Gateway 동작 원리
  • 4Security Group(Stateful)과 Network ACL(Stateless)의 차이 및 적용 범위
  • 53-Tier 웹 아키텍처 실습 — ALB/WAS/DB를 서브넷별로 배치
실습 환경 준비
AWS CLI 설치 및 자격증명 설정
aws configure
VPC 생성 예시
aws ec2 create-vpc --cidr-block 10.0.0.0/16 --region ap-northeast-2
실습 환경 요구사항

AWS 계정, IAM 사용자(VPC 권한), AWS CLI v2 이상

💡개념

온프레미스 → AWS 개념 매핑

온프레미스에서 VLAN, 라우터, 방화벽을 다루던 경험이 있는데, AWS 콘솔을 열면 VPC, Route Table, Security Group이라는 낯선 이름들이 가득합니다. 개념은 같은데 이름이 달라서 처음에는 어디서부터 시작해야 할지 모르게 됩니다. 온프레미스 개념과 AWS 구성 요소의 매핑을 먼저 파악해두면, VPC 설계 문서나 아키텍처 다이어그램이 빠르게 읽히고 장애 진단에서도 "어느 레이어를 봐야 하는가"를 바로 판단할 수 있습니다.

온프레미스 → AWS 개념 매핑

핵심 매핑 테이블

온프레미스에서 쓰던 장비 이름이 AWS에서 어떤 서비스 이름으로 불리는지 먼저 대응 관계를 파악하면, 이후 VPC 설계 문서나 아키텍처 다이어그램이 훨씬 빠르게 읽힙니다.

온프레미스 개념AWS 대응 개념역할
VLAN / 논리 네트워크 분리VPC (Virtual Private Cloud)완전히 격리된 가상 네트워크 공간
L2 스위치 세그먼트SubnetVPC 내 IP 대역 분할
방화벽 (Firewall)Security Group인스턴스 레벨 Stateful 방화벽
ACL (Access Control List)Network ACL서브넷 레벨 Stateless 방화벽
라우터 (Router)Route Table트래픽 경로 결정
인터넷 게이트웨이 / 공인 IP 연결Internet Gateway (IGW)VPC와 인터넷 연결
NAT 장비NAT Gateway프라이빗 인스턴스 아웃바운드 인터넷
전용선 / MPLSDirect Connect온프레미스-AWS 전용 연결
VPN 장비Virtual Private GatewaySite-to-Site VPN 종단

VPC: 논리적으로 격리된 내 데이터센터

VPC(Virtual Private Cloud)는 AWS 클라우드 안에 여러분만의 사설 네트워크 공간을 만드는 것입니다. 온프레미스에서 VLAN을 이용해 네트워크를 논리적으로 분리하듯, VPC는 AWS 인프라 안에서 완전히 격리된 네트워크 환경을 제공합니다.

# VPC 예시
VPC CIDR: 10.0.0.0/16  (65,536개 IP)
  └── 이 범위 안에서 서브넷을 자유롭게 나눔

VPC의 특징:

  • 리전(Region) 단위로 생성됩니다 (서울 리전, 도쿄 리전 등)
  • 다른 VPC와 완전히 격리되어 있습니다 (기본적으로 통신 불가)
  • 하나의 AWS 계정에 여러 VPC를 만들 수 있습니다
  • VPC끼리 연결이 필요하면 VPC Peering 또는 Transit Gateway를 사용합니다

Subnet: L2 스위치 세그먼트

온프레미스에서 L2 스위치로 네트워크를 세그먼트로 나누듯, VPC 안에서 서브넷으로 IP 대역을 분할합니다.

VPC: 10.0.0.0/16
  ├── Public Subnet A  : 10.0.1.0/24  (서울 가용영역 a)
  ├── Public Subnet B  : 10.0.2.0/24  (서울 가용영역 c)
  ├── Private Subnet A : 10.0.11.0/24 (서울 가용영역 a)
  └── Private Subnet B : 10.0.12.0/24 (서울 가용영역 c)

서브넷은 가용 영역(AZ) 단위로 생성됩니다. 고가용성을 위해 여러 AZ에 동일한 역할의 서브넷을 배포하는 것이 표준 패턴입니다.

Security Group: Stateful 방화벽

온프레미스 방화벽과 가장 큰 차이는 Stateful 동작입니다.

온프레미스 Stateless 방화벽:
  → 인바운드 허용: TCP 443
  → 아웃바운드 허용: TCP 1024-65535 (응답 포트 별도 허용 필요)

AWS Security Group (Stateful):
  → 인바운드 허용: TCP 443
  → 응답 트래픽은 자동 허용 (아웃바운드 규칙 불필요)

Security Group은 인스턴스(EC2)에 붙이는 가상 방화벽입니다. 여러 인스턴스에 동일한 Security Group을 적용할 수 있어, 역할별로 그룹을 만들어 관리합니다 (web-sg, app-sg, db-sg 등).

Route Table: 라우터의 소프트웨어 구현

온프레미스 라우터의 라우팅 테이블처럼, AWS Route Table은 트래픽의 다음 경유지를 결정합니다.

Public Subnet Route Table:
  Destination     Target
  10.0.0.0/16    local          ← VPC 내부 통신
  0.0.0.0/0      igw-xxxxxxxx   ← 인터넷으로 (IGW)

Private Subnet Route Table:
  Destination     Target
  10.0.0.0/16    local          ← VPC 내부 통신
  0.0.0.0/0      nat-xxxxxxxx   ← 아웃바운드만 인터넷으로 (NAT GW)

라우팅 테이블에 0.0.0.0/0 → igw-xxxx 경로가 있느냐 없느냐가 Public/Private Subnet을 구분하는 핵심입니다.


💡개념

AWS VPC 3-Tier 아키텍처 구조

EC2에 서비스를 배포했는데 웹 서버에서 직접 DB를 공인 IP로 접근하고, DB 포트가 인터넷에 노출되어 있습니다. 빠르게 만들다 보니 서브넷 구분 없이 전부 Public에 넣은 것입니다. 보안 감사에서 이 구조가 지적되면 VPC를 전면 재설계해야 합니다. 3-Tier 구조를 처음부터 이해하고 설계하면 이 수정 비용을 피할 수 있고, 각 계층이 왜 다른 서브넷에 있어야 하는지 논리적으로 설명할 수 있게 됩니다.

실무에서 가장 많이 쓰이는 VPC 설계 패턴은 3-Tier 구조입니다. 웹, 애플리케이션, 데이터베이스 계층을 각각 다른 서브넷에 배치하여 네트워크 격리를 구현합니다.

3-Tier VPC 아키텍처 전체 그림

인터넷
  │
  ▼
Internet Gateway (IGW)
  │
  ▼
┌─────────────────────────────────────────────────────────┐
│ VPC: 10.0.0.0/16                                        │
│                                                         │
│  ┌──────────────────┐    ┌──────────────────┐           │
│  │  Public Subnet A │    │  Public Subnet B │           │
│  │  10.0.1.0/24     │    │  10.0.2.0/24     │           │
│  │  [Web Server]    │    │  [NAT Gateway]   │           │
│  │  [Load Balancer] │    │  [Bastion Host]  │           │
│  └────────┬─────────┘    └──────────────────┘           │
│           │ (내부 통신)                                  │
│  ┌────────▼─────────┐    ┌──────────────────┐           │
│  │  Private Subnet A│    │  Private Subnet B│           │
│  │  10.0.11.0/24    │    │  10.0.12.0/24    │           │
│  │  [App Server]    │    │  [App Server]    │           │
│  └────────┬─────────┘    └────────┬─────────┘           │
│           │                       │                     │
│  ┌────────▼───────────────────────▼─────────┐           │
│  │  DB Private Subnet                        │           │
│  │  10.0.21.0/24   10.0.22.0/24             │           │
│  │  [RDS Primary]  [RDS Standby]            │           │
│  └──────────────────────────────────────────┘           │
└─────────────────────────────────────────────────────────┘

Public Subnet: 인터넷과 직접 통신 가능한 영역

조건: Route Table에 0.0.0.0/0 → igw-xxxx 경로 존재

Public Subnet에 위치한 EC2 인스턴스에 Elastic IP(공인 IP)를 할당하면, 인터넷에서 직접 접근 가능합니다.

Public Subnet에 배치하는 것들:

  • Application Load Balancer (ALB)
  • NAT Gateway
  • Bastion Host (점프 서버)
  • 공인 IP가 필요한 웹 서버
로컬 터미널
# 실습 디렉토리 준비
mkdir -p /tmp/networking/part6/exam_31 && cd /tmp/networking/part6/exam_31

# Public Subnet Route Table 예시
$ aws ec2 describe-route-tables --route-table-ids rtb-public

Routes:
  - DestinationCidrBlock: 10.0.0.0/16
    GatewayId: local
  - DestinationCidrBlock: 0.0.0.0/0
    GatewayId: igw-0abc1234def56789  ← 이것이 있으면 Public
🔍실행 후 확인할 것
  • 핵심 출력명령 결과에서 성공/실패를 가르는 값을 먼저 확인합니다
  • 대상 식별IP, 포트, 인터페이스, 프로세스명처럼 다음 조치를 결정하는 필드를 봅니다
  • 다음 분기결과가 기대와 다르면 어느 계층을 이어서 점검할지 정합니다

Private Subnet: 인터넷에서 직접 접근 불가한 영역

조건: Route Table에 IGW 경로 없음

Private Subnet의 EC2 인스턴스는 공인 IP를 할당해도 외부에서 접근할 수 없습니다. 라우팅 경로 자체가 없기 때문입니다.

Private Subnet에 배치하는 것들:

  • 애플리케이션 서버 (WAS)
  • 데이터베이스 (RDS)
  • 내부 마이크로서비스

Private → 인터넷 아웃바운드 경로: Private 서브넷은 직접 인터넷에 접근할 수 없고 NAT Gateway를 거쳐야 합니다.

Private EC2 → NAT Gateway (Public Subnet) → IGW → 인터넷
로컬 터미널
# Private Subnet Route Table 예시
$ aws ec2 describe-route-tables --route-table-ids rtb-private

Routes:
  - DestinationCidrBlock: 10.0.0.0/16
    GatewayId: local
  - DestinationCidrBlock: 0.0.0.0/0
    NatGatewayId: nat-0abc1234def56789  ← IGW 대신 NAT GW

NAT Gateway: 프라이빗 인스턴스의 아웃바운드 인터넷 창구

NAT Gateway는 온프레미스 NAT 장비와 동일한 역할을 합니다. Private Subnet 인스턴스의 사설 IP를 공인 IP로 변환하여 인터넷으로 내보냅니다.

NAT Gateway 배치 규칙:

  1. 반드시 Public Subnet에 배치해야 합니다
  2. Elastic IP가 필요합니다 (고정 공인 IP)
  3. Private Subnet의 Route Table에서 NAT GW를 가리켜야 합니다

비용 주의사항: NAT Gateway는 시간당 요금 + 데이터 처리 요금이 발생합니다. 개발/테스트 환경에서 비용을 아끼려면 사용하지 않을 때 삭제를 고려하세요.

Internet Gateway (IGW): VPC의 인터넷 관문

IGW는 VPC와 인터넷 사이의 게이트웨이입니다. 온프레미스의 인터넷 연결 장비(라우터 + 공인 IP)에 해당합니다.

IGW 특징:

  • VPC당 하나만 연결 가능
  • 수평 확장(Scale-out) 가능한 완전 관리형 서비스
  • 가용성은 AWS가 보장 (단일 장애점 없음)
  • IGW 자체는 무료 (데이터 전송 요금은 별도)

AWS CLI로 VPC 구조 확인하기

AWS Management Console이 없어도 CLI로 VPC 구조 전체를 파악할 수 있습니다. 실무에서 원인 분석 시 CLI가 훨씬 빠릅니다.

사전 준비

로컬 터미널
# AWS CLI 설치 확인
aws --version
# aws-cli/2.x.x Python/3.x.x ...

# 자격 증명 설정 확인
aws sts get-caller-identity
# {
#   "Account": "123456789012",
#   "Arn": "arn:aws:iam::123456789012:user/myuser"
# }

# 리전 설정 (서울)
export AWS_DEFAULT_REGION=ap-northeast-2

Step 1: VPC 목록 조회

로컬 터미널
# 현재 계정의 모든 VPC 조회
aws ec2 describe-vpcs \
  --query 'Vpcs[*].{VpcId:VpcId,CIDR:CidrBlock,Name:Tags[?Key==`Name`]|[0].Value,Default:IsDefault}' \
  --output table

# 출력 예시:
# ---------------------------------------------------------------
# |                       DescribeVpcs                          |
# +---------------+-----------------+-----------------+---------+
# |     CIDR      |    Default      |      Name       |  VpcId  |
# +---------------+-----------------+-----------------+---------+
# |  10.0.0.0/16  |  False          |  prod-vpc       |  vpc-abc|
# |  172.31.0.0/16|  True           |  None           |  vpc-xyz|
# +---------------+-----------------+-----------------+---------+

Step 2: 서브넷 구조 파악

로컬 터미널
# VPC_ID 변수 설정
VPC_ID="vpc-0abc1234def56789"

# 해당 VPC의 서브넷 목록
aws ec2 describe-subnets \
  --filters "Name=vpc-id,Values=${VPC_ID}" \
  --query 'Subnets[*].{SubnetId:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone,Name:Tags[?Key==`Name`]|[0].Value,MapPublicIP:MapPublicIpOnLaunch}' \
  --output table

# MapPublicIpOnLaunch=True이면 Public Subnet 가능성 높음
# (Route Table 확인이 최종 판단 기준)

Step 3: Route Table로 Public/Private 판별

로컬 터미널
# 서브넷별 Route Table 연결 확인
aws ec2 describe-route-tables \
  --filters "Name=vpc-id,Values=${VPC_ID}" \
  --query 'RouteTables[*].{RTId:RouteTableId,Routes:Routes[*].{Dest:DestinationCidrBlock,Target:GatewayId || NatGatewayId}}' \
  --output json

# IGW 경로 있는 Route Table → Public
# NAT GW 경로 있는 Route Table → Private (아웃바운드 가능)
# 0.0.0.0/0 경로 없는 Route Table → 완전 격리 Private

# 특정 서브넷의 Route Table 직접 확인
SUBNET_ID="subnet-0abc1234"
aws ec2 describe-route-tables \
  --filters "Name=association.subnet-id,Values=${SUBNET_ID}" \
  --query 'RouteTables[*].Routes'

Step 4: Security Group 규칙 확인

로컬 터미널
# 특정 Security Group 규칙 상세 조회
SG_ID="sg-0abc1234def56789"
aws ec2 describe-security-groups \
  --group-ids ${SG_ID} \
  --query 'SecurityGroups[0].{
    Name:GroupName,
    Inbound:IpPermissions[*].{
      Protocol:IpProtocol,
      FromPort:FromPort,
      ToPort:ToPort,
      CIDR:IpRanges[*].CidrIp
    },
    Outbound:IpPermissionsEgress[*].{
      Protocol:IpProtocol,
      FromPort:FromPort,
      ToPort:ToPort,
      CIDR:IpRanges[*].CidrIp
    }
  }' \
  --output json

Step 5: EC2 인스턴스 네트워크 정보 확인

로컬 터미널
# 인스턴스의 VPC/서브넷/SG/IP 정보 한번에 확인
INSTANCE_ID="i-0abc1234def56789"
aws ec2 describe-instances \
  --instance-ids ${INSTANCE_ID} \
  --query 'Reservations[0].Instances[0].{
    InstanceId:InstanceId,
    State:State.Name,
    PrivateIP:PrivateIpAddress,
    PublicIP:PublicIpAddress,
    VpcId:VpcId,
    SubnetId:SubnetId,
    SecurityGroups:SecurityGroups[*].GroupId
  }' \
  --output json

# PublicIP가 null이고 SubnetId가 Private Subnet이면
# 이 인스턴스는 인터넷에서 직접 접근 불가

NAT Gateway 설정 및 프라이빗 인스턴스 인터넷 연결

Private Subnet의 EC2 인스턴스에서 yum update나 패키지 설치가 필요할 때 NAT Gateway를 올바르게 설정하는 절차입니다.

NAT Gateway 생성 전 체크리스트

로컬 터미널
# 1. Public Subnet ID 확인 (NAT GW는 여기에 배치)
aws ec2 describe-subnets \
  --filters "Name=vpc-id,Values=${VPC_ID}" \
            "Name=tag:Name,Values=*public*" \
  --query 'Subnets[*].{SubnetId:SubnetId,Name:Tags[?Key==`Name`]|[0].Value}'

# 2. Elastic IP 할당 (NAT GW에 연결할 공인 IP)
aws ec2 allocate-address --domain vpc
# {
#   "AllocationId": "eipalloc-0abc1234",
#   "PublicIp": "3.34.xx.xx"
# }
EIP_ALLOC_ID="eipalloc-0abc1234"
PUBLIC_SUBNET_ID="subnet-0abc1234"

NAT Gateway 생성 및 연결

로컬 터미널
# NAT Gateway 생성 (Public Subnet에)
aws ec2 create-nat-gateway \
  --subnet-id ${PUBLIC_SUBNET_ID} \
  --allocation-id ${EIP_ALLOC_ID} \
  --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=prod-nat-gw}]'

# 출력에서 NatGatewayId 저장
NAT_GW_ID="nat-0abc1234def56789"

# NAT Gateway 상태 확인 (available 될 때까지 대기, 약 1-2분 소요)
aws ec2 describe-nat-gateways \
  --nat-gateway-ids ${NAT_GW_ID} \
  --query 'NatGateways[0].State'
# "available"

# Private Subnet Route Table에 NAT GW 경로 추가
PRIVATE_RT_ID="rtb-private0abc1234"
aws ec2 create-route \
  --route-table-id ${PRIVATE_RT_ID} \
  --destination-cidr-block 0.0.0.0/0 \
  --nat-gateway-id ${NAT_GW_ID}
# { "Return": true }

Private 인스턴스에서 인터넷 연결 테스트

로컬 터미널
# Private 인스턴스에 Bastion Host를 통해 접속 후
# (또는 SSM Session Manager 사용)

# 인터넷 연결 테스트
ping -c 3 8.8.8.8
# PING 8.8.8.8: 56 bytes of data.
# 64 bytes from 8.8.8.8: icmp_seq=1 ttl=117 time=1.5 ms

# DNS 해석 테스트
ping -c 3 google.com
# PING google.com (142.250.x.x)

# yum 업데이트 테스트
sudo yum update -y
# Loaded plugins: amazon-id, instance-id
# Resolving Dependencies...

# curl로 외부 연결 테스트
curl -I https://aws.amazon.com
# HTTP/2 200

Bastion Host를 통한 Private 인스턴스 접속

로컬 터미널
# 로컬 PC에서 Bastion Host를 통해 Private 인스턴스로 SSH 점프
# ~/.ssh/config 설정
cat >> ~/.ssh/config << 'EOF'
Host bastion
  HostName 3.34.xx.xx        # Bastion Host 공인 IP
  User ec2-user
  IdentityFile ~/.ssh/my-key.pem

Host private-app
  HostName 10.0.11.10        # Private 인스턴스 사설 IP
  User ec2-user
  IdentityFile ~/.ssh/my-key.pem
  ProxyJump bastion
EOF

# SSH 접속 (자동으로 Bastion 경유)
ssh private-app

VPC Flow Logs로 네트워크 트래픽 분석

Security Group이나 NACL 설정 후 통신이 안 될 때, VPC Flow Logs가 허용/거부 이력을 기록합니다. 실무에서 네트워크 보안 감사 및 트러블슈팅에 핵심적으로 사용됩니다.

VPC Flow Logs 활성화

로컬 터미널
# CloudWatch Logs 그룹 생성
aws logs create-log-group --log-group-name /vpc/flow-logs

# IAM 역할 ARN 확인 (Flow Logs용)
FLOW_LOG_ROLE_ARN="arn:aws:iam::123456789012:role/VPCFlowLogsRole"

# VPC Flow Logs 활성화
aws ec2 create-flow-logs \
  --resource-type VPC \
  --resource-ids ${VPC_ID} \
  --traffic-type ALL \
  --log-destination-type cloud-watch-logs \
  --log-group-name /vpc/flow-logs \
  --deliver-logs-permission-arn ${FLOW_LOG_ROLE_ARN}

Flow Logs 레코드 해석

로컬 터미널
# Flow Log 레코드 형식:
# version account-id interface-id srcaddr dstaddr srcport dstport protocol packets bytes start end action log-status

# 예시 레코드 해석:
# 2 123456789012 eni-abc123 203.0.113.1 10.0.1.10 54321 443 6 10 4096 1620000000 1620000060 ACCEPT OK
#   ↑ ACCEPT: Security Group/NACL에서 허용된 트래픽

# 2 123456789012 eni-abc123 192.168.1.1 10.0.1.10 12345 22  6 5  2048 1620000000 1620000060 REJECT OK
#   ↑ REJECT: Security Group/NACL에서 차단된 트래픽

# CloudWatch Insights 쿼리로 거부된 트래픽 분석
aws logs start-query \
  --log-group-name /vpc/flow-logs \
  --start-time $(date -d '1 hour ago' +%s) \
  --end-time $(date +%s) \
  --query-string 'fields @timestamp, srcAddr, dstAddr, dstPort, action
    | filter action = "REJECT"
    | stats count(*) as rejectCount by srcAddr, dstPort
    | sort rejectCount desc
    | limit 20'

특정 포트 차단 확인

로컬 터미널
# 8080 포트로 들어오는 트래픽이 거부되는지 확인
aws logs filter-log-events \
  --log-group-name /vpc/flow-logs \
  --filter-pattern '[version, accountId, interfaceId, srcAddr, dstAddr, srcPort, dstPort="8080", protocol, packets, bytes, startTime, endTime, action="REJECT", logStatus]' \
  --start-time $(($(date +%s) - 3600))000 \
  --query 'events[*].message'

상황

Private Subnet의 EC2 인스턴스에서 패키지를 설치하려는데 계속 실패합니다.

로컬 터미널
# Private EC2 인스턴스에서 실행
sudo yum update -y

# 출력:
# Loaded plugins: amazon-id, instance-id
# http://amazonlinux.ap-northeast-2.amazonaws.com/2/extras/docker/latest/x86_64/mirror.list:
#   [Errno 14] curl#6 - "Could not resolve host: amazonlinux.ap-northeast-2.amazonaws.com"
# Trying other mirror.
# Error: Cannot find a valid baseurl for repo: amzn2-core

ping으로 확인해도 마찬가지입니다.

로컬 터미널
ping 8.8.8.8
# PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
# (응답 없음 — Ctrl+C로 중단)

진단 과정

1단계: 인스턴스 기본 정보 확인

로컬 또는 서버
# 인스턴스 메타데이터로 서브넷 확인
curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/
# eth0 MAC 주소 확인 후

MAC=$(curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/)
curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC}subnet-id
# subnet-0abc1234def56789 ← Private Subnet

# 공인 IP 없음 확인
curl -s http://169.254.169.254/latest/meta-data/public-ipv4
# 없거나 null

2단계: Route Table 확인

로컬 터미널
# AWS CLI로 해당 서브넷의 Route Table 확인
aws ec2 describe-route-tables \
  --filters "Name=association.subnet-id,Values=subnet-0abc1234def56789" \
  --query 'RouteTables[*].Routes'

# 출력:
# [
#   [
#     {
#       "DestinationCidrBlock": "10.0.0.0/16",
#       "GatewayId": "local",
#       "State": "active"
#     }
#   ]
# ]
# ← 0.0.0.0/0 경로가 없다! NAT Gateway 경로 누락

3단계: NAT Gateway 존재 여부 확인

로컬 터미널
aws ec2 describe-nat-gateways \
  --filter "Name=vpc-id,Values=${VPC_ID}" \
           "Name=state,Values=available" \
  --query 'NatGateways[*].{Id:NatGatewayId,State:State,Subnet:SubnetId}'

# 출력:
# [] ← NAT Gateway가 아예 없거나

# 또는 NAT GW는 있지만 Route Table에 연결이 안 된 경우
# [ { "Id": "nat-0xyz...", "State": "available", "Subnet": "subnet-public-..." } ]

해결 방법

케이스 A: NAT Gateway 자체가 없는 경우

로컬 터미널
# 1. Elastic IP 할당
EIP=$(aws ec2 allocate-address --domain vpc --query 'AllocationId' --output text)

# 2. Public Subnet ID 확인
PUBLIC_SUBNET=$(aws ec2 describe-subnets \
  --filters "Name=vpc-id,Values=${VPC_ID}" \
            "Name=tag:Name,Values=*public*" \
  --query 'Subnets[0].SubnetId' --output text)

# 3. NAT Gateway 생성
NAT_GW=$(aws ec2 create-nat-gateway \
  --subnet-id ${PUBLIC_SUBNET} \
  --allocation-id ${EIP} \
  --query 'NatGateway.NatGatewayId' --output text)

# 4. available 상태 대기
aws ec2 wait nat-gateway-available --nat-gateway-ids ${NAT_GW}

# 5. Private Route Table에 경로 추가
PRIVATE_RT=$(aws ec2 describe-route-tables \
  --filters "Name=association.subnet-id,Values=subnet-0abc1234def56789" \
  --query 'RouteTables[0].RouteTableId' --output text)

aws ec2 create-route \
  --route-table-id ${PRIVATE_RT} \
  --destination-cidr-block 0.0.0.0/0 \
  --nat-gateway-id ${NAT_GW}

케이스 B: NAT GW는 있지만 Route Table 연결 누락

로컬 터미널
# 기존 NAT GW ID 확인
NAT_GW_ID=$(aws ec2 describe-nat-gateways \
  --filter "Name=vpc-id,Values=${VPC_ID}" "Name=state,Values=available" \
  --query 'NatGateways[0].NatGatewayId' --output text)

# Route Table에 경로만 추가
aws ec2 create-route \
  --route-table-id ${PRIVATE_RT} \
  --destination-cidr-block 0.0.0.0/0 \
  --nat-gateway-id ${NAT_GW_ID}

해결 확인

로컬 터미널
# Private 인스턴스에서 다시 테스트
ping -c 3 8.8.8.8
# 64 bytes from 8.8.8.8: icmp_seq=1 ttl=117 time=1.5 ms

sudo yum update -y
# ... 정상 업데이트

예방 방법

인프라 코드(Terraform/CloudFormation)를 사용할 때 Private Subnet Route Table에 NAT GW 경로 설정을 잊는 경우가 많습니다. 코드 리뷰 시 반드시 확인하세요.

HCL
# Terraform 예시 - 이 부분을 빠뜨리면 안 됨!
resource "aws_route" "private_nat" {
  route_table_id         = aws_route_table.private.id
  destination_cidr_block = "0.0.0.0/0"
  nat_gateway_id         = aws_nat_gateway.main.id  # ← 필수!
}

상황

웹 서버 EC2에 Security Group 80번 포트 인바운드를 추가했는데도 브라우저에서 접속이 안 됩니다.

로컬 또는 서버
# 로컬에서 테스트
curl -v http://3.34.xx.xx:80
# * Trying 3.34.xx.xx:80...
# * Connection timed out

Security Group은 분명히 설정했습니다.

로컬 터미널
# Security Group 확인
aws ec2 describe-security-groups --group-ids sg-web
# Inbound Rules:
#   - Type: HTTP, Port: 80, Source: 0.0.0.0/0  ← 있음!
#   - Type: SSH, Port: 22, Source: My IP

원인 분석

Security Group 외에 **Network ACL(NACL)**이 서브넷 레벨에서 트래픽을 차단하고 있습니다.

로컬 터미널
# 서브넷의 NACL 확인
aws ec2 describe-network-acls \
  --filters "Name=association.subnet-id,Values=${SUBNET_ID}" \
  --query 'NetworkAcls[0].Entries'

# 출력:
# [
#   { "RuleNumber": 100, "Protocol": "6", "RuleAction": "allow",
#     "Egress": false, "CidrBlock": "10.0.0.0/8", "PortRange": {"From": 0, "To": 65535} },
#   { "RuleNumber": 32767, "Protocol": "-1", "RuleAction": "deny",
#     "Egress": false, "CidrBlock": "0.0.0.0/0" }
# ]
# ← 내부 IP(10.x.x.x)만 허용, 외부 0.0.0.0/0은 전체 차단!

NACL과 Security Group의 차이

항목Security GroupNetwork ACL
적용 레벨인스턴스(ENI)서브넷
상태StatefulStateless
규칙 우선순위모든 규칙 평가번호 순서대로 평가
기본 정책인바운드 전체 거부기본 NACL은 전체 허용

NACL은 Stateless이므로 인바운드 허용 시 아웃바운드 응답 포트도 별도로 허용해야 합니다.

해결 방법

로컬 터미널
# NACL ID 확인
NACL_ID=$(aws ec2 describe-network-acls \
  --filters "Name=association.subnet-id,Values=${SUBNET_ID}" \
  --query 'NetworkAcls[0].NetworkAclId' --output text)

# 인바운드 HTTP(80) 허용 규칙 추가 (Rule 90 = Rule 100보다 먼저 평가)
aws ec2 create-network-acl-entry \
  --network-acl-id ${NACL_ID} \
  --ingress \
  --rule-number 90 \
  --protocol 6 \
  --rule-action allow \
  --cidr-block 0.0.0.0/0 \
  --port-range From=80,To=80

# NACL은 Stateless! 응답 트래픽을 위한 아웃바운드 Ephemeral 포트도 허용
aws ec2 create-network-acl-entry \
  --network-acl-id ${NACL_ID} \
  --egress \
  --rule-number 90 \
  --protocol 6 \
  --rule-action allow \
  --cidr-block 0.0.0.0/0 \
  --port-range From=1024,To=65535  # Ephemeral ports

교훈

트래픽이 차단될 때는 Security Group과 NACL을 모두 확인하는 습관을 가지세요. 두 계층 모두 허용해야 통신이 됩니다.

트래픽 흐름: 인터넷 → IGW → NACL(서브넷 경계) → Security Group(인스턴스) → EC2
차단 여부:                    ↑ 여기서도 차단 가능    ↑ 여기서도 차단 가능

💼
실무 맥락
현업 패턴

실제 업무에서 VPC를 다루는 상황들

클라우드 인프라 엔지니어나 DevOps 엔지니어로 일하다 보면 VPC 관련 작업이 일상입니다.

신규 프로젝트 VPC 설계

신규 서비스를 AWS에 구축할 때 가장 먼저 VPC 설계를 합니다. 아키텍처 회의에서 나오는 전형적인 질문들:

"이 서비스 CIDR은 뭘로 할까요?"
  → 기존 VPC들과 겹치지 않게 설계 (나중에 VPC Peering 고려)
  → 충분한 IP 여유 확보 (/16 추천, 65,536개)

"DB는 퍼블릭 서브넷에 올리면 안 되죠?"
  → 절대 안 됨. RDS는 반드시 Private Subnet에

"개발/스테이징/프로덕션 VPC를 분리해야 할까요?"
  → 보안과 비용 트레이드오프 논의
  → 최소한 프로덕션은 별도 VPC 권장

보안 감사 대응

보안팀이나 컴플라이언스 감사에서 VPC 설정을 검토하는 경우:

로컬 터미널
# 퍼블릭 서브넷에 있는 인스턴스 목록 (감사용)
# "퍼블릭 IP를 가진 모든 인스턴스를 보여주세요"
aws ec2 describe-instances \
  --filters "Name=network-interface.association.public-ip,Values=*" \
  --query 'Reservations[*].Instances[*].{
    Id:InstanceId,
    Name:Tags[?Key==`Name`]|[0].Value,
    PublicIP:PublicIpAddress,
    Role:Tags[?Key==`Role`]|[0].Value
  }' \
  --output table

비용 최적화

NAT Gateway 비용은 생각보다 많이 나옵니다. 월말 비용 리포트에서 NAT Gateway 비용이 크게 잡히면:

월 NAT Gateway 기본 비용: 약 $32 (한 개당)
데이터 처리 비용: $0.045/GB

절감 방법:
1. 개발 환경 NAT GW → 업무 시간에만 켜두기
2. S3, DynamoDB 등 AWS 서비스는 VPC Endpoint 사용 (NAT GW 통하지 않음)
3. 불필요한 외부 패키지 다운로드 줄이기

인시던트 대응

프로덕션 서비스 장애 시 네트워크 레이어 확인:

장애 알람 발생
  └── 1. Security Group 최근 변경 이력 확인 (CloudTrail)
  └── 2. NACL 규칙 변경 이력 확인
  └── 3. Route Table 변경 이력 확인
  └── 4. VPC Flow Logs에서 REJECT 트래픽 패턴 분석
  └── 5. NAT Gateway 상태 확인 (available?)

자격증 연계

AWS Certified Solutions Architect(SAA, SAP), AWS Certified Advanced Networking(ANS) 시험에서 VPC 관련 문제가 다수 출제됩니다. 이 챕터의 내용은 특히 SAA-C03 시험의 네트워킹 도메인과 직접 연결됩니다.


핵심 정리

개념온프레미스AWS
논리 네트워크 분리VLANVPC
L2 세그먼트L2 스위치 포트Subnet
인스턴스 방화벽호스트 방화벽Security Group (Stateful)
서브넷 ACLACLNetwork ACL (Stateless)
라우팅라우터 라우팅 테이블Route Table
인터넷 연결인터넷 라우터+공인 IPInternet Gateway
사설망 아웃바운드NAT 장비NAT Gateway

Public vs Private Subnet 판별 기준:

  • Route Table에 0.0.0.0/0 → igw-xxxx 있으면 → Public
  • Route Table에 0.0.0.0/0 → nat-xxxx 있으면 → Private (아웃바운드 가능)
  • Route Table에 0.0.0.0/0 경로 없으면 → 완전 격리 Private

NAT Gateway 필수 조건:

  1. Public Subnet에 배치
  2. Elastic IP 연결
  3. Private Subnet Route Table에 경로 추가

지식 확인

퀴즈 — 5문제

Q1

AWS VPC에서 Public Subnet과 Private Subnet을 구분하는 핵심 차이는 무엇인가요?

Q2

Private Subnet의 EC2 인스턴스가 인터넷으로 아웃바운드 통신(예: yum update)을 하려면 무엇이 필요한가요?

Q3

온프레미스의 VLAN(Virtual LAN)에 가장 가까운 AWS 개념은 무엇인가요?

Q4

Security Group의 특성으로 올바른 것은 무엇인가요?

Q5

다음 중 NAT Gateway에 대한 설명으로 틀린 것은 무엇인가요?

0 / 5 답변

🧪 실습으로 확인하기

포트는 열렸다는데 왜 안 되지? — ss/netstat/telnet으로 TCP 진단

초급

"포트 8080 열었는데요?"와 "왜 안 돼요?" 사이의 간극을 메우는 실습. ss로 바인딩 상태를 확인하고, telnet/nc으로 원격 연결을 테스트하고, iptables 방화벽을 진단하고, 바인딩 주소(0.0.0.0 vs 127.0.0.1)까지 수정하는 4단계 TCP 포트 진단 플로우를 완성한다.

35📋 4단계💻 직접 환경
실습 시작하기 →

이것도 배워보세요

networking고급 · 60
[Network] 웹 서버에서 DB 접속 실패 시 원인 격리 프로세스
Networking 트랙 계속
docker입문 · 30
[Docker] 백엔드 개발자에게 Docker와 컨테이너 가상화가 필수인 이유
Docker 트랙 시작점