Published on

EKS Pod만 외부 API 403 - NAT IP·WAF로 해결

Authors

서론

EKS에서 애플리케이션은 정상이고, 클러스터 내부 통신도 문제없는데 Pod에서 외부 API 호출만 403 Forbidden이 뜨는 경우가 있습니다. 흥미로운 포인트는 같은 코드가 로컬/EC2/온프레에선 잘 되고, EKS Pod에서만 403이 난다는 점입니다.

이 상황은 대개 “내가 보낸 요청이 잘못됐다(인증/헤더/포맷)”라기보다, 상대 시스템이 ‘EKS에서 나가는 출구 IP’ 또는 ‘WAF/봇 방어 정책’ 때문에 차단하는 케이스가 많습니다. 즉, 애플리케이션 레벨 문제가 아니라 네트워크 식별자(공인 IP)와 보안 정책(ACL/WAF/Rate limit) 문제로 접근해야 빨리 해결됩니다.

이 글에서는 다음을 목표로 합니다.

  • 403이 내 요청 문제인지(인증), 내 출구 IP 문제인지(NAT), 상대 WAF 차단인지 빠르게 가르는 방법
  • EKS에서 Pod egress의 실제 공인 IP 확인
  • NAT Gateway/Instance로 고정 출구 IP(EIP) 구성과 운영 팁
  • 상대 WAF/봇 방어에서 흔히 막는 패턴과 로그 기반 해결

관련 점검 흐름은 이전 글인 EKS에서 Pod는 정상인데 egress만 막힐 때 점검도 함께 보면 맥락이 더 빨리 잡힙니다.


403의 의미부터 분해하기: “내가 거절당한 이유”

HTTP 403은 서버가 요청을 이해했지만 권한/정책상 거부했다는 뜻입니다. 외부 API에서 403이 올 때는 크게 3갈래입니다.

  1. 인증/인가 실패: API Key, OAuth scope, 서명, 토큰 만료
  2. 출구 IP/지역/ASN 차단: 허용된 IP allowlist에 없거나, 클라우드 IP 대역 차단
  3. WAF/봇 방어/레이트리밋 차단: 특정 헤더/UA/패턴, 비정상 트래픽으로 판단

중요한 힌트는 “EKS Pod에서만”이라는 조건입니다.

  • 로컬에서는 성공 → 코드/인증 자체는 맞을 가능성 증가
  • EKS에서만 실패 → 출구 IP, 프록시, TLS, 헤더 변형, WAF 의심

만약 대상이 OpenAI 같은 외부 API라면 인증 관점 체크리스트는 별도 글(OpenAI Responses API 401 403 인증오류 점검 가이드) 형태로 정리해두었지만, 이 글은 NAT IP·WAF 중심으로 진행합니다.


1단계: Pod에서 “내가 누구로 보이는지”부터 확인

가장 먼저 해야 할 일은 Pod에서 외부로 나갈 때의 공인 IP(egress IP) 를 확인하는 것입니다.

Pod에서 공인 IP 확인 (curl)

kubectl run -it --rm netcheck \
  --image=curlimages/curl:8.5.0 \
  --restart=Never -- sh

# 컨테이너 내부
curl -s https://api.ipify.org
curl -s https://ifconfig.me

여기서 출력되는 IP가 상대 서버가 보는 IP입니다. 이 IP가 바뀌거나(특히 NAT GW 교체/추가), 여러 개로 섞이면(멀티 NAT) allowlist 기반 API에서 403이 날 수 있습니다.

같은 VPC의 EC2(혹은 로컬)과 비교

  • 로컬에서 curl https://api.ipify.org 결과 IP와
  • Pod에서 결과 IP가 다르면

상대 시스템이 로컬 IP는 허용, EKS 출구 IP는 차단했을 가능성이 매우 큽니다.


2단계: EKS에서 Pod egress 경로(출구)를 빠르게 도식화

일반적인 EKS 프라이빗 서브넷 구성은 다음과 같습니다.

  • Pod → 노드 ENI → 프라이빗 서브넷 라우팅 → NAT Gateway(퍼블릭 서브넷) → Internet Gateway → 외부 API

여기서 상대가 보는 공인 IP는 보통 NAT Gateway의 Elastic IP(EIP) 입니다.

NAT Gateway가 맞는지 확인 (AWS CLI)

