
– NAT Gateway를 통해 프라이빗 인스턴스의 외부 통신 열어주기
지금까지 CloudFormation을 활용해 EC2 인스턴스를 퍼블릭 서브넷에 배치하고, IGW와 라우팅 테이블을 연결해서 외부와 통신 가능한 구조를 만들었다.
하지만 실제 운영 환경에서는 외부에서 접근 가능한 인스턴스보다, 외부에서는 접근할 수 없지만 내부에서는 인터넷에 나갈 수 있는 인스턴스가 더 자주 사용된다. 예를 들어, 보안이 중요한 서버나 DB처럼 외부 접속은 막아두되, 보안 패치나 외부 API 호출을 위해 아웃바운드 트래픽은 열어둬야 하는 경우가 그렇다. 이럴 때 사용하는 대표적인 구조가 바로 프라이빗 서브넷 + NAT Gateway 구성이다.
이번 글에서는 퍼블릭/프라이빗 서브넷을 분리하고, 퍼블릭 서브넷에 NAT Gateway를 구성한 뒤, 프라이빗 인스턴스가 NAT를 통해 외부와 통신할 수 있는 구조를 만들어보자.
AWS에서 서브넷은 퍼블릭과 프라이빗으로 나뉘는데, 핵심은 IGW 연결 여부와 퍼블릭 IP 할당 유무다.
퍼블릭 서브넷은 IGW(인터넷 게이트웨이)와 연결되고 퍼블릭 IP가 있어 외부에서 직접 접근이 가능하다. 반면, 프라이빗 서브넷은 IGW와 연결되어 있지 않고 퍼블릭 IP도 없기 때문에 외부에서는 접근할 수 없다. 하지만 NAT Gateway를 경유하면 프라이빗 인스턴스가 외부로 나가는 트래픽은 가능하다.
프라이빗 인스턴스를 외부와 통신 가능하게 만들기 위해서는 아래 구성 순서를 따르게 된다.
0.0.0.0/0 트래픽을 NAT Gateway로 전달하도록 설정한다.
NAT Gateway는 퍼블릭 IP가 필요하므로, 먼저 EIP를 만들어야 한다.
MyNatGWEIP:
Type: AWS::EC2::EIP
Properties:
Domain: VPC
Elastic IP는 AWS 외부에서도 고정된 IP로 접근 가능한 공인 IP 주소다.
이제 EIP를 연결한 NAT Gateway를 퍼블릭 서브넷에 만든다.
MyNatGW:
Type: AWS::EC2::NatGateway
DependsOn: MylGWattachment
Properties:
AllocationId: !GetAtt MyNatGWEIP.AllocationId
SubnetId: !Ref MyPublicSubnet
Tags:
- Key: Name
Value: MyNatGW
DependsOn은 IGW가 먼저 VPC에 연결된 이후 NAT Gateway가 만들어지도록 순서를 보장한다. NAT Gateway는 반드시 퍼블릭 서브넷에 있어야 한다.
프라이빗 서브넷은 퍼블릭과 동일한 VPC 안에서 다른 CIDR 대역으로 만든다.
MyPrivateSubnet:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: 10.0.100.0/24
VpcId: !Ref MyVPC05
AvailabilityZone: !Select [ 0, !GetAZs '' ]
Tags:
- Key: Name
Value: MyPrivateSubnet
해당 서브넷에서 외부로 나가는 트래픽을 NAT Gateway로 보낼 수 있도록 라우팅 테이블을 만든다.
MyPrivateRouting:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref MyVPC05
Tags:
- Key: Name
Value: MyPrivateRouting
MyPrivateRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPrivateRouting
SubnetId: !Ref MyPrivateSubnet
그리고 기본 경로(0.0.0.0/0)를 NAT Gateway로 지정한다.
MyPrivateDefault:
Type: AWS::EC2::Route
DependsOn: MyNatGW
Properties:
RouteTableId: !Ref MyPrivateRouting
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref MyNatGW
프라이빗 서브넷에 EC2 인스턴스를 하나 띄운다. 퍼블릭 IP는 없기 때문에 외부에서 직접 접근은 불가능하지만, UserData에서 ping이나 yum 명령이 동작하면 NAT를 통한 외부 통신이 가능하다는 것을 의미한다.
MyWeb11:
Type: AWS::EC2::Instance
DependsOn: MyNatGW
Properties:
SubnetId: !Ref MyPrivateSubnet
PrivateIpAddress: 10.0.100.101
GroupSet:
- !Ref MyPrivateSecugroup
KeyName: !Ref KeyName
ImageId: !Ref LatestAmiId
InstanceType: t3.micro
Tags:
- Key: Name
Value: MyWeb11
UserData:
Fn::Base64: !Sub |
#!/bin/bash
ping -c 3 8.8.8.8 > /tmp/ping.txt
yum install -y httpd
systemctl enable --now httpd
echo "<h1>Private EC2 Test</h1>" > /var/www/html/index.html
loudFormation으로 스택을 실행한 후, MyWeb1 인스턴스에서 MyWeb11의 프라이빗 IP(예: 10.0.100.101)로 curl 명령을 실행하거나 SSH 접속을 시도했을 때, 모두 정상적으로 연결되는 것도 확인할 수 있었다.

먼저 MyWeb11 인스턴스에서 ping -c 3 8.8.8.8 를 통해서, NAT Gateway를 통해 외부 인터넷으로의 아웃바운드 트래픽이 정상적으로 동작하는 것을 확인했다.

이번 구성은 퍼블릭/프라이빗 서브넷을 명확히 나누고, 퍼블릭 쪽에 NAT Gateway를 설치해서 프라이빗 인스턴스가 외부로 나가는 트래픽만 허용하는 구조다. 실무에서는 웹 서버는 퍼블릭, DB나 내부 백엔드 서버는 프라이빗에 두고 NAT를 연결하는 방식이 일반적이다.