외부에서는 5.6.7.8:8080으로 접속했는데 내부 웹 서버에는 아무 요청도 도착하지 않습니다. 포트 포워딩 규칙은 넣었지만 IP forwarding과 FORWARD 체인을 빠뜨렸습니다.
NAT 장애는 한 줄 규칙 문제가 아니라 패킷이 변환되고 전달되는 전체 경로 문제입니다.
NAT와 포트 포워딩 원리
인터넷 공유기 뒤에 있는 내 PC가 어떻게 유튜브를 볼 수 있을까요? 내부 서버를 외부에서 접속 가능하게 만들려면 무엇을 설정해야 할까요? 이 모든 것의 핵심은 **NAT(Network Address Translation)**입니다. 이 챕터에서는 SNAT과 DNAT의 원리를 이해하고, iptables를 사용하여 실제 포트 포워딩을 구성합니다.
- 1NAT(Network Address Translation) 필요성과 사설 IP 대역(RFC 1918) 개념
- 2SNAT — 내부 사설 IP를 공인 IP로 변환하여 외부 인터넷 통신 허용
- 3DNAT — 외부 요청의 목적지 IP/포트를 내부 서버로 변환하는 포트 포워딩
- 4iptables nat 테이블의 PREROUTING / POSTROUTING 체인 역할과 적용 순서
- 5Masquerade와 SNAT 차이 — 동적 IP 환경 대응
- 6net.ipv4.ip_forward 커널 파라미터와 iptables 규칙 영구 저장
iptables --versionsudo iptables -t nat -L -n -vsysctl net.ipv4.ip_forward/etc/sysctl.conf에 net.ipv4.ip_forward=1을 추가한 뒤 sudo sysctl -p 로 적용합니다. 규칙 영구 저장은 iptables-save > /etc/iptables/rules.v4를 사용하세요.
NAT 원리 이해
SNAT — 내부에서 외부로 나가는 주소 변환
사무실 내부망 서버(192.168.x.x)에서 인터넷 통신이 됩니다. 그런데 사설 IP는 라우팅이 안 되는 주소입니다. 어떻게 인터넷에 나갔다 돌아오는 걸까요? NAT이 주소를 어떻게 변환하는지 이해하지 못하면 클라우드 VPC에서 NAT Gateway가 왜 필요한지, 포트 포워딩이 어떤 원리로 동작하는지 납득하기 어렵습니다.

NAT가 필요한 이유
IPv4 주소 공간(약 43억 개)은 전 세계 기기 수에 비해 턱없이 부족합니다. 이 문제를 해결하기 위해 사설 IP 대역을 내부에서 사용하고, 게이트웨이에서 공인 IP로 변환합니다.
사설 IP 대역 (RFC 1918):
세 가지 대역이 내부 네트워크에서 사용하도록 예약되어 있습니다. 이 주소들은 인터넷에서 라우팅되지 않으므로 중복 사용해도 충돌이 없습니다.
10.0.0.0/8 (10.x.x.x)
172.16.0.0/12 (172.16.x.x ~ 172.31.x.x)
192.168.0.0/16 (192.168.x.x)
SNAT 동작 흐름
SNAT(Source NAT)은 패킷의 출발지 IP 주소를 변환합니다.
내부 서버 (10.0.0.10:54321) → 외부 서버 (1.2.3.4:80)
┌─────────────────────────────────────────────────────────┐
│ 내부 서버 │
│ src: 10.0.0.10:54321 dst: 1.2.3.4:80 │
└───────────────────────────┬─────────────────────────────┘
│
┌──────▼──────┐
│ 게이트웨이 │ ← SNAT 수행
│ (공인: 5.6.7.8) │
└──────┬──────┘
│ src: 5.6.7.8:40001 dst: 1.2.3.4:80
│ (출발지가 공인 IP로 변환됨)
▼
외부 인터넷 (1.2.3.4)
응답 패킷:
1.2.3.4:80 → 5.6.7.8:40001 (게이트웨이 수신)
↓ 역변환 (NAT 테이블 참조)
1.2.3.4:80 → 10.0.0.10:54321 (내부 서버 전달)
NAT 테이블 (연결 추적):
게이트웨이는 응답 패킷이 돌아왔을 때 어느 내부 호스트로 전달해야 하는지 알기 위해 연결 추적 테이블을 유지합니다. 아래는 두 개의 연결이 동시에 진행될 때 테이블이 어떻게 생겼는지 보여줍니다.
게이트웨이 NAT 추적 테이블:
내부 IP:포트 공인 IP:포트 목적지
10.0.0.10:54321 5.6.7.8:40001 1.2.3.4:80
10.0.0.11:60000 5.6.7.8:40002 8.8.8.8:53
Masquerade — 동적 IP 환경의 SNAT
공인 IP가 고정이면 SNAT에서 --to-source 5.6.7.8처럼 명시합니다. 하지만 DHCP나 PPPoE로 IP가 동적 할당된다면 Masquerade를 사용합니다.
# 실습 디렉토리 준비
mkdir -p /tmp/networking/part2/exam_10 && cd /tmp/networking/part2/exam_10
# SNAT (고정 공인 IP)
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 \
-j SNAT --to-source 5.6.7.8
# Masquerade (동적 IP — 가정용 공유기, PPPoE)
iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o ppp0 \
-j MASQUERADE
- 핵심 출력—명령 결과에서 성공/실패를 가르는 값을 먼저 확인합니다
- 대상 식별—IP, 포트, 인터페이스, 프로세스명처럼 다음 조치를 결정하는 필드를 봅니다
- 다음 분기—결과가 기대와 다르면 어느 계층을 이어서 점검할지 정합니다
Masquerade는 ppp0, eth0 등 나가는 인터페이스의 현재 IP를 자동으로 source로 사용합니다.
DNAT와 포트 포워딩 — 외부에서 내부로
사설 IP를 가진 내부 서버를 외부에 공개해야 합니다. 공인 IP는 게이트웨이 한 개뿐이고, 포트 8080으로 오는 요청을 내부의 192.168.1.10:80 서버로 보내야 합니다. 이게 포트 포워딩의 전형적인 사례입니다. DNAT가 어떻게 목적지 주소를 바꾸는지 이해해야 iptables 규칙을 직접 작성하거나 설정 오류를 디버깅할 수 있습니다.

