사설 IP(10.0.1.5)를 가진 서버는 인터넷과 직접 통신할 수 없다. 인터넷 라우터는 사설 IP를 목적지로 받으면 어디로 보낼지 모른다. 그 서버가 google.com에 요청을 보내도, 구글 서버가 10.0.1.5로 응답을 보낼 방법이 없다.
NAT는 이 문제를 해결한다. 패킷이 외부로 나갈 때 사설 IP를 공인 IP로 바꾸고, 응답이 돌아오면 다시 사설 IP로 되돌린다. 내부 서버 입장에서는 인터넷과 직접 통신하는 것처럼 보인다.
SNAT — 출발지 주소 변환
SNAT(Source NAT)는 패킷의 출발지 IP를 바꾼다. 내부 → 외부 방향 트래픽에 쓰인다.
내부 서버 (10.0.1.5:54321) → 구글 (8.8.8.8:80)
NAT 게이트웨이 통과 시:
출발지: 10.0.1.5:54321 → 203.0.113.1:40001 (공인 IP:포트로 교체)
구글이 응답을 보낼 때:
목적지: 203.0.113.1:40001 → NAT 게이트웨이 → 10.0.1.5:54321 (원래 서버로 복원)
여러 서버가 하나의 공인 IP를 공유할 수 있도록, NAT 게이트웨이는 서버마다 다른 포트 번호를 할당한다. 이 방식을 PAT(Port Address Translation) 또는 IP Masquerade라고도 한다. AWS NAT Gateway, 가정용 공유기가 모두 이 방식이다.
DNAT — 목적지 주소 변환
DNAT(Destination NAT)는 패킷의 목적지 IP를 바꾼다. 외부 → 내부 방향, 즉 인바운드 트래픽 라우팅에 쓰인다.
외부 클라이언트 → 203.0.113.1:80 (공인 IP)
DNAT 규칙: 203.0.113.1:80 → 10.0.1.5:8080 (내부 서버)
로드밸런서, 포트 포워딩이 DNAT다. 외부에서 공인 IP의 특정 포트로 오는 요청을 내부 서버로 전달한다.
Connection Tracking
NAT가 동작하려면 변환 테이블을 유지해야 한다. “203.0.113.1:40001에서 온 응답은 10.0.1.5:54321로 돌려줘야 한다"는 매핑을 기억한다.
이것이 Connection Tracking(conntrack) 이다. Linux 커널이 각 연결의 상태(NEW, ESTABLISHED, RELATED, INVALID)와 변환 정보를 테이블에 저장한다.
# conntrack 테이블 확인 (Linux)
conntrack -L
# tcp 6 86399 ESTABLISHED
# src=10.0.1.5 dst=8.8.8.8 sport=54321 dport=80
# src=8.8.8.8 dst=203.0.113.1 sport=80 dport=40001
# [ASSURED]
연결이 오래 유지되거나 너무 많아지면 conntrack 테이블이 가득 찰 수 있다. 테이블이 꽉 차면 새 연결이 NAT를 통과하지 못한다. 트래픽이 많은 환경에서 NAT 게이트웨이 인스턴스의 conntrack 한계가 병목이 되기도 한다.
AWS NAT Gateway
AWS의 private 서브넷 서버가 인터넷에 나가려면 NAT Gateway를 거친다.
private 서브넷 서버 (10.0.11.5)
→ private 서브넷 라우팅 테이블: 0.0.0.0/0 → nat-gateway-id
→ NAT Gateway (public 서브넷에 위치, Elastic IP 보유)
→ Internet Gateway
→ 인터넷
NAT Gateway는 반드시 public 서브넷에 위치해야 한다. 자체 Elastic IP(공인 IP)를 가지고, 그 IP로 SNAT를 수행한다.
인바운드는 허용하지 않는다. 외부에서 먼저 연결을 시작하는 요청은 NAT Gateway를 통과하지 못한다. 이것이 “private 서브넷 서버는 외부에서 직접 접근할 수 없다"는 의미다.
k8s와 NAT
k8s Service도 내부적으로 DNAT를 활용한다. kube-proxy가 iptables 또는 IPVS 규칙을 설치해, ClusterIP로 향하는 트래픽을 실제 파드 IP로 DNAT한다.
파드 → ClusterIP(10.96.0.10):80
kube-proxy iptables 규칙:
목적지 10.96.0.10:80 → 10.244.1.5:8080 (실제 파드 IP)
NodePort도 같은 원리다. 노드의 특정 포트로 들어온 트래픽을 파드로 DNAT한다. 파드에서 나가는 트래픽이 노드 IP로 보이는 것은 SNAT다. 이 모든 것이 커널의 iptables/IPVS 규칙으로 처리된다.
트레이드오프
NAT는 편리하지만 추적을 어렵게 만든다. 로그에 남는 IP가 공인 IP 하나뿐이라 어떤 내부 서버에서 나온 트래픽인지 역추적하기 어렵다. AWS에서는 VPC Flow Logs로 NAT Gateway 앞뒤의 IP를 모두 기록해 이 문제를 보완한다.
SNAT는 단방향이다. 외부 서버가 NAT 뒤에 있는 서버에 먼저 연결을 시작하는 것은 conntrack에 항목이 없으므로 불가능하다. NAT는 “보호 효과"가 있지만, 이것이 방화벽을 대체하지는 않는다.