이전 포스팅에서는 AWS의 VPC 개념과 구조에 대해 알아보았다.
이번에는 지난 번 생성한 IAM 계정에서 인터넷과 통신 가능한 퍼블릭 VPC 네트워크 골격을 AWS 콘솔 또는 CLI로 구성하는 방법을 알아본다.
VPC부터 서브넷, 인터넷 게이트웨이, 라우팅 테이블, 보안 그룹까지 순서대로 만들고, 그 위에 EC2만 배치하면 곧바로 외부와 통신할 수 있는 상태까지 완성해 본다.
이번 실습에서 만드는 자원은 전부 요금이 발생하지 않는 AWS 프리티어 범위 안에서 구성했다.
NAT Gateway, VPC Endpoint, Elastic IP, VPC Flow Logs 같은 유료 자원은 여기서는 사용하지 않는다.
보안 그룹은 의도적으로 느슨하게 구성한다.
추후 이 네트워크 위에 EC2를 올리고 웹 애플리케이션을 배포한 뒤 직접 침투 테스트, 진단 및 하드닝을 실습할 수 있도록 SSH(22)와 애플리케이션 포트(8080)를 외부 전체에 개방한 취약한 상태로 만든다.
리전은 서울(ap-northeast-2)로 고정한다.
AWS 콘솔은 리전마다 자원이 분리되어 표시되므로, 작업 전 우측 상단 리전이 서울로 설정되어 있는지 확인한다.
리전이 다르면 생성한 자원이 목록에 나타나지 않는다.
1. 전체 구조
인터넷에서 들어온 트래픽은 인터넷 게이트웨이(IGW)를 거쳐 VPC로 진입한다.
VPC 내부에서는 라우팅 테이블이 이 트래픽의 방향을 결정한다.
목적지가 VPC 내부면 local로, 외부(인터넷)면 다시 IGW로 향하도록 경로를 지정한다.
이 라우팅 테이블에 연결된 퍼블릭 서브넷 안에 EC2가 위치하며, EC2에 직접 접근하는 트래픽은 마지막으로 보안 그룹(Web-SG)의 인바운드 규칙을 통과해야 인스턴스에 도달한다.
즉 트래픽은 IGW(진입) → 라우팅 테이블(경로 결정) → 서브넷(위치) → 보안 그룹(접근 통제) 순서로 필터링되며 EC2까지 이어지게 된다.

각 자원은 의존 관계를 고려한 순서대로 생성한다.
VPC → 서브넷 → IGW → 라우팅 테이블 → 보안 그룹 순서로 진행한다.
(서브넷은 VPC가 있어야 만들 수 있고, 인터넷 라우트는 IGW가 있어야 대상을 지정할 수 있기 때문)
2. VPC 생성
1️⃣ 개념
VPC(Virtual Private Cloud)는 AWS 계정 안에 만드는 논리적으로 격리된 가상 네트워크다.
리전 단위 자원이며, 이 경계 안에 서브넷·라우팅·보안 규칙을 배치한다.
iptables와 비교해보면 VPC는 하나의 독립된 netfilter 네임스페이스에 대응한다.
이 경계 안에서만 로컬 라우팅과 방화벽 규칙이 유효하다.
CIDR(Classless Inter-Domain Routing)는 네트워크 대역을 표기하는 방식이다.
10.0.0.0/16은 앞 16비트가 고정이라는 뜻으로 약 65,536개의 IP를 담는다.
AWS VPC는 RFC 1918 사설 대역(10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) 안에서 선택해야 하고, 크기는 /16부터 /28까지 지정할 수 있다.
여러 VPC를 피어링하거나 온프레미스와 VPN으로 연결해 대역이 겹칠 수 있는 상황에서는 대역 선택이 중요하겠지만, 이번 구성은 단일 VPC라 어떤 사설 대역을 선택하든 동작에는 차이가 없다.
여기서는 이런 환경에서 널리 쓰이는 표준 대역인 10.0.0.0/16을 사용한다.
2️⃣ 콘솔
🔵 VPC 생성
- VPC 대시보드 → 상단 검색창에 "VPC" 검색 → VPC 생성 → "VPC만" 선택
- 이름 태그: securedeploy-vpc
- IPv4 CIDR: 10.0.0.0/16
- IPv6 없음, 테넌시 기본값
- VPC 암호화 제어: "없음" 선택 - 콘솔에 ($)로 표시되는 것은 유료 옵션이므로 굳이 사용하지 않는다.
- VPC 생성

