
최근 PoC 단계의 서비스의 어드민 콘솔을 빠르게 배포하면서 유저 관리나 인증 같은 무거운 기능을 모두 제외하고 최소한의 기능만 남겼다. 빠르게 검증하기 위한 환경이라 최대한 가볍게 유지해야 했고, 가장 간단하면서도 효과적인 접근 제어 방식인 IP 화이트리스트를 적용하게 됐다.
이 과정에서 생각보다 IP 설정이 까다로웠던 부분이 있었고, 특히 Cloudflare Tunnel과 Nginx를 함께 쓰면서 겪었던 문제와 해결 과정을 정리해둔다.
어드민 콘솔 접근 경로는 다음과 같은 구조다.
Client → Cloudflare → [내부망] → Kubernetes → Cloudflare Tunnel → Nginx
Cloudflare Tunnel을 통해 내부망의 NGINX에 접근하는 구조다.
처음에는 Cloudflare에서 제공하는 헤더인 CF-Connecting-IP를 사용하면 클라이언트 IP를 정확히 얻을 수 있다고 알고 있었다. 따라서 NGINX 설정에서 아래와 같이 구성했다.
real_ip_header CF-Connecting-IP;
하지만 위 설정 이후에도 외부에서 접근 제한이 정상적으로 동작하지 않는 문제가 발생했다.
NGINX의 로그를 확인해보니 $remote_addr가 실제 클라이언트 IP가 아니라 직전 프록시(Cloudflared Tunnel Pod)의 IP가 찍혔다.
log_format main '$time_iso8601 $remote_addr $request\n'
'\t\t[$status] $http_user_agent\n'
'\t\t$http_x_forwarded_for\n';

$remote_addr: Cloudflared Tunnel Pod의 IP$http_x_forwarded_for: 실제 클라이언트의 IPNGINX에서 allow/deny 접근 제어는 $remote_addr를 기준으로 동작하기 때문에, 실제 클라이언트 IP가 $remote_addr로 잡혀야 정상적으로 접근 제어가 가능하다.
실험한 결과, NGINX의 set_real_ip_from 설정을 Cloudflare의 외부 IP 대역이 아닌, 내부망 IP 대역(proxy pod IP 포함)으로 설정하면 정상적으로 실제 클라이언트 IP를 얻을 수 있었다.
| Case | NGINX 설정 | 결과 |
|---|---|---|
| 1 | Cloudflare 외부 IP 대역 신뢰, real_ip_header CF-Connecting-IP; | ❌ Fail |
| 2 | Cloudflare 외부 IP 대역 신뢰, real_ip_header CF-Connecting-IP; real_ip_recursive on; | ❌ Fail |
| 3 | 내부망 IP 대역 신뢰, real_ip_header CF-Connecting-IP; real_ip_recursive on; | ✅ Success |
| 4 | 내부망 IP 대역 신뢰, real_ip_header X-Forwarded-For; real_ip_recursive on; | ✅ Success |
| 5 | 내부망 IP 대역 신뢰, real_ip_header CF-Connecting-IP; | ✅ Success |
| 6 | 내부망 IP 대역 신뢰, real_ip_header X-Forwarded-For; | ✅ Success |
set_real_ip_from)하도록 설정해야 실제 클라이언트 IP를 얻을 수 있다.set_real_ip_from 192.168.0.0/16; # 내부망 IP 대역
real_ip_header CF-Connecting-IP;
real_ip_recursive on;
위 설정을 통해 Cloudflare Tunnel 환경에서도 정상적으로 실제 클라이언트 IP를 얻어 접근 제어가 가능했다.
현재 어드민 콘솔의 IP 화이트리스트는 NGINX의 nginx.conf에 정적으로 설정해 관리하고 있다.
이 방식은 화이트리스트가 변경될 때마다 Dockerfile을 새로 빌드하고 재배포해야 하는 불편함이 있었다.
이러한 문제를 해결하기 위해 아래와 같은 방식을 시도한 적이 있다.
nginx.conf 자체를 Kubernetes의 ConfigMap으로 분리하여 동적으로 관리위 방식들도 실제 환경에서 적용해 본 경험이 있으나, 자세한 내용과 적용 방법은 추후 별도의 포스팅을 통해 다룰 예정이다.