클라이언트 IP 보존 가이드 (HAProxy + PROXY Protocol)
개요
Envoy Gateway NodePort 앞단에 HAProxy를 두고, PROXY Protocol로 실제 클라이언트 IP를 Envoy에 전달하는 구성입니다.
로컬 k3s 환경에서 검증 완료되었습니다.
배경: externalIPs 방식의 한계
아래 조합으로는 클라이언트 IP 보존이 되지 않습니다.
- Service type
LoadBalancer+externalIPs(노드 IP 수동 패치) externalTrafficPolicy: Local설정
externalIPs는 kube-proxy의 KUBE-EXTERNAL-IP chain을 사용하며
externalTrafficPolicy: Local이 적용되지 않아 SNAT가 항상 발생합니다.
결과적으로 Envoy Pod이 받는 소스 IP가 노드 IP로 고정됩니다.
트래픽 흐름
클라이언트
→ HAProxy (80/443, PROXY Protocol 헤더 추가)
→ Envoy NodePort (30080/30443)
→ Envoy Pod (PROXY Protocol 헤더에서 실제 클라이언트 IP 추출)
→ Backend Pod (X-Forwarded-For에 실제 클라이언트 IP 포함)
TCP 레벨에서 SNAT가 발생해도 PROXY Protocol 헤더는 애플리케이션 레이어에 있으므로 영향받지 않습니다.
수정된 파일 목록
envoy-1.37.2/
├── charts/
│ └── gateway-infra/
│ ├── values.yaml # clientIP.proxyProtocol 항목 추가
│ └── templates/
│ └── main.yaml # ClientTrafficPolicy 조건부 추가
적용 방법
1. HAProxy 설정
/etc/haproxy/haproxy.cfg에 설정을 추가합니다.
<NODE_IP> 부분을 실제 Kubernetes 노드 IP로 교체하세요.
NodePort가 기본값(30080/30443)이 아닌 경우 포트도 함께 수정합니다.
2. Helm upgrade (NodePort + PROXY Protocol 활성화)
cd envoy-1.37.2/
# values-infra.yaml에서 clientIP.proxyProtocol: true 로 수정 후 실행하거나 --set 사용
helm upgrade gateway-infra ./charts/gateway-infra \
-n envoy-gateway-system \
-f ./values-infra.yaml \
--set service.type=NodePort \
--set clientIP.proxyProtocol=true
3. NodePort 확인
4. hosts 파일 설정
DNS 서버 없이 hosts 파일을 사용하는 경우, HAProxy가 떠 있는 노드 IP를 도메인에 매핑합니다.
검증
클라이언트 IP 확인
X-Forwarded-For 헤더에 실제 클라이언트 IP가 찍히는지 확인합니다.
NodePort 직접 접근 차단 확인
clientIP.proxyProtocol: true 적용 후 NodePort 직접 접근은 차단됩니다.
이것이 정상입니다.
ClientTrafficPolicy 상태 확인
kubectl get clienttrafficpolicy -n envoy-gateway-system
kubectl describe clienttrafficpolicy enable-proxy-protocol -n envoy-gateway-system
주의 사항
- HAProxy는 반드시
mode tcp를 사용합니다. clientIP.proxyProtocol: true적용 후 NodePort 직접 접근이 차단됩니다.send-proxy-v2는 PROXY Protocol v2(바이너리 형식)입니다.