CloudFormation으로 퍼블릭/프라이빗 서브넷 구성하기

y001·2025년 3월 29일
0
post-thumbnail

시작하면서

– NAT Gateway를 통해 프라이빗 인스턴스의 외부 통신 열어주기

지금까지 CloudFormation을 활용해 EC2 인스턴스를 퍼블릭 서브넷에 배치하고, IGW와 라우팅 테이블을 연결해서 외부와 통신 가능한 구조를 만들었다.

하지만 실제 운영 환경에서는 외부에서 접근 가능한 인스턴스보다, 외부에서는 접근할 수 없지만 내부에서는 인터넷에 나갈 수 있는 인스턴스가 더 자주 사용된다. 예를 들어, 보안이 중요한 서버나 DB처럼 외부 접속은 막아두되, 보안 패치나 외부 API 호출을 위해 아웃바운드 트래픽은 열어둬야 하는 경우가 그렇다. 이럴 때 사용하는 대표적인 구조가 바로 프라이빗 서브넷 + NAT Gateway 구성이다.

이번 글에서는 퍼블릭/프라이빗 서브넷을 분리하고, 퍼블릭 서브넷에 NAT Gateway를 구성한 뒤, 프라이빗 인스턴스가 NAT를 통해 외부와 통신할 수 있는 구조를 만들어보자.


퍼블릭과 프라이빗 서브넷의 차이

AWS에서 서브넷은 퍼블릭과 프라이빗으로 나뉘는데, 핵심은 IGW 연결 여부와 퍼블릭 IP 할당 유무다.
퍼블릭 서브넷은 IGW(인터넷 게이트웨이)와 연결되고 퍼블릭 IP가 있어 외부에서 직접 접근이 가능하다. 반면, 프라이빗 서브넷은 IGW와 연결되어 있지 않고 퍼블릭 IP도 없기 때문에 외부에서는 접근할 수 없다. 하지만 NAT Gateway를 경유하면 프라이빗 인스턴스가 외부로 나가는 트래픽은 가능하다.


NAT Gateway 구성 흐름

프라이빗 인스턴스를 외부와 통신 가능하게 만들기 위해서는 아래 구성 순서를 따르게 된다.

  1. 퍼블릭 서브넷에 NAT Gateway를 배치하고 Elastic IP를 연결한다.
  2. 프라이빗 서브넷을 만들고, 라우팅 테이블을 구성한다.
  3. 프라이빗 라우팅 테이블에 0.0.0.0/0 트래픽을 NAT Gateway로 전달하도록 설정한다.
  4. 프라이빗 인스턴스를 이 서브넷에 배치한다.


NAT Gateway용 Elastic IP 생성

NAT Gateway는 퍼블릭 IP가 필요하므로, 먼저 EIP를 만들어야 한다.

MyNatGWEIP:
  Type: AWS::EC2::EIP
  Properties:
    Domain: VPC

Elastic IP는 AWS 외부에서도 고정된 IP로 접근 가능한 공인 IP 주소다.


NAT Gateway 생성

이제 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를 연결하는 방식이 일반적이다.

0개의 댓글