🔵 DNS 호스트 이름 활성화
생성된 VPC 선택 → 작업 → VPC 설정 편집 → DNS 호스트 이름 활성화 체크.
이후 EC2에 퍼블릭 DNS 이름이 부여되게 하려면 이 설정이 필요하다.

3️⃣ CLI
🔵 VPC 생성
aws ec2 create-vpc \
--cidr-block 10.0.0.0/16 \
--tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=securedeploy-vpc}]'

- IsDefault: false는 사용자가 직접 만든 VPC임을 나타낸다. IsDefault: true는 AWS가 계정 생성 시 자동으로 만든 기본 VPC다.
🔵 DNS 호스트 이름 활성화
aws ec2 modify-vpc-attribute \
--vpc-id <VPC_ID> \
--enable-dns-hostnames
이 명령은 성공해도 아무 출력이 없다.
아래 명령어로 확인할 수 있다.
aws ec2 describe-vpc-attribute \
--vpc-id <VPC_ID> \
--attribute enableDnsHostnames

"Value": true가 나오면 성공한 것이다.
3. 퍼블릭 서브넷 생성
1️⃣ 개념
서브넷은 VPC의 IP 대역을 더 작게 나눈 논리적 구획으로, 하나의 가용 영역(AZ)에 속하며 서브넷 안으로 들어오는 자원(EC2 등)에 IP가 부여된다.
퍼블릭 IP 자동 할당(MapPublicIpOnLaunch)은 이 서브넷에서 새로 시작되는 EC2 인스턴스에 자동으로 퍼블릭 IPv4 주소를 부여하는 설정이다.
이 옵션을 켜면 Elastic IP를 별도로 할당하지 않고도 무료로 퍼블릭 IP를 얻는다.
단, 인스턴스를 중지하면 주소가 반환되고 재시작 시 새 주소가 할당되어 IP주소가 바뀐다.
2️⃣ 콘솔
🔵 서브넷 생성
- VPC 대시보드 → 서브넷 → 서브넷 생성
- VPC 선택: securedeploy-vpc
- 서브넷 이름: securedeploy-public-subnet
- 가용 영역: ap-northeast-2a
- IPv4 서브넷 CIDR: 10.0.1.0/24
- 생성


🔵 퍼블릭 IPv4 주소 자동 할당 활성화
생성된 서브넷 선택 → 작업 → 서브넷 설정 편집 → "퍼블릭 IPv4 주소 자동 할당 활성화" 체크 → 저장

3️⃣ CLI
🔵 서브넷 생성
aws ec2 create-subnet \
--vpc-id <VPC_ID> \
--cidr-block 10.0.1.0/24 \
--availability-zone ap-northeast-2a \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=securedeploy-public-subnet}]'
🔵 퍼블릭 IPv4 주소 자동 할당 활성화
aws ec2 modify-subnet-attribute \
--subnet-id <SUBNET_ID> \
--map-public-ip-on-launch
이 명령은 성공해도 아무 출력이 없다.
아래 명령어로 확인할 수 있다.
aws ec2 describe-subnets \
--subnet-ids <SUBNET_ID> \
--query "Subnets[0].MapPublicIpOnLaunch"
true가 나오면 성공이다.
4️⃣ 확인 포인트
서브넷 목록에는 계정 생성 시 자동으로 만들어진 기본 VPC의 서브넷 6개(각 AZ당 1개, 172.31.0.0/16 대역)가 함께 표시된다.
무료이고 이번 구성과 격리되어 있으므로 그대로 두어도 상관 없다.

생성한 서브넷이 목록에 보이지 않으면 상단 VPC 필터에서 생성한 VPC를 찾아서 선택한다.

