RETROSPECTIVE · 회고
쿠버네티스 뒤에서 만든 URL이 http://내부주소로 나올 때
Network
파일 업로드 API에서 응답의 다운로드 URL을 ServletUriComponentsBuilder.fromCurrentContextPath()로 만들었다. 로컬에서는 멀쩡했는데 운영에 올리자 http://10.x.x.x:8080/files/...처럼 파드 내부 주소와 http가 그대로 나왔다.
원인: 앱이 보는 요청은 원래 요청이 아니다
HTTPS는 Ingress(로드밸런서)에서 끝나고, 애플리케이션은 Ingress가 다시 보낸 내부 HTTP 요청을 받는다. 그래서 요청 객체의 scheme, host, port는 내부 값이다. 원래 요청 정보는 프록시가 붙여주는 헤더에만 남아 있다.
X-Forwarded-Proto: httpsX-Forwarded-Host: example.comX-Forwarded-Port: 443
해결: forwarded 헤더를 해석하도록 명시
server:
forward-headers-strategy: framework # 또는 native
framework: 스프링의ForwardedHeaderFilter가 요청을 감싸서getScheme(),getServerName()등이 원래 값을 돌려준다.native: 내장 톰캣이 직접 처리한다(RemoteIpValve).
실행 환경을 자동으로 감지해 켜지는 경우도 있지만, 환경에 따라 달라지므로 명시해두는 편이 안전했다.
같이 확인할 것
- Ingress가 실제로
X-Forwarded-*헤더를 넘기는지 확인한다. 중간 프록시가 하나 더 있으면 값이 덮이거나 누락될 수 있다. - 이 헤더는 클라이언트가 임의로 넣을 수도 있다. 신뢰하는 프록시를 거친 요청에서만 해석하도록 해야 스푸핑된 host로 링크가 만들어지는 걸 막을 수 있다.
- 꼭 절대 URL이 필요하지 않다면 상대 경로를 내려주거나, 외부 base URL을 설정값으로 두는 것도 방법이다.