Skip to content

필사 모드: Traefik Advanced — Middleware Design, TLS Options, Multi-Provider

English
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

Introduction

When you use Traefik purely as a basic reverse proxy and then requirements start piling up — wanting authentication applied uniformly across every route, accepting only certain clients via mTLS, sending just 5 percent of traffic to a new version — the default configuration quickly hits its limits. This article covers the next stage: the advanced features you need when running Traefik seriously in production.

A typical real-world situation looks like this. As microservices grow into the dozens, duplicating authentication logic per service becomes inefficient. At the same time, the security team requires mutual TLS authentication for external partner integrations, and the platform team wants to standardize canary and blue-green deployments for zero-downtime releases. All of these needs are solved through Traefik middleware, TLSOption, advanced service features, and multi-provider composition.

As of 2026, the Kubernetes Ingress API is effectively frozen. No new features are being added to Ingress, and the center of gravity is shifting toward its successor standard, the Gateway API. Traefik supports both its own IngressRoute CRD and a Gateway API provider, so we will also examine how the advanced patterns in this article map onto Gateway API filter and policy resources.

The goal here is not a mere feature list but conveying a sense of design — when and how to combine each feature. Therefore, each conceptual explanation is followed by CRD YAML and commands you can actually apply.

Middleware Fundamentals

Middleware is a processing unit that intervenes before a request reaches the backend service, or before a response returns to the client, to transform behavior. By separating cross-cutting concerns such as header injection, authentication, rate limiting, path rewriting, and compression from route definitions, it makes them reusable.

In Traefik, middleware is declared with the Kubernetes Middleware CRD and referenced in IngressRoute rules. The key point is that middleware applies as an ordered chain. If a middleware earlier in the chain rejects a request, later middleware and the backend are never invoked.

Request flow

Client

|

v

[EntryPoint :websecure]

|

v

[Router match] --- Host(api.example.com) && PathPrefix(/v1)

|

v

[Middleware chain]

1. rate-limit (rate limiting)

2. forward-auth (SSO authentication)

3. strip-prefix (path rewriting)

4. secure-headers (security headers)

|

v

[Service] --- weighted / mirroring / sticky

|

v

Pod (backend)

The most important principle in middleware design is ordering. Placing rate limiting before authentication means failed-auth traffic also counts toward the rate limit, which helps reduce the attack surface. Conversely, path rewriting should come after authentication so the backend receives the path it expects.

Middleware Chain Design Patterns

Listing several middleware on every route invites mistakes and duplication. Traefik provides the chain middleware type, letting you bundle frequently used combinations under a single name.

First, define the individual middleware.

apiVersion: traefik.io/v1alpha1

kind: Middleware

metadata:

name: rate-limit

namespace: edge

spec:

rateLimit:

average: 100

burst: 50

period: 1s

sourceCriterion:

ipStrategy:

depth: 1

apiVersion: traefik.io/v1alpha1

kind: Middleware

metadata:

name: secure-headers

namespace: edge

spec:

headers:

browserXssFilter: true

contentTypeNosniff: true

frameDeny: true

stsSeconds: 31536000

stsIncludeSubdomains: true

stsPreload: true

customResponseHeaders:

X-Robots-Tag: "noindex, nofollow"

apiVersion: traefik.io/v1alpha1

kind: Middleware

metadata:

name: strip-api-prefix

namespace: edge

spec:

stripPrefix:

prefixes:

- /v1

Now bundle them into a chain.

apiVersion: traefik.io/v1alpha1

kind: Middleware

metadata:

name: api-edge-chain

namespace: edge

spec:

chain:

middlewares:

- name: rate-limit

- name: forward-auth-sso

- name: strip-api-prefix

- name: secure-headers

The route only needs to reference the single chain.

apiVersion: traefik.io/v1alpha1

kind: IngressRoute

metadata:

name: api-route

namespace: edge

spec:

entryPoints:

- websecure

routes:

- match: Host(`api.example.com`) && PathPrefix(`/v1`)

kind: Rule

middlewares:

- name: api-edge-chain

services:

- name: api-backend

port: 8080

tls:

secretName: api-example-com-tls

The advantages of this structure are clear. Managing common policy in one place means a change to the security-header policy propagates to all routes instantly. Route definitions also become concise, improving readability and review efficiency.

Implementing SSO with forwardAuth