DNAT 동작 흐름
DNAT(Destination NAT)은 패킷의 목적지 IP/포트를 변환합니다. 포트 포워딩이 대표적인 DNAT 활용 사례입니다.
외부 사용자가 공인 IP의 8080 포트에 접속
외부 사용자 (203.0.113.5:50000) → 게이트웨이 (5.6.7.8:8080)
┌─────────────────────────────────────────────────────────┐
│ 게이트웨이 PREROUTING 체인 │
│ src: 203.0.113.5:50000 │
│ dst: 5.6.7.8:8080 → 10.0.0.2:80 (DNAT 변환) │
└───────────────────────────┬─────────────────────────────┘
│
▼ ip_forward=1 이어야 전달!
┌──────────────┐
│ 내부 웹서버 │
│ 10.0.0.2:80 │
└──────────────┘
iptables 처리 흐름 전체
iptables에는 여러 테이블과 체인이 있습니다. NAT는 nat 테이블에서 처리됩니다.
패킷 수신
│
▼
[nat] PREROUTING ← DNAT 여기서 (목적지 변환)
│
▼
라우팅 결정
│
├─(로컬 프로세스)→ [filter] INPUT
│
└─(포워딩)──────→ [filter] FORWARD ← ip_forward=1 필요
│
▼
[nat] POSTROUTING ← SNAT/Masquerade 여기서
│
▼
패킷 송신
DNAT 설정의 핵심 요소
iptables -t nat -A PREROUTING \
-p tcp \ # 프로토콜 (tcp/udp)
--dport 8080 \ # 외부에서 접속하는 포트
-j DNAT \ # 액션: Destination NAT
--to-destination 10.0.0.2:80 # 내부 서버 IP:포트
반드시 필요한 추가 설정: ip_forward가 비활성화되면 NAT 규칙이 있어도 포워딩이 안 됩니다.
이 명령은 시스템 설정 파일을 변경합니다. 기존 파일 백업과 적용 후 검증 방법을 준비하지 않으면 재부팅이나 서비스 재시작 때 장애가 반복될 수 있습니다.
# ip_forward 활성화 (없으면 DNAT 후 패킷이 드랍됨!)
echo 1 > /proc/sys/net/ipv4/ip_forward
# 또는 영구 설정
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p
실습 — iptables NAT 구성
NAT를 사용하려면 먼저 커널의 IP 포워딩을 활성화해야 합니다.
# 현재 ip_forward 상태 확인
cat /proc/sys/net/ipv4/ip_forward
# 0 이면 비활성화 상태
# 즉시 활성화 (재부팅 시 초기화됨)
sudo sysctl -w net.ipv4.ip_forward=1
# 또는
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
# 영구 활성화 (재부팅 후에도 유지)
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.d/99-ip-forward.conf
sudo sysctl --system
# 확인
sysctl net.ipv4.ip_forward
# net.ipv4.ip_forward = 1
인터페이스 구성 확인: 어떤 인터페이스가 외부(WAN)/내부(LAN)인지 먼저 확인합니다.
# 네트워크 인터페이스 목록
ip addr show
# 예상 환경:
# eth0: 공인(외부) 인터페이스 - 5.6.7.8
# eth1: 사설(내부) 인터페이스 - 10.0.0.1
# 라우팅 테이블
ip route show
현재 iptables 규칙 확인: 기존에 설정된 NAT 규칙을 먼저 파악합니다.
# nat 테이블 확인
sudo iptables -t nat -L -n -v
# filter 테이블 확인 (FORWARD 체인)
sudo iptables -L FORWARD -n -v
외부에서 게이트웨이의 8080 포트로 들어오는 트래픽을 내부 웹 서버(10.0.0.2:80)로 전달합니다.
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 1. DNAT 규칙 추가 (PREROUTING 체인)
sudo iptables -t nat -A PREROUTING \
-p tcp \
--dport 8080 \
-j DNAT \
--to-destination 10.0.0.2:80
# 2. FORWARD 체인에서 내부 서버로의 트래픽 허용
sudo iptables -A FORWARD \
-p tcp \
-d 10.0.0.2 \
--dport 80 \
-m state \
--state NEW,ESTABLISHED,RELATED \
-j ACCEPT
# 3. 응답 패킷도 허용 (ESTABLISHED 연결)
sudo iptables -A FORWARD \
-m state \
--state ESTABLISHED,RELATED \
-j ACCEPT
# 4. SNAT/Masquerade (내부 서버가 외부로 응답할 때 출발지 변환)
sudo iptables -t nat -A POSTROUTING \
-s 10.0.0.0/24 \
-o eth0 \
-j MASQUERADE
# 규칙 확인
sudo iptables -t nat -L -n -v
sudo iptables -L FORWARD -n -v
테스트: 외부에서 포트 포워딩이 실제로 동작하는지 확인합니다.
# 외부에서 포트 포워딩 테스트
curl http://5.6.7.8:8080/
# → 10.0.0.2의 웹 서버 응답이 와야 함
# 내부에서 확인 (게이트웨이에서)
curl http://10.0.0.2:80/
여러 포트 포워딩 예시: 서비스별로 다른 포트를 각각 포워딩하는 패턴입니다.
# SSH 포워딩: 외부 2222 → 내부 10.0.0.3:22
sudo iptables -t nat -A PREROUTING \
-p tcp --dport 2222 \
-j DNAT --to-destination 10.0.0.3:22
# HTTPS 포워딩: 외부 443 → 내부 10.0.0.2:443
sudo iptables -t nat -A PREROUTING \
-p tcp --dport 443 \
-j DNAT --to-destination 10.0.0.2:443
# UDP DNS 포워딩: 외부 53 → 내부 DNS 서버 10.0.0.5:53
sudo iptables -t nat -A PREROUTING \
-p udp --dport 53 \
-j DNAT --to-destination 10.0.0.5:53
iptables 규칙은 재부팅 시 사라집니다. 영구 저장 방법을 알아봅니다.
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 현재 iptables 규칙 저장
sudo iptables-save > /etc/iptables/rules.v4
# 저장된 규칙 확인
cat /etc/iptables/rules.v4
# 규칙 복원
sudo iptables-restore < /etc/iptables/rules.v4
systemd 서비스로 부팅 시 자동 적용 (Ubuntu): iptables 규칙은 재부팅 시 초기화되므로 영구화가 필요합니다.
# iptables-persistent 패키지 설치
sudo apt-get install iptables-persistent
# 현재 규칙을 영구 저장
sudo netfilter-persistent save
# 서비스 상태 확인
sudo systemctl status netfilter-persistent
RHEL/CentOS (firewalld 대신 iptables 직접 사용 시): iptables-save로 규칙을 저장하고 재부팅 시 복원합니다.
# iptables 서비스 설치
sudo yum install iptables-services
# 규칙 저장
sudo service iptables save
# /etc/sysconfig/iptables 에 저장됨
# 부팅 시 자동 시작
sudo systemctl enable iptables
규칙 삭제 방법: 잘못 설정한 규칙은 -D 옵션으로 특정 규칙만 삭제합니다.
# 특정 규칙 삭제 (-D: delete)
sudo iptables -t nat -D PREROUTING \
-p tcp --dport 8080 \
-j DNAT --to-destination 10.0.0.2:80
# 모든 nat 테이블 규칙 초기화
sudo iptables -t nat -F
# 규칙 번호로 삭제
sudo iptables -t nat -L PREROUTING --line-numbers
sudo iptables -t nat -D PREROUTING 2 # 2번 규칙 삭제
트러블슈팅
증상
iptables DNAT 규칙을 추가했는데 외부에서 접속이 되지 않습니다.
# 게이트웨이에서 규칙 확인
sudo iptables -t nat -L PREROUTING -n -v
# Chain PREROUTING (policy ACCEPT)
# target prot opt source destination
# DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:10.0.0.2:80
# 규칙은 있는데 외부에서 curl 하면?
curl http://5.6.7.8:8080/
# curl: (7) Failed to connect to 5.6.7.8 port 8080: Connection refused
진단
# ip_forward 상태 확인
cat /proc/sys/net/ipv4/ip_forward
# 0 ← 비활성화 상태!
# 패킷이 드랍되는지 확인
sudo iptables -L FORWARD -n -v
# Chain FORWARD (policy DROP) ← DROP 정책!
# → ip_forward=0이거나 FORWARD 체인이 DROP 정책이면 포워딩 안 됨
패킷 흐름 추적: iptables LOG 타겟으로 NAT 규칙을 통과하는 패킷을 기록합니다.
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# iptables 로그 규칙 추가 (진단용)
sudo iptables -t nat -I PREROUTING 1 \
-p tcp --dport 8080 \
-j LOG --log-prefix "NAT-PRE: "
sudo iptables -I FORWARD 1 \
-p tcp \
-j LOG --log-prefix "FWD: "
# 로그 확인
sudo journalctl -f | grep -E "NAT-PRE|FWD"
# 외부에서 접속 시도 후 로그 확인
해결
이 명령은 방화벽 정책을 변경해 현재 접속 중인 세션이나 운영 트래픽에 즉시 영향을 줄 수 있습니다. 적용 전 허용 대상 IP·포트와 롤백 명령을 확인하세요.
# 1. ip_forward 활성화
sudo sysctl -w net.ipv4.ip_forward=1
# 2. FORWARD 체인 정책 또는 규칙 확인
sudo iptables -L FORWARD -n -v
# FORWARD 정책이 DROP이라면 내부 서버로 향하는 트래픽 명시적 허용
sudo iptables -A FORWARD \
-d 10.0.0.2 \
-p tcp \
--dport 80 \
-j ACCEPT
# 3. 영구 설정
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/99-forward.conf
sudo sysctl --system
체크리스트
□ net.ipv4.ip_forward = 1 확인
□ iptables FORWARD 체인 정책 및 규칙 확인
□ iptables PREROUTING DNAT 규칙 존재 확인
□ 내부 서버 방화벽에서 해당 포트 허용 확인
□ 내부 서버 서비스가 실제로 실행 중인지 확인
증상
외부에서는 curl http://5.6.7.8:8080/이 정상 동작하는데, 같은 내부망의 다른 서버에서 공인 IP로 접속하면 실패합니다.
# 내부 서버 (10.0.0.10)에서 실행
curl http://5.6.7.8:8080/
# 연결 안 됨 또는 타임아웃
원인
이것은 Hairpin NAT 문제입니다. 내부에서 공인 IP로 나가는 패킷이 게이트웨이에서 DNAT되어 10.0.0.2로 향하지만, 응답 패킷이 게이트웨이를 거치지 않고 직접 10.0.0.10으로 가려 해서 연결이 끊깁니다.
내부 서버 (10.0.0.10)
│ src: 10.0.0.10 dst: 5.6.7.8:8080
▼
게이트웨이 (DNAT 수행)
│ src: 10.0.0.10 dst: 10.0.0.2:80 ← 목적지는 변환됨
▼
내부 웹서버 (10.0.0.2)
│ 응답: src: 10.0.0.2 dst: 10.0.0.10
│ ← 게이트웨이 거치지 않고 직접 응답! (동일 서브넷)
│ 10.0.0.10 입장: 나는 5.6.7.8에 연결했는데
│ 10.0.0.2가 응답? → 연결 끊음
해결 — SNAT 추가 (Hairpin NAT)
# 내부에서 공인 IP로 접속 시 출발지도 게이트웨이 IP로 변환
sudo iptables -t nat -A POSTROUTING \
-s 10.0.0.0/24 \
-d 10.0.0.2 \
-p tcp \
--dport 80 \
-j MASQUERADE
# 이렇게 하면:
# 10.0.0.10 → 5.6.7.8:8080
# DNAT: dst 5.6.7.8:8080 → 10.0.0.2:80
# SNAT: src 10.0.0.10 → 10.0.0.1 (게이트웨이)
# 10.0.0.2 응답: dst 10.0.0.1 → 게이트웨이
# 게이트웨이가 역변환: 10.0.0.10에게 전달
실무 맥락
AWS에서의 NAT
AWS에서는 대부분의 NAT를 관리형 서비스로 처리합니다.
AWS NAT 구성 옵션:
1. NAT Gateway (관리형)
- 고가용성, 자동 스케일
- 시간당 비용 발생
- 권장: 프로덕션 환경
2. NAT Instance (EC2)
- iptables Masquerade 직접 설정
- 비용 절감, 커스터마이징 가능
- 단일 장애점 주의
# NAT Instance 설정 (EC2 Amazon Linux)
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p
iptables -t nat -A POSTROUTING \
-s 10.0.0.0/16 \
-o eth0 \
-j MASQUERADE
쿠버네티스에서의 NAT
쿠버네티스 kube-proxy는 서비스 ClusterIP를 실제 Pod IP로 DNAT합니다.
# 쿠버네티스 서비스 포트포워딩과 NAT 확인
sudo iptables -t nat -L -n | grep KUBE
# 예시 출력:
# KUBE-SERVICES all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes service rules */
# DNAT tcp -- 0.0.0.0/0 10.96.0.1 tcp dpt:443 to:192.168.1.10:6443
포트 포워딩 보안 고려사항
포트 포워딩 설정 시 보안 체크리스트:
□ 필요한 포트만 최소한으로 열기
□ 소스 IP 제한 추가 (-s 203.0.113.0/24)
□ 불필요한 포트는 정기적으로 닫기
□ fail2ban 등 브루트포스 차단 도구 적용
□ 포트 포워딩 목록을 문서화하여 팀 공유
□ VPN으로 대체 가능한지 검토 (더 안전)
실무에서 자주 보는 NAT 시나리오
# 1. 사무실 → 인터넷 (Masquerade)
iptables -t nat -A POSTROUTING -s 192.168.0.0/16 -o wan0 -j MASQUERADE
# 2. 외부 → 내부 웹 서버
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to 10.0.0.10:80
iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to 10.0.0.10:443
# 3. 외부 → 내부 SSH (비표준 포트로 노이즈 줄이기)
iptables -t nat -A PREROUTING -p tcp --dport 2222 -j DNAT --to 10.0.0.5:22
# 4. 소스 IP 제한 포트포워딩 (관리 포트)
iptables -t nat -A PREROUTING \
-s 203.0.113.0/24 \ # 허용된 관리 IP 대역만
-p tcp --dport 8443 \
-j DNAT --to 10.0.0.100:443
정리
NAT 유형
├── SNAT (Source NAT)
│ ├── 내부 → 외부 방향
│ ├── 사설 IP → 공인 IP 변환
│ ├── POSTROUTING 체인에서 처리
│ └── Masquerade: 동적 IP 환경용 SNAT
│
└── DNAT (Destination NAT)
├── 외부 → 내부 방향 (포트 포워딩)
├── 공인 IP:포트 → 사설 IP:포트 변환
└── PREROUTING 체인에서 처리
iptables NAT 핵심 명령어
├── DNAT: iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.2:80
├── Masquerade: iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE
└── ip_forward: sysctl -w net.ipv4.ip_forward=1 (필수!)
주요 트러블슈팅
├── 포워딩 안 됨 → ip_forward=0 확인
├── FORWARD 체인 DROP 정책 → 허용 규칙 추가
└── Hairpin NAT → 내부망에서 공인 IP 접속 시 SNAT 추가 필요
다음 챕터에서는 VPN과 제로 트러스트 보안 아키텍처를 학습하여, 원격 접속 환경을 안전하게 구축하는 방법을 배웁니다.