4. 인터넷 게이트웨이(IGW) 생성 및 연결
1️⃣ 개념
IGW(Internet Gateway)는 VPC와 인터넷을 연결하는 관문이다.
VPC 하나에 IGW 하나만 연결할 수 있으며, IGW의 존재와 연결 자체로는 과금이 되지 않는다.
IGW의 작동 방식을 iptables의 NAT와 비교해서 이해할 수 있다.
VPC 내부 EC2가 인터넷으로 나갈 때, 라우팅 테이블이 트래픽을 IGW로 보내고 IGW가 EC2의 사설 IP를 퍼블릭 IP로 변환해 내보낸다.
iptables로 치면 POSTROUTING 체인에서 NAT을 적용하는 역할에 해당한다.
인바운드는 반대 방향으로 IGW를 거쳐 사설 IP로 되돌아 들어온다.
2️⃣ 콘솔
🔵 IGW 생성
- VPC 대시보드 → 인터넷 게이트웨이 → 인터넷 게이트웨이 생성
- 이름: securedeploy-igw → 생성

🔵 VPC에 연결
계정에는 기본 VPC용으로 자동 생성된 IGW가 이미 하나 있다. (Name 태그가 비어 있고 이미 Attached 상태)
이번에 만든 것과 별개이므로 그대로 둔다.
IGW를 만들기만 하고 VPC에 연결하지 않으면 [상태]가 Detached이므로 연결(attach)까지 마쳐야 유효하다.
작업 → VPC에 연결 → securedeploy-vpc 선택 → 연결



연결이 되면 [상태]가 Attached가 된다.

3️⃣ CLI
🔵 IGW 생성
aws ec2 create-internet-gateway \
--tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=securedeploy-igw}]'

🔵 VPC에 연결
aws ec2 attach-internet-gateway \
--internet-gateway-id <IGW_ID> \
--vpc-id <VPC_ID>
이 명령은 성공해도 아무 출력이 없다.
아래 명령어로 확인할 수 있다.
aws ec2 describe-internet-gateways \
--internet-gateway-ids <IGW_ID> \
--query "InternetGateways[0].Attachments"
State: "available", VpcId: 생성한 VPC가 나오면 성공이다.
5. 라우팅 테이블 생성 및 인터넷 라우트 설정
1️⃣ 개념
라우팅 테이블은 "이 목적지로 가는 패킷은 저 게이트웨이로 내보낸다"를 정의하는 규칙 모음이다.
서브넷 안의 장비가 패킷을 보낼 때 서브넷에 연결된 라우팅 테이블을 참조해 어느 게이트웨이로 보낼지 결정한다.
각 라우트는 Destination(어디로 가는 패킷인가)과 Target(어느 게이트웨이로 내보낼 것인가) 두 부분으로 구성된다.
이번에 다루는 라우트는 두 개다.
| Route | 의미 |
| 10.0.0.0/16 → local | 목적지가 VPC 내부면 VPC 안에서 자체 전달. 자동 생성, 삭제·수정 불가 |
| 0.0.0.0/0 → IGW | 그 외 모든 목적지(=인터넷)는 IGW로. 직접 추가하는 라우트 |
🔵 Longest Prefix Match
여러 라우트가 동시에 매칭될 때는 더 좁은 범위(prefix가 긴 쪽)가 우선한다.
목적지 10.0.1.10은 두 라우트에 모두 매칭되지만 10.0.0.0/16이 더 좁아 local로 향한다.
8.8.8.8은 0.0.0.0/0에만 매칭되어 IGW로 향한다.
이 규칙은 리눅스 라우팅과도 동일하다.