The forwardAuth pattern delegates the authentication decision to a central auth server. Before sending a request to the backend, Traefik forwards a copy to the designated auth server; if the auth server returns a 2xx, the request passes, otherwise the auth server response is returned to the client as-is.

apiVersion: traefik.io/v1alpha1

kind: Middleware

metadata:

name: forward-auth-sso

namespace: edge

spec:

forwardAuth:

address: http://auth-service.auth.svc.cluster.local:4180/oauth2/auth

trustForwardHeader: true

authResponseHeaders:

- X-Auth-Request-User

- X-Auth-Request-Email

- X-Auth-Request-Groups

authRequestHeaders:

- Cookie

- Authorization

The authResponseHeaders setting is the crux. When the auth server returns user information in headers as the verification result, Traefik extracts only those headers and forwards them to the backend. The backend receives trustworthy user identity information without performing token verification itself.

Combined with an auth gateway such as oauth2-proxy, this completes OIDC-based SSO. You must route a separate sign-in path so that oauth2-proxy can redirect unauthenticated requests to the login page.

forwardAuth sequence

Client --(1) request--> Traefik

Traefik --(2) verify /oauth2/auth--> auth-service

auth-service --(3a) 200 OK + user headers--> Traefik --(4) call backend--> Backend

auth-service --(3b) 401/302--> Traefik --(5) return same response--> Client

Setting trustForwardHeader to true trusts the X-Forwarded-* headers, which should only be enabled when the layer in front of Traefik is trustworthy. For an entrypoint exposed directly to the public, Traefik would blindly trust headers the client forged, so caution is required.

Fine-Grained TLS Control with TLSOption

Default TLS settings are often insufficient. One route may need to allow only TLS 1.3, while another opens a broader cipher suite for legacy clients. The TLSOption CRD handles this fine-grained control.

apiVersion: traefik.io/v1alpha1

kind: TLSOption

metadata:

name: modern-tls

namespace: edge

spec:

minVersion: VersionTLS13

sniStrict: true

alpnProtocols:

- h2

- http/1.1

apiVersion: traefik.io/v1alpha1

kind: TLSOption

metadata:

name: intermediate-tls

namespace: edge

spec:

minVersion: VersionTLS12

cipherSuites:

- TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256

- TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

- TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

- TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

curvePreferences:

- CurveP521

- CurveP384

minVersion enforces the minimum TLS version, and setting sniStrict to true rejects connections without SNI. Note that cipherSuites settings are ignored under TLS 1.3. Cipher suite control is only meaningful in the TLS 1.2 range, so to apply a modern security policy it is simpler and safer to raise minVersion to VersionTLS13.

A route references a TLSOption as follows.

apiVersion: traefik.io/v1alpha1

kind: IngressRoute

metadata:

name: secure-route

namespace: edge

spec:

entryPoints:

- websecure

routes:

- match: Host(`secure.example.com`)

kind: Rule

services:

- name: secure-backend

port: 8443

tls:

secretName: secure-example-com-tls

options:

name: modern-tls

namespace: edge

mTLS and TLSStore

Mutual TLS authentication requires not only the server but also the client to present a certificate. It is common in external partner integrations, service-to-service secure communication, and zero-trust environments. It is configured in the clientAuth section of TLSOption.

apiVersion: traefik.io/v1alpha1

kind: TLSOption

metadata:

name: mtls-required

namespace: edge

spec:

minVersion: VersionTLS13

clientAuth:

secretNames:

- partner-ca-bundle

clientAuthType: RequireAndVerifyClientCert

The behavior changes significantly depending on the clientAuthType value. The table below summarizes it.

| clientAuthType | Requires client cert | Performs verification | When cert absent |

| --- | --- | --- | --- |

| NoClientCert | No | No | Pass |

| RequestClientCert | Requests only | No | Pass |

| RequireAnyClientCert | Yes | No | Reject |

| VerifyClientCertIfGiven | Optional | Verifies if presented | Pass |

| RequireAndVerifyClientCert | Yes | Always verifies | Reject |

For true mTLS in production, you must choose RequireAndVerifyClientCert. RequestClientCert performs no verification, so it is suitable only for collecting certificates.

TLSStore is the resource that defines a default certificate. It specifies a fallback certificate to use when no certificate matches the SNI. The cluster-wide default is set with a TLSStore named default.