aws ec2 describe-route-tables \
  --filters "Name=vpc-id,Values=vpc-xxxx" \
  --query 'RouteTables[].Routes[?DestinationCidrBlock==`0.0.0.0/0`]' \
  --output table
  • 프라이빗 서브넷의 0.0.0.0/0 대상이 nat-...이면 NAT Gateway 경유
  • igw-...이면 퍼블릭 서브넷(노드가 퍼블릭 IP 보유 가능)

NAT 구성이 꼬였거나 라우팅이 다른 서브넷으로 빠지면, 예상치 못한 IP로 나가면서 403이 발생할 수 있습니다.


3단계: “왜 403이 EKS에서만?” 자주 나오는 원인 Top 6

원인 1) 상대 API가 IP allowlist 기반인데 NAT EIP가 바뀜

NAT Gateway를 재생성하거나, 다른 NAT로 라우팅이 바뀌면 출구 IP가 바뀝니다.

  • 운영 중 NAT 교체
  • 멀티 AZ NAT 구성에서 서브넷별로 NAT가 다름
  • 비용 절감 목적으로 NAT Instance로 전환 후 EIP 변경

해결: NAT EIP를 고정하고, 상대 allowlist에 반영(또는 고정 egress 프록시 도입)

원인 2) 멀티 NAT로 인해 출구 IP가 여러 개로 섞임

프라이빗 서브넷이 여러 AZ에 있고, 각 AZ마다 NAT GW가 있으면 Pod가 어느 노드/AZ에 뜨느냐에 따라 출구 IP가 달라질 수 있습니다.

해결:

  • 상대 allowlist에 모든 NAT EIP 등록
  • 혹은 특정 AZ로 워크로드 고정(권장도는 낮음)

원인 3) 상대가 AWS/클라우드 ASN을 통째로 차단

일부 서비스는 봇/스크래핑 방어로 클라우드 대역을 광범위하게 막습니다. 이 경우 EKS(=AWS)에서만 403이 날 수 있습니다.

해결:

  • 상대에 “우리 출구 IP(EIP) allow” 요청
  • 가능하면 전용 프록시/전용 회선/파트너 채널 사용

원인 4) WAF가 User-Agent/헤더/패턴을 차단

Pod의 HTTP 클라이언트가 특정 헤더를 누락하거나(예: User-Agent), 비정상적으로 보이는 요청을 보내면 WAF 규칙에 걸릴 수 있습니다.

