Proxy / Reverse Proxy / Gateway

3줄 요약

  • Proxy, reverse proxy, API gateway는 단순 통로가 아니라 TLS, routing, header, timeout, body size, auth, rate limit, WAF 정책을 적용하는 HTTP 경계다.
  • 백엔드 장애에서 앱 로그가 없으면 proxy/gateway/WAF/LB가 응답했을 수 있으므로 응답 주체, access log, upstream status, request id를 먼저 분리해야 한다.
  • 실전에서는 path rewrite, forwarded header 신뢰, client IP 추출, NGINX timeout/buffer, gateway 정책, WAF 오탐을 애플리케이션 API 계약의 일부로 문서화해야 한다.

핵심 정리

  • Reverse proxy는 서버 앞에서 TLS termination, routing, compression, buffering, body limit, timeout, access log, upstream 선택을 수행한다.
  • Gateway는 인증, 인가, quota, rate limit, request/response transformation, schema validation, observability를 중앙화한다.
  • WAF는 공격 패턴과 bot을 차단하지만 정상 트래픽도 오탐할 수 있다. 이때 앱 로그 없이 403/429가 발생한다.
  • X-Forwarded-For, X-Forwarded-Proto, Forwarded는 신뢰 가능한 proxy chain에서 온 값만 해석해야 한다.
  • proxy_pass의 slash, rewrite rule, Host header, upstream DNS, context path 차이는 404/502/redirect loop의 흔한 원인이다.

헷갈리는 지점

  • 502/504를 보면 앱 장애라고 단정하기 쉽다.
    • 핵심 판단 포인트는 proxy가 upstream connect, DNS, TLS, timeout, protocol mismatch 때문에 응답했을 수 있다는 것이다.
  • X-Forwarded-For의 첫 번째 IP를 항상 client IP로 믿기 쉽다.
    • 핵심 판단 포인트는 외부 client도 header를 조작할 수 있으므로 trusted proxy 범위에서 오른쪽부터 해석해야 한다는 것이다.
  • Gateway에 인증을 넣으면 앱 보안은 끝났다고 생각하기 쉽다.
    • 핵심 판단 포인트는 gateway가 보장하는 identity와 앱이 신뢰하는 header 사이의 위조 방지 경계를 정해야 한다는 것이다.
  • path rewrite는 URL 모양만 바꾸는 사소한 설정이라고 보기 쉽다.
    • 핵심 판단 포인트는 rewrite 결과가 app routing, redirect URL, static path, OpenAPI 문서, health check와 모두 맞아야 한다는 것이다.

확인 질문

  • proxy에서 만든 413, 429, 502, 504는 왜 앱 로그에 없을 수 있는가?
    • 요청이 애플리케이션에 도달하기 전 proxy/gateway/WAF에서 차단되거나 실패 응답이 만들어졌기 때문이다.
  • reverse proxy 뒤에서 HTTPS scheme을 올바르게 판단하려면 무엇이 필요한가?
    • 신뢰 가능한 proxy가 X-Forwarded-ProtoForwarded를 설정하고, 앱 framework가 trusted proxy 설정을 통해 그 값을 해석해야 한다.
  • WAF 오탐을 의심할 때 인프라 팀에 무엇을 전달해야 하는가?
    • 발생 시각, URL, method, client IP 대역, request id, WAF rule id, 차단된 payload 특징, 정상 기대 동작을 전달해야 한다.
  • path rewrite 장애를 빠르게 찾으려면 어떤 로그가 필요한가?
    • 외부 original URI, rewrite 후 upstream URI, upstream host, app이 실제로 받은 path를 같은 request id로 비교해야 한다.