apiVersion: traefik.io/v1alpha1

kind: TLSStore

metadata:

name: default

namespace: edge

spec:

defaultCertificate:

secretName: wildcard-example-com-tls

Without this configuration, Traefik may present a self-signed default certificate for unmatched SNI requests, triggering browser warnings.

Advanced Service Features

A Traefik service can express more than a simple backend designation. Weighted round-robin, mirroring, and sticky sessions are the prime examples.

Weighted Routing

Distributes traffic across multiple backends by ratio. It is the foundation of canary deployments.

apiVersion: traefik.io/v1alpha1

kind: TraefikService

metadata:

name: api-weighted

namespace: edge

spec:

weighted:

services:

- name: api-stable

port: 8080

weight: 90

- name: api-canary

port: 8080

weight: 10

Giving stable a weight of 90 and canary a weight of 10 sends roughly 10 percent of traffic to the new version. The IngressRoute references this TraefikService just like an ordinary service.

Mirroring

Replicates a copy of real traffic to a separate backend. Because the response is discarded, you can test a new version with live traffic without affecting the client.

apiVersion: traefik.io/v1alpha1

kind: TraefikService

metadata:

name: api-mirrored

namespace: edge

spec:

mirroring:

name: api-stable

port: 8080

mirrors:

- name: api-shadow

port: 8080

percent: 20

The setting above replicates 20 percent of traffic to api-shadow. Shadow traffic testing is a powerful tool for safely verifying how a new version behaves under real load patterns.

Sticky Sessions

Pins the same client to the same backend. It is required for legacy applications that hold session state in memory.

apiVersion: traefik.io/v1alpha1

kind: TraefikService

metadata:

name: api-sticky

namespace: edge

spec:

weighted:

services:

- name: api-stable

port: 8080

weight: 1

sticky:

cookie:

name: traefik_backend

secure: true

httpOnly: true

sameSite: strict

When possible, designing the application to be stateless and eliminating dependence on sticky sessions is preferable for scalability and resilience.

Multi-Provider Composition

Traefik has a multi-provider architecture that reads multiple configuration sources simultaneously. You can enable Kubernetes CRD, Kubernetes Ingress, file, Consul, Gateway API, and more together.

providers:

kubernetesCRD:

allowCrossNamespace: false

allowExternalNameServices: false

kubernetesGateway: {}

file:

directory: /etc/traefik/dynamic

watch: true

Each provider creates routers and services with its own namespace prefix. A viable strategy is to use CRD-based routing primarily in one cluster, statically define cluster-external legacy services through the file provider, and progressively adopt the Gateway API in parallel for the new standard.

| Provider | Primary use | Dynamic update | Notes |

| --- | --- | --- | --- |

| kubernetesCRD | Traefik-native IngressRoute etc. | Yes | Most feature-rich |

| kubernetesGateway | Gateway API standard | Yes | Future standard, highly portable |

| kubernetesIngress | Standard Ingress compatibility | Yes | API frozen, no new features |

| file | External static definitions | Yes (watch) | Useful for legacy integration |

A caveat with multi-provider use is router priority. If different providers define overlapping hosts, conflicts can arise based on priority rules, so it is best to clearly separate host and path namespaces per provider.

Mapping to the Gateway API

Given the trajectory in 2026, it is important to know the migration path to the Gateway API. Many of Traefik advanced middleware features map onto Gateway API filters and policy resources.

| Traefik feature | Gateway API equivalent |

| --- | --- |

| Middleware (header manipulation) | RequestHeaderModifier filter on HTTPRoute |

| Middleware (path rewriting) | URLRewrite filter on HTTPRoute |

| Middleware (redirect) | RequestRedirect filter on HTTPRoute |

| weighted TraefikService | weight on HTTPRoute backendRefs |

| TLSOption | TLS settings and policy on a Gateway listener |

| forwardAuth | ExtAuth-related extension (implementation-specific) |

Note that the core Gateway API specification does not yet cover all advanced middleware such as forwardAuth or rate limiting as a standard. Such features are handled through implementation-specific extensions or the ExtensionRef filter, and Traefik also supports some by linking its own Middleware via ExtensionRef. Therefore, if you want full portability, use only features expressible with core filters, and accept implementation dependency for advanced features as a trade-off.

Yaegi Plugins