예:

  • curl/7.xx 기본 UA 차단
  • Accept: */* 조합 차단
  • 특정 경로에 대한 레이트리밋

해결: WAF 로그/차단 사유를 확인하고 룰 예외 처리

원인 5) 회사/파트너 측이 “국가/지역” 또는 “IP 평판”으로 차단

AWS 리전의 IP가 특정 정책에 걸릴 수 있습니다.

해결: 리전 변경, 고정 IP + 평판 개선, 사전 협의

원인 6) 프록시/미들웨어가 403을 만들고 있음

외부 API가 아니라 중간 프록시(사내 egress proxy, 서비스 메쉬 egress gateway)가 403을 반환하는 경우도 있습니다.

해결:

  • 응답 헤더의 Server, Via, X-Cache, X-Amzn-ErrorType 등으로 발신자를 추적
  • Envoy/NGINX/프록시 로그 확인

4단계: NAT EIP 고정으로 “출구 IP”를 안정화하기

상대가 IP allowlist를 요구한다면, EKS에서 나가는 공인 IP를 고정하는 것이 정석입니다.

NAT Gateway + Elastic IP 확인

aws ec2 describe-nat-gateways \
  --filter "Name=vpc-id,Values=vpc-xxxx" \
  --query 'NatGateways[].{NatId:NatGatewayId,Subnet:SubnetId,Eips:NatGatewayAddresses[].PublicIp,State:State}' \
  --output table

여기서 PublicIp가 곧 egress IP 후보입니다.

멀티 AZ NAT에서 “어느 NAT로 나가는지” 통제

  • 프라이빗 서브넷 라우트 테이블을 AZ별로 분리하고
  • 각 서브넷이 자기 AZ NAT로만 나가게 구성하는 것이 일반적입니다.

그러면 결과적으로 AZ마다 출구 IP가 다를 수 있음을 전제로 운영해야 합니다.

실무 팁: 상대 allowlist를 요청할 때

  • “EKS 클러스터 egress IP는 이 2~3개(EIP)입니다” 형태로 제공
  • NAT 교체 시 EIP 유지(가능하면 기존 EIP 재사용) 절차를 런북에 넣기

5단계: WAF 차단이면 “403의 본문/헤더”가 힌트다

상대가 WAF를 쓰는 경우, 403 응답에는 종종 힌트가 있습니다.

403 응답의 헤더/바디를 최대한 수집

curl -v https://api.example.com/v1/resource \
  -H 'User-Agent: my-service/1.0' \
  -H 'Accept: application/json'
  • Server: cloudflare / cf-ray → Cloudflare WAF 가능성
  • x-amzn-RequestId / x-amzn-ErrorType → API Gateway/Lambda/ALB 계열 가능성
  • HTML로 “Access denied” 템플릿 → WAF/봇 방어 가능성 증가

(내가 운영하는) ALB + AWS WAF에서 403이라면

내 서비스 앞단 ALB+WAF에서 403이 나는 케이스도 자주 섞입니다. 이때는 WAF 로그를 CloudWatch/S3로 보고 “어떤 룰이 막았는지”를 확인해야 합니다.

WAF 로그 기반 트러블슈팅은 EKS ALB Ingress WAF 403 차단 로그로 푸는 법에 자세히 정리해두었습니다.


6단계: 재현 가능한 최소 테스트로 “IP 차단 vs 요청 차단”을 분리

다음 2가지를 분리하면 해결 속도가 급격히 빨라집니다.

  • 같은 요청을 다른 출구 IP로 보내면 성공하는가? → IP 차단
  • 같은 출구 IP에서 헤더/UA를 바꾸면 성공하는가? → WAF/요청 패턴 차단

테스트 A: Pod에서 헤더만 바꿔보기

# 기본
curl -s -o /dev/null -w "%{http_code}\n" https://api.example.com/health

# UA/Accept 명시
curl -s -o /dev/null -w "%{http_code}\n" https://api.example.com/health \
  -H 'User-Agent: Mozilla/5.0 (compatible; mybot/1.0)' \
  -H 'Accept: application/json'

테스트 B: 같은 VPC의 다른 출구(예: 퍼블릭 EC2)에서 호출

퍼블릭 서브넷 EC2에서 동일 요청을 보내 200이 나오면, Pod egress IP만 차단일 가능성이 큽니다.


7단계: 운영 관점의 권장 아키텍처(현실적인 선택지)

선택지 1) NAT Gateway EIP allowlist (가장 흔함)

  • 장점: 단순, 비용/운영 예측 가능
  • 단점: 멀티 AZ면 IP가 여러 개, NAT 비용 발생

선택지 2) 고정 egress 프록시(예: Squid/Envoy) + 단일 EIP

  • 장점: 출구 IP를 1개로 만들기 쉬움, 정책/감사/캐시 가능
  • 단점: 프록시 운영 부담, SPOF 방지 설계 필요

선택지 3) PrivateLink/파트너 전용 연결

  • 장점: 인터넷/WAF 변수 감소, 보안/안정성 우수
  • 단점: 상대가 지원해야 함, 비용/구성 복잡

8단계: 체크리스트(현장에서 바로 쓰는 순서)

  1. Pod에서 api.ipify.orgegress 공인 IP 확인
  2. 403 응답의 헤더/바디를 수집(curl -v)
  3. 프라이빗 서브넷 라우팅에서 NAT GW/IGW 경로 확인
  4. NAT GW의 EIP 목록을 정리(멀티 AZ면 여러 개)
  5. 상대에게 allowlist 요청 또는 차단 사유 확인(WAF 룰/봇 방어)
  6. 헤더(UA/Accept), 요청 빈도, 재시도 정책을 조정해 WAF 오탐 줄이기

Pod egress 자체가 막혀 403이 아니라 타임아웃/연결 실패라면, 네트워크 레벨 점검은 EKS에서 Pod는 정상인데 egress만 막힐 때 점검 흐름대로 보시면 됩니다.


결론

EKS에서만 외부 API가 403을 반환할 때는 “코드가 틀렸다”보다 출구 IP(NAT EIP) 또는 WAF/봇 방어 정책을 먼저 의심하는 것이 효율적입니다. Pod에서 실제 egress IP를 확인하고, NAT EIP를 고정/정리해 상대 allowlist에 반영하면 대부분 해결됩니다. 그 다음 단계로 403 응답의 힌트를 기반으로 WAF 차단 룰을 좁혀가면, 재현 가능한 형태로 원인을 특정할 수 있습니다.

운영 중에는 NAT/EIP 변경이 곧 장애로 이어질 수 있으니, “우리 서비스의 egress IP 목록”을 문서화하고 변경 절차(런북)로 관리하는 것을 권장합니다.