Headers middleware configuration for conditional response header injection
0 reputation · 11 Mar 2023, 12:06 UTC
0 reputation · 11 Mar 2023, 12:06 UTC
Traefik Proxy utilizes the Headers middleware to inject, modify, or remove HTTP headers at Layer 7. This is commonly used to enforce security policies like HSTS or to pass custom metadata to downstream services via dynamic configuration in YAML or Kubernetes labels.
Current documentation outlines the ability to apply headers globally or per-service. However, there is uncertainty regarding the ability to conditionally inject a response header based on the value of an incoming request header within a single middleware definition, without creating multiple distinct routers for every possible header permutation.
Does the Headers middleware support conditional logic for response injection based on request attributes? If not, what is the recommended architectural approach to achieve this behavior in Traefik v3.0?
31775 reputation · 11 Mar 2023, 17:07 UTC
The Traefik Headers middleware does **not** evaluate request attributes to decide whether to inject a response header; it only applies static header maps.
The middleware runs for every request, but its configuration consists of fixed key/value pairs for request and response headers. Traefik’s expression language is reserved for router rules (Header(), PathPrefix(), etc.) and is not exposed inside the Headers middleware. Therefore, conditional logic based on an incoming header cannot be expressed directly in a single Headers definition.
According to the Traefik v3.0 reference, the Headers middleware supports fields such as customRequestHeaders, customResponseHeaders, accessControlAllowMethods, etc., all of which are static values. No conditional or templating mechanism is documented.
traefik/header-plugin or develop a simple Go plugin).traefik.yml) or via a Kubernetes Middleware CRD:# traefik.yml
experimental:
plugins:
header-condition:
moduleName: github.com/traefik/header-plugin
version: v0.1.0
# dynamic config (YAML)
http:
middlewares:
inject-cond:
plugin:
header-condition:
# Example: if request header X-Foo equals "bar", set response header X-Custom to "baz"
requestHeader: "X-Foo"
requestValue: "bar"
responseHeader: "X-Custom"
responseValue: "baz"
http:
routers:
myservice:
rule: Host(`example.com`)
service: myservice
middlewares:
- inject-cond
If you prefer not to use a plugin, you can create separate routers each with a Header() matcher (e.g., Header(`X-Foo`, `bar`)) and reuse the same Headers middleware. This works but leads to a linear increase in routers for each distinct header/value pair, which may be undesirable at scale.
To decide whether a single router with a Header() matcher is sufficient, please confirm the exact request header name and the value (or set of values) you need to match.
Use comments to ask for clarification. Post a solution as an answer.
31,775 reputation · 11 Mar 2023, 17:02 UTC
Traefik’s Headers middleware can’t evaluate request headers itself, but you can still limit its effect by attaching it to a router that only matches when a particular request header is present. In v3.0 you can write a rule like Rule: Header(X-Feature, "enabled") and then apply a single Headers middleware that adds the desired response header. If you need several header values, combine them in one rule with logical operators (&&, ||) or use a single rule that matches multiple values (Header(X-Feature, "enabled|beta")). This keeps the number of routers small while still delivering conditional headers.
http:
routers:
feature-enabled:
rule: "Header(X-Feature, \"enabled\")"
service: app
middlewares:
- inject-feature-header
middlewares:
inject-feature-header:
headers:
customResponseHeaders:
X-Feature-Injected: "true"