Traefik embeds a Go interpreter called Yaegi, allowing it to dynamically load middleware plugins written in Go without compilation. This is useful when you need to implement internal policy as code.

Declare the plugin in the static configuration.

experimental:

plugins:

customHeader:

moduleName: github.com/example/traefik-custom-header

version: v0.2.0

The core skeleton of a plugin is Go code like the following.

package customheader

"context"

"net/http"

)

type Config struct {

HeaderName string `json:"headerName,omitempty"`

HeaderValue string `json:"headerValue,omitempty"`

}

func CreateConfig() *Config {

return &Config{}

}

type CustomHeader struct {

next http.Handler

name string

headerName string

headerValue string

}

func New(ctx context.Context, next http.Handler, config *Config, name string) (http.Handler, error) {

return &CustomHeader{

next: next,

name: name,

headerName: config.HeaderName,

headerValue: config.HeaderValue,

}, nil

}

func (c *CustomHeader) ServeHTTP(rw http.ResponseWriter, req *http.Request) {

req.Header.Set(c.headerName, c.headerValue)

c.next.ServeHTTP(rw, req)

}

The declared plugin is referenced as a plugin type in a Middleware CRD.

apiVersion: traefik.io/v1alpha1

kind: Middleware

metadata:

name: add-custom-header

namespace: edge

spec:

plugin:

customHeader:

headerName: X-Internal-Trace

headerValue: edge-gateway

Since Yaegi is an interpreter, it runs slower than compiled Go. A plugin that performs heavy computation on the hot path can affect latency, so we recommend separating performance-critical logic into a dedicated sidecar or a properly built middleware.

Canary and Blue-Green Deployments

Using the weighted service shown earlier, you can implement canary deployments easily. The key is to adjust weights gradually.

Step 1: send only 5 percent to the canary

kubectl patch traefikservice api-weighted -n edge --type merge \

-p '{"spec":{"weighted":{"services":[{"name":"api-stable","port":8080,"weight":95},{"name":"api-canary","port":8080,"weight":5}]}}}'

After observing metrics with no issues, raise to 25 percent

kubectl patch traefikservice api-weighted -n edge --type merge \

-p '{"spec":{"weighted":{"services":[{"name":"api-stable","port":8080,"weight":75},{"name":"api-canary","port":8080,"weight":25}]}}}'

Final cutover: 100 percent

kubectl patch traefikservice api-weighted -n edge --type merge \

-p '{"spec":{"weighted":{"services":[{"name":"api-stable","port":8080,"weight":0},{"name":"api-canary","port":8080,"weight":100}]}}}'

Blue-green keeps two environments running in advance and switches the router service reference all at once. You either swap weights 0 and 100 instantly, or change the route service name from blue to green.

Canary progression curve

Traffic ratio

100% | ____ green/canary

| ___/

50% | ______/

| _____/

5% | _____/

0% |_/_______________________________ time

T0 T1 T2 T3 T4 T5

confirm metric/error-rate gate at each step

You must place a metric gate between each step. Defining an automatic or manual rollback procedure when indicators such as error rate, latency, and saturation exceed thresholds is the foundation of safe operations.

Observability: Metrics and Tracing

To operate advanced routing, you must make visible what flows where. Traefik natively supports Prometheus metrics and OpenTelemetry tracing.

metrics:

prometheus:

addEntryPointsLabels: true

addRoutersLabels: true

addServicesLabels: true

buckets:

- 0.1

- 0.3

- 1.2

- 5.0

tracing:

otlp:

http:

endpoint: http://otel-collector.observability.svc.cluster.local:4318/v1/traces

Enabling addServicesLabels lets you view request counts and latency separately per service, so during a canary deployment you can directly compare the performance of stable and canary. However, high label cardinality increases the Prometheus load, so in environments with very many routers, enable addRoutersLabels with care.

Tracing is especially useful for finding bottlenecks in request paths where an external call such as forwardAuth is involved. You can distinguish span by span whether the auth server response is slow or the backend is slow.

Production Pitfalls

Here are the pitfalls frequently encountered in real operations.

First, a missing middleware namespace reference. When referencing middleware from another namespace, the name alone will not find it. You must follow the provider-prefix format of name-at-namespace-at-provider, or place it in the same namespace. Cross-namespace references also depend on the allowCrossNamespace setting.