🔵 퍼블릭 서브넷의 정의
퍼블릭 서브넷은 자신의 라우팅 테이블에 0.0.0.0/0 → IGW 라우트가 있는 서브넷을 말한다.
이 라우트가 없으면 프라이빗 서브넷이다.
즉 서브넷을 퍼블릭으로 만드는 것은 서브넷 자체의 속성이 아니라, 어떤 라우팅 테이블에 연결되어 있느냐다.
메인(Main) 라우팅 테이블은 VPC 생성 시 자동으로 딸려 오는 폴백 RT다.
명시적으로 다른 RT에 연결되지 않은 서브넷은 자동으로 이 테이블을 사용한다.
이 실습에서는 별도의 커스텀 RT를 만들어 서브넷을 명시적으로 연결했다.
이렇게 하면 각 서브넷이 어떤 RT를 사용하는지 보이기 때문에 감사와 진단이 쉬워진다.
2️⃣ 콘솔
🔵 라우팅 테이블 생성
- VPC 대시보드 → 라우팅 테이블 → 라우팅 테이블 생성
- 이름: securedeploy-public-rt
- VPC: securedeploy-vpc → 생성

🔵 인터넷 라우트 추가
- 생성된 RT 선택 → 하단 "라우팅" 탭 → 라우팅 편집 → 라우팅 추가
- 대상: 0.0.0.0/0, 대상 유형: 인터넷 게이트웨이 → securedeploy-igw 선택
- 변경 사항 저장



🔵 서브넷과 라우팅 테이블 연결
- 하단 "서브넷 연결" 탭 → 서브넷 연결 편집
- securedeploy-public-subnet 체크 → 연결 저장


3️⃣ CLI
🔵 라우팅 테이블 생성
aws ec2 create-route-table \
--vpc-id <VPC_ID> \
--tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=securedeploy-public-rt}]'

🔵 인터넷 라우트 추가
aws ec2 create-route \
--route-table-id <RTB_ID> \
--destination-cidr-block 0.0.0.0/0 \
--gateway-id <IGW_ID>
"Return": true가 나오면 성공.
🔵 서브넷과 라우팅 테이블 연결
aws ec2 associate-route-table \
--route-table-id <RTB_ID> \
--subnet-id <SUBNET_ID>
AssociationId가 반환된다.
아래 명령어로 최종 확인한다.
aws ec2 describe-route-tables \
--route-table-ids <RTB_ID> \
--query "RouteTables[0].[Routes,Associations]"
- Routes에 10.0.0.0/16 → local(기본)과 0.0.0.0/0 → igw- xxxx... 두 개가 있어야 함
- Associations에 subnet-xxxx...가 연결되어 있어야 함
이 단계까지 마치면 서브넷은 0.0.0.0/0 → IGW 라우트를 가진 퍼블릭 서브넷이 된다.
6. 보안 그룹(Web-SG) 생성
1️⃣ 개념
보안 그룹(Security Group)은 EC2 인스턴스 단위의 가상 방화벽이다.
스테이트풀(stateful) 방식이라, 아웃바운드로 허용된 요청의 응답은 인바운드 규칙 없이도 자동으로 허용된다.
이는 iptables에서 conntrack으로 ESTABLISHED,RELATED 상태를 허용하는 동작과 같다.
보안 그룹은 conntrack이 항상 켜진 상태의 방화벽으로 이해할 수 있다.
🔵 NACL(Network ACL)과의 차이
| 구분 | 보안 그룹 | NACL |
| 적용 단위 | 인스턴스 | 서브넷 |
| 상태 | 스테이트풀 | 스테이트리스 |
| 규칙 | 허용(allow)만 | 허용 + 명시적 거부(deny) |
iptables과 비교하면 NACL은 규칙 순서와 명시적 DROP이 있는 전통적인 체인에 가깝고, 보안 그룹은 허용 규칙만 나열하는 화이트리스트 방식에 가깝다. 이 실습에서는 보안 그룹만 설정한다.
2️⃣ 의도적으로 취약한 구성
추후 EC2에 웹 애플리케이션을 배포한 뒤 직접 침투 테스트로 진단할 취약점을 미리 심어두는 의도이므로 느슨하게 구성한다.
관리 포트(22)와 애플리케이션 포트(8080)를 외부 전체에 개방한다.
여기서는 진단과 하드닝의 Before 상태를 확보하는 것이 목적이다.
| 방향 | 유형 | 포트 | 소스/대상 | 실습 의도 |
| Inbound | SSH | 22 | 0.0.0.0/0 | 관리 포트가 외부 전체에 노출 |
| Inbound | 사용자 지정 TCP | 8080 | 0.0.0.0/0 | 평문 HTTP + 앱 포트 직노출 |
| Outbound | 모든 트래픽 | 전체 | 0.0.0.0/0 | 아웃바운드 제어는 이번 범위 밖 |
3️⃣ 콘솔
🔵 보안 그룹 생성
- VPC 대시보드 → 보안 그룹 → 보안 그룹 생성
- 이름: Web-SG
- 설명: IntraPortal web SG - initial loose config for vulnerability diagnosis
- VPC: securedeploy-vpc


