NAT Gateway 대신 NAT Instance로 비용 절감하기 (with 트러블슈팅)
NAT Instance 설정 방법
본 글은 AWS 공식 문서를 기반으로 작성되었습니다. 다만, 공식 문서의 설정대로 진행했을 때 ICMP(ping) 요청이 REJECT 되는 문제가 발생하여 문제 원인을 분석하고 해결한 과정을 정리합니다.
1. Private Subnet 인스턴스의 인터넷 통신 방법
Private Subnet에 위치한 인스턴스들이 인터넷에 접속할 수 있도록 주소를 변환해주는 것으로 NAT Gateway와 NAT Instance가 존재합니다. NAT Gateway는 AWS에서 관리하는 완전 관리형 서비스이고 NAT Instance는 사용자가 직접 EC2 인스턴스를 구축하여 NAT 역할을 하도록 설정하는 방식입니다.
NAT Gateway는 완전 관리형 서비스이기 때문에 고가용성 및 확장성을 자동으로 제공하지만, NAT Instance는 인스턴스를 직접 관리해야하므로 고가용성을 보장하지 않습니다.
그럼에도 NAT Gateway를 대신하여 NAT Instance를 사용하곤 하는데 그 이유는 NAT Gateway를 사용하는 경우 비용이 많이 발생하기 때문입니다. NAT Gateway는 프로비저닝되어 실행되는 시간 및 데이터 양 두 부분에 있어 각각 비용이 발생합니다. (2025.08 기준으로 시간당 0.059 USD, GB당 0.059 USD) 한 달(31일)동안 NAT Gateway를 사용하게 되면 단순히 실행 시간만으로도 약 43.90(0.059 * 24 * 31) USD의 고정 비용이 발생합니다.
반면에 NAT Instance의 NAT 역할을 하는 EC2 인스턴스를 사용하므로 NAT Gateway 보다 적은 비용이 발생합니다. 예로, t3.small 스펙(2vCPU, 2GiB, 5Gbps)을 사용하는 인스턴스의 경우 시간당 0.025 USD 비용이 부과되고 이를 한달 비용으로 계산하면 약 19.34 USD 비용이 발생합니다. 데이터 전송량은 제외한 가격만 비교하였을 때 NAT Instance는 NAT Gateway에 비해 약 24 USD를 절감할 수 있습니다.
물론 NAT Instance는 고가용성을 보장하지 않으므로 개발 및 스테이징 환경에서 사용하는 것이 적합하고 운영 환경에서는 NAT Gateway를 사용하는 것이 권장됩니다.
2. NAT Instance 설정 방법
2-1. EC2 생성
- AMI: amzn2-ami-hvm-2.0.20250808.1-x86_64-gp2 (서울 리전 기준 AMI ID: ami-095919fccdf5fb49b)
- Subnet: Public Subnet
- 보안그룹: 인바운드 및 아웃바운드 그룹 둘 다 0.0.0.0/0에 대해 모든 트래픽 허용합니다. 단, 운영 환경에서는 안정성을 위해 최소 권한 원칙을 준수해야 합니다.
2-2. EIP 할당 및 Private Subnet Route table 트래픽 경로 수정
- NAT Instance는 EIP를 할당해야 합니다.
- Private Subnet을 위한 라우팅 테이블에서 다음 규칙을 추가합니다:
- Destiniation: 0.0.0.0/0
- Target: NAT Instance
NAT Instance는 Public Subnet에 생성하므로 Public IP를 할당해도 되지만, EIP를 할당하는 것이 권장됩니다. EIP는 고정된 Public IP 주소이기 때문에 추후에 IP 주소가 변경되어 세션이 끊기는 문제를 방지할 수 있습니다.
Public Subnet이 아닌 Private Subnet의 라우팅 테이블에 규칙을 추가해야합니다. 기존에 설정되어 있는 NAT Gateway 규칙을 제거하고 NAT Instance를 위한 규칙을 추가하세요.
2-3. 소스 대상 확인 중지
NAT Instance를 사용하기 위해서는 소스 대상 확인(Source / destination checking)을 중지(stop)해야 합니다. 왜냐하면 NAT 인스턴스가 Private Subnet에 있는 EC2 인스턴스를 대신하여 트래픽을 송수신해야하기 때문입니다.
만약 stop하지 않는다면 NAT Instance 입장에서는 Private Subnet에서 발생한 트래픽의 소스 IP가 자신의 IP 주소가 아니기 때문에 해당 패킷을 삭제합니다. 또한, 인터넷으로부터 응답을 받을 때도 대상 IP가 NAT Instance의 IP와 다르기 때문에 해당 패킷을 삭제합니다. 이렇게 설정되어 있는 이유는 인스턴스가 다른 인스턴스의 IP 주소를 스푸핑하여 트래픽을 가로채는 것을 방지하기 위한 AWS 기능이기 때문입니다.
3. iptables 및 IP 포워딩 설정
3-1. iptables 서비스 설치 및 실행
1
2
3
4
yum update -y # 시스템 패키지 최신화
yum install -y iptables-services # iptables 서비스 설치
systemctl enable iptables # 부팅 시 iptables 자동 실행
systemctl start iptables # iptables 서비스 시작
3-2. IP 포워딩 활성화
NAT Instance가 패킷을 전달할 수 있도록 포워딩을 허용합니다.
1
2
3
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf # 커널에 IP 포워딩 옵션 추가
sysctl -p # 변경사항 적용
cat /proc/sys/net/ipv4/ip_forward # 실제 적용 여부 확인 (1이면 활성화)
3-3. NAT 규칙 설정 (소스 IP 변환 규칙)
Private Subnet EC2의 소스 IP를 NAT Instance의 Public IP로 변환하여 외부 인터넷에 접근이 가능하도록 합니다.
3-4. FORWARD 체인 규칙 (패킷 전달 허용)
기본 포워딩 규칙을 설정하여 내부 -> 외부 트래픽 및 응답 패킷을 허용합니다.
IP 포워딩 활성화 (커널 레벨에서 라우팅 허용):
1
2
3
iptables -A FORWARD -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT # 외부 응답 트래픽 허용
iptables -A FORWARD -o eth0 -j ACCEPT # 내부 → 외부 트래픽 허용
service iptables save # 규칙 저장
NAT Masquerade 규칙 추가 (소스 IP 변환):
1
2
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # NAT: 내부 IP → NAT 인스턴스의 공인 IP로 변환
iptables -t nat -L POSTROUTING -vn # NAT 규칙 확인
설정을 마치고 “iptables -L FORWARD -vn –line-numbers” 실행 시 기본적으로 아래와 같은 REJECT 규칙이 존재합니다:
1
2
3
4
5
6
7
$ sudo iptables -L FORWARD -vn --line-numbers
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 89 5716 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
2 0 0 ACCEPT all -- eth0 * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
3 0 0 ACCEPT all -- * eth0 0.0.0.0/0 0.0.0.0/0
iptables는 규칙을 위에서부터 순차적으로 검사하므로 num이 낮을수록 먼저 적용됩니다. 따라서 1번 규칙이 가장 높은 우선 순위를 갖게 됩니다.
1번 규칙에 모든 ICMP 프로토콜에 대해서 REJECT로 설정되어 있으므로 Private Subnet의 EC2 인스턴스에서 “ping 8.8.8.8”를 입력했을 때 트래픽이 차단되어 “Destination Host Prohibited” 에러 메시지가 출력됩니다. 즉, Private Subnet → NAT Instance → 외부로 나가는 패킷이 차단되어, “ping 8.8.8.8” 시 “Destination Host Prohibited” 오류가 발생합니다.
이 문제를 해결하기 위해서는 iptables에 ACCEPT 규칙을 REJECT 위로 올려야 합니다.
3-5. Destination Host Prohibited 문제 해결
10.0.0.0/16은 제 환경에서 Private Subent이 속한 VPC의 CIDR 주소입니다. 이 주소를 본인 환경에 맞춰 수정하세요.
1
2
3
4
5
# 응답 패킷 허용 규칙을 최상단에 배치
sudo iptables -I FORWARD 1 -m state --state RELATED,ESTABLISHED -j ACCEPT
# Private Subnet에서 나가는 트래픽 허용 (10.0.0.0/16 → 외부)
sudo iptables -I FORWARD 2 -s 10.0.0.0/16 -j ACCEPT
설정을 마치고 “iptables -L FORWARD -vn –line-numbers”를 입력하면 다음 형태로 출력됩니다:
1
2
3
4
5
6
7
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 128K 519M ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
2 1677 101K ACCEPT all -- * * 10.0.0.0/16 0.0.0.0/0
3 131 8580 REJECT all -- * * 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
4 0 0 ACCEPT all -- eth0 * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
5 0 0 ACCEPT all -- * eth0 0.0.0.0/0 0.0.0.0/0
트러블 슈팅
ping(ICMP)은 성공하나 HTTPS 실패
만약 iptables 규칙이 ICMP 전용 MASQUERADE로만 되어 있다면 다음 문제가 발생합니다:
- Ping(ICMP): 성공
- HTTPS(TCP 443): 실패 → ex. ECS 태스크가 CloudWatch Logs에 로그를 쓰지 못함
문제가 되는 규칙 예시:
1
2
3
4
5
sudo iptables -t nat -L -vn
Chain POSTROUTING (policy ACCEPT 313 packets, 20532 bytes)
pkts bytes target prot opt in out source destination
9 756 MASQUERADE icmp -- * * 10.0.0.0/16 0.0.0.0/0
해결 방법:
1
2
3
4
5
# 1. 기존 ICMP 요청만 허용하는 MASQUERADE 삭제
sudo iptables -t nat -D POSTROUTING -p icmp -s ${VPC_CIDR} -j MASQUERADE # ex. VPC_CIDR=10.0.0.0/16
# 2. 모든 프로토콜을 NAT가 처리하도록 설정
sudo iptables -t nat -A POSTROUTING -s ${VPC_CIDR} -o eth0 -j MASQUERADE