Second, cipherSuites being ignored under TLS 1.3. If a security scanner flags a specific cipher and adjusting cipherSuites changes nothing, in most cases it is because the connection is negotiating to TLS 1.3.

Third, the header-forgery risk of forwardAuth. Exposing an entrypoint directly to the public while trustForwardHeader is on lets clients forge headers such as X-Forwarded-User. Outside the trust boundary, you must place a middleware up front that strips authentication-related headers.

Fourth, the conflict between sticky sessions and zero-downtime deployment. If a sticky cookie is pinned to a specific pod, the session breaks when that pod terminates during a rolling update. You must design session draining together with graceful shutdown.

Fifth, the side effects of mirroring. If the mirror target is a backend that performs write operations, data may be modified twice. The mirror must always be read-only or in an isolated environment.

Troubleshooting

Establishing a fixed verification order speeds up diagnosis when problems arise.

Confirm via the API that routers, middleware, and services registered correctly

kubectl port-forward -n edge deploy/traefik 8080:8080

curl -s http://localhost:8080/api/http/routers | jq '.[] | {name, status, rule}'

curl -s http://localhost:8080/api/http/middlewares | jq '.[] | {name, status}'

Check CRD application state and events

kubectl describe ingressroute api-route -n edge

kubectl get events -n edge --sort-by=.lastTimestamp

Check TLS handshake and certificate

openssl s_client -connect secure.example.com:443 -servername secure.example.com </dev/null 2>/dev/null | openssl x509 -noout -dates -subject

Test a call with an mTLS client certificate

curl -v --cert client.crt --key client.key https://secure.example.com/health

If the dashboard API status field is not enabled, it indicates a configuration error. When a middleware is in a warning state, it is usually because the referenced target does not exist or the namespace does not match.

Temporarily raising the log level to DEBUG lets you trace router matching and middleware application in detail. However, log volume explodes in production, so be sure to revert it after diagnosis.

Conclusion: Production Checklist

Traefik advanced features are powerful, but combining them incorrectly leads to outages that are hard to debug. We recommend the checklist below for pre-deployment review.

- Is the middleware chain order as intended (rate limit, then auth, then rewrite, then security headers)?

- Is forwardAuth trustForwardHeader enabled only within the trust boundary?

- Is there a middleware up front on the public entrypoint that strips authentication-related headers?

- Is TLSOption minVersion set in line with the security policy (TLS 1.3 recommended)?

- Does the mTLS segment perform verification with RequireAndVerifyClientCert?

- Is a default certificate specified in TLSStore to prevent warnings on match failure?

- Is a metric gate and rollback procedure defined at each canary step?

- Is the mirror target read-only or isolated so there is no double data modification?

- When using sticky sessions, are graceful shutdown and session draining designed in?

- Is Prometheus label cardinality at a manageable level?

- Do Yaegi plugins avoid introducing hot-path latency?

- Are there no host/path conflicts among multiple providers?

- When migrating to the Gateway API, have you distinguished features replaceable by core filters from dependent ones?

Checking these items habitually elevates Traefik from a simple proxy into a trustworthy production gateway. As next steps, we recommend evaluating automated certificate issuance integration with cert-manager and a progressive migration to Gateway-API-based routing.

References

- [Traefik Official Documentation](https://doc.traefik.io/traefik/)

- [Traefik Middleware Overview](https://doc.traefik.io/traefik/middlewares/overview/)

- [Traefik forwardAuth Middleware](https://doc.traefik.io/traefik/middlewares/http/forwardauth/)

- [Traefik TLS Configuration](https://doc.traefik.io/traefik/https/tls/)

- [Traefik Kubernetes CRD Provider](https://doc.traefik.io/traefik/providers/kubernetes-crd/)

- [Traefik Plugin Development Guide](https://plugins.traefik.io/create)

- [Kubernetes Ingress Concepts](https://kubernetes.io/docs/concepts/services-networking/ingress/)

- [Gateway API Official Documentation](https://gateway-api.sigs.k8s.io/)

- [cert-manager Official Documentation](https://cert-manager.io/docs/)

- [Helm Official Documentation](https://helm.sh/docs/)

현재 단락 (1/408)

When you use Traefik purely as a basic reverse proxy and then requirements start piling up — wanting...

작성 글자: 0원문 글자: 19,853작성 단락: 0/408