Traefik 마이그레이션 문서
Traefik 마이그레이션 문서 (Traefik Migration Documentation)
본문
마이그레이션: 버전 사이에 필요한 단계
이 가이드는 서로 다른 Traefik v3 버전 간 업그레이드를 위한 자세한 마이그레이션 단계를 제공해요. 각 섹션은 원활한 전환에 필요한 breaking change, 폐기(deprecation) 항목, 설정 업데이트를 다룹니다.
v3.7.14
Ingress-NGINX 프로바이더: 생성된 이름 (generated names)
v3.7.14까지 Ingress-NGINX 프로바이더는 자체가 생성하는 라우터, 서비스, serversTransports, TLS 옵션의 이름에서 Ingress와 Secret 이름의 마침표(dot)를 대시(dash)로 바꿨어요.
그래서 my.ingress와 my-ingress라는 두 리소스가 같은 이름을 만들어냈고, 하나가 다른 하나를 조용히 덮어썼어요.
v3.7.14부터 리소스 이름은 그대로 유지돼요. 즉 my.ingress라는 Ingress의 라우터는 이제 default-my-ingress-rule-0-path-0이 아니라 default-my.ingress-rule-0-path-0예요.
이전 이름에 의존하던 대시보드, 알림, API 쿼리는 업데이트해야 해요.
nginx.ingress.kubernetes.io/ssl-passthrough 애노테이션을 가진 Ingress에 대해 HTTP 엔트리포인트에서 생성되는 라우터와 미들웨어도 이름이 변경돼요.
이제는 나온 Ingress 규칙과 경로에 따라 --rule--path-로 이름이 붙는데, ---http가 아니라요.
Kubernetes Gateway API 프로바이더: 요청을 똑같이 잘 일치시키는 라우트
v3.7.14까지 같은 리스너의 두 라우트가 완전히 같은 규칙의 라우터를 만들 수 있었어요.
이는 예를 들어 호스트 이름이 없는 라우트와 리스너의 호스트 이름을 가진 라우트가 있을 때 발생해요.
두 라우트 중 하나가 요청을 처리했지만, 어느 것인지 알 수 없었어요. 설정을 리로드할 때마다 라우트가 바뀔 수도 있었죠.
v3.7.14부터 우선순위를 가진 라우트만 요청을 처리해요.
사양(specification)은 더 오래된 라우트에 우선권을 주고, 그다음 {namespace}/{name} 사전순의 첫 라우트에 우선권을 줘요.
Traefik은 나머지 라우트의 라우터를 만들지 않아요.
Traefik은 로그에 경고를 쓰고, 규칙을 처리하는 라우터의 이름을 알려줘요.
Kubernetes Gateway API 프로바이더: TLSRoute 라우터 이름
v3.7.14까지 여러 TLS 리스너(엔트리포인트 공유)에 연결된 TLSRoute는 같은 이름의 라우터를 만들었고, 그중 하나만 유지됐어요.
v3.7.14부터 TLSRoute 라우터 이름의 해시 접미사도 라우터 규칙에서 파생되므로, 모든 TLSRoute 라우터와 그로부터 파생된 서비스의 이름이 바뀌어요.
이전 이름에 의존하던 대시보드, 알림, API 쿼리는 업데이트해야 해요.
OpenTelemetry 메트릭: 지수 히스토그램 (exponential histograms)
v3.7.14까지 traefik_*_request_duration_seconds 히스토그램은 OTEL_EXPORTER_OTLP_METRICS_DEFAULT_HISTOGRAM_AGGREGATION이 base2_exponential_bucket_histogram으로 설정돼 있어도 항상 명시적 버킷으로 내보내졌어요.
v3.7.14부터 이 히스토그램들은 이 환경 변수를 따르고, metrics.otlp.explicitBoundaries 옵션은 명시적 버킷 히스토그램에만 적용돼요.
지수 집계가 활성화되면 이 히스토그램의 버킷 시리즈에 의존하는 대시보드와 알림은 업데이트해야 해요.
v3.7.13
h2c 업그레이드 요청 (h2c Upgrade Requests)
v3.7.13부터 Traefik은 Upgrade: h2c와 HTTP2-Settings 요청 헤더를 더 이상 백엔드로 전달하지 않아요.
Traefik은 폐기된 h2c 업그레이드 메커니즘을 구현하지 않고, prior knowledge로 암호화되지 않은 HTTP/2만 제공해요. 그 헤더들을 전달하면 Traefik 자신이 클라이언트와 협상하지 않은 업그레이드를 백엔드가 수락하게 만들 수 있었어요.
이전에 그런 업그레이드를 수락하던 백엔드는 이제 그 요청을 HTTP/1.1로 처리해요.
암호화되지 않은 HTTP/2로 백엔드에 도달하려면 h2c 스킴으로 서버를 선언하세요:
파일 (YAML)
## Dynamic configuration
http:
services:
my-service:
loadBalancer:
servers:
- url: "h2c://private-ip-server-1:8080"
파일 (TOML)
## Dynamic configuration
[http.services]
[http.services.my-service.loadBalancer]
[[http.services.my-service.loadBalancer.servers]]
url = "h2c://private-ip-server-1:8080"
서버 URL 대신 스킴을 노출하는 프로바이더도 같은 방식으로 받아들여요.
traefik.http.services..loadbalancer.server.scheme=h2c 라벨,
Kubernetes CRD의 scheme: h2c 옵션,
또는 traefik.ingress.kubernetes.io/service.serversscheme: h2c Kubernetes Ingress 애노테이션으로요.
요청 대상 유효성 검사 (Request Target Validation)
v3.7.13부터 루트가 없는(rootless) 대상, 즉 스킴 뒤에 슬래시로 시작하지 않는 무언가로 이루어진 대상이 오면 400 Bad Request 응답으로 거부돼요.
그런 대상은 rfc9112#section-3.2가 허용하는 네 가지 형태 중 어느 것도 아니에요.
예를 들어 http:example.com/admin 같은 루트 없는 대상은 경로가 없어서,
경로 처리와 라우팅 규칙을 벗어나면서도 백엔드의 리소스를 가리키게 돼요.
이 거부는 설정할 수 없어요. 그런 대상을 허용하면 우회(bypass)가 다시 생기기 때문이죠.
검증이 라우팅 전에 일어나므로 거부된 요청은 액세스 로그에 기록되지 않아요.
DEBUG 로그 레벨에서만 보여요.
Consul Catalog 및 Nomad: 충돌하는 서비스 설정
Consul Catalog와 Nomad 프로바이더는 각 서비스 인스턴스의 설정을 따로 만들고, 그다음 모두 합쳐요. v3.7.13까지 인스턴스는 노드, 서비스 이름, 서비스 ID의 정규화된 연결로 식별됐는데 이는 모호해요. 두 개의 서로 다른 인스턴스가 같은 식별자를 만들어낼 수 있었고, 마지막 것을 제외한 나머지 설정은 조용히 버려졌죠.
v3.7.13부터 이 식별자는 모호하지 않고, 모든 인스턴스가 합치기에 기여해요.
새로 감지된 충돌 (Newly detected conflicts)
이전에 버려졌던 설정이 이제 병합돼요. 여러 인스턴스가 정의한 라우터나 미들웨어는 모든 인스턴스가 똑같이 정의할 때만 유지되고, 서비스는 인스턴스들이 서버(이것은 함께 풀링됨)를 제외한 모든 것에 동의할 때만 유지돼요. 그렇지 않으면 리소스가 완전히 제거되고, 오류가 기록되며, 업그레이드 전에 처리되던 라우터가 사라질 수 있어요. 병합 순서도 바뀌고, 그에 따라 로드 밸런서의 서버 순서도 바뀌어요.
v3.7.12
AliasHeadersStrategy
v3.7.12부터 새로운 aliasHeadersStrategy 엔트리포인트 옵션이 v3.6.20에서 도입된 underscoreHeadersStrategy 옵션을 폐기시키고 대체해요.
Go는 헤더 이름을 대시에서만 정규화(canonicalize)하므로 X-Auth-User, X_Auth_User, X.Auth.User를 세 개의 서로 다른 헤더로 처리해요. 반면 헤더 이름에서 변수 이름을 파생하는 백엔드(CGI, WSGI, PHP, NGINX, ...)는 이름을 대문자로 올리고 문자도 숫자도 아닌 모든 문자를 언더스코어로 바꿔요. 그들에게는 위 세 이름이 같은 HTTP_X_AUTH_USER 변수예요.
underscoreHeadersStrategy 옵션은 이름에 언더스코어 문자가 포함된 헤더 이름만 처리해서, 다른 별칭 형태는 그대로 둬요. 그 동작은 변하지 않았어요.
언더스코어는 그런 별칭을 만드는 문자 중 하나일 뿐이에요. HTTP가 헤더 이름에서 허용하는 문자 중 문자, 숫자, 대시를 제외한 것은 모두 별칭을 만들 수 있어요. 즉 !, #, $, %, &, ', *, +, ., ^, _, `, |, ~예요. aliasHeadersStrategy 옵션은 모두 처리해요:
-
keep (기본값): 별칭 이름을 가진 요청 헤더는 그대로 전달돼요.
-
delete: 이름에 문자, 숫자, 대시가 아닌 문자가 포함된 요청 헤더는 요청에서 조용히 제거돼요.
-
reject: 이름에 문자, 숫자, 대시가 아닌 문자가 포함된 헤더를 가진 요청은 400 Bad Request 응답으로 거부돼요.
기본값은 keep라서 기존 동작은 보존돼요.
파일 (YAML)
entryPoints:
websecure:
address: ':443'
http:
aliasHeadersStrategy: delete
파일 (TOML)
[entryPoints.websecure]
address = ":443"
[entryPoints.websecure.http]
aliasHeadersStrategy = "delete"
CLI
--entryPoints.websecure.address=:443
--entryPoints.websecure.http.aliasHeadersStrategy=delete
underscoreHeadersStrategy를 설정하면 폐기 경고가 기록돼요.
두 옵션을 서로 다른 값으로 구성하면 설치 설정이 유효하지 않게 돼요.
Traefik은 이제 이 옵션 없이 남겨진 모든 엔트리포인트에 대해 시작 시 경고를 기록해요. 요청 헤더를 관리하는 미들웨어가 별칭 이름으로 스푸핑되지 않도록 이 옵션에 의존하거든요.
자세한 내용은 엔트리포인트 aliasHeadersStrategy 옵션과 별칭 이름을 가진 헤더(Headers with Aliasing Names) 문서를 참고하세요.
TCP 및 UDP 가중 서비스: 음수 가중치 (Negative Weights)
TCP 또는 UDP 가중 서비스의 음수 가중치는 이제 서비스가 만들어질 때 거부돼요. 이전에는 그런 설정이 로드 밸런서가 잠금(lock)을 쥔 채 선택 루프를 무한히 돌게 해서, CPU 코어 하나를 소모하고 Traefik이 재시작될 때까지 그 서비스로의 모든 후속 연결을 막았어요.
음수 가중치를 선언하는 가중 서비스는 이제 API에서 오류와 함께 disabled로 보고되고, 이를 참조하는 라우터는 만들어지지 않아요.
음수 가중치는 양수로, 또는 자식 서비스를 로테이션에서 빼려면 0으로 바꾸세요.
TCP 및 UDP 가중 서비스: 자식 서비스 오류 (Child Service Errors)
TCP 또는 UDP 가중 서비스의 자식이 예를 들어 존재하지 않아 만들어질 수 없을 때,
부모 가중 서비스는 이제 HTTP 가중 서비스가 그랬던 것처럼 API에서 오류와 함께 disabled로 보고돼요.
이전에는 그런 부모 서비스가 오류도 상태도 보고하지 않았어요.
이는 보고되는 내용만 바뀌는 거예요. 부모 서비스를 참조하는 라우터는 이미 만들어지지 않았었죠.
v3.7.11
안전한 이름 설정 옵션 (Safe naming configuration option)
v3.7.11부터 새로운 safeNaming 프로바이더 옵션은 Kubernetes CRD 프로바이더가 생성하는 라우터, 미들웨어, 서비스에 대해 충돌 안전(collision-safe) 이름을 활성화해요. 네임스페이스나 리소스 간에 이름이 충돌할 수 있는 현재 이름 체계 대신에요.
생성된 이름은 평탄화·정규화되는 대신 그 객체의 정체성에서 파생되고, 라우트를 위해 생성된 이름은 규칙 대신 라우트 인덱스에서 파생돼요. 예를 들어 default 네임스페이스에 whoami라는 Kubernetes Service와 test.route라는 IngressRoute가 있을 때:
default-whoami-80 -> default_whoami_80
default-test-route-6b204d94623b3df4370c -> default_test.route_0
이 옵션은 기본적으로 비활성화되어 있어서 기존 동작을 보존해요.
관찰성 (Observability)
이 이름들은 사용자에게 보여요. 대시보드와 API, 액세스 로그의 RouterName·ServiceName 필드, 메트릭의 router·service 라벨에 나타나죠.
safeNaming을 활성화하면 Kubernetes CRD 라우터·미들웨어·서비스 이름에 매칭되는 대시보드, 알림 규칙, 로그 쿼리도 그에 맞게 업데이트해야 해요.
자세한 내용은 safeNaming 프로바이더 문서를 참고하세요.
충돌하는 TLS 옵션 (Conflicting TLS options)
TLS 옵션은 라우터에 설정되지만, 라우팅이 일어나기 전인 TLS 핸드셰이크 중에 적용되므로 라우터가 아닌 라우터 규칙에서 찾은 호스트 이름에 매핑돼요. 같은 엔트리포인트의 여러 라우터가 서로 다른 TLS 옵션으로 같은 호스트 이름을 처리할 때,
Traefik은 어떤 옵션을 적용할지 결정할 수 없고, 그 호스트 이름에 대해 default TLS 옵션으로 대체(fallback)돼요.
default TLS 옵션이 충돌 해결의 대체(fallback)이므로, 그것이 대체할 수 있는 옵션보다 덜 안전해서는 안 돼요. 예를 들어 상호 TLS 인증(clientAuth)에 의존하는 라우터는, 호스트 이름에 충돌이 있어서 그것을 요구하지 않는 default TLS 옵션으로 대체되면 더 이상 그것을 강제하지 않아요.
자세한 내용은 GHSA-g55h-rg46-x9c5를 참고하세요.
v3.7.11부터 새로운 core.strictTLSOptions 설치 설정 옵션이 이 대체를 비활성화해요. 충돌에 연루된 라우터는 오류로 표시되고 전혀 만들어지지 않아요.
이 옵션은 기존 동작을 보존하려고 기본적으로 비활성화되어 있지만, 활성화하는 것을 권장해요:
파일 (YAML)
## Install configuration
core:
strictTLSOptions: true
파일 (TOML)
## Install configuration
[core]
strictTLSOptions = true
CLI
## Install configuration
--core.strictTLSOptions=true
비활성화된 라우터 (Disabled routers)
이 옵션은 fail-closed로 동작해요. 충돌이 해당 엔트리포인트에서 충돌하는 호스트 이름을 처리하는 모든 라우터를, 충돌이 해결될 때까지 비활성화해요.
자세한 내용은 충돌하는 TLS 옵션(Conflicting TLS Options) 문서를 참고하세요.
Kubernetes CRD: 클러스터 전체 기본 TLSOption과 TLSStore
Kubernetes CRD 프로바이더에서 default라는 이름의 TLSOption과 TLSStore는 정의된 네임스페이스와 관계없이 클러스터 전체로 적용돼요. 따라서 단일 네임스페이스에서 하나를 만들 수 있는 사람은 누구나, TLS 옵션을 명시적으로 참조하지 않는 라우터의 TLS 정책(상호 TLS 인증 포함)을 교체할 수 있어요.
v3.7.11부터 새로운 defaultTLSResourcesNamespace 프로바이더 옵션이 이 리소스들을 클러스터 운영자가 제어하는 네임스페이스로 한정해요.
이 옵션은 기존 동작을 보존하려고 기본적으로 비어 있지만, 설정하는 것을 권장해요:
파일 (YAML)
## Install configuration
providers:
kubernetesCRD:
defaultTLSResourcesNamespace: traefik
파일 (TOML)
## Install configuration
[providers.kubernetesCRD]
defaultTLSResourcesNamespace = "traefik"
CLI
## Install configuration
--providers.kubernetescrd.defaultTLSResourcesNamespace=traefik
무시되는 리소스 (Ignored resources)
설정된 네임스페이스 밖에 정의된 default 리소스는 무시되고, 네임스페이스가 붙은 이름으로도 참조할 수 없어요. TLSStore의 경우, 이것이 정의하는 인증서에도 적용돼요.
자세한 내용은 Kubernetes CRD 프로바이더 문서를 참고하세요.
v3.7.10
Kubernetes Gateway API 프로바이더: 생성된 라우터·미들웨어·서비스 이름
v3.7.10부터 Kubernetes Gateway API 프로바이더는 생성하는 라우터 이름의 해시 접미사를 라우트 규칙 하나가 아니라 모든 라우트·Gateway·리스너 식별 필드에서 파생해요.
이는 네임스페이스·이름·Gateway·리스너가 우연히 같은 문자열로 연결되는 서로 다른 라우트들이 단일 생성된 라우터 이름에서 충돌하는 것을 막기 위해 필요한 거예요.
생성된 라우터 이름은 같은 전체 모양을 유지해요:
<route kind>-<route namespace>-<route name>-gw-<gateway namespace>-<gateway name>-ep-<entry point>-<rule index>-<hash>
하지만 `` 접미사는 더 이상 라우트 규칙 하나에서만 계산되지 않으므로 바뀌어요.
예를 들어 default 네임스페이스의 http-app-1이라는 HTTPRoute는 이전에 httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-af329269dd38031b03e3 라우터를 생성했는데, 이제는 httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93로 생성돼요.
미들웨어 이름은 라우터 이름에서 파생되므로 그에 맞게 바뀌어요. 예를 들어 -requestheadermodifier-0처럼요.
생성된 서비스 이름은 이전에는 백엔드 참조만으로 만들어졌어요:
<backend namespace>-<backend name>-```
이제는 생성된 대상 라우트 규칙이 접두사로 붙어요:
<route kind>-<route namespace>-<route name>-gw-<gateway namespace>-<gateway name>-ep-<entry point>-<rule index>-<hash>-svc-<backend namespace>-<backend name>-<backend index>
예를 들어 default 네임스페이스의 whoami 백엔드는 이전에 default-whoami-http-80@kubernetesgateway로 노출됐는데, 이제는 httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-svc-default-whoami-0@kubernetesgateway로 노출돼요.
| 경고 (Warning) | 관찰성 (Observability)
이 이름들은 사용자에게 보여요. 대시보드와 API, 액세스 로그의 RouterName·ServiceName 필드, 메트릭의 router·service 라벨에 나타나죠.
Gateway API 라우터·미들웨어·서비스 이름에 매칭되는 대시보드, 알림 규칙, 로그 쿼리는 그에 맞게 업데이트해야 해요.
Kubernetes Gateway API 프로바이더
v3.7.10부터 Kubernetes Gateway API 프로바이더는 사양 v1.6.1을 지원해요.
TCPRoute는 Gateway API v1.6.0에서 Standard 채널로 승격됐고, 새로운 v1 버전을 가져요.
Traefik v3.7은 여전히 v1alpha2 버전으로 TCPRoute를 감시하는데,
Standard 채널 CRD는 더 이상 그 버전을 제공하지 않아요.
TCPRoute를 사용하면서 Gateway API v1.6.1 CRD로 업그레이드한다면,
실험 채널(experimental channel) CRD를 설치해야 해요.
Traefik에서 TCPRoute 지원을 활성화하려면 experimentalChannel 옵션이 여전히 필요해요.
| 경고 (Warning) | experimentalChannel이 활성화된 Standard 채널 CRD
Traefik은 TCPRoute의 v1alpha2 버전을 감시할 수 없고, Kubernetes Gateway 프로바이더는 시작을 끝내지 못해요. 어떤 Gateway API 리소스도 제공되지 않아요. TCPRoute뿐만 아니라요.
오류는 기록되지 않고, Traefik은 계속 실행되며, 다른 프로바이더는 영향을 받지 않아요.
Traefik v3.7은 v1.5.x CRD와 계속 하위 호환돼요. 클러스터의 CRD 업그레이드는 v1.6.1 리소스에 의존할 때만 필요해요.
| 참고 (Note) | v3.8에서 예정 (Upcoming in v3.8)
Traefik v3.8은 Gateway API CRD를 v1.6.x로 업데이트해야 하며, 그 대가로 TCPRoute에 experimentalChannel 옵션이 더 이상 필요 없게 돼요.
(선택 사항) v1.6.1 CRD 적용:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.1/standard-install.yaml
실험 채널(TCPRoute에 필요)의 경우:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.1/experimental-install.yaml
v3.7.9
HTTP/1 CONNECT 요청
v3.7.9부터 HTTP/1 CONNECT 요청은 501 Not Implemented 응답으로 거부돼요.
HTTP/1 CONNECT 요청은 이 변경 전에는 기능하지 않았으므로, 이 거부는 그것을 명확히 해 줘요.
v3.7.8
Kubernetes CRD: Errors 미들웨어 errorRequestHeaders
Errors 미들웨어용으로 v3.6.15에서 도입된 errorRequestHeaders 옵션은 Kubernetes CRD 프로바이더에 노출되지 않았어요.
v3.7.8부터 Middleware CRD에서 설정할 수 있어요.
이 새 옵션을 사용하려면 Traefik을 업그레이드하기 전에 Kubernetes CRD를 클러스터에서 업데이트해야 해요. 그러려면 v3.7용 CRD 매니페스트를 적용하세요:
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.7/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
자세한 내용은 Error Pages 미들웨어 문서를 참고하세요.
v3.7.7
와일드카드 Host 매처 (Wildcard Host matcher)
v3.7.7부터 Host 매처는 TCP HostSNI() 매처와 일관되게, 단순한 *를 catch-all로 취급해요.
Host()는 이제 호스트와 관계없이 모든 요청을, 호스트가 전혀 없는 요청까지도 일치시켜요.
이전에는 *가 단일 와일드카드 라벨로 취급됐으므로, Host(*)는 단일 세그먼트(예: localhost)로 이루어진 호스트만 일치시키고 다중 세그먼트 호스트(예: example.com)는 일치시키지 않았어요.
자세한 내용은 HTTP 라우팅 규칙 문서를 참고하세요.
v3.7.6
Kubernetes Gateway API 프로바이더: 생성된 서비스·미들웨어 이름
v3.7.6부터 Kubernetes Gateway API 프로바이더는 생성하는 서비스·미들웨어의 이름을 백엔드 참조 하나에서가 아니라 그들이 속한 라우트 규칙에서 파생해요.
이는 같은 백엔드를 참조하는 서로 다른 라우트 규칙들이 단일 생성된 설정에서 충돌하는 것을 막기 위해 필요해요.
생성된 서비스 이름은 이전에는 백엔드 참조만으로 만들어졌어요:
<backend namespace>-<backend name>-<port>
이제는 생성된 대상 라우트 규칙이 접두사로 붙어요:
<route kind>-<route namespace>-<route name>-gw-<gateway namespace>-<gateway name>-ep-<entry point>-<rule index>-<rule hash>-svc-<backend namespace>-<backend name>-<backend index>
예를 들어 default 네임스페이스의 whoami 백엔드는 이전에 default-whoami-http-80@kubernetesgateway로 노출됐는데, 이제는 httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-af329269dd38031b03e3-svc-default-whoami-0@kubernetesgateway로 노출돼요.
관찰성 (Observability)
이 이름들은 사용자에게 보여요. 대시보드와 API, 액세스 로그의 ServiceName 필드, 메트릭의 service 라벨에 나타나죠.
Gateway API 서비스 이름에 매칭되는 대시보드, 알림 규칙, 로그 쿼리는 그에 맞게 업데이트해야 해요.
UnderscoreHeadersStrategy
v3.7.12부터 폐기됨 (Deprecated since v3.7.12)
언더스코어만이 아니라 모든 별칭 문자를 처리하는 aliasHeadersStrategy 옵션을 대신 사용하세요.
v3.6.20부터 새로운 underscoreHeadersStrategy 엔트리포인트 옵션은 이름에 언더스코어가 있는 요청 헤더를 라우팅 전에 어떻게 처리할지 정의해요:
-
keep (기본값): 언더스코어가 있는 요청 헤더는 그대로 전달돼요.
-
delete: 이름에 언더스코어 문자가 포함된 요청 헤더는 요청에서 조용히 제거돼요.
-
reject: 이름에 언더스코어 문자가 포함된 헤더를 가진 요청은 400 Bad Request 응답으로 거부돼요.
기본값은 keep라서 기존 동작은 보존돼요.
이 옵션이 존재하는 이유는 언더스코어가 HTTP 헤더 이름에서 유효한 문자인데, Go는 대시에서만 헤더 이름을 정규화하기 때문이에요.
그 결과, 대시 형태(예: ForwardAuth authResponseHeaders 옵션이 설정한 X-Auth-User)로 헤더를 관리하는 미들웨어는 그 헤더의 언더스코어 변형(예: X_Auth_User)을 보지 못해서, 덮어쓰거나 제거할 수 없어요.
많은 백엔드가 두 형태를 같은 변수로 매핑해요(CGI, WSGI, PHP, NGINX, ...). 그들에게는 X-Auth-User와 X_Auth_User가 같은 헤더예요. 그런 백엔드를 상대로 클라이언트는 대시 형태만 관리하는 미들웨어를 언더스코어 변형으로 우회(smuggle)해서, 백엔드가 스푸핑된 값을 읽게 할 수 있어요. 미들웨어가 제공하려던 보호가 우회되는 거예요.
보안 (Security)
엔트리포인트가 헤더 이름의 언더스코어와 대시를 똑같이 해석하는 백엔드를 마주할 때,
기본 keep 전략을 유지하는 것은 권장되지 않아요. 위에서 설명한 헤더 스푸핑에 백엔드가 노출되거든요.
그런 엔트리포인트에서는 underscoreHeadersStrategy를 delete나 reject로 설정하세요.
v3.7.3
Kubernetes Gateway API 프로바이더
v3.7.3부터 Kubernetes Gateway API 프로바이더가 사용하는 Kubernetes 클라이언트의 QPS와 Burst 값이 각각 50과 100으로 증가했어요 (Kubernetes 클라이언트 기본값의 10배).
Kubernetes Gateway API 프로바이더는 Kubernetes Gateway API 사양을 준수하기 위해 상태 업데이트를 집중적으로 기록해요. 이 변경은 Kubernetes API 속도 제한과 관련된 성능 문제를 피하는 데 도움이 돼요. 새 라우팅 설정을 만들 때 설정 시간이 늘어날 수 있거든요.
이 값들은 kubernetesGateway.qps와 kubernetesGateway.burst 프로바이더 옵션으로 설정할 수 있어요.
BasicAuth 미들웨어
v3.7.3부터 BasicAuth 미들웨어는 성공적으로 만들어지려면 비어 있지 않은 users 설정이 필요해요.
이전에는 미들웨어가 성공적으로 만들어졌지만 모든 요청에 항상 401 상태 코드를 반환했어요.
이제는 오류가 발생하고, 그것을 사용하는 라우터는 마운트 해제돼요. 같은 요청에 대해 401 대신 404 상태 코드가 제공돼요.
StripPrefix 및 StripPrefixRegex 미들웨어
v3.7.3부터 StripPrefix 미들웨어와 StripPrefixRegex 미들웨어는 설정된 접두사를 제거한 경로가 그 정규화된(normalised) 형태와 달라지면(즉 정규화로 축소되는 .나 .. 세그먼트를 포함하는 경로) 요청을 거부해요(400 Bad Request).
이는 잘린 경로가 업스트림 서비스에 의해 다른 리소스로 해석되는 것을 막아요.
/api 접두사가 설정된 예시:
| 요청 경로 (Request path) | 제거 후 경로 (Path after strip) | 정규화된 경로 (Normalised path) | 결과 (Result) |
| /api/foo | /foo | /foo | 200 (전송됨) |
| /api/ | / | / | 200 (전송됨) |
| /api./foo | /./foo | /foo | 400 |
| /api../foo | /../foo | /foo | 400 |
v3.7.1
Kubernetes 프로바이더: crossProviderNamespaces
v3.7.1에서 Kubernetes CRD, Ingress, Gateway 프로바이더에 새로운 crossProviderNamespaces 옵션이 제공돼요.
Traefik은 한 프로바이더의 리소스를 다른 프로바이더로 참조하는(크로스 프로바이더 참조) 가능성을 제공해요.
하지만 Kubernetes 프로바이더 맥락에서,
그런 참조(예: myservice@kubernetescrd)는 사용자가 네임스페이스 경계를 넘을 수 있게 하면서,
운영자만 노출할 수 있어야 하는 @internal 서비스도 노출하게 해요.
이 새로운 crossProviderNamespaces 옵션은 Kubernetes 리소스가 크로스 프로바이더 참조를 사용할 수 있는 네임스페이스를 제한해요.
동작은 다음과 같아요:
| 값 (Value) | 동작 (Behavior) |
| 설정 안 함 (not set) | 모든 Kubernetes 리소스가 크로스 프로바이더 참조를 선언할 수 있어요. |
| [] | 크로스 프로바이더 참조를 선언하는 모든 Kubernetes 리소스가 거부돼요. |
| ["ns-a"] | 나열된 네임스페이스의 Kubernetes 리소스만 크로스 프로바이더 참조를 선언할 수 있어요. |
자세한 내용은 Kubernetes CRD, Kubernetes Ingress, Kubernetes Gateway 프로바이더 문서를 참고하세요.
v3.7.0
Ingress NGINX 프로바이더
v3.7.0부터 Ingress NGINX 프로바이더는 nginx.ingress.kubernetes.io/custom-headers 애노테이션을 지원해서 클라이언트로 전달되는 응답에 커스텀 헤더를 추가할 수 있어요.
따라서 해당 RBAC(KubernetesIngressNGINX 프로바이더 RBAC 참고)에 configmaps 권한이 추가됐어요.
필수 RBAC 업데이트 (Required RBAC Updates):
...
- apiGroups:
- ""
resources:
- configmaps
verbs:
- list
- watch
...
Kubernetes Gateway API 프로바이더
v3.7.0부터 Kubernetes Gateway API 프로바이더는 사양 v1.5.1을 지원하는데,
이를 위해 Gateway API CRD를 업데이트해야 해요.
TLSRoute는 Standard 채널로 승격되어 더 이상 experimentalChannel 옵션을 요구하지 않아요.
experimentalChannel 옵션은 이제 TCPRoute에만 필요해요.
업데이트된 CRD 적용 (Apply Updated CRDs):
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml
실험 채널의 경우:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/experimental-install.yaml
Kubernetes CRD 프로바이더
Kubernetes CRD 프로바이더에서 retry 미들웨어의 새 옵션이나 새 ingressClassName 필드를 사용하려면 CRD를 업데이트해야 해요.
업데이트된 CRD 적용 (Apply Updated CRDs):
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.7/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
와일드카드 Host 및 HostSNI
v3.7.0부터 Host와 HostSNI 매처는 와일드카드 서브도메인 매칭(예: *.example.com)을 지원해요.
이는 단일 레벨 와일드카드 접두사로 도메인의 직접 서브도메인을 매칭하게 해 줘요.
예를 들어 *.example.com은 foo.example.com과 일치하지만 foo.bar.example.com이나 example.com 자체와는 일치하지 않아요.
이 기능은 v3 규칙 구문(기본값)에서만 사용할 수 있어요.
와일드카드 도메인을 가진 TLSOptions
v3.7.0부터 TLSOptions를 와일드카드 Host·HostSNI 매처(예: Host(*.example.com))를 가진 라우터와 연결할 수 있어요.
이로써 와일드카드 도메인에 서로 다른 TLS 옵션을 설정할 수 있어요.
이전에는 TLSOptions 선택이 정확한 Host 일치로 제한됐고, HostRegexp나 와일드카드를 사용하면 No domain found in rule HostRegexp(...) the TLS option foo cannot be applied 같은 경고 메시지와 함께 기본 TLS 옵션으로 대체됐어요.
참고: HostRegexp 매처에 대한 TLSOptions는 여전히 지원되지 않아요. 대신 와일드카드 Host 매처를 사용하세요.
v3.6.25
Kubernetes Gateway API 프로바이더: 생성된 라우터·미들웨어·서비스 이름
v3.6.25부터 Kubernetes Gateway API 프로바이더는 생성하는 라우터 이름의 해시 접미사를 라우트 규칙 하나가 아니라 모든 라우트·Gateway·리스너 식별 필드에서 파생해요.
이는 네임스페이스·이름·Gateway·리스너가 우연히 같은 문자열로 연결되는 서로 다른 라우트들이 단일 생성된 라우터 이름에서 충돌하는 것을 막기 위해 필요한 거예요.
생성된 라우터 이름은 같은 전체 모양을 유지해요:
<route kind>-<route namespace>-<route name>-gw-<gateway namespace>-<gateway name>-ep-<entry point>-<rule index>-<hash>
하지만 `` 접미사는 더 이상 라우트 규칙 하나에서만 계산되지 않으므로 바뀌어요.
예를 들어 default 네임스페이스의 http-app-1이라는 HTTPRoute는 이전에 httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-af329269dd38031b03e3 라우터를 생성했는데, 이제는 httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93로 생성돼요.
미들웨어 이름은 라우터 이름에서 파생되므로 그에 맞게 바뀌어요. 예를 들어 -requestheadermodifier-0처럼요.
생성된 서비스 이름은 이전에는 백엔드 참조만으로 만들어졌어요:
<backend namespace>-<backend name>-<port>
이제는 생성된 대상 라우트 규칙이 접두사로 붙어요:
<route kind>-<route namespace>-<route name>-gw-<gateway namespace>-<gateway name>-ep-<entry point>-<rule index>-<hash>-svc-<backend namespace>-<backend name>-<backend index>
예를 들어 default 네임스페이스의 whoami 백엔드는 이전에 default-whoami-http-80@kubernetesgateway로 노출됐는데, 이제는 httproute-default-http-app-1-gw-default-my-gateway-ep-web-0-799bcbf0c2317c5d1c93-svc-default-whoami-0@kubernetesgateway로 노출돼요.
| 경고 (Warning) | 관찰성 (Observability)
이 이름들은 사용자에게 보여요. 대시보드와 API, 액세스 로그의 RouterName·ServiceName 필드, 메트릭의 router·service 라벨에 나타나죠.
Gateway API 라우터·미들웨어·서비스 이름에 매칭되는 대시보드, 알림 규칙, 로그 쿼리는 그에 맞게 업데이트해야 해요.
v3.6.24
Kubernetes CRD: Errors 미들웨어 errorRequestHeaders
Errors 미들웨어용으로 v3.6.15에서 도입된 errorRequestHeaders 옵션은 Kubernetes CRD 프로바이더에 노출되지 않았어요.
v3.6.24부터 Middleware CRD에서 설정할 수 있어요.
이 새 옵션을 사용하려면 Traefik을 업그레이드하기 전에 Kubernetes CRD를 클러스터에서 업데이트해야 해요. 그러려면 v3.6용 CRD 매니페스트를 적용하세요:
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.6/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
자세한 내용은 Error Pages 미들웨어 문서를 참고하세요.
HTTP/1 CONNECT 요청
v3.6.24부터 HTTP/1 CONNECT 요청은 501 Not Implemented 응답으로 거부돼요.
HTTP/1 CONNECT 요청은 이 변경 전에는 기능하지 않았으므로, 이 거부는 그것을 명확히 해 줘요.
v3.6.22
UnderscoreHeadersStrategy
| 경고 (Warning) |
v3.7.12부터 폐기됨 (Deprecated since v3.7.12)
언더스코어만이 아니라 모든 별칭 문자를 처리하는 aliasHeadersStrategy 옵션을 대신 사용하세요.
v3.6.22부터 새로운 underscoreHeadersStrategy 엔트리포인트 옵션은 이름에 언더스코어가 있는 요청 헤더를 라우팅 전에 어떻게 처리할지 정의해요:
-
keep (기본값): 언더스코어가 있는 요청 헤더는 그대로 전달돼요.
-
delete: 이름에 언더스코어 문자가 포함된 요청 헤더는 요청에서 조용히 제거돼요.
-
reject: 이름에 언더스코어 문자가 포함된 헤더를 가진 요청은 400 Bad Request 응답으로 거부돼요.
기본값은 keep라서 기존 동작은 보존돼요.
이 옵션이 존재하는 이유는 언더스코어가 HTTP 헤더 이름에서 유효한 문자인데, Go는 대시에서만 헤더 이름을 정규화하기 때문이에요.
그 결과, 대시 형태(예: ForwardAuth authResponseHeaders 옵션이 설정한 X-Auth-User)로 헤더를 관리하는 미들웨어는 그 헤더의 언더스코어 변형(예: X_Auth_User)을 보지 못해서, 덮어쓰거나 제거할 수 없어요.
많은 백엔드가 두 형태를 같은 변수로 매핑해요(CGI, WSGI, PHP, NGINX, ...). 그들에게는 X-Auth-User와 X_Auth_User가 같은 헤더예요. 그런 백엔드를 상대로 클라이언트는 대시 형태만 관리하는 미들웨어를 언더스코어 변형으로 우회(smuggle)해서, 백엔드가 스푸핑된 값을 읽게 할 수 있어요. 미들웨어가 제공하려던 보호가 우회되는 거예요.
| 경고 (Warning) | 보안 (Security)
엔트리포인트가 헤더 이름의 언더스코어와 대시를 똑같이 해석하는 백엔드를 마주할 때,
기본 keep 전략을 유지하는 것은 권장되지 않아요. 위에서 설명한 헤더 스푸핑에 백엔드가 노출되거든요.
그런 엔트리포인트에서는 underscoreHeadersStrategy를 delete나 reject로 설정하세요.
v3.6.19
Kubernetes Gateway API 프로바이더
v3.6.19부터 Kubernetes Gateway API 프로바이더가 사용하는 Kubernetes 클라이언트의 QPS와 Burst 값이 각각 50과 100으로 증가했어요 (Kubernetes 클라이언트 기본값의 10배).
Kubernetes Gateway API 프로바이더는 Kubernetes Gateway API 사양을 준수하기 위해 상태 업데이트를 집중적으로 기록해요. 이 변경은 Kubernetes API 속도 제한과 관련된 성능 문제를 피하는 데 도움이 돼요. 새 라우팅 설정을 만들 때 설정 시간이 늘어날 수 있거든요.
이 값들은 kubernetesGateway.qps와 kubernetesGateway.burst 프로바이더 옵션으로 설정할 수 있어요.
BasicAuth 미들웨어
v3.6.19부터 BasicAuth 미들웨어는 성공적으로 만들어지려면 비어 있지 않은 users 설정이 필요해요.
이전에는 미들웨어가 성공적으로 만들어졌지만 모든 요청에 항상 401 상태 코드를 반환했어요.
이제는 오류가 발생하고, 그것을 사용하는 라우터는 마운트 해제돼요. 같은 요청에 대해 401 대신 404 상태 코드가 제공돼요.
StripPrefix 및 StripPrefixRegex 미들웨어
v3.6.19부터 StripPrefix 미들웨어와 StripPrefixRegex 미들웨어는 설정된 접두사를 제거한 경로가 그 정규화된(normalised) 형태와 달라지면(즉 정규화로 축소되는 .나 .. 세그먼트를 포함하는 경로) 요청을 거부해요(400 Bad Request).
이는 잘린 경로가 업스트림 서비스에 의해 다른 리소스로 해석되는 것을 막아요.
/api 접두사가 설정된 예시:
| 요청 경로 (Request path) | 제거 후 경로 (Path after strip) | 정규화된 경로 (Normalised path) | 결과 (Result) |
| /api/foo | /foo | /foo | 200 (전송됨) |
| /api/ | / | / | 200 (전송됨) |
| /api./foo | /./foo | /foo | 400 |
| /api../foo | /../foo | /foo | 400 |
v3.6.17
Kubernetes 프로바이더: crossProviderNamespaces
v3.6.17에서 Kubernetes CRD, Ingress, Gateway 프로바이더에 새로운 crossProviderNamespaces 옵션이 제공돼요.
Traefik은 한 프로바이더의 리소스를 다른 프로바이더로 참조하는(크로스 프로바이더 참조) 가능성을 제공해요.
하지만 Kubernetes 프로바이더 맥락에서,
그런 참조(예: myservice@kubernetescrd)는 사용자가 네임스페이스 경계를 넘을 수 있게 하면서,
운영자만 노출할 수 있어야 하는 @internal 서비스도 노출하게 해요.
이 새로운 crossProviderNamespaces 옵션은 Kubernetes 리소스가 크로스 프로바이더 참조를 사용할 수 있는 네임스페이스를 제한해요.
동작은 다음과 같아요:
| 값 (Value) | 동작 (Behavior) |
| 설정 안 함 (not set) | 모든 Kubernetes 리소스가 크로스 프로바이더 참조를 선언할 수 있어요. |
| [] | 크로스 프로바이더 참조를 선언하는 모든 Kubernetes 리소스가 거부돼요. |
| ["ns-a"] | 나열된 네임스페이스의 Kubernetes 리소스만 크로스 프로바이더 참조를 선언할 수 있어요. |
자세한 내용은 Kubernetes CRD, Kubernetes Ingress, Kubernetes Gateway 프로바이더 문서를 참고하세요.
v3.6.16
Docker 프로바이더: 최소 Docker Engine 버전
v3.6.16부터 Docker 프로바이더는 Docker API 버전 v1.40 이상(Docker Engine v19.03)을 요구해요.
더 오래된(수명이 끝난) Docker Engine 버전을 사용하는 사용자는 Docker Engine을 업데이트하거나,
DOCKER_API_VERSION 환경 변수로 Traefik이 사용하는 API 버전을 덮어써야 해요.
v3.6.15
v3.6.15에서 Errors 미들웨어에 새로운 errorRequestHeaders 옵션이 추가됐어요.
기본적으로 동작은 변하지 않아요. 모든 원본 요청 헤더가 오류 페이지 서비스로 전달돼요.
오류 페이지 서비스가 별도의 신뢰 도메인에 있다면, errorRequestHeaders를 사용해 전달되는 헤더를 제한하는 것을 고려하세요.
자세한 내용은 Error Pages 미들웨어 문서를 참고하세요.
v3.6.14
Kubernetes CRD: Chain 미들웨어와 allowCrossNamespace
v3.6.14에서 Chain 미들웨어는 이제 Kubernetes CRD 프로바이더의 allowCrossNamespace 옵션을 존중해요.
이전에는 Chain이 allowCrossNamespace 설정과 관계없이 다른 네임스페이스의 미들웨어를 참조할 수 있었어요.
allowCrossNamespace가 false(기본값)로 설정되어 있고 Chain 미들웨어가 자기와 다른 네임스페이스의 미들웨어를 참조하면,
이제 전체 Chain이 거부되고 오류가 기록돼요.
ForwardAuth 미들웨어: trustForwardHeader
v3.6.14부터 trustForwardHeader 옵션은 폐기되었고 다음 주요 버전에서 제거될 거예요.
forwardedHeaders.trustedIPs 옵션으로 엔트리포인트 레벨에서 신뢰된 IP를 설정하고,
이 미들웨어에서는 trustForwardHeader를 true로 설정하세요.
trustForwardHeader가 명시적으로 설정되지 않으면 Traefik은 경고를 기록해요. 그 동작이 일관되지 않기 때문이에요. 일부 X-Forwarded-* 헤더(예: X-Forwarded-For, X-Forwarded-Proto)는 제거되는 반면 다른 것(예: X-Forwarded-Prefix)은 그대로 전달돼요.
경고를 없애고 보안 우려를 피하려면 ForwardAuth 미들웨어 설정에서 trustForwardHeader를 true나 false로 명시적으로 설정하세요.
자세한 내용은 ForwardAuth 미들웨어 문서를 참고하세요.
v3.6.9
ForwardAuth 미들웨어의 maxResponseBodySize 설정
v3.6.9에서 ForwardAuth 미들웨어 설정에 새로운 maxResponseBodySize 옵션이 추가됐어요.
이 옵션의 기본값은 -1로, 응답 본문 크기에 제한이 없다는 뜻이에요.
하지만 DoS 공격과 메모리 고갈 같은 성능·보안 문제를 피하려면 이 옵션을 적절한 값으로 설정하는 것을 강력히 권장해요.
자세한 내용은 ForwardAuth 미들웨어 문서를 참고하세요.
Kubernetes CRD 프로바이더
Kubernetes CRD 프로바이더에서 ForwardAuth 미들웨어의 새 maxResponseBodySize 옵션을 사용하려면 CRD를 업데이트해야 해요.
업데이트된 CRD 적용 (Apply Updated CRDs):
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.6/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
v3.6.8
헬스 체크 요청 경로 (Health Check Request Path)
v3.6.8부터 헬스 체크 요청에 설정된 경로는 상대 URL인지 검증되며, 그렇지 않으면 헬스 체크가 실패해요.
v3.6.7
인코딩된 문자 설정 기본값 (Encoded Characters Configuration Default Values)
v3.6.7부터 인코딩된 문자 옵션들은 true 기본값을 가져요.
즉 Traefik은 기본적으로 특정 인코딩된 문자 집합이 포함된 경로의 요청을 거부하지 않아요.
이제 인코딩된 문자의 보안 강화(security hardening)를 구성하는 것은 사용자의 몫이에요.
다음은 false로 설정해 허용하지 않을 수 있는 인코딩된 문자 목록이에요:
| 인코딩된 문자 (Encoded Character) | 문자 (Character) | 설정 옵션 (Config options) | 기본값 (Default value) |
| %2f 또는 %2F | / (슬래시) | entryPoints. .http.encodedCharacters .allowEncodedSlash | true |
| %5c 또는 %5C | \ (백슬래시) | entryPoints. .http.encodedCharacters .allowEncodedBackSlash | true |
| %00 | NULL (널 문자) | entryPoints. .http.encodedCharacters .allowEncodedNullCharacter | true |
| %3b 또는 %3B | ; (세미콜론) | entryPoints. .http.encodedCharacters .allowEncodedSemicolon | true |
| %25 | % (퍼센트) | entryPoints. .http.encodedCharacters .allowEncodedPercent | true |
| %3f 또는 %3F | ? (물음표) | entryPoints. .http.encodedCharacters .allowEncodedQuestionMark | true |
| %23 | # (해시) | entryPoints. .http.encodedCharacters .allowEncodedHash | true |
참고: 이 검사는 쿼리 파라미터에 대해서는 하지 않고, RFC3986 section-3에 정의된 요청 경로에 대해서만 해요.
자세한 내용은 엔트리포인트 encodedCharacters 옵션 문서를 참고하세요.
v3.6.4
요청 경로의 인코딩된 문자 (Encoded Characters in Request Path)
v3.6.4부터 보안상의 이유로 Traefik은 기본적으로 특정 인코딩된 문자 집합이 포함된 경로의 요청을 거부해요.
그런 요청이 오면 Traefik은 400 Bad Request 상태 코드로 응답해요.
다음은 기본적으로 거부되는 인코딩된 문자 목록과, 그것을 허용하기 위한 해당 설정 옵션이에요:
| 인코딩된 문자 (Encoded Character) | 문자 (Character) | 인코딩된 문자를 허용할 설정 옵션 (Config option to allow the encoded character) |
| %2f 또는 %2F | / (슬래시) | entryPoints. .http.encodedCharacters .allowEncodedSlash |
| %5c 또는 %5C | \ (백슬래시) | entryPoints. .http.encodedCharacters .allowEncodedBackSlash |
| %00 | NULL (널 문자) | entryPoints. .http.encodedCharacters .allowEncodedNullCharacter |
| %3b 또는 %3B | ; (세미콜론) | entryPoints. .http.encodedCharacters .allowEncodedSemicolon |
| %25 | % (퍼센트) | entryPoints. .http.encodedCharacters .allowEncodedPercent |
| %3f 또는 %3F | ? (물음표) | entryPoints. .http.encodedCharacters .allowEncodedQuestionMark |
| %23 | # (해시) | entryPoints. .http.encodedCharacters .allowEncodedHash |
자세한 내용은 엔트리포인트 encodedCharacters 옵션 문서를 참고하세요.
v3.6.2
Ingress NGINX 프로바이더
KubernetesIngressNGINX 프로바이더는 v3.6.2에서 더 이상 실험적이지 않으며, experimental.kubernetesIngressNGINX 옵션 없이 활성화할 수 있어요.
폐기된 설정 (Deprecated Configuration):
Experimental kubernetesIngressNGINX option (deprecated)
마이그레이션 단계 (Migration Steps):
-
experimental 섹션에서 kubernetesIngressNGINX 옵션을 제거하세요
-
kubernetesIngressNGINX 프로바이더 문서를 사용해 프로바이더를 설정하세요
v3.6.0
Kubernetes Gateway API 프로바이더
v3.6.0부터 Kubernetes Gateway API 프로바이더는 사양 v1.4.0만 지원하는데,
이를 위해 Gateway API CRD를 업데이트해야 해요.
업데이트된 CRD 적용 (Apply Updated CRDs):
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml
실험 채널의 경우:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/experimental-install.yaml
Kubernetes CRD 프로바이더
Kubernetes CRD 프로바이더에서 새 leasttime 로드 밸런서 알고리즘을 사용하려면 CRD를 업데이트해야 해요.
업데이트된 CRD 적용 (Apply Updated CRDs):
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.6/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
v3.5.4
OpenTelemetry로 인증서 메트릭 이름 변경 (Certificate Metric Renamed with OpenTelemetry)
v3.5.4부터 OpenTelemetry를 사용할 때 traefik_tls_certs_not_after_milliseconds 메트릭의 이름이 traefik_tls_certs_not_after_seconds로 바뀌어요.
이 변경은 메트릭 이름을 실제 단위 정밀도(초)에 맞춘 거예요.
v3.5.2
ProxyProtocol 옵션 폐기 (Deprecation of ProxyProtocol option)
v3.5.2부터 TCP LoadBalancer의 proxyProtocol 옵션은 폐기됐어요.
이 옵션은 이제 TCPServersTransport 레벨에서 설정할 수 있으니 자세한 내용은 문서를 참고하세요.
Kubernetes CRD 프로바이더
Kubernetes CRD 프로바이더에서 새 proxyprotocol 옵션을 사용하려면 CRD를 업데이트해야 해요.
업데이트된 CRD 적용 (Apply Updated CRDs):
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.5/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
v3.5.0
관찰성 (Observability)
라우터와 엔트리포인트의 TraceVerbosity
v3.5.0부터 엔트리포인트와 라우터 모두에 새로운 traceVerbosity 옵션이 제공돼요.
이 옵션은 추적 스팬의 세부 수준을 제어하게 해 줘요.
라우터는 엔트리포인트에서 상속한 값을 덮어쓸 수 있어요.
영향 (Impact):
-
추적에 의존한다면, 원하는 세부 수준을 명시적으로 설정하도록 설정을 검토하세요.
-
기존 설정은 덮어쓰지 않으면 기본적으로 최소(minimal)가 되며, 이전보다 더 적은 스팬이 생성돼요.
가능한 값은:
-
minimal: 라우터가 처리하는 각 요청에 대해 서버 스팬 하나와 클라이언트 스팬 하나를 생성해요.
-
detailed: 라우터가 처리하는 각 요청에 대해 실행되는 각 미들웨어에 대한 추가 스팬 생성을 활성화해요.
엔트리포인트와 동적 라우터의 업데이트된 문서를 참고하세요.
K8s 리소스 속성 (K8s Resource Attributes)
v3.5.0부터 OTel 추적/로그/메트릭이 활성화되면 semconv 속성 k8s.pod.name과 k8s.pod.uid가 OTel 리소스 속성에 자동으로 주입돼요.
그를 위해 다음 권한을 Traefik Kubernetes RBAC에 추가해야 해요:
...
- apiGroups:
- ""
resources:
- pods
verbs:
- get
...
v3.4.5
MultiPath TCP
v3.4.5부터 v3.4.2에서 도입된 MultiPath TCP 지원이 제거됐어요.
일부 플랫폼에서 MPTCP를 활성화하면 Traefik이 다음 오류 로그 메시지로 멈출 수 있는 것으로 보여요:
- set tcp X.X.X.X:X->X.X.X.X:X: setsockopt: operation not supported
하지만 GODEBUG 환경 변수의 multipathtcp 변수를 설정하면 다시 활성화할 수 있어요. 관련 Go 문서를 참고하세요.
v3.4.1
요청 경로 정규화 (Request Path Normalization)
v3.4.1부터 요청 경로는 더 나은 일관성과 보안을 위해 RFC 3986 표준에 따라 정규화돼요.
정규화 과정 (Normalization Process):
-
예약되지 않은 문자 디코딩 (Unreserved Character Decoding):
%2E(.) 같은 문자는 리터럴 형태로 디코딩돼요 -
대소문자 정규화 (Case Normalization): 퍼센트 인코딩된 문자는 대문자로 바뀌어요 (
%2e는%2E가 됨)
이것은 RFC 3986 퍼센트 인코딩 정규화와 대소문자 정규화 표준을 따릅니다.
처리 순서 (Processing Order):
-
경로 정규화 (비활성화할 수 없음)
-
경로 위생화 (활성화된 경우) (Path sanitization)
라우팅에서 예약 문자 처리 (Reserved Character Handling in Routing)
v3.4.1부터 라우터 규칙 매칭 중 예약 문자(RFC 3986 기준)는 라우팅 모호성을 막기 위해 인코딩된 채로 유지돼요.
왜 중요한가 (Why This Matters): 예약 문자는 디코딩되면 요청 경로의 의미를 바꿔요. 라우팅 중 인코딩된 채로 유지하면 보안 취약점을 막고 예측 가능한 라우팅 동작을 보장해요.
요청 경로 매칭 예시 (Request Path Matching Examples)
다음 표는 경로 매칭 동작이 어떻게 바뀌었는지 보여줘요:
| 요청 경로 (Request Path) | 라우터 규칙 (Router Rule) | Traefik v3.4.0 | Traefik v3.4.1 | 설명 (Explanation) |
| /foo%2Fbar | PathPrefix(/foo/bar) | 일치 (Match) | 불일치 (No match) | %2F (/)은 인코딩된 채로 유지되어 잘못된 일치를 막아요 |
| /foo/../bar | PathPrefix(/foo) | 불일치 (No match) | 불일치 (No match) | 경로 이동(traversal)은 위생화되어 사라져요 |
| /foo/../bar | PathPrefix(/bar) | 일치 (Match) | 일치 (Match) | 위생화 후 /bar로 해석돼요 |
| /foo/%2E%2E/bar | PathPrefix(/foo) | 일치 (Match) | 불일치 (No match) | 인코딩된 점은 정규화된 뒤 위생화돼요 |
| /foo/%2E%2E/bar | PathPrefix(/bar) | 불일치 (No match) | 일치 (Match) | 정규화 + 위생화 후 /bar로 해석돼요 |
v3.3에서 v3.4로
Kubernetes CRD 프로바이더
로드 밸런싱 전략 업데이트 (Load-Balancing Strategy Updates)
v3.4부터 HTTP 서비스 정의는 더 나은 트래픽 분배를 위해 추가 로드 밸런싱 전략을 지원해요.
업데이트된 CRD 적용 (Apply Updated CRDs):
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.4/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
새 전략 값 (New Strategy Values):
-
wrr (Weighted Round Robin)
-
p2c (Power of Two Choices)
| 경고 (Warning) | 폐기 (Deprecation)
RoundRobin 전략은 폐기됐지만 여전히 지원돼요(wrr와 동일). 다음 주요 릴리스에서 제거될 거예요.
자세한 내용은 HTTP 서비스 로드 밸런싱 문서를 참고하세요.
ServersTransport CA 인증서 설정 (ServersTransport CA Certificate Configuration)
ServersTransport와 ServersTransportTCP CRD에 새로운 rootCAs 옵션이 추가됐어요. CA 인증서용으로 ConfigMap과 Secret을 모두 지원하며 rootCAsSecrets 옵션을 대체해요.
업데이트 적용 (Apply Updates):
# Update CRDs
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.4/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
# Update RBACs
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.4/docs/content/reference/dynamic-configuration/kubernetes-crd-rbac.yml
새 설정 형식 (New Configuration Format):
---
apiVersion: traefik.io/v1alpha1
kind: ServersTransport
metadata:
name: foo
namespace: bar
spec:
rootCAs:
- configMap: ca-config-map
- secret: ca-secret
---
apiVersion: traefik.io/v1alpha1
kind: ServersTransportTCP
metadata:
name: foo
namespace: bar
spec:
rootCAs:
- configMap: ca-config-map
- secret: ca-secret
| 경고 (Warning) | 폐기 (Deprecation)
rootCAsSecrets 옵션(Secret만)은 여전히 지원되지만 폐기됐어요. 다음 주요 릴리스에서 제거될 거예요.
규칙 구문 설정 (Rule Syntax Configuration)
v3.4에서 규칙 구문 설정 옵션은 다음 주요 버전에서 제거될 거예요.
폐기된 옵션 (Deprecated Options):
-
core.defaultRuleSyntax (정적 설정)
-
ruleSyntax (라우터 옵션)
이 옵션들은 v2에서 v3 구문으로 마이그레이션하기 위한 과도기적 도우미였어요. 다음 주요 릴리스 전에 모든 라우터 규칙이 v3 구문을 사용하도록 하세요.
v3.3.6
요청 경로 위생화 (Request Path Sanitization)
v3.3.6부터 들어오는 요청 경로는 보안과 일관성을 위해 처리 전에 자동으로 정리돼요.
무엇이 바뀌었나 (What's Changed):
다음 경로 세그먼트는 이제 해석되고 축소돼요:
-
/../ (부모 디렉토리 참조)
-
/./ (현재 디렉토리 참조)
-
중복 슬래시 세그먼트 (//)
위생화 비활성화 (Disabling Sanitization):
# EntryPoint HTTP configuration
entryPoints:
web:
address: ":80"
http:
sanitizePath: false # Not recommended
| 위험 (Danger) | 보안 경고 (Security Warning)
sanitizePath: false로 설정하는 것은 안전하지 않아요. 이 옵션은 URL 인코딩을 제대로 하지 않는 레거시 클라이언트와 함께만 사용해야 해요. 이 보안 기능을 비활성화하는 대신 요청이 항상 제대로 URL 인코딩되도록 하세요.
위험 예시 (Example Risk): "/" 문자를 포함하는 Base64 데이터는 경로 위생화가 비활성화되고 데이터가 URL 인코딩되지 않으면 안전하지 않은 라우팅으로 이어질 수 있어요.
v3.3.5
Compress 미들웨어 기본 인코딩 (Compress Middleware Default Encodings)
v3.3.5에서 기본 압축 알고리즘은 gzip 압축을 우선하도록 재정렬됐어요.
새 기본값 (New Default): gzip, br, zstd
이 변경은 다음 중 하나에 해당하는 요청에 영향을 줘요:
-
Accept-Encoding 헤더에 선호 알고리즘을 지정하지 않는 요청
-
Accept-Encoding 헤더에 순서 선호가 없는 요청
재정렬은 더 새로운 압축 알고리즘을 지원하지 못할 수 있는 오래된 클라이언트와의 더 나은 호환성을 보장하는 데 도움이 돼요.
v3.3.4
OpenTelemetry 요청 기간 메트릭 (OpenTelemetry Request Duration Metric)
v3.3.4에서 OpenTelemetry 요청 기간 메트릭의 단위가 다른 프로바이더와 명명 규칙에 맞게 표준화됐어요.
변경 내용 (Change Details):
-
메트릭: traefik_(entrypoint|router|service)_request_duration_seconds
-
이전 단위 (Old Unit): 밀리초 (Milliseconds)
-
새 단위 (New Unit): 초 (Seconds)
이 변경은 모든 메트릭 프로바이더에서 일관성을 보장하고 표준 명명 규칙을 따릅니다.
v3.2에서 v3.3로
ACME DNS 인증서 리졸버 (ACME DNS Certificate Resolver)
v3.3에서 DNS 챌린지 설정 옵션은 명확성을 위해 재구성됐어요.
마이그레이션 필요 (Migration Required):
| 폐기된 옵션 (Deprecated Option) | 새 옵션 (New Option) |
| acme.dnsChallenge.delaybeforecheck | acme.dnsChallenge.propagation.delayBeforeChecks |
| acme.dnsChallenge.disablepropagationcheck | acme.dnsChallenge.propagation.disableChecks |
추적 전역 속성 (Tracing Global Attributes)
v3.3에서 추적 설정이 그 목적을 더 잘 반영하도록 명확해졌어요.
마이그레이션 필요 (Migration Required):
-
이전 (Old): tracing.globalAttributes
-
새 (New): tracing.resourceAttributes
이전 옵션 이름은 전역 스팬 속성이 아니라 컬렉터용 리소스 속성을 특별히 추가하므로 오해의 소지가 있었어요.
v3.2.2
Swarm 프로바이더 라벨 업데이트 (Swarm Provider Label Updates)
v3.2.2에서 Swarm 전용 라벨이 폐기됐고 향후 버전에서 제거될 거예요.
마이그레이션 필요 (Migration Required):
| 폐기된 라벨 (Deprecated Label) | 새 라벨 (New Label) |
| traefik.docker.network | traefik.swarm.network |
| traefik.docker.lbswarm | traefik.swarm.lbswarm |
v3.2.1
X-Forwarded-Prefix 헤더 변경 (X-Forwarded-Prefix Header Changes)
v3.2.1에서 X-Forwarded-Prefix 헤더는 이제 다른 X-Forwarded-* 헤더처럼 처리돼요. 신뢰되지 않은 소스에서 보내면 Traefik이 제거해요.
이 변경은 신뢰되지 않은 클라이언트의 헤더 스푸핑을 막아 보안을 개선해요. 설정 세부 사항은 Forwarded 헤더 문서를 참고하세요.
v3.1에서 v3.2로
Kubernetes CRD 프로바이더
여러 CRD에 새로운 선택적 필드가 추가됐어요. 이 업데이트는 하위 호환이며 새 기능만 추가해요.
최신 CRD 적용 (Apply the latest CRDs):
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.3/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
업데이트된 리소스 (Updated Resources):
-
TraefikService (PR #11032)
-
RateLimit & InFlightReq 미들웨어 (PR #9747)
-
Compress 미들웨어 (PR #10943)
Kubernetes Gateway 프로바이더 Standard 채널
v3.2부터 Kubernetes Gateway 프로바이더는 GRPCRoute 리소스를 지원해요.
따라서 해당 RBAC(KubernetesGateway 프로바이더 RBAC 참고)에서,
grcroutes와 grpcroutes/status 권한을 추가해야 해요.
필수 RBAC 업데이트 (Required RBAC Updates):
...
- apiGroups:
- gateway.networking.k8s.io
resources:
- grpcroutes
verbs:
- get
- list
- watch
- apiGroups:
- gateway.networking.k8s.io
resources:
- grpcroutes/status
verbs:
- update
...
Kubernetes Gateway 프로바이더 실험 채널
Kubernetes Gateway v1.2.0-rc1의 breaking change 때문에 Traefik v3.3은 실험 기능이 활성화될 때 Kubernetes Gateway v1.2.x만 지원해요.
새 기능: BackendTLSPolicy 지원 (New Feature: BackendTLSPolicy Support)
프로바이더는 이제 BackendTLSPolicy 리소스를 지원해요.
따라서 해당 RBAC(KubernetesGateway 프로바이더 RBAC 참고)에서,
backendtlspolicies와 backendtlspolicies/status 권한을 추가해야 해요.
필수 RBAC 업데이트 (Required RBAC Updates):
...
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
- watch
- apiGroups:
- gateway.networking.k8s.io
resources:
- backendtlspolicies
verbs:
- get
- list
- watch
- apiGroups:
- gateway.networking.k8s.io
resources:
- backendtlspolicies/status
verbs:
- update
...
v3.1.0에서 v3.1.1로
IngressClass 조회 (IngressClass Lookup)
disableIngressClassLookup 옵션은 폐기됐고 다음 주요 버전에서 제거될 거예요.
마이그레이션 필요 (Migration Required):
-
이전 (Old): disableIngressClassLookup
-
새 (New): disableClusterScopeResources
새 옵션은 IngressClass와 Nodes 리소스 모두를 포함해 클러스터 범위 리소스 발견에 대해 더 넓은 제어를 제공해요.
v3.0에서 v3.1로
Kubernetes 프로바이더 RBAC
v3.1부터 Traefik의 Kubernetes 프로바이더는 서비스 엔드포인트 발견에 EndpointSlices API(Kubernetes >=v1.21 필요)를 사용해요. 이 변경은 또한 NodePort 로드 밸런싱 기능을 도입해요.
모든 Kubernetes 프로바이더에 다음 RBAC 업데이트가 필요해요:
- endpoints 권한을 제거하고 endpointslices를 추가하세요:
# Remove this section from your RBAC
# - apiGroups: [""]
# resources: ["endpoints"]
# verbs: ["get", "list", "watch"]
# Add this section instead
- apiGroups:
- discovery.k8s.io
resources:
- endpointslices
verbs:
- list
- watch
- NodePort 지원을 위해 nodes 권한을 추가하세요:
- apiGroups:
- ""
resources:
- nodes
verbs:
- get
- list
- watch
| 참고 (Note) | 영향을 받는 프로바이더 (Affected Providers)
이 변경들은 다음에 적용돼요:
-
KubernetesIngress 프로바이더
-
KubernetesCRD 프로바이더
-
KubernetesGateway 프로바이더
Gateway API: KubernetesGateway 프로바이더
KubernetesGateway 프로바이더는 v3.1에서 더 이상 실험적이지 않으며, experimental.kubernetesgateway 옵션 없이 활성화할 수 있어요.
폐기된 설정 (Deprecated Configuration):
Experimental kubernetesgateway option (deprecated)
마이그레이션 단계 (Migration Steps):
-
experimental 섹션에서 kubernetesgateway 옵션을 제거하세요
-
KubernetesGateway 프로바이더 문서를 사용해 프로바이더를 설정하세요