HTTP 301이 뜨는 이유 — ALB ssl-redirect
curl work-api.test.example.io/readyz를 날렸더니 200 대신 이게 돌아왔다.
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
</body>
</html>
https://를 명시해서 치면 {"status":"ready"}. 같은 엔드포인트인데 왜 한쪽은 301이고 한쪽은 200인가.
301은 오류가 아니라 의도된 보안 설정이다
301 Moved Permanently는 리소스가 영구적으로 다른 URL로 이동했다는 의미다. 클라이언트에게 앞으로는 새 URL을 쓰라고 알리며, Location 헤더에 새 주소가 포함된다.
curl -v로 확인하면:
< HTTP/1.1 301 Moved Permanently
< Location: https://work-api.test.example.io/readyz
http://로 보낸 요청을 https://로 리다이렉트하고 있다. HTTP는 평문이기 때문에 인증 토큰·쿠키가 노출될 위험이 있어서, HTTP 요청을 HTTPS로 강제 전환하는 것이 보안 표준이다.
301을 보내는 주체는 ALB다
EKS + ALB + Ingress 구조에서 트래픽 경로는 다음과 같다.
Route53
↓
ALB (HTTP 80 → HTTPS 443 redirect)
↓
Ingress → Service → Pod
301을 보내는 후보는 세 곳이다: ALB Listener Rule, nginx ingress annotation, 또는 애플리케이션 코드. 실제 Ingress 설정을 보면 원인이 바로 보인다.
annotations:
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/ssl-redirect: '443' # ← 이것alb.ingress.kubernetes.io/ssl-redirect: '443' — AWS Load Balancer Controller는 이 annotation을 보고 ALB를 다음과 같이 구성한다.
| 리스너 | 동작 |
|---|---|
| 80 | Redirect → 443, 상태 코드 HTTP_301 |
| 443 | TargetGroup으로 forward |
301은 Ingress나 Pod가 아니라 ALB 레벨에서 발생한다. 이 annotation을 제거하면 301이 사라지고 HTTP 직접 접근이 가능해지지만, 보안상 권장하지 않는다.
브라우저에서는 301이 보이지 않는 이유
브라우저로 http://work-api.test.example.io/readyz를 열면 301이 뜨지 않고 바로 응답이 온다. 301이 사라진 게 아니라, 브라우저가 301을 받고 자동으로 따라가기 때문이다.
HTTP 스펙상 301은 클라이언트가 새 URL로 재요청해야 한다고 정의되어 있고, 브라우저는 이를 UX 차원에서 자동 처리한다. 추가로 브라우저는 301 결과를 캐싱하기 때문에, 같은 URL을 다시 열면 서버에 요청조차 보내지 않고 바로 https://로 간다.
curl은 기본적으로 리다이렉트를 자동으로 따라가지 않는다. API 클라이언트나 스크립트는 리다이렉트를 명시적으로 인지해야 하는 경우가 많아 기본 동작이 멈추는 것이다.
| 클라이언트 | 301 수신 시 동작 | 보이는 것 |
|---|---|---|
| 브라우저 | Location으로 자동 재요청 | 최종 응답(200)만 보임 |
| curl (기본) | 301 응답에서 멈춤 | 301 HTML 그대로 출력 |
| curl -L | 자동으로 따라감 | 최종 응답(200)이 출력 |
# 301에서 멈춤 (기본)
curl http://work-api.test.example.io/readyz
# 브라우저처럼 자동으로 따라감
curl -L http://work-api.test.example.io/readyz이 탐구가 남긴 것
ssl-redirect annotation 하나가 ALB 레벨에서 HTTPS 강제 전환을 구현한다. 301은 어떤 오류가 아니라 의도된 보안 설정이다. curl에서 예상치 못한 301을 만나면 -v로 Location 헤더를 확인하고, 리다이렉트를 따라가려면 -L 옵션을 쓴다.