🔵 인바운드 규칙 추가
- 인바운드 규칙:
- 규칙 추가 → 유형: SSH, 소스: Anywhere-IPv4 (0.0.0.0/0), 설명: SSH open - to be hardened
- 규칙 추가 → 유형: 사용자 지정 TCP, 포트: 8080, 소스: Anywhere-IPv4 (0.0.0.0/0), 설명: HTTP 8080 open - to be hardened
- 아웃바운드 규칙: 기본값 유지
- 생성


콘솔에 뜨는 노란 경고 배너("소스가 0.0.0.0/0인 규칙은 모든 IP에서 액세스 가능…")는 이번 구성에서는 의도된 것이므로 넘어간다.
4️⃣ CLI
🔵 보안 그룹 생성
aws ec2 create-security-group \
--group-name Web-SG \
--description "IntraPortal web SG - initial loose config for vulnerability diagnosis" \
--vpc-id <VPC_ID> \
--tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value=Web-SG}]'
🔵 인바운드 규칙 추가
인바운드 규칙 두 개를 한번에 추가한다.
aws ec2 authorize-security-group-ingress \
--group-id <SG_ID> \
--ip-permissions \
'IpProtocol=tcp,FromPort=22,ToPort=22,IpRanges=[{CidrIp=0.0.0.0/0,Description="SSH open - to be hardened"}]' \
'IpProtocol=tcp,FromPort=8080,ToPort=8080,IpRanges=[{CidrIp=0.0.0.0/0,Description="HTTP 8080 open - to be hardened"}]'
아래 명령어로 확인한다.
aws ec2 describe-security-groups \
--group-ids <SG_ID> \
--query "SecurityGroups[0].IpPermissions"
포트 22와 8080이 0.0.0.0/0으로 열려있는 게 확인되면 성공이다.
7. 정리
위 실습에서 생성한 VPC와 각 자원 간의 관계는 다음과 같다.
VPC가 모든 자원의 최상위 컨테이너이며, 서브넷·IGW·라우팅 테이블·보안 그룹이 모두 VPC에 소속된다.
그 위에서 각 자원은 서로를 참조한다.
IGW는 VPC에 연결(attach)되고, 라우팅 테이블은 IGW를 라우트 대상(target)으로 참조하며, 서브넷은 라우팅 테이블에 연결(associate)된다.
보안 그룹은 추후 서브넷 안에 배치될 EC2에 적용(apply)된다.

| 자원 | 관계 | 대상 자원 | AWS 동작 |
| IGW | attach | VPC | attach-internet-gateway |
| 라우팅 테이블 | target | IGW | create-route ... --gateway-id |
| 서브넷 | associate | 라우팅 테이블 | associate-route-table |
| EC2 | 배치 | 서브넷 | 인스턴스 시작 시 서브넷 지정 |
| 보안 그룹 | apply | EC2 | 인스턴스 시작 시 SG 지정 |
'Journey to Security > 클라우드' 카테고리의 다른 글
| [AWS] 웹 애플리케이션 배포를 위한 EC2 인스턴스 생성 (0) | 2026.07.06 |
|---|---|
| [AWS] 온보딩 활동으로 크레딧 벌기 - AWS Budgets 설정 (0) | 2026.07.06 |
| [AWS] EC2 인스턴스 접속을 위한 키 페어 생성 (0) | 2026.07.06 |
| [AWS] VPC 구조와 설계: 클라우드 사설 네트워크의 기본 개념 (0) | 2026.07.03 |
| [AWS] IAM 사용자·그룹·MFA 설정 및 CLI 연동 (0) | 2026.07.02 |