Compare commits

..

94 Commits

Author SHA1 Message Date
Kevin Pollet 1268620453 Strip managedFields in informers
Co-authored-by: Piotr Maksymiuk <piotr.maksymiuk@docplanner.com>
2026-06-25 15:26:05 +02:00
Ali Amer b5e7a48bcd Support TLS and Backend TLS Policy SAN validation 2026-06-24 16:48:12 +02:00
Jenthe Noordsij ec80d1145c Increase timeout for Docker image sync job to 30 minutes 2026-06-12 17:12:06 +02:00
qwerty8811 2391520b50 Add optional X-Forwarded-Scheme and X-Scheme headers in forwarded headers middleware 2026-06-12 11:16:07 +02:00
qwerty8811 6cc3dd8d40 Add reportNodeInternalIPs option to report node internal IPs in Ingress status 2026-06-12 10:26:07 +02:00
Anatole Lucet bcf768ee09 Update Gateway API statuses once routing config is built
Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
2026-06-11 10:10:07 +02:00
kevinpollet 51b9a37615 Merge branch v3.7 into master 2026-06-10 17:05:29 +02:00
Kevin Pollet 26c96a3935 Prepare release v3.7.5 2026-06-10 16:46:07 +02:00
kevinpollet cb9e8ab510 Merge branch v3.6 into v3.7 2026-06-10 16:16:05 +02:00
Kevin Pollet b46e795f41 Prepare release v3.6.21 2026-06-10 16:02:11 +02:00
kevinpollet e53a37b869 Merge branch v2.11 into v3.6 2026-06-10 15:34:13 +02:00
Kevin Pollet ad1c1fc2f2 Prepare release v2.11.50 2026-06-10 15:28:05 +02:00
Romain 0209f984eb Fix snicheck for routers with no hosts
Co-authored-by: Gina A. <70909035+gndz07@users.noreply.github.com>
2026-06-10 15:16:06 +02:00
Kevin Pollet e043982244 Support BackendTLSPolicy for TLSRoute 2026-06-10 12:10:05 +02:00
Tim Schumacher 149e62d6db Bump to github.com/pires/go-proxyproto v0.12.0 2026-06-09 17:24:05 +02:00
Julien Salleyron 4ef4c09300 Fix routers with same host, different tlsoptions on different entryPoint
Co-authored-by: Romain <rtribotte@users.noreply.github.com>
2026-06-09 17:08:07 +02:00
Learloj d5ad3eb63b Pass endpointslice fencing on ingress-nginx provider 2026-06-09 16:28:05 +02:00
Baptiste Mayelle 8447bfc71e Reject cross-provider references with backendRefs.namespace 2026-06-09 16:24:05 +02:00
KirylJazzSax dc4b6fe2c6 Support Backend TLS policy for gRPC backends 2026-06-09 16:22:05 +02:00
Gina A. 15ecff2bbd Skip ingress when auth-secret resolution fails 2026-06-08 14:08:05 +02:00
kevinpollet 8773d7ead4 Merge branch v3.7 into master 2026-06-05 16:01:41 +02:00
Romain 74b6408475 Prepare release v3.7.4 2026-06-05 15:56:04 +02:00
kevinpollet 708aa38f36 Merge branch v3.6 into v3.7 2026-06-05 15:26:12 +02:00
Romain 1137f1f807 Prepare release v3.6.20 2026-06-05 15:20:05 +02:00
kevinpollet 15c47f9cb4 Merge branch v2.11 into v3.6 2026-06-05 14:51:59 +02:00
Romain ba8830fdef Prepare release v2.11.49 2026-06-05 14:48:04 +02:00
Julien Salleyron b6bb80f8ff Fix snicheck with keepalive 2026-06-05 14:36:05 +02:00
Anatole Lucet 6ddda32184 Fix BackendTLSPolicy status update
Co-authored-by: Kevin Pollet <pollet.kevin@gmail.com>
2026-06-05 12:16:08 +02:00
Gina A. 5404f6fb25 Bump axios to v1.17.0 2026-06-05 11:22:05 +02:00
Gina A. 5d123f52e1 Bump react-router and jsdom 2026-06-05 11:20:05 +02:00
bzyy1024 d653ee3d73 Fix redis write timeout option configuration 2026-06-04 16:22:06 +02:00
Romain f32f05f811 Bump github.com/quic-go/quic-go to v0.59.1 2026-06-04 16:12:05 +02:00
Romain 5ea71f1c3a Prepare release v3.7.3 2026-06-04 15:14:05 +02:00
romain 48ba249ba7 Merge branch v3.6 into v3.7 2026-06-04 14:06:26 +02:00
Romain 281ce42477 Prepare release v3.6.19 2026-06-04 11:28:16 +02:00
romain 4c71ee3d18 Merge branch v2.11 into v3.6 2026-06-04 11:00:28 +02:00
Romain 2c436f3c23 Prepare release v2.11.48 2026-06-04 10:36:22 +02:00
Romain a664812e9c Compute resolved tlsOptions after applying models
Co-authored-by: Gina A. <70909035+gndz07@users.noreply.github.com>
2026-06-04 10:16:05 +02:00
Romain 85290af77d Bump github.com/fsnotify/fsnotify to v1.10.1 2026-06-03 15:50:05 +02:00
Romain e38281d8ad Prepare release v3.7.2 2026-06-03 15:34:05 +02:00
romain 4aa82efc76 Merge branch v3.6 into v3.7 2026-06-03 14:53:03 +02:00
Romain 32da599169 Prepare release v3.6.18 2026-06-03 11:50:05 +02:00
romain 468e0c8d55 Merge branch v2.11 into v3.6 2026-06-03 11:10:58 +02:00
Kevin Pollet dcbe752df5 Change default values and expose configuration for Kubernetes client QPS and Burst
Co-authored-by: Anatole Lucet <anatole.lucet@proton.me>
2026-06-03 11:06:05 +02:00
Romain 855561306f Prepare release v2.11.47 2026-06-03 11:02:05 +02:00
Romain f25d48e039 Bump golang.org/x/crypto to v0.52.0 2026-06-03 09:14:05 +02:00
romain d468a3e4d0 Merge branch v2.11 into v3.6 2026-06-03 09:14:04 +02:00
Gina A. a669522eca Clear Ssl-Client-* headers when no client certificate is present 2026-06-02 10:40:06 +02:00
Marcell Pünkösd 3697409701 Fix race condition in tests accessing global variables in parallel 2026-06-01 16:18:05 +02:00
filip2mac 9a276c3aeb Add nginx.ingress.kubernetes.io/enable-global-auth to the list of supported annotations 2026-06-01 09:56:05 +02:00
Kevin Pollet af31587841 Bump github.com/bytedance/sonic to v1.15.1 2026-05-30 10:30:05 +02:00
Yuxiao Zeng 8c05c1b1a7 Improve file provider behavior regarding dangling symlinks 2026-05-29 14:14:05 +02:00
Kevin Pollet 9c94e3b493 Bump github.com/moby/spdystream to v0.5.1 2026-05-29 09:48:09 +02:00
Kevin Pollet fc83948b1e Bump golang.org/x/net to v0.55.0 2026-05-29 09:14:05 +02:00
Kevin Pollet 83b36871c3 Add ingressClassName to Kubernetes CRD provider migration guide 2026-05-28 17:10:15 +02:00
Romain 892bcc288b Reject requests with different paths after StripPrefix and StripPrefixRegex normalisation 2026-05-28 15:56:25 +02:00
Julien Salleyron 5026ca97d0 Move snicheck to ctx instead of simulated routing 2026-05-28 10:30:07 +02:00
Sébastien Lemay 2c03850b90 Capitalize NGINX in kubernetesIngressNGINX 2026-05-28 09:38:12 +02:00
Romain f9d9b72380 Avoid ingress path matcher injection and backport 11d251415 2026-05-27 16:32:10 +02:00
romain 29406d4289 Merge current branch v3.7 into master 2026-05-27 14:51:50 +02:00
romain 6e0198ca1e Merge current branch v3.6 into v3.7 2026-05-27 14:20:33 +02:00
Emile Vauge 9d5b03d2ea Add @LBF38 as a current maintainer 2026-05-22 17:24:05 +02:00
Cali Nelson 1db7d439a4 Allow query parameters to be dropped from RequestPath in access log 2026-05-22 15:40:06 +02:00
Nick ee07d0f4d2 Escape exact gRPC method matches 2026-05-22 11:42:06 +02:00
Mark Bonnekessel 1c9a3d21ed Remove whitespace in HTML tag 2026-05-22 10:20:06 +02:00
quyentonndbs 30c118e552 Polish grammar in migration guides 2026-05-22 10:08:06 +02:00
Cristian Baldi 743a63369c Trim quotes from proxy_set_header header name 2026-05-22 10:06:05 +02:00
Emile Vauge a6b16426f2 Surface the Ingress status race condition during NGINX coexistence 2026-05-22 09:52:05 +02:00
Armin ecf5182056 Fix typo in accesslogs field name 2026-05-22 09:42:17 +02:00
Ali Amer d58fd9ac89 Fix TCP router service resolution in dashboard flow diagram 2026-05-22 09:40:06 +02:00
Sheddy 8d2e7db6e3 Replace generated File routing reference page 2026-05-21 15:24:07 +02:00
faukah eec68dce06 flake.nix: cleanup, refactor 2026-05-20 15:44:06 +02:00
Simon Delicata 6736725654 docs: add AGENTS.md contributor guide for AI agents 2026-05-20 14:32:06 +02:00
Kaan f2b11cd50d fix(accesslog): escape double quotes in quoted log fields 2026-05-18 16:02:06 +02:00
Michel Loiseleur f3c6d14caa Document new chart behavior on Gateway API 2026-05-18 15:32:07 +02:00
Romain 4d9031bdb2 Add error on basic auth build if users is empty 2026-05-18 15:06:09 +02:00
Kevin Pollet fa49e2bcad Prepare release v3.7.1 2026-05-11 15:10:05 +02:00
kevinpollet e116b8b859 Merge branch v3.6 into v3.7 2026-05-11 14:46:31 +02:00
Kevin Pollet 32c0861937 Prepare release v3.6.17 2026-05-11 14:44:04 +02:00
kevinpollet c876ed1191 Merge branch v2.11 into v3.6 2026-05-11 14:22:35 +02:00
Kevin Pollet 22460f0a62 Prepare release v2.11.46 2026-05-11 14:20:05 +02:00
kevinpollet 1337363cf6 Merge branch v3.6 into v3.7 2026-05-11 12:01:00 +02:00
kevinpollet 72fcf30d6b Merge branch v2.11 into v3.6 2026-05-11 11:16:29 +02:00
Kevin Pollet 83cc8fee5d Make resolveReference method as a function 2026-05-11 11:14:06 +02:00
romain fc482fda97 Merge branch v2.11 into v3.6 2026-05-11 09:35:34 +02:00
Romain 36a565a599 Fix cross-provider ref check for Kubernetes CRD provider 2026-05-07 16:58:05 +02:00
romain 8c7634bcde Merge branch v2.11 into v3.6 2026-05-07 11:47:33 +02:00
Romain 28604083a4 Add CrossProviderNamespaces option
Co-authored-by: Gina A. <70909035+gndz07@users.noreply.github.com>
2026-05-06 14:49:23 +02:00
Romain ff824c2333 Rework contributor references in the v3.7.0 changelog 2026-05-06 09:48:05 +02:00
Sheddy edd7d2eb33 Service-level Middleware Documentation 2026-05-04 13:56:05 +02:00
mmatur f7c0fdea57 Merge branch v3.7 into master 2026-04-30 16:47:39 +02:00
mmatur 9893e89628 Merge branch v3.7 into master 2026-04-22 14:40:14 +02:00
romain 786f7192e1 Merge branch v3.7 into master 2026-04-09 11:46:50 +02:00
kevinpollet 174e5d8111 Merge branch v3.7 into master 2026-03-26 14:05:54 +01:00
160 changed files with 7944 additions and 3479 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ on:
jobs:
sync:
runs-on: ubuntu-latest
timeout-minutes: 15
timeout-minutes: 30
permissions:
packages: write
contents: read
+3
View File
@@ -348,6 +348,9 @@ linters:
text: 'appendAssign: append result not assigned to the same slice'
linters:
- gocritic
- path: pkg/server/conncontext.go
linters:
- fatcontext
paths:
- pkg/provider/kubernetes/crd/generated/
+113
View File
@@ -0,0 +1,113 @@
# Traefik — Contributor Guide for AI Agents
Traefik is a modern HTTP reverse proxy and load balancer that discovers services from orchestrators (Kubernetes, Docker, Nomad, ...) and wires up routing dynamically. This file is the canonical guide for AI coding agents (Claude Code, Codex, Gemini, Cursor, ...) working in this repository; `CLAUDE.md` is a thin pointer to this file. For everything not covered here, defer to [`CONTRIBUTING.md`](./CONTRIBUTING.md) and [`docs/content/contributing/`](./docs/content/contributing/).
> **Training-data notice.** Traefik evolved significantly between v2 and v3 (label formats, provider names, CRD shapes, middleware names). If anything you think you know about Traefik contradicts this file or the current code, trust this file and the code — not your training data.
## Core vocabulary
These terms appear everywhere in the code and configuration. Use them precisely; they are not interchangeable.
- **EntryPoint** — a network listener (port + protocol).
- **Router** — matches an incoming request and selects a service.
- **Middleware** — transforms a request or response in the routing chain (auth, headers, rate limiting, ...).
- **Service** — defines how to load-balance to backend servers.
- **Provider** — a source of dynamic configuration (Kubernetes CRD, Docker labels, a file, an HTTP endpoint, ...).
- **Static vs Dynamic configuration** — two distinct domains:
- *Static* is set at startup (entrypoints, providers, global options) and lives under [`pkg/config/static`](./pkg/config/static).
- *Dynamic* is produced by providers at runtime (routers, services, middlewares) and lives under [`pkg/config/dynamic`](./pkg/config/dynamic).
These terms are accurate for the code, but user-facing docs deliberately hide the distinction to keep things simpler for readers: when writing or editing under [`docs/content/`](./docs/content), prefer **install configuration** (over *static*) and **routing configuration** (over *dynamic*).
At request time the components chain in this order:
```
Client → EntryPoint → Router → Middleware chain → Service → Backend
```
The middleware chain is ordered: middlewares run in the sequence declared on the router, and the router match happens *before* any middleware runs.
## Where things live
- `cmd/traefik/` — main.
- `pkg/provider/` — one subpackage per provider (Kubernetes, Docker, file, ...).
- `pkg/server/` — routing core, middleware chain, configuration watcher.
- `pkg/middlewares/` — HTTP and TCP middleware implementations.
- `pkg/config/static`, `pkg/config/dynamic` — the two config domains above.
- `pkg/plugins/` — Yaegi and WASM plugin runtimes.
- `pkg/observability/logs/` — logging helpers; the project uses `github.com/rs/zerolog` exclusively.
- `webui/` — React dashboard. Built assets under `webui/static/` are embedded into the Go binary via `//go:embed` (see `webui/embed.go`) and must be regenerated with `make generate-webui` (Docker required) — they are not meant to be hand-edited.
- `integration/` — integration tests; reusable fixtures under `integration/fixtures/`.
- `docs/content/` — MkDocs sources for the public documentation.
## Before you edit
Read two or three existing files in the same package before adding a new one, and copy their structure. Do not invent new directory layouts, file-naming conventions, or abstraction boundaries — match the neighbours. When adding a new provider, read two existing providers under `pkg/provider/`; when adding a middleware, read two under `pkg/middlewares/`.
## Build, test, lint
The Go version is declared in [`go.mod`](./go.mod) — check there rather than hard-coding a version. All day-to-day commands go through `make`:
```bash
make binary # build the traefik binary (runs generate-webui first)
make test-unit # run Go unit tests
make test-integration # run integration tests (requires Docker)
make lint # run golangci-lint
make validate-files # misspell, shellcheck, generated-files check
make validate # lint + validate-files (run this before pushing)
make fmt # gofumpt / goimports
make generate # regenerate non-CRD generated code (deepcopy, etc.)
make generate-crd # regenerate Kubernetes CRD clientset + deepcopy
make generate-webui # rebuild the embedded WebUI assets (Docker required)
make docs-serve # preview the documentation locally
```
Full environment setup (Docker, `GOPATH` layout, Tailscale for Docker Desktop users, how to target a single integration test via `TESTFLAGS`) is documented in [`docs/content/contributing/building-testing.md`](./docs/content/contributing/building-testing.md). CI runs `make validate` and fails if `make generate` or `make generate-crd` leave the tree dirty — always commit regenerated files alongside the source change that triggered them.
## Code style
Standard Go formatting (`gofumpt`/`goimports`) and `golangci-lint` cover most rules automatically; run `make lint` to catch them. Two project-specific rules that tooling does **not** enforce:
- **Comments answer *why*, not *what*.** Comments that restate what the code already says are noise: they go stale and waste review time. Only add a comment when it records *why* the code exists — a constraint, a past incident, a spec reference, an edge case. Comments explaining *how* should be rare and usually indicate the code needs to be clearer. When a comment is present, it **must end with a period**.
- **Assertion messages are minimal.** Prefer `assert.Equal(t, expected, actual)` over `assert.Equal(t, expected, actual, "detailed explanation")`. The test name provides the context; a descriptive message is usually noise.
Prefer modern standard-library packages (`slices`, `maps`, `cmp`, ...) over hand-rolled helpers or third-party libraries when the Go version in `go.mod` supports them.
## Common patterns
- **Logging.** The project uses `github.com/rs/zerolog` exclusively — do not import `log`, `slog`, or `logrus`. Inside a middleware, get a logger via `middlewares.GetLogger(ctx, name, typeName)` (see [`pkg/middlewares/middleware.go`](./pkg/middlewares/middleware.go)) where `typeName` is a package-level `const` like `const typeNameForward = "ForwardAuth"`. Elsewhere, extract the logger from the context with `log.Ctx(ctx)` and attach it to a new context with `.WithContext(ctx)`.
- **Context propagation.** `context.Context` is always the first argument, named `ctx`. Avoid `context.Background()` in request paths; propagate from the caller. Define custom context keys as unexported struct types (`type myKey struct{}`) to prevent collisions.
## Testing conventions
- Unit tests live next to the code as `*_test.go` files using `testing.T` with `testify/assert` and `testify/require`.
- Use `require.*` for preconditions that must stop the test on failure (setup, must-not-be-nil). Use `assert.*` for independent checks where you want the test to keep running and report every failure.
- Integration tests under `integration/` are built on `testify/suite` (see `integration/integration_test.go`) and reuse fixtures from `integration/fixtures/`. New fixtures should follow the pattern of the existing ones.
- New providers require integration tests.
- Prefer running a focused test over the whole suite while iterating. When iterating on a failing test, capture the output to a file once and grep it (`... > /tmp/out.log 2>&1`) rather than re-running the suite with different `TESTFLAGS`. See [`docs/content/contributing/building-testing.md`](./docs/content/contributing/building-testing.md) for the `TESTFLAGS` invocation.
## Documentation
User-facing features need matching documentation updates under `docs/content/`. Integrate new pages into the existing structure rather than creating parallel sections. Preview locally with `make docs-serve`.
## Contributing etiquette
- **Target the right branch** (the [PR template](./.github/PULL_REQUEST_TEMPLATE.md) is authoritative): enhancements go to `master`; bug fixes and documentation updates go to the current maintenance branches (`v3.6` for v3, `v2.11` for v2, security-fixes only). Forward-ports from the maintenance branches up to `master` are handled by maintainers.
- Keep pull requests small and focused; one logical change per PR.
- For anything beyond a bug fix, open an issue first and wait for a maintainer to confirm the direction before investing significant work.
- Follow the full guide in [`docs/content/contributing/submitting-pull-requests.md`](./docs/content/contributing/submitting-pull-requests.md).
## AI assistance disclosure
Traefik welcomes AI-assisted contributions, provided a few simple rules are followed:
- **Declare substantial AI assistance** with an `Assisted-by:` trailer at the bottom of the commit message whenever an agent produced a meaningful portion of the diff — for example `Assisted-by: Claude Opus 4.6`. Trivial edits such as a typo fix or a one-line rename do not need a trailer.
- **Keep issue and PR conversations human.** Do not let an agent post comments, review replies, or triage messages on your behalf. If an agent drafted a message for you, rewrite it in your own voice before sending — maintainers need to know they are talking to a person, not a bot.
- **Align with a maintainer before generating code for anything larger than a bug fix.** An agent can produce thousands of lines in minutes; maintainer review capacity cannot scale the same way. Open an issue, state the intended approach, and wait for confirmation before asking an agent to implement it.
## Things to avoid
- Do not hand-edit generated files — notably `**/zz_generated*.go`, everything under `pkg/provider/kubernetes/crd/generated/`, and `webui/static/`. Regenerate them via `make generate`, `make generate-crd`, or `make generate-webui` and commit the result.
- Do not skip `make lint` and `make validate-files` (or `make validate`) before pushing.
- Do not opportunistically reformat, rename, or refactor files you did not otherwise need to touch. Drive-by changes turn a reviewable diff into noise — scope every PR to one logical change.
- Do not include unrelated refactors, formatting-only changes to untouched files, or speculative abstractions in a feature PR.
+347 -180
View File
@@ -1,3 +1,170 @@
## [v3.7.5](https://github.com/traefik/traefik/tree/v3.7.5) (2026-06-10)
[All Commits](https://github.com/traefik/traefik/compare/v3.7.4...v3.7.5)
**Bug fixes:**
- **[k8s/ingress-nginx]** Skip ingress when auth-secret resolution fails ([#13323](https://github.com/traefik/traefik/pull/13323) @gndz07)
- **[k8s/ingress-nginx]** Pass endpointslice fencing on ingress-nginx provider ([#13290](https://github.com/traefik/traefik/pull/13290) @Learloj)
- **[k8s/gatewayapi]** Reject cross-provider references with backendRefs.namespace ([#13322](https://github.com/traefik/traefik/pull/13322) @youkoulayley)
- **[server]** Bump to github.com/pires/go-proxyproto v0.12.0 ([#13313](https://github.com/traefik/traefik/pull/13313) @timschumi)
- **[tls]** Fix routers with same host, different tlsoptions on different entryPoint ([#13329](https://github.com/traefik/traefik/pull/13329) @juliens)
- **[tls]** Fix snicheck for routers with no hosts ([#13333](https://github.com/traefik/traefik/pull/13333) @rtribotte)
## [v3.6.21](https://github.com/traefik/traefik/tree/v3.6.21) (2026-06-10)
[All Commits](https://github.com/traefik/traefik/compare/v3.6.20...v3.6.21)
**Bug fixes:**
- **[k8s/gatewayapi]** Reject cross-provider references with backendRefs.namespace ([#13322](https://github.com/traefik/traefik/pull/13322) @youkoulayley)
- **[server]** Bump to github.com/pires/go-proxyproto v0.12.0 ([#13313](https://github.com/traefik/traefik/pull/13313) @timschumi)
- **[tls]** Fix routers with same host, different tlsoptions on different entryPoint ([#13329](https://github.com/traefik/traefik/pull/13329) @juliens)
- **[tls]** Fix snicheck for routers with no hosts ([#13333](https://github.com/traefik/traefik/pull/13333) @rtribotte)
## [v2.11.50](https://github.com/traefik/traefik/tree/v2.11.50) (2026-06-10)
[All Commits](https://github.com/traefik/traefik/compare/v2.11.49...v2.11.50)
**Bug fixes:**
- **[tls]** Fix routers with same host, different tlsoptions on different entryPoint ([#13329](https://github.com/traefik/traefik/pull/13329) @juliens)
- **[tls]** Fix snicheck for routers with no hosts ([#13333](https://github.com/traefik/traefik/pull/13333) @rtribotte)
## [v3.7.4](https://github.com/traefik/traefik/tree/v3.7.4) (2026-06-05)
[All Commits](https://github.com/traefik/traefik/compare/v3.7.3...v3.7.4)
**Bug fixes:**
- **[middleware]** Fix redis write timeout option configuration ([#13273](https://github.com/traefik/traefik/pull/13273) @bzyy1024)
- **[webui]** Bump react-router and jsdom ([#13301](https://github.com/traefik/traefik/pull/13301) @gndz07)
- **[k8s/gatewayapi]** Fix BackendTLSPolicy status update ([#13306](https://github.com/traefik/traefik/pull/13306) @AnatoleLucet)
- **[http3]** Bump github.com/quic-go/quic-go to v0.59.1 ([#13300](https://github.com/traefik/traefik/pull/13300) @rtribotte)
- **[webui]** Bump axios to v1.17.0 ([#13299](https://github.com/traefik/traefik/pull/13299) @gndz07)
- **[tls]** Fix snicheck with keepalive ([#13305](https://github.com/traefik/traefik/pull/13305) @juliens)
## [v3.6.20](https://github.com/traefik/traefik/tree/v3.6.20) (2026-06-05)
[All Commits](https://github.com/traefik/traefik/compare/v3.6.19...v3.6.20)
**Bug fixes:**
- **[middleware]** Fix redis write timeout option configuration ([#13273](https://github.com/traefik/traefik/pull/13273) @bzyy1024)
- **[webui]** Bump react-router and jsdom ([#13301](https://github.com/traefik/traefik/pull/13301) @gndz07)
- **[k8s/gatewayapi]** Fix BackendTLSPolicy status update ([#13306](https://github.com/traefik/traefik/pull/13306) @AnatoleLucet)
- **[http3]** Bump github.com/quic-go/quic-go to v0.59.1 ([#13300](https://github.com/traefik/traefik/pull/13300) @rtribotte)
- **[webui]** Bump axios to v1.17.0 ([#13299](https://github.com/traefik/traefik/pull/13299) @gndz07)
- **[tls]** Fix snicheck with keepalive ([#13305](https://github.com/traefik/traefik/pull/13305) @juliens)
## [v2.11.49](https://github.com/traefik/traefik/tree/v2.11.49) (2026-06-05)
[All Commits](https://github.com/traefik/traefik/compare/v2.11.48...v2.11.49)
**Bug fixes:**
- **[http3]** Bump github.com/quic-go/quic-go to v0.59.1 ([#13300](https://github.com/traefik/traefik/pull/13300) @rtribotte)
- **[webui]** Bump axios to v1.17.0 ([#13299](https://github.com/traefik/traefik/pull/13299) @gndz07)
- **[tls]** Fix snicheck with keepalive ([#13305](https://github.com/traefik/traefik/pull/13305) @juliens)
## [v3.7.3](https://github.com/traefik/traefik/tree/v3.7.3) (2026-06-04)
[All Commits](https://github.com/traefik/traefik/compare/v3.7.1...v3.7.3)
**Bug fixes:**
- **[tls]** Compute resolved tlsOptions after applying models ([#13291](https://github.com/traefik/traefik/pull/13291) @rtribotte)
- **[webui, tcp]** Fix TCP router service resolution in dashboard flow diagram ([#13155](https://github.com/traefik/traefik/pull/13155) @aliamerj)
- **[k8s/ingress-nginx]** Trim quotes from proxy_set_header header name ([#13203](https://github.com/traefik/traefik/pull/13203) @crisbal)
- **[accesslogs]** Escape double quotes in quoted log fields ([#13180](https://github.com/traefik/traefik/pull/13180) @KaanSimsek)
- **[k8s/gatewayapi]** Escape exact gRPC method matches ([#13201](https://github.com/traefik/traefik/pull/13201) @nickmnt)
- **[logs, middleware]** Allow query parameters to be dropped from RequestPath in access log ([#13091](https://github.com/traefik/traefik/pull/13091) @calinelson)
- **[k8s/ingress-nginx]** Clear Ssl-Client-* headers when no client certificate is present ([#13260](https://github.com/traefik/traefik/pull/13260) @gndz07)
- **[k8s/gatewayapi]** Bump github.com/moby/spdystream to v0.5.1 ([#13252](https://github.com/traefik/traefik/pull/13252) @kevinpollet)
- **[file]** Improve file provider behavior regarding dangling symlinks ([#12449](https://github.com/traefik/traefik/pull/12449) @fh-yuxiao-zeng)
- **[server]** Bump github.com/bytedance/sonic to v1.15.1 ([#13254](https://github.com/traefik/traefik/pull/13254) @kevinpollet)
- **[middleware, authentication]** Add error on basic auth build if users is empty ([#13195](https://github.com/traefik/traefik/pull/13195) @rtribotte)
- **[k8s/ingress]** Avoid ingress path matcher injection and backport 11d251415 ([#13227](https://github.com/traefik/traefik/pull/13227) @rtribotte)
- **[server]** Move snicheck to ctx instead of simulated routing ([#13214](https://github.com/traefik/traefik/pull/13214) @juliens)
- **[middleware]** Reject requests with different paths after StripPrefix and StripPrefixRegex normalisation ([#13215](https://github.com/traefik/traefik/pull/13215) @rtribotte)
- **[server]** Bump golang.org/x/net to v0.55.0 ([#13251](https://github.com/traefik/traefik/pull/13251) @kevinpollet)
- **[k8s/gatewayapi]** Change default values and expose configuration for Kubernetes client QPS and Burst ([#13277](https://github.com/traefik/traefik/pull/13277) @kevinpollet)
- **[server]** Bump golang.org/x/crypto to v0.52.0 ([#13276](https://github.com/traefik/traefik/pull/13276) @rtribotte)
**Documentation:**
- **[k8s]** Document new chart behavior on Gateway API ([#13167](https://github.com/traefik/traefik/pull/13167) @mloiseleur)
- **[file]** Replace generated File routing reference page ([#13170](https://github.com/traefik/traefik/pull/13170) @sheddy-traefik)
- **[k8s/crd]** Fix typo in accesslogs field name ([#13177](https://github.com/traefik/traefik/pull/13177) @PlayMTL)
- **[k8s/ingress-nginx]** Surface the Ingress status race condition during NGINX coexistence ([#13205](https://github.com/traefik/traefik/pull/13205) @emilevauge)
- Polish grammar in migration guides ([#13174](https://github.com/traefik/traefik/pull/13174) @quyentonndbs)
- **[middleware]** Remove whitespace in HTML tag ([#13160](https://github.com/traefik/traefik/pull/13160) @marbon87)
- Add @LBF38 as a current maintainer ([#13225](https://github.com/traefik/traefik/pull/13225) @emilevauge)
- Add ingressClassName to Kubernetes CRD provider migration guide ([#13248](https://github.com/traefik/traefik/pull/13248) @kevinpollet)
- **[k8s/ingress-nginx]** Add nginx.ingress.kubernetes.io/enable-global-auth to the list of supported annotations ([#13219](https://github.com/traefik/traefik/pull/13219) @filip2mac)
- **[k8s/ingress-nginx]** Capitalize NGINX in kubernetesIngressNGINX ([#13236](https://github.com/traefik/traefik/pull/13236) @smellems)
## [v3.6.19](https://github.com/traefik/traefik/tree/v3.6.19) (2026-06-04)
[All Commits](https://github.com/traefik/traefik/compare/v3.6.17...v3.6.19)
**Bug fixes:**
- **[tls]** Compute resolved tlsOptions after applying models ([#13291](https://github.com/traefik/traefik/pull/13291) @rtribotte)
- **[accesslogs]** Escape double quotes in quoted log fields ([#13180](https://github.com/traefik/traefik/pull/13180) @KaanSimsek)
- **[k8s/gatewayapi]** Escape exact gRPC method matches ([#13201](https://github.com/traefik/traefik/pull/13201) @nickmnt)
- **[logs, middleware]** Allow query parameters to be dropped from RequestPath in access log ([#13091](https://github.com/traefik/traefik/pull/13091) @calinelson)
- **[k8s/gatewayapi]** Bump github.com/moby/spdystream to v0.5.1 ([#13252](https://github.com/traefik/traefik/pull/13252) @kevinpollet)
- **[file]** Improve file provider behavior regarding dangling symlinks ([#12449](https://github.com/traefik/traefik/pull/12449) @fh-yuxiao-zeng)
- **[server]** Bump github.com/bytedance/sonic to v1.15.1 ([#13254](https://github.com/traefik/traefik/pull/13254) @kevinpollet)
- **[middleware, authentication]** Add error on basic auth build if users is empty ([#13195](https://github.com/traefik/traefik/pull/13195) @rtribotte)
- **[k8s/ingress]** Avoid ingress path matcher injection and backport 11d251415 ([#13227](https://github.com/traefik/traefik/pull/13227) @rtribotte)
- **[server]** Move snicheck to ctx instead of simulated routing ([#13214](https://github.com/traefik/traefik/pull/13214) @juliens)
- **[middleware]** Reject requests with different paths after StripPrefix and StripPrefixRegex normalisation ([#13215](https://github.com/traefik/traefik/pull/13215) @rtribotte)
- **[server]** Bump golang.org/x/net to v0.55.0 ([#13251](https://github.com/traefik/traefik/pull/13251) @kevinpollet)
- **[k8s/gatewayapi]** Change default values and expose configuration for Kubernetes client QPS and Burst ([#13277](https://github.com/traefik/traefik/pull/13277) @kevinpollet)
- **[server]** Bump golang.org/x/crypto to v0.52.0 ([#13276](https://github.com/traefik/traefik/pull/13276) @rtribotte)
**Documentation:**
- **[file]** Replace generated File routing reference page ([#13170](https://github.com/traefik/traefik/pull/13170) @sheddy-traefik)
- **[k8s/crd]** Fix typo in accesslogs field name ([#13177](https://github.com/traefik/traefik/pull/13177) @PlayMTL)
- **[k8s/ingress-nginx]** Surface the Ingress status race condition during NGINX coexistence ([#13205](https://github.com/traefik/traefik/pull/13205) @emilevauge)
- Polish grammar in migration guides ([#13174](https://github.com/traefik/traefik/pull/13174) @quyentonndbs)
- **[middleware]** Remove whitespace in HTML tag ([#13160](https://github.com/traefik/traefik/pull/13160) @marbon87)
- Add @LBF38 as a current maintainer ([#13225](https://github.com/traefik/traefik/pull/13225) @emilevauge)
- **[k8s/ingress-nginx]** Capitalize NGINX in kubernetesIngressNGINX ([#13236](https://github.com/traefik/traefik/pull/13236) @smellems)
## [v2.11.48](https://github.com/traefik/traefik/tree/v2.11.48) (2026-06-04)
[All Commits](https://github.com/traefik/traefik/compare/v2.11.46...v2.11.48)
**Bug fixes:**
- **[tls]** Compute resolved tlsOptions after applying models ([#13291](https://github.com/traefik/traefik/pull/13291) @rtribotte)
- **[middleware, authentication]** Add error on basic auth build if users is empty ([#13195](https://github.com/traefik/traefik/pull/13195) @rtribotte)
- **[k8s/ingress]** Avoid ingress path matcher injection and backport 11d251415 ([#13227](https://github.com/traefik/traefik/pull/13227) @rtribotte)
- **[server]** Move snicheck to ctx instead of simulated routing ([#13214](https://github.com/traefik/traefik/pull/13214) @juliens)
- **[middleware]** Reject requests with different paths after StripPrefix and StripPrefixRegex normalisation ([#13215](https://github.com/traefik/traefik/pull/13215) @rtribotte)
- **[server]** Bump golang.org/x/net to v0.55.0 ([#13251](https://github.com/traefik/traefik/pull/13251) @kevinpollet)
- **[server]** Bump golang.org/x/crypto to v0.52.0 ([#13276](https://github.com/traefik/traefik/pull/13276) @rtribotte)
-
## [v3.7.2](https://github.com/traefik/traefik/tree/v3.7.2) (2026-06-03)
[All Commits](https://github.com/traefik/traefik/compare/v3.7.1...v3.7.2)
Release canceled.
## [v3.6.18](https://github.com/traefik/traefik/tree/v3.6.18) (2026-06-03)
[All Commits](https://github.com/traefik/traefik/compare/v3.6.17...v3.6.18)
Release canceled.
## [v2.11.47](https://github.com/traefik/traefik/tree/v2.11.47) (2026-06-03)
[All Commits](https://github.com/traefik/traefik/compare/v2.11.46...v2.11.47)
Release canceled.
## [v3.7.1](https://github.com/traefik/traefik/tree/v3.7.1) (2026-05-11)
[All Commits](https://github.com/traefik/traefik/compare/v3.7.0...v3.7.1)
**Bug fixes:**
- **[k8s/ingress, k8s/crd, k8s/gatewayapi]** Add CrossProviderNamespaces option ([#13094](https://github.com/traefik/traefik/pull/13094) @rtribotte)
- **[k8s/crd]** Fix cross-provider ref check for Kubernetes CRD provider ([#13121](https://github.com/traefik/traefik/pull/13121) @rtribotte)
## [v3.6.17](https://github.com/traefik/traefik/tree/v3.6.17) (2026-05-11)
[All Commits](https://github.com/traefik/traefik/compare/v3.6.16...v3.6.17)
**Bug fixes:**
- **[k8s/ingress, k8s/crd, k8s/gatewayapi]** Add CrossProviderNamespaces option ([#13094](https://github.com/traefik/traefik/pull/13094) @rtribotte)
- **[k8s/crd]** Fix cross-provider ref check for Kubernetes CRD provider ([#13121](https://github.com/traefik/traefik/pull/13121) @rtribotte)
## [v2.11.46](https://github.com/traefik/traefik/tree/v2.11.46) (2026-05-11)
[All Commits](https://github.com/traefik/traefik/compare/v2.11.45...v2.11.46)
**Bug fixes:**
- **[k8s/ingress, k8s/crd, k8s/gatewayapi]** Add CrossProviderNamespaces option ([#13094](https://github.com/traefik/traefik/pull/13094) @rtribotte)
- **[k8s/crd]** Fix cross-provider ref check for Kubernetes CRD provider ([#13121](https://github.com/traefik/traefik/pull/13121) @rtribotte)
## [v3.7.0](https://github.com/traefik/traefik/tree/v3.7.0) (2026-05-05)
[All Commits](https://github.com/traefik/traefik/compare/v3.6.0-rc1...v3.7.0)
@@ -17,52 +184,52 @@
- **[k8s/knative]** Support knative v1.20.0 ([#12441](https://github.com/traefik/traefik/pull/12441) @idurgakalyan)
- **[k8s/gatewayapi]** Bump sigs.k8s.io/gateway-api to v1.5.1 ([#12768](https://github.com/traefik/traefik/pull/12768) @mmatur)
- **[k8s/ingress-nginx, middleware, authentication]** Add support for auth-snippet ([#12778](https://github.com/traefik/traefik/pull/12778) @juliens)
- **[accesslogs, otel]** Allow Stdio access logs alongsige OTLP logging ([#12307](https://github.com/traefik/traefik/pull/12307) by [Mulgish](https://github.com/Mulgish))
- **[acme]** Add CertificateTimeout ACME configuration option ([#12278](https://github.com/traefik/traefik/pull/12278) by [ceko](https://github.com/ceko))
- **[k8s/ingress-nginx]** Support nginx.ingress.kubernetes.io/allowlist-source-range ([#12659](https://github.com/traefik/traefik/pull/12659) by [ris-tlp](https://github.com/ris-tlp))
- **[k8s/crd]** Add ingressClassName field to the CRDs spec ([#12313](https://github.com/traefik/traefik/pull/12313) by [kkrypt0nn](https://github.com/kkrypt0nn))
- **[k8s/crd]** Service failover support in TraefikService CRD ([#12733](https://github.com/traefik/traefik/pull/12733) by [jspdown](https://github.com/jspdown))
- **[k8s/crd, service]** Support cipher suites configuration with ServersTransport ([#11965](https://github.com/traefik/traefik/pull/11965) by [NEwa-05](https://github.com/NEwa-05))
- **[k8s/ingress, middleware, k8s/crd, service, k8s/gatewayapi]** Services middleware and Gateway API filters on HTTP backends ([#12544](https://github.com/traefik/traefik/pull/12544) by [juliens](https://github.com/juliens))
- **[k8s/ingress-nginx]** Add nginx.ingress.kubernetes.io/proxy-connect-timeout annotation ([#12572](https://github.com/traefik/traefik/pull/12572) by [gndz07](https://github.com/gndz07))
- **[k8s/ingress-nginx]** Add rewrite-target nginx annotations support ([#12534](https://github.com/traefik/traefik/pull/12534) by [LBF38](https://github.com/LBF38))
- **[k8s/ingress-nginx]** Add support for app-root nginx annotation ([#12576](https://github.com/traefik/traefik/pull/12576) by [LBF38](https://github.com/LBF38))
- **[k8s/ingress-nginx]** Add support for auth-signin annotation ([#12502](https://github.com/traefik/traefik/pull/12502) by [DesalLama](https://github.com/DesalLama))
- **[k8s/ingress-nginx]** Add support for from-to-www-redirect NGINX annotation ([#12610](https://github.com/traefik/traefik/pull/12610) by [LBF38](https://github.com/LBF38))
- **[k8s/ingress-nginx]** Add support for proxy-read-timeout and proxy-send-timeout NGINX annotations ([#12630](https://github.com/traefik/traefik/pull/12630) by [LBF38](https://github.com/LBF38))
- **[k8s/ingress-nginx]** Add support for session-cookie-expires nginx annotation ([#12558](https://github.com/traefik/traefik/pull/12558) by [LBF38](https://github.com/LBF38))
- **[k8s/ingress-nginx]** Add support for upstream-hash-by NGINX annotation ([#12749](https://github.com/traefik/traefik/pull/12749) by [LBF38](https://github.com/LBF38))
- **[k8s/ingress-nginx]** Allow entry points to be specified on Nginx Ingresses ([#12727](https://github.com/traefik/traefik/pull/12727) by [ajacques](https://github.com/ajacques))
- **[k8s/ingress-nginx]** Implement proxy-http-version annotation ([#12743](https://github.com/traefik/traefik/pull/12743) by [KshitijBharde](https://github.com/KshitijBharde))
- **[k8s/ingress-nginx]** Nginx x-forwarded-prefix annotation ([#12697](https://github.com/traefik/traefik/pull/12697) by [nandorKollar](https://github.com/nandorKollar))
- **[k8s/ingress-nginx]** Support auth-tls-secret and auth-tls-verify-client annotations ([#12595](https://github.com/traefik/traefik/pull/12595) by [gndz07](https://github.com/gndz07))
- **[k8s/ingress-nginx]** Support limit-rpm annotation for ingress-nginx ([#12703](https://github.com/traefik/traefik/pull/12703) by [Ph4rell](https://github.com/Ph4rell))
- **[k8s/ingress-nginx]** Support limit-rps annotation for Ingress NGINX ([#12709](https://github.com/traefik/traefik/pull/12709) by [amazon7737](https://github.com/amazon7737))
- **[k8s/ingress-nginx]** Support NGINX buffering annotations ([#12459](https://github.com/traefik/traefik/pull/12459) by [blasko03](https://github.com/blasko03))
- **[k8s/ingress-nginx]** Support NGINX canary annotations ([#12739](https://github.com/traefik/traefik/pull/12739) by [kevinpollet](https://github.com/kevinpollet))
- **[k8s/ingress-nginx]** Support NGINX custom-headers annotation ([#12414](https://github.com/traefik/traefik/pull/12414) by [nandorKollar](https://github.com/nandorKollar))
- **[k8s/ingress-nginx]** Support NGINX upstream-vhost annotation ([#12412](https://github.com/traefik/traefik/pull/12412) by [nandorKollar](https://github.com/nandorKollar))
- **[k8s/ingress-nginx]** Support NGINX whitelist-source-range annotation ([#12423](https://github.com/traefik/traefik/pull/12423) by [blasko03](https://github.com/blasko03))
- **[k8s/ingress-nginx]** Support permanent-redirect and temporal-redirect annotations ([#12561](https://github.com/traefik/traefik/pull/12561) by [LBF38](https://github.com/LBF38))
- **[k8s/ingress-nginx]** Support proxy-next-upstream* annotations ([#12710](https://github.com/traefik/traefik/pull/12710) by [gndz07](https://github.com/gndz07))
- **[k8s/ingress-nginx]** Support server-alias annotation for Ingress NGINX ([#12707](https://github.com/traefik/traefik/pull/12707) by [amazon7737](https://github.com/amazon7737))
- **[k8s/ingress-nginx]** Support upstream-keepalive-timeout ([#12708](https://github.com/traefik/traefik/pull/12708) by [jcob-sikorski](https://github.com/jcob-sikorski))
- **[k8s/ingress-nginx]** Add support for variable interpolation in auth-signin NGINX annotation ([#12640](https://github.com/traefik/traefik/pull/12640) by [LBF38](https://github.com/LBF38))
- **[k8s/ingress-nginx]** Implement server-snippet and configuration-snippet annotations ([#12715](https://github.com/traefik/traefik/pull/12715) by [juliens](https://github.com/juliens))
- **[k8s/ingress-nginx]** Add custom-http-errors and default-backend annotations ([#12637](https://github.com/traefik/traefik/pull/12637) by [juliens](https://github.com/juliens))
- **[k8s/ingress-nginx]** Support auth-tls-pass-certificate-to-upstream annotation ([#12629](https://github.com/traefik/traefik/pull/12629) by [gndz07](https://github.com/gndz07))
- **[metrics]** Support file path for metrics.influxdb2.token option ([#12458](https://github.com/traefik/traefik/pull/12458) by [barhun](https://github.com/barhun))
- **[middleware]** Add encodedCharacters middleware ([#12555](https://github.com/traefik/traefik/pull/12555) by [gndz07](https://github.com/gndz07))
- **[middleware]** Enable retries based on HTTP response status codes, timeout, and non-idempotent methods ([#12667](https://github.com/traefik/traefik/pull/12667) by [LBF38](https://github.com/LBF38))
- **[middleware, authentication]** Add authSignInURL in forward auth middleware ([#12293](https://github.com/traefik/traefik/pull/12293) by [kyounghunJang](https://github.com/kyounghunJang))
- **[server]** Add global option to disable X-Forwarded-For appending ([#12374](https://github.com/traefik/traefik/pull/12374) by [lbenguigui](https://github.com/lbenguigui))
- **[server]** Replace Split in loops with more efficient SplitSeq ([#12316](https://github.com/traefik/traefik/pull/12316) by [boqishan](https://github.com/boqishan))
- **[service]** Failover according to response status code ([#12596](https://github.com/traefik/traefik/pull/12596) by [lbenguigui](https://github.com/lbenguigui))
- **[tls]** Make TLSStore gracefully handle missing secrets ([#12522](https://github.com/traefik/traefik/pull/12522) by [david-garcia-garcia](https://github.com/david-garcia-garcia))
- **[webui]** Add dashboard name configuration ([#12410](https://github.com/traefik/traefik/pull/12410) by [gndz07](https://github.com/gndz07))
- **[webui]** Web UI dashboard improvements ([#12236](https://github.com/traefik/traefik/pull/12236) by [gndz07](https://github.com/gndz07))
- **[webui]** Details pages UI improvement ([#12377](https://github.com/traefik/traefik/pull/12377) by [gndz07](https://github.com/gndz07))
- Use unicode.MaxASCII for clearer ASCII check ([#12741](https://github.com/traefik/traefik/pull/12741) by [1911860538](https://github.com/1911860538))
- **[accesslogs, otel]** Allow Stdio access logs alongsige OTLP logging ([#12307](https://github.com/traefik/traefik/pull/12307) @Mulgish)
- **[acme]** Add CertificateTimeout ACME configuration option ([#12278](https://github.com/traefik/traefik/pull/12278) @ceko)
- **[k8s/ingress-nginx]** Support nginx.ingress.kubernetes.io/allowlist-source-range ([#12659](https://github.com/traefik/traefik/pull/12659) @ris-tlp)
- **[k8s/crd]** Add ingressClassName field to the CRDs spec ([#12313](https://github.com/traefik/traefik/pull/12313) @kkrypt0nn)
- **[k8s/crd]** Service failover support in TraefikService CRD ([#12733](https://github.com/traefik/traefik/pull/12733) @jspdown)
- **[k8s/crd, service]** Support cipher suites configuration with ServersTransport ([#11965](https://github.com/traefik/traefik/pull/11965) @NEwa-05)
- **[k8s/ingress, middleware, k8s/crd, service, k8s/gatewayapi]** Services middleware and Gateway API filters on HTTP backends ([#12544](https://github.com/traefik/traefik/pull/12544) @juliens)
- **[k8s/ingress-nginx]** Add nginx.ingress.kubernetes.io/proxy-connect-timeout annotation ([#12572](https://github.com/traefik/traefik/pull/12572) @gndz07)
- **[k8s/ingress-nginx]** Add rewrite-target nginx annotations support ([#12534](https://github.com/traefik/traefik/pull/12534) @LBF38)
- **[k8s/ingress-nginx]** Add support for app-root nginx annotation ([#12576](https://github.com/traefik/traefik/pull/12576) @LBF38)
- **[k8s/ingress-nginx]** Add support for auth-signin annotation ([#12502](https://github.com/traefik/traefik/pull/12502) @DesalLama)
- **[k8s/ingress-nginx]** Add support for from-to-www-redirect NGINX annotation ([#12610](https://github.com/traefik/traefik/pull/12610) @LBF38)
- **[k8s/ingress-nginx]** Add support for proxy-read-timeout and proxy-send-timeout NGINX annotations ([#12630](https://github.com/traefik/traefik/pull/12630) @LBF38)
- **[k8s/ingress-nginx]** Add support for session-cookie-expires nginx annotation ([#12558](https://github.com/traefik/traefik/pull/12558) @LBF38)
- **[k8s/ingress-nginx]** Add support for upstream-hash-by NGINX annotation ([#12749](https://github.com/traefik/traefik/pull/12749) @LBF38)
- **[k8s/ingress-nginx]** Allow entry points to be specified on Nginx Ingresses ([#12727](https://github.com/traefik/traefik/pull/12727) @ajacques)
- **[k8s/ingress-nginx]** Implement proxy-http-version annotation ([#12743](https://github.com/traefik/traefik/pull/12743) @KshitijBharde)
- **[k8s/ingress-nginx]** Nginx x-forwarded-prefix annotation ([#12697](https://github.com/traefik/traefik/pull/12697) @nandorKollar)
- **[k8s/ingress-nginx]** Support auth-tls-secret and auth-tls-verify-client annotations ([#12595](https://github.com/traefik/traefik/pull/12595) @gndz07)
- **[k8s/ingress-nginx]** Support limit-rpm annotation for ingress-nginx ([#12703](https://github.com/traefik/traefik/pull/12703) @Ph4rell)
- **[k8s/ingress-nginx]** Support limit-rps annotation for Ingress NGINX ([#12709](https://github.com/traefik/traefik/pull/12709) @amazon7737)
- **[k8s/ingress-nginx]** Support NGINX buffering annotations ([#12459](https://github.com/traefik/traefik/pull/12459) @blasko03)
- **[k8s/ingress-nginx]** Support NGINX canary annotations ([#12739](https://github.com/traefik/traefik/pull/12739) @kevinpollet)
- **[k8s/ingress-nginx]** Support NGINX custom-headers annotation ([#12414](https://github.com/traefik/traefik/pull/12414) @nandorKollar)
- **[k8s/ingress-nginx]** Support NGINX upstream-vhost annotation ([#12412](https://github.com/traefik/traefik/pull/12412) @nandorKollar)
- **[k8s/ingress-nginx]** Support NGINX whitelist-source-range annotation ([#12423](https://github.com/traefik/traefik/pull/12423) @blasko03)
- **[k8s/ingress-nginx]** Support permanent-redirect and temporal-redirect annotations ([#12561](https://github.com/traefik/traefik/pull/12561) @LBF38)
- **[k8s/ingress-nginx]** Support proxy-next-upstream* annotations ([#12710](https://github.com/traefik/traefik/pull/12710) @gndz07)
- **[k8s/ingress-nginx]** Support server-alias annotation for Ingress NGINX ([#12707](https://github.com/traefik/traefik/pull/12707) @amazon7737)
- **[k8s/ingress-nginx]** Support upstream-keepalive-timeout ([#12708](https://github.com/traefik/traefik/pull/12708) @jcob-sikorski)
- **[k8s/ingress-nginx]** Add support for variable interpolation in auth-signin NGINX annotation ([#12640](https://github.com/traefik/traefik/pull/12640) @LBF38)
- **[k8s/ingress-nginx]** Implement server-snippet and configuration-snippet annotations ([#12715](https://github.com/traefik/traefik/pull/12715) @juliens)
- **[k8s/ingress-nginx]** Add custom-http-errors and default-backend annotations ([#12637](https://github.com/traefik/traefik/pull/12637) @juliens)
- **[k8s/ingress-nginx]** Support auth-tls-pass-certificate-to-upstream annotation ([#12629](https://github.com/traefik/traefik/pull/12629) @gndz07)
- **[metrics]** Support file path for metrics.influxdb2.token option ([#12458](https://github.com/traefik/traefik/pull/12458) @barhun)
- **[middleware]** Add encodedCharacters middleware ([#12555](https://github.com/traefik/traefik/pull/12555) @gndz07)
- **[middleware]** Enable retries based on HTTP response status codes, timeout, and non-idempotent methods ([#12667](https://github.com/traefik/traefik/pull/12667) @LBF38)
- **[middleware, authentication]** Add authSignInURL in forward auth middleware ([#12293](https://github.com/traefik/traefik/pull/12293) @kyounghunJang)
- **[server]** Add global option to disable X-Forwarded-For appending ([#12374](https://github.com/traefik/traefik/pull/12374) @lbenguigui)
- **[server]** Replace Split in loops with more efficient SplitSeq ([#12316](https://github.com/traefik/traefik/pull/12316) @boqishan)
- **[service]** Failover according to response status code ([#12596](https://github.com/traefik/traefik/pull/12596) @lbenguigui)
- **[tls]** Make TLSStore gracefully handle missing secrets ([#12522](https://github.com/traefik/traefik/pull/12522) @david-garcia-garcia)
- **[webui]** Add dashboard name configuration ([#12410](https://github.com/traefik/traefik/pull/12410) @gndz07)
- **[webui]** Web UI dashboard improvements ([#12236](https://github.com/traefik/traefik/pull/12236) @gndz07)
- **[webui]** Details pages UI improvement ([#12377](https://github.com/traefik/traefik/pull/12377) @gndz07)
- Use unicode.MaxASCII for clearer ASCII check ([#12741](https://github.com/traefik/traefik/pull/12741) @1911860538)
**Bug fixes:**
- **[k8s/ingress-nginx]** Add ipAllowListStrategy option for allowlist/whitelist annotations ([#12932](https://github.com/traefik/traefik/pull/12932) @mathieuherbert)
@@ -125,77 +292,77 @@
- **[http]** Add maxResponseBodySize configuration on HTTP provider ([#12788](https://github.com/traefik/traefik/pull/12788) @gndz07)
- **[tls]** Support fragmented TLS client hello ([#12787](https://github.com/traefik/traefik/pull/12787) @rtribotte)
- **[middleware, authentication]** Make basic auth check timing constant ([#12803](https://github.com/traefik/traefik/pull/12803) @rtribotte)
- **[acme]** Add missing renew options ([#12467](https://github.com/traefik/traefik/pull/12467) by [ldez](https://github.com/ldez))
- **[acme]** Add timeout to ACME-TLS/1 challenge handshake ([#12516](https://github.com/traefik/traefik/pull/12516) by [LBF38](https://github.com/LBF38))
- **[acme]** Alter TLS renewal period ([#12479](https://github.com/traefik/traefik/pull/12479) by [LtHummus](https://github.com/LtHummus))
- **[acme]** Bump github.com/go-acme/lego/v4 to v4.28.0 ([#12218](https://github.com/traefik/traefik/pull/12218) by [ldez](https://github.com/ldez))
- **[acme]** Bump github.com/go-acme/lego/v4 to v4.29.0 ([#12333](https://github.com/traefik/traefik/pull/12333) by [ldez](https://github.com/ldez))
- **[acme]** Bump github.com/go-acme/lego/v4 to v4.30.1 ([#12432](https://github.com/traefik/traefik/pull/12432) by [ldez](https://github.com/ldez))
- **[acme]** Bump github.com/go-acme/lego/v4 to v4.31.0 ([#12529](https://github.com/traefik/traefik/pull/12529) by [ldez](https://github.com/ldez))
- **[acme]** Bump github.com/go-acme/lego/v4 to v4.32.0 ([#12702](https://github.com/traefik/traefik/pull/12702) by [ldez](https://github.com/ldez))
- **[acme]** Remove invalid private key in log ([#12574](https://github.com/traefik/traefik/pull/12574) by [juliens](https://github.com/juliens))
- **[acme]** Replace hardcoded references to LetsEncrypt in log messages ([#12464](https://github.com/traefik/traefik/pull/12464) by [schildbach](https://github.com/schildbach))
- **[cli]** Fix health check ping ([#12512](https://github.com/traefik/traefik/pull/12512) by [olamilekan000](https://github.com/olamilekan000))
- **[docker]** Auto-negotiate Docker API Version ([#12256](https://github.com/traefik/traefik/pull/12256) by [felixbuenemann](https://github.com/felixbuenemann))
- **[docker]** Bump Docker and OpenTelemetry dependencies ([#12761](https://github.com/traefik/traefik/pull/12761) by [mmatur](https://github.com/mmatur))
- **[docker, docker/swarm]** Auto-negotiate Docker API version ([#12262](https://github.com/traefik/traefik/pull/12262) by [kevinpollet](https://github.com/kevinpollet))
- **[fastproxy]** Bump github.com/valyala/fasthttp to v1.69.0 ([#12763](https://github.com/traefik/traefik/pull/12763) by [kevinpollet](https://github.com/kevinpollet))
- **[healthcheck]** Reject absolute URL in healthcheck path configuration ([#12653](https://github.com/traefik/traefik/pull/12653) by [rtribotte](https://github.com/rtribotte))
- **[healthcheck]** Validate healthcheck path configuration ([#12642](https://github.com/traefik/traefik/pull/12642) by [rtribotte](https://github.com/rtribotte))
- **[healthcheck, grpc]** Remove path parsing with grpc healthcheck ([#12760](https://github.com/traefik/traefik/pull/12760) by [rtribotte](https://github.com/rtribotte))
- **[http3]** Bump github.com/quic-go/quic-go to v0.57.0 ([#12308](https://github.com/traefik/traefik/pull/12308) by [GreyXor](https://github.com/GreyXor))
- **[http3]** Bump github.com/quic-go/quic-go to v0.57.1 ([#12319](https://github.com/traefik/traefik/pull/12319) by [GreyXor](https://github.com/GreyXor))
- **[http3]** Bump github.com/quic-go/quic-go to v0.58.0 ([#12448](https://github.com/traefik/traefik/pull/12448) by [GreyXor](https://github.com/GreyXor))
- **[http3]** Bump github.com/quic-go/quic-go to v0.59.0 ([#12553](https://github.com/traefik/traefik/pull/12553) by [jnoordsij](https://github.com/jnoordsij))
- **[k8s]** Fix condition used for serving and fenced endpoints ([#12521](https://github.com/traefik/traefik/pull/12521) by [LBF38](https://github.com/LBF38))
- **[k8s/gatewayapi]** Fix Gateway API router's rules ([#12753](https://github.com/traefik/traefik/pull/12753) by [rtribotte](https://github.com/rtribotte))
- **[k8s/ingress]** Fix panic for empty defaultBackend and defaultBackend without resources ([#12509](https://github.com/traefik/traefik/pull/12509) by [gndz07](https://github.com/gndz07))
- **[k8s/ingress-nginx]** Add AllowCrossNamespaceResources and GlobalAllowedResponseHeader options to control custom headers annotations ([#12680](https://github.com/traefik/traefik/pull/12680) by [rtribotte](https://github.com/rtribotte))
- **[k8s/ingress-nginx]** Deprecate Kubernetes Ingress NGINX provider experimental flag ([#12286](https://github.com/traefik/traefik/pull/12286) by [rtribotte](https://github.com/rtribotte))
- **[k8s/ingress-nginx]** Fix nginx rewrite target ([#12730](https://github.com/traefik/traefik/pull/12730) by [mmatur](https://github.com/mmatur))
- **[k8s/ingress-nginx]** Fix NGINX sslredirect annotation support ([#12387](https://github.com/traefik/traefik/pull/12387) by [rtribotte](https://github.com/rtribotte))
- **[k8s/ingress-nginx]** Fix nginx.ingress.kubernetes.io/proxy-ssl-verify annotation support ([#12351](https://github.com/traefik/traefik/pull/12351) by [rtribotte](https://github.com/rtribotte))
- **[k8s/ingress-nginx]** Fix SSL redirect to match NGINX behavior ([#12361](https://github.com/traefik/traefik/pull/12361) by [mmatur](https://github.com/mmatur))
- **[k8s/ingress-nginx]** Fix the service name for ingress-nginx provider ([#12352](https://github.com/traefik/traefik/pull/12352) by [mmatur](https://github.com/mmatur))
- **[k8s/ingress-nginx]** Fix use-regex nginx annotation ([#12531](https://github.com/traefik/traefik/pull/12531) by [LBF38](https://github.com/LBF38))
- **[k8s/ingress-nginx]** Prevent Ingress Nginx provider http router to attach to an entrypoint with TLS ([#12528](https://github.com/traefik/traefik/pull/12528) by [rtribotte](https://github.com/rtribotte))
- **[metrics, tracing, accesslogs]** Fix ObservabilityConfig SetDefaults ([#12636](https://github.com/traefik/traefik/pull/12636) by [mmatur](https://github.com/mmatur))
- **[middleware]** Fix case sensitivity on x-forwarded headers for Connection ([#12690](https://github.com/traefik/traefik/pull/12690) by [LBF38](https://github.com/LBF38))
- **[middleware]** Fix HasSecureHeadersDefined returning false when stsSeconds is 0 ([#12684](https://github.com/traefik/traefik/pull/12684) by [veeceey](https://github.com/veeceey))
- **[middleware, authentication]** Add maxResponseBodySize configuration to forwardAuth middleware ([#12694](https://github.com/traefik/traefik/pull/12694) by [gndz07](https://github.com/gndz07))
- **[middleware, authentication]** Change ForwardAuth error log level from DEBUG to ERROR ([#12324](https://github.com/traefik/traefik/pull/12324) by [murataslan1](https://github.com/murataslan1))
- **[middleware, authentication]** Handle empty/missing User-Agent header ([#12545](https://github.com/traefik/traefik/pull/12545) by [a-stangl](https://github.com/a-stangl))
- **[middleware, k8s, k8s/ingress-nginx]** Fix from to www nginx annotation ([#12736](https://github.com/traefik/traefik/pull/12736) by [mmatur](https://github.com/mmatur))
- **[middleware, k8s/ingress-nginx]** Fix custom error pages behavior for ingress-nginx provider ([#12738](https://github.com/traefik/traefik/pull/12738) by [mmatur](https://github.com/mmatur))
- **[otel]** Bump go.opentelemetry.io/otel dependencies ([#12754](https://github.com/traefik/traefik/pull/12754) by [rtribotte](https://github.com/rtribotte))
- **[plugins]** Validate plugin module name ([#12291](https://github.com/traefik/traefik/pull/12291) by [kevinpollet](https://github.com/kevinpollet))
- **[redis]** Fix mutually exclusive verification for Redis ([#12442](https://github.com/traefik/traefik/pull/12442) by [juliens](https://github.com/juliens))
- **[server]** Bump golang.org/x/crypto to v0.45.0 ([#12296](https://github.com/traefik/traefik/pull/12296) by [kevinpollet](https://github.com/kevinpollet))
- **[server]** Bump golang.org/x/net to v0.51.0 ([#12756](https://github.com/traefik/traefik/pull/12756) by [kevinpollet](https://github.com/kevinpollet))
- **[server]** Filter unknown nodes with file and env for the deprecation loader ([#12227](https://github.com/traefik/traefik/pull/12227) by [rtribotte](https://github.com/rtribotte))
- **[server]** Fix deny encoded characters ([#12454](https://github.com/traefik/traefik/pull/12454) by [rtribotte](https://github.com/rtribotte))
- **[server]** Fix deny encoded characters ([#12457](https://github.com/traefik/traefik/pull/12457) by [rtribotte](https://github.com/rtribotte))
- **[server]** Fix multi-layer routing with models ([#12258](https://github.com/traefik/traefik/pull/12258) by [juliens](https://github.com/juliens))
- **[server]** Fix TLS handshake error handling ([#12692](https://github.com/traefik/traefik/pull/12692) by [juliens](https://github.com/juliens))
- **[server]** Make encoded character options opt-in ([#12540](https://github.com/traefik/traefik/pull/12540) by [gndz07](https://github.com/gndz07))
- **[server]** Make the aggregator compute provider namespace for router's parentRefs ([#12235](https://github.com/traefik/traefik/pull/12235) by [rtribotte](https://github.com/rtribotte))
- **[server]** Print access logs for rejected requests and warn about new behavior ([#12424](https://github.com/traefik/traefik/pull/12424) by [kevinpollet](https://github.com/kevinpollet))
- **[server]** Print access logs for rejected requests and warn about new behavior ([#12426](https://github.com/traefik/traefik/pull/12426) by [rtribotte](https://github.com/rtribotte))
- **[server]** Reject suspicious encoded characters ([#12360](https://github.com/traefik/traefik/pull/12360) by [rtribotte](https://github.com/rtribotte))
- **[server]** Remove conn deadline after STARTTLS negociation ([#12639](https://github.com/traefik/traefik/pull/12639) by [rtribotte](https://github.com/rtribotte))
- **[service]** Avoid recursion with services ([#12591](https://github.com/traefik/traefik/pull/12591) by [juliens](https://github.com/juliens))
- **[tls]** Fix verifyServerCertMatchesURI function behavior ([#12575](https://github.com/traefik/traefik/pull/12575) by [kevinpollet](https://github.com/kevinpollet))
- **[tls, server]** Cap TLS record length to RFC 8446 limit in ClientHello peeking ([#12638](https://github.com/traefik/traefik/pull/12638) by [mmatur](https://github.com/mmatur))
- **[tracing, otel]** Use ParentBased sampler to respect parent span sampling decision ([#12403](https://github.com/traefik/traefik/pull/12403) by [xe-leon](https://github.com/xe-leon))
- **[udp]** Revert "Avoid allocations in readLoop by using sync.Pool" ([#12267](https://github.com/traefik/traefik/pull/12267) by [kevinpollet](https://github.com/kevinpollet))
- **[webui]** Bump dependencies of documentation and webui ([#12581](https://github.com/traefik/traefik/pull/12581) by [gndz07](https://github.com/gndz07))
- **[webui]** Fix basePath validation for dashboard template ([#12729](https://github.com/traefik/traefik/pull/12729) by [gndz07](https://github.com/gndz07))
- **[webui]** Fix blocked navigation on Safari ([#12231](https://github.com/traefik/traefik/pull/12231) by [gndz07](https://github.com/gndz07))
- **[webui]** Fix missing type definition ([#12780](https://github.com/traefik/traefik/pull/12780) by [gndz07](https://github.com/gndz07))
- **[webui]** Fix priority display in dashboard and ACME bypass redirect ([#12740](https://github.com/traefik/traefik/pull/12740) by [mmatur](https://github.com/mmatur))
- **[webui]** Restore remote Upgrade to Hub button web component ([#12219](https://github.com/traefik/traefik/pull/12219) by [gndz07](https://github.com/gndz07))
- **[webui]** Use url.Parse to validate X-Forwarded-Prefix value ([#12643](https://github.com/traefik/traefik/pull/12643) by [kevinpollet](https://github.com/kevinpollet))
- **[webui]** Validate X-Forwarded-Prefix value for dashboard redirect ([#12514](https://github.com/traefik/traefik/pull/12514) by [LBF38](https://github.com/LBF38))
- **[acme]** Add missing renew options ([#12467](https://github.com/traefik/traefik/pull/12467) @ldez)
- **[acme]** Add timeout to ACME-TLS/1 challenge handshake ([#12516](https://github.com/traefik/traefik/pull/12516) @LBF38)
- **[acme]** Alter TLS renewal period ([#12479](https://github.com/traefik/traefik/pull/12479) @LtHummus)
- **[acme]** Bump github.com/go-acme/lego/v4 to v4.28.0 ([#12218](https://github.com/traefik/traefik/pull/12218) @ldez)
- **[acme]** Bump github.com/go-acme/lego/v4 to v4.29.0 ([#12333](https://github.com/traefik/traefik/pull/12333) @ldez)
- **[acme]** Bump github.com/go-acme/lego/v4 to v4.30.1 ([#12432](https://github.com/traefik/traefik/pull/12432) @ldez)
- **[acme]** Bump github.com/go-acme/lego/v4 to v4.31.0 ([#12529](https://github.com/traefik/traefik/pull/12529) @ldez)
- **[acme]** Bump github.com/go-acme/lego/v4 to v4.32.0 ([#12702](https://github.com/traefik/traefik/pull/12702) @ldez)
- **[acme]** Remove invalid private key in log ([#12574](https://github.com/traefik/traefik/pull/12574) @juliens)
- **[acme]** Replace hardcoded references to LetsEncrypt in log messages ([#12464](https://github.com/traefik/traefik/pull/12464) @schildbach)
- **[cli]** Fix health check ping ([#12512](https://github.com/traefik/traefik/pull/12512) @olamilekan000)
- **[docker]** Auto-negotiate Docker API Version ([#12256](https://github.com/traefik/traefik/pull/12256) @felixbuenemann)
- **[docker]** Bump Docker and OpenTelemetry dependencies ([#12761](https://github.com/traefik/traefik/pull/12761) @mmatur)
- **[docker, docker/swarm]** Auto-negotiate Docker API version ([#12262](https://github.com/traefik/traefik/pull/12262) @kevinpollet)
- **[fastproxy]** Bump github.com/valyala/fasthttp to v1.69.0 ([#12763](https://github.com/traefik/traefik/pull/12763) @kevinpollet)
- **[healthcheck]** Reject absolute URL in healthcheck path configuration ([#12653](https://github.com/traefik/traefik/pull/12653) @rtribotte)
- **[healthcheck]** Validate healthcheck path configuration ([#12642](https://github.com/traefik/traefik/pull/12642) @rtribotte)
- **[healthcheck, grpc]** Remove path parsing with grpc healthcheck ([#12760](https://github.com/traefik/traefik/pull/12760) @rtribotte)
- **[http3]** Bump github.com/quic-go/quic-go to v0.57.0 ([#12308](https://github.com/traefik/traefik/pull/12308) @GreyXor)
- **[http3]** Bump github.com/quic-go/quic-go to v0.57.1 ([#12319](https://github.com/traefik/traefik/pull/12319) @GreyXor)
- **[http3]** Bump github.com/quic-go/quic-go to v0.58.0 ([#12448](https://github.com/traefik/traefik/pull/12448) @GreyXor)
- **[http3]** Bump github.com/quic-go/quic-go to v0.59.0 ([#12553](https://github.com/traefik/traefik/pull/12553) @jnoordsij)
- **[k8s]** Fix condition used for serving and fenced endpoints ([#12521](https://github.com/traefik/traefik/pull/12521) @LBF38)
- **[k8s/gatewayapi]** Fix Gateway API router's rules ([#12753](https://github.com/traefik/traefik/pull/12753) @rtribotte)
- **[k8s/ingress]** Fix panic for empty defaultBackend and defaultBackend without resources ([#12509](https://github.com/traefik/traefik/pull/12509) @gndz07)
- **[k8s/ingress-nginx]** Add AllowCrossNamespaceResources and GlobalAllowedResponseHeader options to control custom headers annotations ([#12680](https://github.com/traefik/traefik/pull/12680) @rtribotte)
- **[k8s/ingress-nginx]** Deprecate Kubernetes Ingress NGINX provider experimental flag ([#12286](https://github.com/traefik/traefik/pull/12286) @rtribotte)
- **[k8s/ingress-nginx]** Fix nginx rewrite target ([#12730](https://github.com/traefik/traefik/pull/12730) @mmatur)
- **[k8s/ingress-nginx]** Fix NGINX sslredirect annotation support ([#12387](https://github.com/traefik/traefik/pull/12387) @rtribotte)
- **[k8s/ingress-nginx]** Fix nginx.ingress.kubernetes.io/proxy-ssl-verify annotation support ([#12351](https://github.com/traefik/traefik/pull/12351) @rtribotte)
- **[k8s/ingress-nginx]** Fix SSL redirect to match NGINX behavior ([#12361](https://github.com/traefik/traefik/pull/12361) @mmatur)
- **[k8s/ingress-nginx]** Fix the service name for ingress-nginx provider ([#12352](https://github.com/traefik/traefik/pull/12352) @mmatur)
- **[k8s/ingress-nginx]** Fix use-regex nginx annotation ([#12531](https://github.com/traefik/traefik/pull/12531) @LBF38)
- **[k8s/ingress-nginx]** Prevent Ingress Nginx provider http router to attach to an entrypoint with TLS ([#12528](https://github.com/traefik/traefik/pull/12528) @rtribotte)
- **[metrics, tracing, accesslogs]** Fix ObservabilityConfig SetDefaults ([#12636](https://github.com/traefik/traefik/pull/12636) @mmatur)
- **[middleware]** Fix case sensitivity on x-forwarded headers for Connection ([#12690](https://github.com/traefik/traefik/pull/12690) @LBF38)
- **[middleware]** Fix HasSecureHeadersDefined returning false when stsSeconds is 0 ([#12684](https://github.com/traefik/traefik/pull/12684) @veeceey)
- **[middleware, authentication]** Add maxResponseBodySize configuration to forwardAuth middleware ([#12694](https://github.com/traefik/traefik/pull/12694) @gndz07)
- **[middleware, authentication]** Change ForwardAuth error log level from DEBUG to ERROR ([#12324](https://github.com/traefik/traefik/pull/12324) @murataslan1)
- **[middleware, authentication]** Handle empty/missing User-Agent header ([#12545](https://github.com/traefik/traefik/pull/12545) @a-stangl)
- **[middleware, k8s, k8s/ingress-nginx]** Fix from to www nginx annotation ([#12736](https://github.com/traefik/traefik/pull/12736) @mmatur)
- **[middleware, k8s/ingress-nginx]** Fix custom error pages behavior for ingress-nginx provider ([#12738](https://github.com/traefik/traefik/pull/12738) @mmatur)
- **[otel]** Bump go.opentelemetry.io/otel dependencies ([#12754](https://github.com/traefik/traefik/pull/12754) @rtribotte)
- **[plugins]** Validate plugin module name ([#12291](https://github.com/traefik/traefik/pull/12291) @kevinpollet)
- **[redis]** Fix mutually exclusive verification for Redis ([#12442](https://github.com/traefik/traefik/pull/12442) @juliens)
- **[server]** Bump golang.org/x/crypto to v0.45.0 ([#12296](https://github.com/traefik/traefik/pull/12296) @kevinpollet)
- **[server]** Bump golang.org/x/net to v0.51.0 ([#12756](https://github.com/traefik/traefik/pull/12756) @kevinpollet)
- **[server]** Filter unknown nodes with file and env for the deprecation loader ([#12227](https://github.com/traefik/traefik/pull/12227) @rtribotte)
- **[server]** Fix deny encoded characters ([#12454](https://github.com/traefik/traefik/pull/12454) @rtribotte)
- **[server]** Fix deny encoded characters ([#12457](https://github.com/traefik/traefik/pull/12457) @rtribotte)
- **[server]** Fix multi-layer routing with models ([#12258](https://github.com/traefik/traefik/pull/12258) @juliens)
- **[server]** Fix TLS handshake error handling ([#12692](https://github.com/traefik/traefik/pull/12692) @juliens)
- **[server]** Make encoded character options opt-in ([#12540](https://github.com/traefik/traefik/pull/12540) @gndz07)
- **[server]** Make the aggregator compute provider namespace for router's parentRefs ([#12235](https://github.com/traefik/traefik/pull/12235) @rtribotte)
- **[server]** Print access logs for rejected requests and warn about new behavior ([#12424](https://github.com/traefik/traefik/pull/12424) @kevinpollet)
- **[server]** Print access logs for rejected requests and warn about new behavior ([#12426](https://github.com/traefik/traefik/pull/12426) @rtribotte)
- **[server]** Reject suspicious encoded characters ([#12360](https://github.com/traefik/traefik/pull/12360) @rtribotte)
- **[server]** Remove conn deadline after STARTTLS negociation ([#12639](https://github.com/traefik/traefik/pull/12639) @rtribotte)
- **[service]** Avoid recursion with services ([#12591](https://github.com/traefik/traefik/pull/12591) @juliens)
- **[tls]** Fix verifyServerCertMatchesURI function behavior ([#12575](https://github.com/traefik/traefik/pull/12575) @kevinpollet)
- **[tls, server]** Cap TLS record length to RFC 8446 limit in ClientHello peeking ([#12638](https://github.com/traefik/traefik/pull/12638) @mmatur)
- **[tracing, otel]** Use ParentBased sampler to respect parent span sampling decision ([#12403](https://github.com/traefik/traefik/pull/12403) @xe-leon)
- **[udp]** Revert "Avoid allocations in readLoop by using sync.Pool" ([#12267](https://github.com/traefik/traefik/pull/12267) @kevinpollet)
- **[webui]** Bump dependencies of documentation and webui ([#12581](https://github.com/traefik/traefik/pull/12581) @gndz07)
- **[webui]** Fix basePath validation for dashboard template ([#12729](https://github.com/traefik/traefik/pull/12729) @gndz07)
- **[webui]** Fix blocked navigation on Safari ([#12231](https://github.com/traefik/traefik/pull/12231) @gndz07)
- **[webui]** Fix missing type definition ([#12780](https://github.com/traefik/traefik/pull/12780) @gndz07)
- **[webui]** Fix priority display in dashboard and ACME bypass redirect ([#12740](https://github.com/traefik/traefik/pull/12740) @mmatur)
- **[webui]** Restore remote Upgrade to Hub button web component ([#12219](https://github.com/traefik/traefik/pull/12219) @gndz07)
- **[webui]** Use url.Parse to validate X-Forwarded-Prefix value ([#12643](https://github.com/traefik/traefik/pull/12643) @kevinpollet)
- **[webui]** Validate X-Forwarded-Prefix value for dashboard redirect ([#12514](https://github.com/traefik/traefik/pull/12514) @LBF38)
**Documentation:**
- **[service]** Service-level Middleware Documentation ([#13095](https://github.com/traefik/traefik/pull/13095) @nmengin)
@@ -225,69 +392,69 @@
- Fix start up message format ([#12806](https://github.com/traefik/traefik/pull/12806) @mloiseleur)
- Remove unsupported servers[n].address from TCP label examples ([#12817](https://github.com/traefik/traefik/pull/12817) @sheddy-traefik)
- Bump mkdocs-traefiklabs to use consent mode ([#12804](https://github.com/traefik/traefik/pull/12804) @darkweaver87)
- **[acme]** Add missing ACME options and clean up table for more visibility ([#12208](https://github.com/traefik/traefik/pull/12208) by [sheddy-traefik](https://github.com/sheddy-traefik))
- **[api]** Fix typo in API dashboard configuration instructions ([#12335](https://github.com/traefik/traefik/pull/12335) by [NAICOLAS](https://github.com/NAICOLAS))
- **[docker]** Add documentation for loadbalancer.server.url in Docker and Swarm providers ([#12289](https://github.com/traefik/traefik/pull/12289) by [webash](https://github.com/webash))
- **[docker]** Update docker in-depth setup guide ([#12682](https://github.com/traefik/traefik/pull/12682) by [mdevino](https://github.com/mdevino))
- **[docker/swarm]** Update swarm.md traefik version ([#12508](https://github.com/traefik/traefik/pull/12508) by [DBouraoui](https://github.com/DBouraoui))
- **[k8s]** Fix Gateway API version and the list of features supported ([#12254](https://github.com/traefik/traefik/pull/12254) by [nmengin](https://github.com/nmengin))
- **[k8s]** Fix Kubernetes reference yml file ([#12406](https://github.com/traefik/traefik/pull/12406) by [mmatur](https://github.com/mmatur))
- **[k8s]** Fix kubernetes.md with correct http redirections ([#12603](https://github.com/traefik/traefik/pull/12603) by [MartenM](https://github.com/MartenM))
- **[k8s]** Fix Nginx provider documentation ([#12266](https://github.com/traefik/traefik/pull/12266) by [nmengin](https://github.com/nmengin))
- **[k8s]** Improve the K8S multi-tenancy security note ([#12444](https://github.com/traefik/traefik/pull/12444) by [nmengin](https://github.com/nmengin))
- **[k8s]** Make labelSelector option casing more consistent ([#12658](https://github.com/traefik/traefik/pull/12658) by [holysoles](https://github.com/holysoles))
- **[k8s, k8s/ingress-nginx]** Add configmaps right to Ingress NGINX RBAC ([#12557](https://github.com/traefik/traefik/pull/12557) by [kevinpollet](https://github.com/kevinpollet))
- **[k8s/gatewayapi]** Fix links of Helm chart values reference to providers.kubernetesGateway.enabled ([#12315](https://github.com/traefik/traefik/pull/12315) by [shouhei](https://github.com/shouhei))
- **[k8s/ingress, k8s]** Fix Kubernetes Ingress provider documentation ([#12443](https://github.com/traefik/traefik/pull/12443) by [nmengin](https://github.com/nmengin))
- **[k8s/ingress-nginx]** Add auth-signin to unsupported nginx annotations list ([#12370](https://github.com/traefik/traefik/pull/12370) by [fibsifan](https://github.com/fibsifan))
- **[k8s/ingress-nginx]** Add RBAC documentation for Ingress NGINX provider ([#12445](https://github.com/traefik/traefik/pull/12445) by [nmn3m](https://github.com/nmn3m))
- **[k8s/ingress-nginx]** Add temporary note to advertise the incoming NGINX annotations ([#12699](https://github.com/traefik/traefik/pull/12699) by [nmengin](https://github.com/nmengin))
- **[k8s/ingress-nginx]** Fix default value of ingress-nginx provider in documentation ([#12328](https://github.com/traefik/traefik/pull/12328) by [mloiseleur](https://github.com/mloiseleur))
- **[k8s/ingress-nginx]** Fix ingress-nginx annotations documentation ([#12510](https://github.com/traefik/traefik/pull/12510) by [nmengin](https://github.com/nmengin))
- **[k8s/ingress-nginx]** Improve ingress-nginx provider documentation ([#12288](https://github.com/traefik/traefik/pull/12288) by [sheddy-traefik](https://github.com/sheddy-traefik))
- **[k8s/ingress-nginx]** Improve the configuration options display of the Kubernetes ingress-nginx provider ([#12297](https://github.com/traefik/traefik/pull/12297) by [mloiseleur](https://github.com/mloiseleur))
- **[k8s/ingress-nginx]** NGINX Ingress Controller to Traefik Migration Guide ([#12318](https://github.com/traefik/traefik/pull/12318) by [sheddy-traefik](https://github.com/sheddy-traefik))
- **[middleware]** Correct documentation for Digest auth ([#12651](https://github.com/traefik/traefik/pull/12651) by [Zash](https://github.com/Zash))
- **[middleware]** Fix default encodings in compress middleware ([#12216](https://github.com/traefik/traefik/pull/12216) by [Belphemur](https://github.com/Belphemur))
- **[middleware, k8s/crd]** Fix the errors middleware's document for Kubernetes CRD ([#12600](https://github.com/traefik/traefik/pull/12600) by [yuito-it](https://github.com/yuito-it))
- **[service]** Fix loadbalancer doc for highest random weight ([#12283](https://github.com/traefik/traefik/pull/12283) by [ozon2](https://github.com/ozon2))
- **[tls]** Clarify SNI selection ([#12482](https://github.com/traefik/traefik/pull/12482) by [AnuragEkkati](https://github.com/AnuragEkkati))
- Add @gndz07 as a current maintainer ([#12594](https://github.com/traefik/traefik/pull/12594) by [emilevauge](https://github.com/emilevauge))
- Add a Breaking change note to the changelog ([#12398](https://github.com/traefik/traefik/pull/12398) by [nmengin](https://github.com/nmengin))
- Add documentation about checkNewVersion ([#12298](https://github.com/traefik/traefik/pull/12298) by [darkweaver87](https://github.com/darkweaver87))
- Add missing `.http` to TOML table names ([#12713](https://github.com/traefik/traefik/pull/12713) by [Darsstar](https://github.com/Darsstar))
- Add product comparison matrix and features page ([#12037](https://github.com/traefik/traefik/pull/12037) by [sheddy-traefik](https://github.com/sheddy-traefik))
- Bring back security section on API & Dashboard documentation page ([#12507](https://github.com/traefik/traefik/pull/12507) by [gndz07](https://github.com/gndz07))
- Clarify doc about encoded characters rejection ([#12391](https://github.com/traefik/traefik/pull/12391) by [rtribotte](https://github.com/rtribotte))
- Clean Up Menu Entries & Update Expose Overview ([#12405](https://github.com/traefik/traefik/pull/12405) by [sheddy-traefik](https://github.com/sheddy-traefik))
- Correct encoded characters allowance in entrypoints.md ([#12679](https://github.com/traefik/traefik/pull/12679) by [Apflkuacha](https://github.com/Apflkuacha))
- Correctly Format the HTTP Service Documentation ([#12311](https://github.com/traefik/traefik/pull/12311) by [sheddy-traefik](https://github.com/sheddy-traefik))
- Document negative priority support for routers ([#12505](https://github.com/traefik/traefik/pull/12505) by [understood-the-assignment](https://github.com/understood-the-assignment))
- Document Path matcher placeholder removal in v3 migration guide ([#12570](https://github.com/traefik/traefik/pull/12570) by [sheddy-traefik](https://github.com/sheddy-traefik))
- Fix API basepath option documentation ([#12744](https://github.com/traefik/traefik/pull/12744) by [nmengin](https://github.com/nmengin))
- Fix broken links in TCP Service and HTTP Router documentation ([#12215](https://github.com/traefik/traefik/pull/12215) by [sheddy-traefik](https://github.com/sheddy-traefik))
- Fix code copy button positioning ([#12520](https://github.com/traefik/traefik/pull/12520) by [AnuragEkkati](https://github.com/AnuragEkkati))
- Fix encoded characters entryPoint option documentation ([#12384](https://github.com/traefik/traefik/pull/12384) by [rtribotte](https://github.com/rtribotte))
- Fix encoded characters option documentation ([#12373](https://github.com/traefik/traefik/pull/12373) by [kevinpollet](https://github.com/kevinpollet))
- Fix encodedCharacters entryPoint option documentation ([#12385](https://github.com/traefik/traefik/pull/12385) by [rtribotte](https://github.com/rtribotte))
- Fix incorrect TOML example in entrypoints docs ([#12711](https://github.com/traefik/traefik/pull/12711) by [mfmfuyu](https://github.com/mfmfuyu))
- Fix link description in Traefik Proxy documentation ([#12488](https://github.com/traefik/traefik/pull/12488) by [schaerfo](https://github.com/schaerfo))
- Fix Menu Item Naming ([#12431](https://github.com/traefik/traefik/pull/12431) by [sheddy-traefik](https://github.com/sheddy-traefik))
- Fix migration guide indentation ([#12365](https://github.com/traefik/traefik/pull/12365) by [kevinpollet](https://github.com/kevinpollet))
- Fix migration guide URLs in deprecation notice ([#12430](https://github.com/traefik/traefik/pull/12430) by [alexmar07](https://github.com/alexmar07))
- Fix typo in kubernetes.md ([#12515](https://github.com/traefik/traefik/pull/12515) by [EdwardSalkeld](https://github.com/EdwardSalkeld))
- Fix typo in v3.6 migration guide ([#12212](https://github.com/traefik/traefik/pull/12212) by [jnoordsij](https://github.com/jnoordsij))
- Fix typo on JWT documentation ([#12616](https://github.com/traefik/traefik/pull/12616) by [mdevino](https://github.com/mdevino))
- Improve Service Reference page ([#12541](https://github.com/traefik/traefik/pull/12541) by [sheddy-traefik](https://github.com/sheddy-traefik))
- Improve the structure of the routing reference pages ([#12429](https://github.com/traefik/traefik/pull/12429) by [sheddy-traefik](https://github.com/sheddy-traefik))
- Increased content width in documentation ([#12632](https://github.com/traefik/traefik/pull/12632) by [tobiasge](https://github.com/tobiasge))
- Remove extra dots in migration guide ([#12573](https://github.com/traefik/traefik/pull/12573) by [rtribotte](https://github.com/rtribotte))
- Remove extraneous dots in migration guide ([#12571](https://github.com/traefik/traefik/pull/12571) by [dathbe](https://github.com/dathbe))
- Restore documentation on http.maxHeaderBytes ([#12440](https://github.com/traefik/traefik/pull/12440) by [mloiseleur](https://github.com/mloiseleur))
- Split Expose User Guides & Add Multi-Layer Routing Section ([#12238](https://github.com/traefik/traefik/pull/12238) by [sheddy-traefik](https://github.com/sheddy-traefik))
- Update Configuration Overview Page ([#12202](https://github.com/traefik/traefik/pull/12202) by [sheddy-traefik](https://github.com/sheddy-traefik))
- Update SECURITY.md ([#12304](https://github.com/traefik/traefik/pull/12304) by [cwayne18](https://github.com/cwayne18))
- Update SECURITY.md to streamline information ([#12310](https://github.com/traefik/traefik/pull/12310) by [emilevauge](https://github.com/emilevauge))
- **[acme]** Add missing ACME options and clean up table for more visibility ([#12208](https://github.com/traefik/traefik/pull/12208) @sheddy-traefik)
- **[api]** Fix typo in API dashboard configuration instructions ([#12335](https://github.com/traefik/traefik/pull/12335) @NAICOLAS)
- **[docker]** Add documentation for loadbalancer.server.url in Docker and Swarm providers ([#12289](https://github.com/traefik/traefik/pull/12289) @webash)
- **[docker]** Update docker in-depth setup guide ([#12682](https://github.com/traefik/traefik/pull/12682) @mdevino)
- **[docker/swarm]** Update swarm.md traefik version ([#12508](https://github.com/traefik/traefik/pull/12508) @DBouraoui)
- **[k8s]** Fix Gateway API version and the list of features supported ([#12254](https://github.com/traefik/traefik/pull/12254) @nmengin)
- **[k8s]** Fix Kubernetes reference yml file ([#12406](https://github.com/traefik/traefik/pull/12406) @mmatur)
- **[k8s]** Fix kubernetes.md with correct http redirections ([#12603](https://github.com/traefik/traefik/pull/12603) @MartenM)
- **[k8s]** Fix Nginx provider documentation ([#12266](https://github.com/traefik/traefik/pull/12266) @nmengin)
- **[k8s]** Improve the K8S multi-tenancy security note ([#12444](https://github.com/traefik/traefik/pull/12444) @nmengin)
- **[k8s]** Make labelSelector option casing more consistent ([#12658](https://github.com/traefik/traefik/pull/12658) @holysoles)
- **[k8s, k8s/ingress-nginx]** Add configmaps right to Ingress NGINX RBAC ([#12557](https://github.com/traefik/traefik/pull/12557) @kevinpollet)
- **[k8s/gatewayapi]** Fix links of Helm chart values reference to providers.kubernetesGateway.enabled ([#12315](https://github.com/traefik/traefik/pull/12315) @shouhei)
- **[k8s/ingress, k8s]** Fix Kubernetes Ingress provider documentation ([#12443](https://github.com/traefik/traefik/pull/12443) @nmengin)
- **[k8s/ingress-nginx]** Add auth-signin to unsupported nginx annotations list ([#12370](https://github.com/traefik/traefik/pull/12370) @fibsifan)
- **[k8s/ingress-nginx]** Add RBAC documentation for Ingress NGINX provider ([#12445](https://github.com/traefik/traefik/pull/12445) @nmn3m)
- **[k8s/ingress-nginx]** Add temporary note to advertise the incoming NGINX annotations ([#12699](https://github.com/traefik/traefik/pull/12699) @nmengin)
- **[k8s/ingress-nginx]** Fix default value of ingress-nginx provider in documentation ([#12328](https://github.com/traefik/traefik/pull/12328) @mloiseleur)
- **[k8s/ingress-nginx]** Fix ingress-nginx annotations documentation ([#12510](https://github.com/traefik/traefik/pull/12510) @nmengin)
- **[k8s/ingress-nginx]** Improve ingress-nginx provider documentation ([#12288](https://github.com/traefik/traefik/pull/12288) @sheddy-traefik)
- **[k8s/ingress-nginx]** Improve the configuration options display of the Kubernetes ingress-nginx provider ([#12297](https://github.com/traefik/traefik/pull/12297) @mloiseleur)
- **[k8s/ingress-nginx]** NGINX Ingress Controller to Traefik Migration Guide ([#12318](https://github.com/traefik/traefik/pull/12318) @sheddy-traefik)
- **[middleware]** Correct documentation for Digest auth ([#12651](https://github.com/traefik/traefik/pull/12651) @Zash)
- **[middleware]** Fix default encodings in compress middleware ([#12216](https://github.com/traefik/traefik/pull/12216) @Belphemur)
- **[middleware, k8s/crd]** Fix the errors middleware's document for Kubernetes CRD ([#12600](https://github.com/traefik/traefik/pull/12600) @yuito-it)
- **[service]** Fix loadbalancer doc for highest random weight ([#12283](https://github.com/traefik/traefik/pull/12283) @ozon2)
- **[tls]** Clarify SNI selection ([#12482](https://github.com/traefik/traefik/pull/12482) @AnuragEkkati)
- Add @gndz07 as a current maintainer ([#12594](https://github.com/traefik/traefik/pull/12594) @emilevauge)
- Add a Breaking change note to the changelog ([#12398](https://github.com/traefik/traefik/pull/12398) @nmengin)
- Add documentation about checkNewVersion ([#12298](https://github.com/traefik/traefik/pull/12298) @darkweaver87)
- Add missing `.http` to TOML table names ([#12713](https://github.com/traefik/traefik/pull/12713) @Darsstar)
- Add product comparison matrix and features page ([#12037](https://github.com/traefik/traefik/pull/12037) @sheddy-traefik)
- Bring back security section on API & Dashboard documentation page ([#12507](https://github.com/traefik/traefik/pull/12507) @gndz07)
- Clarify doc about encoded characters rejection ([#12391](https://github.com/traefik/traefik/pull/12391) @rtribotte)
- Clean Up Menu Entries & Update Expose Overview ([#12405](https://github.com/traefik/traefik/pull/12405) @sheddy-traefik)
- Correct encoded characters allowance in entrypoints.md ([#12679](https://github.com/traefik/traefik/pull/12679) @Apflkuacha)
- Correctly Format the HTTP Service Documentation ([#12311](https://github.com/traefik/traefik/pull/12311) @sheddy-traefik)
- Document negative priority support for routers ([#12505](https://github.com/traefik/traefik/pull/12505) @understood-the-assignment)
- Document Path matcher placeholder removal in v3 migration guide ([#12570](https://github.com/traefik/traefik/pull/12570) @sheddy-traefik)
- Fix API basepath option documentation ([#12744](https://github.com/traefik/traefik/pull/12744) @nmengin)
- Fix broken links in TCP Service and HTTP Router documentation ([#12215](https://github.com/traefik/traefik/pull/12215) @sheddy-traefik)
- Fix code copy button positioning ([#12520](https://github.com/traefik/traefik/pull/12520) @AnuragEkkati)
- Fix encoded characters entryPoint option documentation ([#12384](https://github.com/traefik/traefik/pull/12384) @rtribotte)
- Fix encoded characters option documentation ([#12373](https://github.com/traefik/traefik/pull/12373) @kevinpollet)
- Fix encodedCharacters entryPoint option documentation ([#12385](https://github.com/traefik/traefik/pull/12385) @rtribotte)
- Fix incorrect TOML example in entrypoints docs ([#12711](https://github.com/traefik/traefik/pull/12711) @mfmfuyu)
- Fix link description in Traefik Proxy documentation ([#12488](https://github.com/traefik/traefik/pull/12488) @schaerfo)
- Fix Menu Item Naming ([#12431](https://github.com/traefik/traefik/pull/12431) @sheddy-traefik)
- Fix migration guide indentation ([#12365](https://github.com/traefik/traefik/pull/12365) @kevinpollet)
- Fix migration guide URLs in deprecation notice ([#12430](https://github.com/traefik/traefik/pull/12430) @alexmar07)
- Fix typo in kubernetes.md ([#12515](https://github.com/traefik/traefik/pull/12515) @EdwardSalkeld)
- Fix typo in v3.6 migration guide ([#12212](https://github.com/traefik/traefik/pull/12212) @jnoordsij)
- Fix typo on JWT documentation ([#12616](https://github.com/traefik/traefik/pull/12616) @mdevino)
- Improve Service Reference page ([#12541](https://github.com/traefik/traefik/pull/12541) @sheddy-traefik)
- Improve the structure of the routing reference pages ([#12429](https://github.com/traefik/traefik/pull/12429) @sheddy-traefik)
- Increased content width in documentation ([#12632](https://github.com/traefik/traefik/pull/12632) @tobiasge)
- Remove extra dots in migration guide ([#12573](https://github.com/traefik/traefik/pull/12573) @rtribotte)
- Remove extraneous dots in migration guide ([#12571](https://github.com/traefik/traefik/pull/12571) @dathbe)
- Restore documentation on http.maxHeaderBytes ([#12440](https://github.com/traefik/traefik/pull/12440) @mloiseleur)
- Split Expose User Guides & Add Multi-Layer Routing Section ([#12238](https://github.com/traefik/traefik/pull/12238) @sheddy-traefik)
- Update Configuration Overview Page ([#12202](https://github.com/traefik/traefik/pull/12202) @sheddy-traefik)
- Update SECURITY.md ([#12304](https://github.com/traefik/traefik/pull/12304) @cwayne18)
- Update SECURITY.md to streamline information ([#12310](https://github.com/traefik/traefik/pull/12310) @emilevauge)
**Misc:**
- Make FLAGS Make variable usable ([#13009](https://github.com/traefik/traefik/pull/13009) @twz123)
+1
View File
@@ -0,0 +1 @@
@AGENTS.md
+1
View File
@@ -24,6 +24,7 @@ description: "Traefik Proxy is an open source software with a thriving community
* Baptiste Mayelle [@youkoulayley](https://github.com/youkoulayley)
* Jesper Noordsij [@jnoordsij](https://github.com/jnoordsij)
* Gina Adzani [@gndz07](https://github.com/gndz07)
* Mathis Urien [@LBF38](https://github.com/LBF38)
## Past Maintainers
+33 -10
View File
@@ -93,6 +93,12 @@ For a complete list of supported annotations and behavioral differences, see the
The Kubernetes Ingress NGINX provider requires **Traefik v3.6.2 or later**.
!!! info "Legacy Scheme Headers"
If your applications still depend on ingress-nginx's legacy `X-Forwarded-Scheme` or `X-Scheme` headers,
enable `entryPoints.<name>.forwardedHeaders.addXForwardedSchemeHeaders=true` on the entrypoints that receive this traffic.
This keeps `X-Forwarded-Proto` unchanged and restores the compatibility headers at the entrypoint level for every provider.
---
## Prerequisites
@@ -230,6 +236,10 @@ When you find one of these keys, translate the underlying intent rather than try
```
Install Traefik with the Kubernetes Ingress NGINX provider enabled. Both controllers will serve the same Ingress resources simultaneously.
!!! warning "Read the status race condition note first"
Running both controllers against the same Ingresses creates contention on the `status.loadBalancer.ingress[]` field. Before installing, review the [Ingress Status Race Condition](#status-race) section in Step 3 and decide which mitigation to apply (disable `publishService` on Traefik, or use a transitional IngressClass).
### Add Traefik Helm Repository
```bash
@@ -242,7 +252,7 @@ helm repo update
```bash
helm upgrade --install traefik traefik/traefik \
--namespace traefik --create-namespace \
--set providers.kubernetesIngressNginx.enabled=true
--set providers.kubernetesIngressNGINX.enabled=true
```
Or using a [values file](https://github.com/traefik/traefik-helm-chart/blob/master/traefik/VALUES.md) for more configuration:
@@ -250,7 +260,7 @@ Or using a [values file](https://github.com/traefik/traefik-helm-chart/blob/mast
```yaml tab="traefik-values.yaml"
...
providers:
kubernetesIngressNginx:
kubernetesIngressNGINX:
enabled: true
...
```
@@ -355,11 +365,20 @@ echo $(kubectl get svc -n traefik traefik -o go-template='{{ $ing := index .stat
Some ISPs ignore DNS TTL values to reduce traffic costs, caching records longer than specified. After removing NGINX from DNS, keep NGINX running for at least 24-48 hours before uninstalling to avoid dropping traffic from users whose ISPs have stale DNS caches.
??? info "ExternalDNS Users"
<a id="status-race"></a>
If you use [ExternalDNS](https://github.com/kubernetes-sigs/external-dns) to automatically manage DNS records based on Ingress status, both NGINX and Traefik will compete to update the Ingress status with their LoadBalancer IPs when `publishService` is enabled. Traefik typically wins because it updates faster, which can cause unexpected traffic shifts.
!!! warning "Ingress Status Race Condition During Coexistence"
**Recommended approach for ExternalDNS:**
While both controllers manage the same Ingress resources (same `ingressClassName: nginx`), they will both attempt to write the LoadBalancer address into `status.loadBalancer.ingress[]` on every Ingress they own. Each controller overwrites the other in a tight reconciliation loop, with no error reported in the logs (just repeated `Updated ingress status` info lines on both sides).
Routing itself is not affected: both controllers correctly serve traffic during the coexistence window. The flapping status field affects anything that watches it:
- [ExternalDNS](https://github.com/kubernetes-sigs/external-dns), which may shift DNS records back and forth between the two LoadBalancer IPs.
- kube-state-metrics, monitoring dashboards, and alerting rules that observe Ingress status.
- GitOps tools such as ArgoCD or Flux, which will report a permanent drift on every affected Ingress.
- Custom operators reconciling on the Ingress status field.
**Recommended mitigation (option 1): disable status publishing on Traefik during coexistence**
1. **[Install Traefik](#step-1-install-traefik-alongside-nginx) with `publishService` disabled**:
@@ -372,9 +391,11 @@ echo $(kubectl get svc -n traefik traefik -o go-template='{{ $ing := index .stat
enabled: false # Disable to prevent status updates
```
2. **Test Traefik** using [port-forward](#step-2-verify-traefik-is-handling-traffic) or a separate test hostname
Traefik keeps serving the Ingresses normally. It only stops writing the status field, leaving NGINX as the sole writer.
3. **Switch DNS via NGINX** - Configure NGINX to publish Traefik's service address:
2. **Test Traefik** using [port-forward](#step-2-verify-traefik-is-handling-traffic) or a separate test hostname.
3. **Switch DNS via NGINX** (ExternalDNS users only). Configure NGINX to publish Traefik's service address so ExternalDNS points traffic to Traefik:
```yaml
# nginx-values.yaml
@@ -383,11 +404,13 @@ echo $(kubectl get svc -n traefik traefik -o go-template='{{ $ing := index .stat
pathOverride: "traefik/traefik" # Points to Traefik's service
```
This makes NGINX update the Ingress status with Traefik's LoadBalancer IP, causing ExternalDNS to point traffic to Traefik.
4. **Verify traffic flows through Traefik**. At this point, you can still roll back by removing the `pathOverride`.
4. **Verify traffic flows through Traefik** - At this point, you can still rollback by removing the `pathOverride`
5. **[Enable `publishService` on Traefik](#step-1-install-traefik-alongside-nginx)** and [uninstall NGINX](#step-4-uninstall-ingress-nginx-controller).
5. **[Enable `publishService` on Traefik](#step-1-install-traefik-alongside-nginx)** and [uninstall NGINX](#step-4-uninstall-ingress-nginx-controller)
**Alternative mitigation (option 2): use a transitional IngressClass**
Give the migrating NGINX a distinct IngressClass (for example `nginx-migration`) so the two controllers never own the same Ingress at the same time. This is the approach SUSE documents for RKE2 migrations: see [SUSE: Migrate from Ingress NGINX to Traefik](https://documentation.suse.com/cloudnative/rke2/latest/en/reference/ingress_migration.html). This avoids any contention on `status.loadBalancer.ingress[]` entirely, at the cost of a short traffic-cutover step instead of a progressive DNS shift.
### Option B: External Load Balancer with Weighted Traffic
+1 -1
View File
@@ -17,7 +17,7 @@ For more information about the changes in Traefik v2, please refer to the [v2 do
We created a tool to help during the migration: [traefik-migration-tool](https://github.com/traefik/traefik-migration-tool)
This tool allows to:
This tool lets you:
- convert `Ingress` to Traefik `IngressRoute` resources.
- convert `acme.json` file from v1 to v2 format.
+1 -1
View File
@@ -680,7 +680,7 @@ It can be configured in the install configuration.
##### Configure the Syntax Per Router
The rule syntax can also be configured on a per-router basis.
This allows to have heterogeneous router configurations and ease migration.
This allows you to have heterogeneous router configurations and ease migration.
??? example "An example router with syntax configuration"
+146 -1
View File
@@ -9,6 +9,89 @@ This guide provides detailed migration steps for upgrading between different Tra
---
## v3.8.0
### `peerCertURI` option deprecation
Starting with `v3.8.0`, the `peerCertURI` option is deprecated in the `ServersTransport` and `ServersTransportTCP` configurations and will be removed in the next major version.
The new `peerCertSANs` option replaces it and supports multiple Subject Alternative Names (SANs) of type `URI` or `DNSName`.
Please check out the [ServersTransport](../reference/routing-configuration/http/load-balancing/serverstransport.md#opt-peerCertSANs) and [ServersTransportTCP](../reference/routing-configuration/tcp/serverstransport.md#opt-serverstransport-tls-peerCertSANs) documentation for more details.
#### Kubernetes CRD Provider
To use the new `peerCertSANs` field on `ServersTransport` and `ServersTransportTCP` resources with the Kubernetes CRD provider, you need to update your CRDs.
**Apply Updated CRDs:**
```shell
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.8/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml
```
## v3.7.3
### Kubernetes Gateway API Provider
Starting with `v3.7.3`, the QPS and Burst values of the Kubernetes client used by the Kubernetes Gateway API provider have been increased to `50` and `100` respectively (10x the default values of the Kubernetes client).
The Kubernetes Gateway API provider writes status updates intensively to comply with the Kubernetes Gateway API specification.
This change helps avoid performance issues related to Kubernetes API rate limiting, which can increase the setup time when a new routing configuration is built.
These values are configurable through the [`kubernetesGateway.qps`](../reference/install-configuration/providers/kubernetes/kubernetes-gateway.md#opt-providers-kubernetesgateway-qps)
and [`kubernetesGateway.burst`](../reference/install-configuration/providers/kubernetes/kubernetes-gateway.md#opt-providers-kubernetesgateway-burst) provider options.
### BasicAuth Middleware
From version `v3.7.3` onwards, the BasicAuth middleware requires a non-empty users configuration in order to be built successfully.
Previously, the middleware would be built successfully but always return a 401 status code for any request.
Now, an error occurs and any routers using it will be unmounted. For the same request, a 404 status code is served instead of a 401 status code.
### StripPrefix and StripPrefixRegex Middleware
From version `v3.7.3` onwards, the StripPrefix middleware and the StripPrefixRegex middleware reject requests (`400 Bad Request`)
when stripping the configured prefix produces a path that differs from its normalised form
(i.e. a path containing `.` or `..` segments that would be collapsed by normalisation).
This prevents the stripped path from being interpreted as a different resource by the upstream service.
Examples with a configured prefix of `/api`:
| Request path | Path after strip | Normalised path | Result |
|--------------|------------------|-----------------|--------------|
| `/api/foo` | `/foo` | `/foo` | `200` (sent) |
| `/api/` | `/` | `/` | `200` (sent) |
| `/api./foo` | `/./foo` | `/foo` | `400` |
| `/api../foo` | `/../foo` | `/foo` | `400` |
---
## v3.7.1
### Kubernetes providers: `crossProviderNamespaces`
In `v3.7.1`, a new `crossProviderNamespaces` option is available on the Kubernetes CRD, Ingress, and Gateway providers.
Traefik offers the possibility to reference resources from one provider to another (cross-provider references).
However, in the context of Kubernetes providers,
those references (e.g. `myservice@kubernetescrd`) allow a user to cross namespace boundaries,
as well as exposing `@internal` services, that only the operator should be able to expose.
This new `crossProviderNamespaces` option restricts in which namespaces Kubernetes resources are allowed to use cross-provider references.
The behavior is as follows:
| Value | Behavior |
|------------|-------------------------------------------------------------------------------------------|
| not set | All Kubernetes resources can declare cross-provider references. |
| `[]` | Every Kubernetes resource declaring a cross-provider reference is rejected. |
| `["ns-a"]` | Only Kubernetes resources in the listed namespaces can declare cross-provider references. |
Please check out the [Kubernetes CRD](../reference/install-configuration/providers/kubernetes/kubernetes-crd.md#opt-providers-kubernetesCRD-crossProviderNamespaces), [Kubernetes Ingress](../reference/install-configuration/providers/kubernetes/kubernetes-ingress.md#opt-providers-kubernetesIngress-crossProviderNamespaces),
and [Kubernetes Gateway](../reference/install-configuration/providers/kubernetes/kubernetes-gateway.md#opt-providers-kubernetesGateway-crossProviderNamespaces) provider documentation for more details.
---
## v3.7.0
### Ingress NGINX Provider
@@ -53,7 +136,7 @@ kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/downloa
### Kubernetes CRD Provider
To use the new options of the `retry` middleware with the Kubernetes CRD provider, you need to update your CRDs.
To use the new options of the `retry` middleware or the new `ingressClassName` field with the Kubernetes CRD provider, you need to update your CRDs.
**Apply Updated CRDs:**
@@ -80,6 +163,68 @@ Note: TLSOptions for `HostRegexp` matchers remains unsupported. Use wildcard `Ho
---
## v3.6.19
### Kubernetes Gateway API Provider
Starting with `v3.6.19`, the QPS and Burst values of the Kubernetes client used by the Kubernetes Gateway API provider have been increased to `50` and `100` respectively (10x the default values of the Kubernetes client).
The Kubernetes Gateway API provider writes status updates intensively to comply with the Kubernetes Gateway API specification.
This change helps avoid performance issues related to Kubernetes API rate limiting, which can increase the setup time when a new routing configuration is built.
These values are configurable through the [`kubernetesGateway.qps`](../reference/install-configuration/providers/kubernetes/kubernetes-gateway.md#opt-providers-kubernetesgateway-qps)
and [`kubernetesGateway.burst`](../reference/install-configuration/providers/kubernetes/kubernetes-gateway.md#opt-providers-kubernetesgateway-burst) provider options.
### BasicAuth Middleware
From version `v3.6.19` onwards, the BasicAuth middleware requires a non-empty users configuration in order to be built successfully.
Previously, the middleware would be built successfully but always return a 401 status code for any request.
Now, an error occurs and any routers using it will be unmounted. For the same request, a 404 status code is served instead of a 401 status code.
### StripPrefix and StripPrefixRegex Middleware
From version `v3.6.19` onwards, the StripPrefix middleware and the StripPrefixRegex middleware reject requests (`400 Bad Request`)
when stripping the configured prefix produces a path that differs from its normalised form
(i.e. a path containing `.` or `..` segments that would be collapsed by normalisation).
This prevents the stripped path from being interpreted as a different resource by the upstream service.
Examples with a configured prefix of `/api`:
| Request path | Path after strip | Normalised path | Result |
|--------------|------------------|-----------------|--------------|
| `/api/foo` | `/foo` | `/foo` | `200` (sent) |
| `/api/` | `/` | `/` | `200` (sent) |
| `/api./foo` | `/./foo` | `/foo` | `400` |
| `/api../foo` | `/../foo` | `/foo` | `400` |
---
## v3.6.17
### Kubernetes providers: `crossProviderNamespaces`
In `v3.6.17`, a new `crossProviderNamespaces` option is available on the Kubernetes CRD, Ingress, and Gateway providers.
Traefik offers the possibility to reference resources from one provider to another (cross-provider references).
However, in the context of Kubernetes providers,
those references (e.g. `myservice@kubernetescrd`) allow a user to cross namespace boundaries,
as well as exposing `@internal` services, that only the operator should be able to expose.
This new `crossProviderNamespaces` option restricts in which namespaces Kubernetes resources are allowed to use cross-provider references.
The behavior is as follows:
| Value | Behavior |
|------------|-------------------------------------------------------------------------------------------|
| not set | All Kubernetes resources can declare cross-provider references. |
| `[]` | Every Kubernetes resource declaring a cross-provider reference is rejected. |
| `["ns-a"]` | Only Kubernetes resources in the listed namespaces can declare cross-provider references. |
Please check out the [Kubernetes CRD](../reference/install-configuration/providers/kubernetes/kubernetes-crd.md#opt-providers-kubernetesCRD-crossProviderNamespaces), [Kubernetes Ingress](../reference/install-configuration/providers/kubernetes/kubernetes-ingress.md#opt-providers-kubernetesIngress-crossProviderNamespaces),
and [Kubernetes Gateway](../reference/install-configuration/providers/kubernetes/kubernetes-gateway.md#opt-providers-kubernetesGateway-crossProviderNamespaces) provider documentation for more details.
## v3.6.16
### Docker provider: minimum Docker Engine version
@@ -175,6 +175,7 @@ When using the `json` format, you can customize which fields are included in you
- **Request Fields:** You can choose to `keep`, `drop`, or `redact` any of the standard request fields. A complete list of available fields like `ClientHost`, `RequestMethod`, and `Duration` can be found in the [reference documentation](../reference/install-configuration/observability/logs-and-accesslogs.md#json-format-fields).
- **Request Headers:** You can also specify which request headers should be included in the logs, and whether their values should be `kept`, `dropped`, or `redacted`.
- **Request Query Parameters:** You can choose to `keep` or `drop` the query parameters for a request.
!!! info
For detailed configuration options, refer to the [reference documentation](../reference/install-configuration/observability/logs-and-accesslogs.md).
@@ -2493,9 +2493,25 @@ spec:
description: MinVersion defines the minimum TLS version to use when
contacting backend servers.
type: string
peerCertSANs:
description: PeerCertSANs defines the peer cert Subject Alternative
Names used to match against SAN during the peer certificate verification.
items:
description: SAN represents a Subject Alternative Name.
properties:
type:
description: SANType is the type of the Subject Alternative
Name.
type: string
value:
type: string
type: object
type: array
peerCertURI:
description: PeerCertURI defines the peer cert URI used to match against
SAN URI during the peer certificate verification.
description: |-
PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
type: string
rootCAs:
description: RootCAs defines a list of CA certificate Secrets or ConfigMaps
@@ -2647,10 +2663,26 @@ spec:
insecureSkipVerify:
description: InsecureSkipVerify disables TLS certificate verification.
type: boolean
peerCertSANs:
description: PeerCertSANs defines the peer cert Subject Alternative
Names used to match against SAN during the peer certificate
verification.
items:
description: SAN represents a Subject Alternative Name.
properties:
type:
description: SANType is the type of the Subject Alternative
Name.
type: string
value:
type: string
type: object
type: array
peerCertURI:
description: |-
MaxIdleConnsPerHost controls the maximum idle (keep-alive) to keep per-host.
PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
type: string
rootCAs:
description: RootCAs defines a list of CA certificate Secrets
@@ -123,9 +123,25 @@ spec:
description: MinVersion defines the minimum TLS version to use when
contacting backend servers.
type: string
peerCertSANs:
description: PeerCertSANs defines the peer cert Subject Alternative
Names used to match against SAN during the peer certificate verification.
items:
description: SAN represents a Subject Alternative Name.
properties:
type:
description: SANType is the type of the Subject Alternative
Name.
type: string
value:
type: string
type: object
type: array
peerCertURI:
description: PeerCertURI defines the peer cert URI used to match against
SAN URI during the peer certificate verification.
description: |-
PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
type: string
rootCAs:
description: RootCAs defines a list of CA certificate Secrets or ConfigMaps
@@ -93,10 +93,26 @@ spec:
insecureSkipVerify:
description: InsecureSkipVerify disables TLS certificate verification.
type: boolean
peerCertSANs:
description: PeerCertSANs defines the peer cert Subject Alternative
Names used to match against SAN during the peer certificate
verification.
items:
description: SAN represents a Subject Alternative Name.
properties:
type:
description: SANType is the type of the Subject Alternative
Name.
type: string
value:
type: string
type: object
type: array
peerCertURI:
description: |-
MaxIdleConnsPerHost controls the maximum idle (keep-alive) to keep per-host.
PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
type: string
rootCAs:
description: RootCAs defines a list of CA certificate Secrets
@@ -15,6 +15,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| <a id="opt-accesslog-fields-headers-defaultmode" href="#opt-accesslog-fields-headers-defaultmode" title="#opt-accesslog-fields-headers-defaultmode">accesslog.fields.headers.defaultmode</a> | Default mode for fields: keep | drop | redact | drop |
| <a id="opt-accesslog-fields-headers-names-name" href="#opt-accesslog-fields-headers-names-name" title="#opt-accesslog-fields-headers-names-name">accesslog.fields.headers.names._name_</a> | Override mode for headers | |
| <a id="opt-accesslog-fields-names-name" href="#opt-accesslog-fields-names-name" title="#opt-accesslog-fields-names-name">accesslog.fields.names._name_</a> | Override mode for fields | |
| <a id="opt-accesslog-fields-queryparameters-defaultmode" href="#opt-accesslog-fields-queryparameters-defaultmode" title="#opt-accesslog-fields-queryparameters-defaultmode">accesslog.fields.queryparameters.defaultmode</a> | Default mode for query parameters: keep | drop | keep |
| <a id="opt-accesslog-filepath" href="#opt-accesslog-filepath" title="#opt-accesslog-filepath">accesslog.filepath</a> | Access log file path. Stdout is used when omitted or empty. | |
| <a id="opt-accesslog-filters-minduration" href="#opt-accesslog-filters-minduration" title="#opt-accesslog-filters-minduration">accesslog.filters.minduration</a> | Keep access logs when request took longer than the specified duration. | 0 |
| <a id="opt-accesslog-filters-retryattempts" href="#opt-accesslog-filters-retryattempts" title="#opt-accesslog-filters-retryattempts">accesslog.filters.retryattempts</a> | Keep access logs when at least one retry happened. | false |
@@ -84,6 +85,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| <a id="opt-entrypoints-name-address" href="#opt-entrypoints-name-address" title="#opt-entrypoints-name-address">entrypoints._name_.address</a> | Entry point address. | |
| <a id="opt-entrypoints-name-allowacmebypass" href="#opt-entrypoints-name-allowacmebypass" title="#opt-entrypoints-name-allowacmebypass">entrypoints._name_.allowacmebypass</a> | Enables handling of ACME TLS and HTTP challenges with custom routers. | false |
| <a id="opt-entrypoints-name-asdefault" href="#opt-entrypoints-name-asdefault" title="#opt-entrypoints-name-asdefault">entrypoints._name_.asdefault</a> | Adds this EntryPoint to the list of default EntryPoints to be used on routers that don't have any Entrypoint defined. | false |
| <a id="opt-entrypoints-name-forwardedheaders-addxforwardedschemeheaders" href="#opt-entrypoints-name-forwardedheaders-addxforwardedschemeheaders" title="#opt-entrypoints-name-forwardedheaders-addxforwardedschemeheaders">entrypoints._name_.forwardedheaders.addxforwardedschemeheaders</a> | Add the X-Forwarded-Scheme and X-Scheme headers. | false |
| <a id="opt-entrypoints-name-forwardedheaders-connection" href="#opt-entrypoints-name-forwardedheaders-connection" title="#opt-entrypoints-name-forwardedheaders-connection">entrypoints._name_.forwardedheaders.connection</a> | List of Connection headers that are allowed to pass through the middleware chain before being removed. | |
| <a id="opt-entrypoints-name-forwardedheaders-insecure" href="#opt-entrypoints-name-forwardedheaders-insecure" title="#opt-entrypoints-name-forwardedheaders-insecure">entrypoints._name_.forwardedheaders.insecure</a> | Trust all forwarded headers. | false |
| <a id="opt-entrypoints-name-forwardedheaders-notappendxforwardedfor" href="#opt-entrypoints-name-forwardedheaders-notappendxforwardedfor" title="#opt-entrypoints-name-forwardedheaders-notappendxforwardedfor">entrypoints._name_.forwardedheaders.notappendxforwardedfor</a> | Disable appending RemoteAddr to X-Forwarded-For header. Defaults to false (appending is enabled). | false |
@@ -353,6 +355,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| <a id="opt-providers-kubernetescrd-allowemptyservices" href="#opt-providers-kubernetescrd-allowemptyservices" title="#opt-providers-kubernetescrd-allowemptyservices">providers.kubernetescrd.allowemptyservices</a> | Allow the creation of services without endpoints. | false |
| <a id="opt-providers-kubernetescrd-allowexternalnameservices" href="#opt-providers-kubernetescrd-allowexternalnameservices" title="#opt-providers-kubernetescrd-allowexternalnameservices">providers.kubernetescrd.allowexternalnameservices</a> | Allow ExternalName services. | false |
| <a id="opt-providers-kubernetescrd-certauthfilepath" href="#opt-providers-kubernetescrd-certauthfilepath" title="#opt-providers-kubernetescrd-certauthfilepath">providers.kubernetescrd.certauthfilepath</a> | Kubernetes certificate authority file path (not needed for in-cluster client). | |
| <a id="opt-providers-kubernetescrd-crossprovidernamespaces" href="#opt-providers-kubernetescrd-crossprovidernamespaces" title="#opt-providers-kubernetescrd-crossprovidernamespaces">providers.kubernetescrd.crossprovidernamespaces</a> | List of namespaces from which IngressRoute, IngressRouteTCP, IngressRouteUDP, and TraefikService are allowed to declare cross-provider references. | |
| <a id="opt-providers-kubernetescrd-disableclusterscoperesources" href="#opt-providers-kubernetescrd-disableclusterscoperesources" title="#opt-providers-kubernetescrd-disableclusterscoperesources">providers.kubernetescrd.disableclusterscoperesources</a> | Disables the lookup of cluster scope resources (incompatible with IngressClasses and NodePortLB enabled services). | false |
| <a id="opt-providers-kubernetescrd-endpoint" href="#opt-providers-kubernetescrd-endpoint" title="#opt-providers-kubernetescrd-endpoint">providers.kubernetescrd.endpoint</a> | Kubernetes server endpoint (required for external cluster client). | |
| <a id="opt-providers-kubernetescrd-ingressclass" href="#opt-providers-kubernetescrd-ingressclass" title="#opt-providers-kubernetescrd-ingressclass">providers.kubernetescrd.ingressclass</a> | Value of ingressClassName field or kubernetes.io/ingress.class annotation to watch for. | |
@@ -362,12 +365,15 @@ THIS FILE MUST NOT BE EDITED BY HAND
| <a id="opt-providers-kubernetescrd-throttleduration" href="#opt-providers-kubernetescrd-throttleduration" title="#opt-providers-kubernetescrd-throttleduration">providers.kubernetescrd.throttleduration</a> | Ingress refresh throttle duration | 0 |
| <a id="opt-providers-kubernetescrd-token" href="#opt-providers-kubernetescrd-token" title="#opt-providers-kubernetescrd-token">providers.kubernetescrd.token</a> | Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token. | |
| <a id="opt-providers-kubernetesgateway" href="#opt-providers-kubernetesgateway" title="#opt-providers-kubernetesgateway">providers.kubernetesgateway</a> | Enables Kubernetes Gateway API provider. | false |
| <a id="opt-providers-kubernetesgateway-burst" href="#opt-providers-kubernetesgateway-burst" title="#opt-providers-kubernetesgateway-burst">providers.kubernetesgateway.burst</a> | Defines the maximum burst of requests to the Kubernetes API server. | 100 |
| <a id="opt-providers-kubernetesgateway-certauthfilepath" href="#opt-providers-kubernetesgateway-certauthfilepath" title="#opt-providers-kubernetesgateway-certauthfilepath">providers.kubernetesgateway.certauthfilepath</a> | Kubernetes certificate authority file path (not needed for in-cluster client). | |
| <a id="opt-providers-kubernetesgateway-crossprovidernamespaces" href="#opt-providers-kubernetesgateway-crossprovidernamespaces" title="#opt-providers-kubernetesgateway-crossprovidernamespaces">providers.kubernetesgateway.crossprovidernamespaces</a> | List of namespaces from which Gateway API routes are allowed to declare TraefikService backendRef references. | |
| <a id="opt-providers-kubernetesgateway-endpoint" href="#opt-providers-kubernetesgateway-endpoint" title="#opt-providers-kubernetesgateway-endpoint">providers.kubernetesgateway.endpoint</a> | Kubernetes server endpoint (required for external cluster client). | |
| <a id="opt-providers-kubernetesgateway-experimentalchannel" href="#opt-providers-kubernetesgateway-experimentalchannel" title="#opt-providers-kubernetesgateway-experimentalchannel">providers.kubernetesgateway.experimentalchannel</a> | Toggles Experimental Channel resources support (TCPRoute, TLSRoute...). | false |
| <a id="opt-providers-kubernetesgateway-labelselector" href="#opt-providers-kubernetesgateway-labelselector" title="#opt-providers-kubernetesgateway-labelselector">providers.kubernetesgateway.labelselector</a> | Kubernetes label selector to select specific GatewayClasses. | |
| <a id="opt-providers-kubernetesgateway-namespaces" href="#opt-providers-kubernetesgateway-namespaces" title="#opt-providers-kubernetesgateway-namespaces">providers.kubernetesgateway.namespaces</a> | Kubernetes namespaces. | |
| <a id="opt-providers-kubernetesgateway-nativelbbydefault" href="#opt-providers-kubernetesgateway-nativelbbydefault" title="#opt-providers-kubernetesgateway-nativelbbydefault">providers.kubernetesgateway.nativelbbydefault</a> | Defines whether to use Native Kubernetes load-balancing by default. | false |
| <a id="opt-providers-kubernetesgateway-qps" href="#opt-providers-kubernetesgateway-qps" title="#opt-providers-kubernetesgateway-qps">providers.kubernetesgateway.qps</a> | Defines the maximum QPS to the Kubernetes API server. Setting this to a negative value will disable client-side ratelimiting. | 50 |
| <a id="opt-providers-kubernetesgateway-statusaddress-hostname" href="#opt-providers-kubernetesgateway-statusaddress-hostname" title="#opt-providers-kubernetesgateway-statusaddress-hostname">providers.kubernetesgateway.statusaddress.hostname</a> | Hostname used for Kubernetes Gateway status address. | |
| <a id="opt-providers-kubernetesgateway-statusaddress-ip" href="#opt-providers-kubernetesgateway-statusaddress-ip" title="#opt-providers-kubernetesgateway-statusaddress-ip">providers.kubernetesgateway.statusaddress.ip</a> | IP used to set Kubernetes Gateway status address. | |
| <a id="opt-providers-kubernetesgateway-statusaddress-service" href="#opt-providers-kubernetesgateway-statusaddress-service" title="#opt-providers-kubernetesgateway-statusaddress-service">providers.kubernetesgateway.statusaddress.service</a> | Published Kubernetes Service to copy status addresses from. | |
@@ -379,6 +385,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| <a id="opt-providers-kubernetesingress-allowemptyservices" href="#opt-providers-kubernetesingress-allowemptyservices" title="#opt-providers-kubernetesingress-allowemptyservices">providers.kubernetesingress.allowemptyservices</a> | Allow creation of services without endpoints. | false |
| <a id="opt-providers-kubernetesingress-allowexternalnameservices" href="#opt-providers-kubernetesingress-allowexternalnameservices" title="#opt-providers-kubernetesingress-allowexternalnameservices">providers.kubernetesingress.allowexternalnameservices</a> | Allow ExternalName services. | false |
| <a id="opt-providers-kubernetesingress-certauthfilepath" href="#opt-providers-kubernetesingress-certauthfilepath" title="#opt-providers-kubernetesingress-certauthfilepath">providers.kubernetesingress.certauthfilepath</a> | Kubernetes certificate authority file path (not needed for in-cluster client). | |
| <a id="opt-providers-kubernetesingress-crossprovidernamespaces" href="#opt-providers-kubernetesingress-crossprovidernamespaces" title="#opt-providers-kubernetesingress-crossprovidernamespaces">providers.kubernetesingress.crossprovidernamespaces</a> | List of namespaces from which Ingresses or Services are allowed to declare Middlewares, TLSOptions, or ServersTransport references. | |
| <a id="opt-providers-kubernetesingress-disableclusterscoperesources" href="#opt-providers-kubernetesingress-disableclusterscoperesources" title="#opt-providers-kubernetesingress-disableclusterscoperesources">providers.kubernetesingress.disableclusterscoperesources</a> | Disables the lookup of cluster scope resources (incompatible with IngressClasses and NodePortLB enabled services). | false |
| <a id="opt-providers-kubernetesingress-disableingressclasslookup" href="#opt-providers-kubernetesingress-disableingressclasslookup" title="#opt-providers-kubernetesingress-disableingressclasslookup">providers.kubernetesingress.disableingressclasslookup</a> | Disables the lookup of IngressClasses (Deprecated, please use DisableClusterScopeResources). | false |
| <a id="opt-providers-kubernetesingress-endpoint" href="#opt-providers-kubernetesingress-endpoint" title="#opt-providers-kubernetesingress-endpoint">providers.kubernetesingress.endpoint</a> | Kubernetes server endpoint (required for external cluster client). | |
@@ -389,6 +396,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| <a id="opt-providers-kubernetesingress-labelselector" href="#opt-providers-kubernetesingress-labelselector" title="#opt-providers-kubernetesingress-labelselector">providers.kubernetesingress.labelselector</a> | Kubernetes Ingress label selector to use. | |
| <a id="opt-providers-kubernetesingress-namespaces" href="#opt-providers-kubernetesingress-namespaces" title="#opt-providers-kubernetesingress-namespaces">providers.kubernetesingress.namespaces</a> | Kubernetes namespaces. | |
| <a id="opt-providers-kubernetesingress-nativelbbydefault" href="#opt-providers-kubernetesingress-nativelbbydefault" title="#opt-providers-kubernetesingress-nativelbbydefault">providers.kubernetesingress.nativelbbydefault</a> | Defines whether to use Native Kubernetes load-balancing mode by default. | false |
| <a id="opt-providers-kubernetesingress-reportnodeinternalips" href="#opt-providers-kubernetesingress-reportnodeinternalips" title="#opt-providers-kubernetesingress-reportnodeinternalips">providers.kubernetesingress.reportnodeinternalips</a> | Report node internal IPs in Ingress status. | false |
| <a id="opt-providers-kubernetesingress-strictprefixmatching" href="#opt-providers-kubernetesingress-strictprefixmatching" title="#opt-providers-kubernetesingress-strictprefixmatching">providers.kubernetesingress.strictprefixmatching</a> | Make prefix matching strictly comply with the Kubernetes Ingress specification (path-element-wise matching instead of character-by-character string matching). | false |
| <a id="opt-providers-kubernetesingress-throttleduration" href="#opt-providers-kubernetesingress-throttleduration" title="#opt-providers-kubernetesingress-throttleduration">providers.kubernetesingress.throttleduration</a> | Ingress refresh throttle duration | 0 |
| <a id="opt-providers-kubernetesingress-token" href="#opt-providers-kubernetesingress-token" title="#opt-providers-kubernetesingress-token">providers.kubernetesingress.token</a> | Kubernetes bearer token (not needed for in-cluster client). It accepts either a token value or a file path to the token. | |
@@ -89,6 +89,7 @@ additionalArguments:
| <a id="opt-asDefault" href="#opt-asDefault" title="#opt-asDefault">`asDefault`</a> | Mark the `entryPoint` to be in the list of default `entryPoints`.<br /> `entryPoints`in this list are used (by default) on HTTP and TCP routers that do not define their own `entryPoints` option.<br /> More information [here](#asdefault). | false | No |
| <a id="opt-allowACMEByPass" href="#opt-allowACMEByPass" title="#opt-allowACMEByPass">`allowACMEByPass`</a> | Enables handling of ACME TLS and HTTP challenges with custom routers instead of the internal ACME router. | false | No |
| <a id="opt-forwardedHeaders-connection" href="#opt-forwardedHeaders-connection" title="#opt-forwardedHeaders-connection">`forwardedHeaders.`<br />`connection`</a> | List of Connection headers that are allowed to pass through the middleware chain before being removed. | false | No |
| <a id="opt-forwardedHeaders-addXForwardedSchemeHeaders" href="#opt-forwardedHeaders-addXForwardedSchemeHeaders" title="#opt-forwardedHeaders-addXForwardedSchemeHeaders">`forwardedHeaders.`<br />`addXForwardedSchemeHeaders`</a> | Add the compatibility headers `X-Forwarded-Scheme` and `X-Scheme`. | false | No |
| <a id="opt-forwardedHeaders-insecure" href="#opt-forwardedHeaders-insecure" title="#opt-forwardedHeaders-insecure">`forwardedHeaders.`<br />`insecure`</a> | Set the insecure mode to always trust the forwarded headers information (`X-Forwarded-*`).<br />We recommend to use this option only for tests purposes, not in production. | false | No |
| <a id="opt-forwardedHeaders-trustedIPs" href="#opt-forwardedHeaders-trustedIPs" title="#opt-forwardedHeaders-trustedIPs">`forwardedHeaders.`<br />`trustedIPs`</a> | Set the IPs or CIDR from where Traefik trusts the forwarded headers information (`X-Forwarded-*`). | - | No |
| <a id="opt-forwardedHeaders-notAppendXForwardedFor" href="#opt-forwardedHeaders-notAppendXForwardedFor" title="#opt-forwardedHeaders-notAppendXForwardedFor">`forwardedHeaders.`<br />`notAppendXForwardedFor`</a> | When set to `true`, Traefik will not append the client's `RemoteAddr` to the `X-Forwarded-For` header. The existing header is preserved as-is. If no `X-Forwarded-For` header exists, none will be added. | false | No |
@@ -392,6 +393,37 @@ You can configure Traefik to trust the forwarded headers information (`X-Forward
--entryPoints.web.forwardedHeaders.connection=foobar
```
??? info "`forwardedHeaders.addXForwardedSchemeHeaders`"
Add the compatibility headers `X-Forwarded-Scheme` and `X-Scheme` next to `X-Forwarded-Proto`.
This is primarily useful when migrating from ingress-nginx and your applications still rely on these legacy headers.
When enabled, these compatibility headers follow the same value as `X-Forwarded-Proto`.
```yaml tab="File (YAML)"
## Static configuration
entryPoints:
websecure:
address: ":443"
forwardedHeaders:
addXForwardedSchemeHeaders: true
```
```toml tab="File (TOML)"
## Static configuration
[entryPoints]
[entryPoints.websecure]
address = ":443"
[entryPoints.websecure.forwardedHeaders]
addXForwardedSchemeHeaders = true
```
```bash tab="CLI"
## Static configuration
--entryPoints.websecure.address=:443
--entryPoints.websecure.forwardedHeaders.addXForwardedSchemeHeaders=true
```
### HTTP3
As HTTP/3 actually uses UDP, when Traefik is configured with a TCP `entryPoint`
@@ -171,6 +171,9 @@ accessLog:
User-Agent: redact
# Drop the Authorization header value
Authorization: drop
queryParameters:
# Drop all query parameters
defaultMode: drop
```
```toml tab="File (TOML)"
@@ -194,6 +197,9 @@ accessLog:
[accessLog.fields.headers.names]
User-Agent = "redact"
Authorization = "drop"
[accessLog.fields.queryParameters]
defaultMode = "drop"
```
```sh tab="CLI"
@@ -208,6 +214,7 @@ accessLog:
--accesslog.fields.headers.defaultmode=keep
--accesslog.fields.headers.names.User-Agent=redact
--accesslog.fields.headers.names.Authorization=drop
--accesslog.fields.queryparameters.defaultmode=drop
```
### Configuration Options
@@ -228,6 +235,7 @@ The section below describes how to configure Traefik access logs using the stati
| <a id="opt-accesslog-fields-names" href="#opt-accesslog-fields-names" title="#opt-accesslog-fields-names">`accesslog.fields.names`</a> | Set the fields list to display in the access logs (format `name:mode`).<br /> Available fields list [here](#json-format-fields). | [ ] | No |
| <a id="opt-accesslog-fields-headers-defaultMode" href="#opt-accesslog-fields-headers-defaultMode" title="#opt-accesslog-fields-headers-defaultMode">`accesslog.fields.headers.defaultMode`</a> | Mode to apply by default to the access logs headers (`keep`, `redact` or `drop`). | drop | No |
| <a id="opt-accesslog-fields-headers-names" href="#opt-accesslog-fields-headers-names" title="#opt-accesslog-fields-headers-names">`accesslog.fields.headers.names`</a> | Set the headers list to display in the access logs (format `name:mode`). | [ ] | No |
| <a id="opt-accesslog-fields-queryParameters-defaultMode" href="#opt-accesslog-fields-queryParameters-defaultMode" title="#opt-accesslog-fields-queryParameters-defaultMode">`accesslog.fields.queryParameters.defaultMode`</a> | Mode to apply by default to the access logs query parameters (`keep` or `drop`) | keep | No |
### OpenTelemetry
@@ -65,6 +65,7 @@ providers:
| <a id="opt-providers-kubernetesCRD-allowEmptyServices" href="#opt-providers-kubernetesCRD-allowEmptyServices" title="#opt-providers-kubernetesCRD-allowEmptyServices">`providers.kubernetesCRD.allowEmptyServices`</a> | Allows creating a route to reach a service that has no endpoint available.<br />It allows Traefik to handle the requests and responses targeting this service (applying middleware or observability operations) before returning a `503` HTTP Status. | false | No |
| <a id="opt-providers-kubernetesCRD-allowCrossNamespace" href="#opt-providers-kubernetesCRD-allowCrossNamespace" title="#opt-providers-kubernetesCRD-allowCrossNamespace">`providers.kubernetesCRD.allowCrossNamespace`</a> | Allows the `IngressRoutes` to reference resources in namespaces other than theirs. | false | No |
| <a id="opt-providers-kubernetesCRD-allowExternalNameServices" href="#opt-providers-kubernetesCRD-allowExternalNameServices" title="#opt-providers-kubernetesCRD-allowExternalNameServices">`providers.kubernetesCRD.allowExternalNameServices`</a> | Allows the `IngressRoutes` to reference ExternalName services. | false | No |
| <a id="opt-providers-kubernetesCRD-crossProviderNamespaces" href="#opt-providers-kubernetesCRD-crossProviderNamespaces" title="#opt-providers-kubernetesCRD-crossProviderNamespaces">`providers.kubernetesCRD.crossProviderNamespaces`</a> | List of namespaces from which `IngressRoute`, `IngressRouteTCP`, `IngressRouteUDP`, and `TraefikService` are allowed to declare cross-provider references (e.g. `myservice@file`).<br />When unset, all namespaces are allowed. When set to `[]`, every cross-provider reference is rejected. | [] | No |
| <a id="opt-providers-kubernetesCRD-nativeLBByDefault" href="#opt-providers-kubernetesCRD-nativeLBByDefault" title="#opt-providers-kubernetesCRD-nativeLBByDefault">`providers.kubernetesCRD.nativeLBByDefault`</a> | Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik for every `IngressRoute` by default.<br />It can be overridden in the [`Service`](../../../../reference/routing-configuration/kubernetes/crd/http/service.md#opt-nativeLB). | false | No |
| <a id="opt-providers-kubernetesCRD-disableClusterScopeResources" href="#opt-providers-kubernetesCRD-disableClusterScopeResources" title="#opt-providers-kubernetesCRD-disableClusterScopeResources">`providers.kubernetesCRD.disableClusterScopeResources`</a> | Prevent from discovering cluster scope resources (`IngressClass` and `Nodes`).<br />By doing so, it alleviates the requirement of giving Traefik the rights to look up for cluster resources.<br />Furthermore, Traefik will not handle IngressRoutes with IngressClass references, therefore such Ingresses will be ignored (please note that annotations are not affected by this option).<br />This will also prevent from using the `NodePortLB` options on services. | false | No |
@@ -16,8 +16,7 @@ For more details, check out the conformance [report](https://github.com/kubernet
!!! info "Using The Helm Chart"
When using the Traefik [Helm Chart](../../../../getting-started/kubernetes.md#install-traefik), the CRDs (Custom Resource Definitions) and RBAC (Role-Based Access Control) are automatically managed for you.
The only remaining task is to enable the `kubernetesGateway` in the chart [values](https://github.com/traefik/traefik-helm-chart/blob/master/traefik/values.yaml).
When using the Traefik [Helm Chart](../../../../getting-started/kubernetes.md#install-traefik), the RBAC (Role-Based Access Control) are automatically managed for you.
## Requirements
@@ -30,10 +29,10 @@ For more details, check out the conformance [report](https://github.com/kubernet
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.5.1/standard-install.yaml
```
2. Install/update the Traefik [RBAC](../../../dynamic-configuration/kubernetes-gateway-rbac.yml).
2. If you are not using the Helm Chart, install/update the Traefik [RBAC](../../../dynamic-configuration/kubernetes-gateway-rbac.yml) for Gateway API.
```bash
# Install Traefik RBACs.
# Install Traefik RBACs for Gateway API.
kubectl apply -f https://raw.githubusercontent.com/traefik/traefik/v3.7/docs/content/reference/dynamic-configuration/kubernetes-gateway-rbac.yml
```
@@ -67,21 +66,24 @@ providers:
<!-- markdownlint-disable MD013 -->
| Field | Description | Default | Required |
|:----------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
| <a id="opt-providers-providersThrottleDuration" href="#opt-providers-providersThrottleDuration" title="#opt-providers-providersThrottleDuration">`providers.providersThrottleDuration`</a> | Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event.<br />If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded.<br />**This option cannot be set per provider, but the throttling algorithm applies to each of them independently.** | 2s | No |
| <a id="opt-providers-kubernetesGateway-endpoint" href="#opt-providers-kubernetesGateway-endpoint" title="#opt-providers-kubernetesGateway-endpoint">`providers.kubernetesGateway.endpoint`</a> | Server endpoint URL.<br />More information [here](#endpoint). | "" | No |
| <a id="opt-providers-kubernetesGateway-experimentalChannel" href="#opt-providers-kubernetesGateway-experimentalChannel" title="#opt-providers-kubernetesGateway-experimentalChannel">`providers.kubernetesGateway.experimentalChannel`</a> | Toggles support for the Experimental Channel resources ([Gateway API release channels documentation](https://gateway-api.sigs.k8s.io/concepts/versioning/#release-channels)).<br />(ex: `TCPRoute`) | false | No |
| <a id="opt-providers-kubernetesGateway-token" href="#opt-providers-kubernetesGateway-token" title="#opt-providers-kubernetesGateway-token">`providers.kubernetesGateway.token`</a> | Bearer token used for the Kubernetes client configuration. | "" | No |
| <a id="opt-providers-kubernetesGateway-certAuthFilePath" href="#opt-providers-kubernetesGateway-certAuthFilePath" title="#opt-providers-kubernetesGateway-certAuthFilePath">`providers.kubernetesGateway.certAuthFilePath`</a> | Path to the certificate authority file.<br />Used for the Kubernetes client configuration. | "" | No |
| <a id="opt-providers-kubernetesGateway-namespaces" href="#opt-providers-kubernetesGateway-namespaces" title="#opt-providers-kubernetesGateway-namespaces">`providers.kubernetesGateway.namespaces`</a> | Array of namespaces to watch.<br />If left empty, watch all namespaces. | [] | No |
| <a id="opt-providers-kubernetesGateway-labelselector" href="#opt-providers-kubernetesGateway-labelselector" title="#opt-providers-kubernetesGateway-labelselector">`providers.kubernetesGateway.labelselector`</a> | Allow filtering on `GatewayClass` only. If left empty, Traefik processes all GatewayClass objects in the configured namespaces.<br />See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details. | "" | No |
| <a id="opt-providers-kubernetesGateway-throttleDuration" href="#opt-providers-kubernetesGateway-throttleDuration" title="#opt-providers-kubernetesGateway-throttleDuration">`providers.kubernetesGateway.throttleDuration`</a> | Minimum amount of time to wait between two Kubernetes events before producing a new configuration.<br />This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration.<br />If empty, every event is caught. | 0s | No |
| <a id="opt-providers-kubernetesGateway-nativeLBByDefault" href="#opt-providers-kubernetesGateway-nativeLBByDefault" title="#opt-providers-kubernetesGateway-nativeLBByDefault">`providers.kubernetesGateway.nativeLBByDefault`</a> | Defines whether to use Native Kubernetes load-balancing mode by default. For more information, please check out the `traefik.io/service.nativelb` service annotation documentation. | false | No |
| <a id="opt-providers-kubernetesGateway-statusAddress-hostname" href="#opt-providers-kubernetesGateway-statusAddress-hostname" title="#opt-providers-kubernetesGateway-statusAddress-hostname">`providers.kubernetesGateway.`<br />`statusAddress.hostname`</a> | Hostname copied to the Gateway `status.addresses`. | "" | No |
| <a id="opt-providers-kubernetesGateway-statusAddress-ip" href="#opt-providers-kubernetesGateway-statusAddress-ip" title="#opt-providers-kubernetesGateway-statusAddress-ip">`providers.kubernetesGateway.`<br />`statusAddress.ip`</a> | IP address copied to the Gateway `status.addresses`, and currently only supports one IP value (IPv4 or IPv6). | "" | No |
| <a id="opt-providers-kubernetesGateway-statusAddress-service-namespace" href="#opt-providers-kubernetesGateway-statusAddress-service-namespace" title="#opt-providers-kubernetesGateway-statusAddress-service-namespace">`providers.kubernetesGateway.`<br />`statusAddress.service.namespace`</a> | The namespace of the Kubernetes service to copy status addresses from.<br />When using third parties tools like External-DNS, this option can be used to copy the service `loadbalancer.status` (containing the service's endpoints IPs) to the Gateway `status.addresses`. | "" | No |
| <a id="opt-providers-kubernetesGateway-statusAddress-service-name" href="#opt-providers-kubernetesGateway-statusAddress-service-name" title="#opt-providers-kubernetesGateway-statusAddress-service-name">`providers.kubernetesGateway.`<br />`statusAddress.service.name`</a> | The name of the Kubernetes service to copy status addresses from.<br />When using third parties tools like External-DNS, this option can be used to copy the service `loadbalancer.status` (containing the service's endpoints IPs) to the Gateway `status.addresses`. | "" | No |
| Field | Description | Default | Required |
|:----------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
| <a id="opt-providers-providersThrottleDuration" href="#opt-providers-providersThrottleDuration" title="#opt-providers-providersThrottleDuration">`providers.providersThrottleDuration`</a> | Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event.<br />If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded.<br />**This option cannot be set per provider, but the throttling algorithm applies to each of them independently.** | 2s | No |
| <a id="opt-providers-kubernetesGateway-endpoint" href="#opt-providers-kubernetesGateway-endpoint" title="#opt-providers-kubernetesGateway-endpoint">`providers.kubernetesGateway.endpoint`</a> | Server endpoint URL.<br />More information [here](#endpoint). | "" | No |
| <a id="opt-providers-kubernetesGateway-experimentalChannel" href="#opt-providers-kubernetesGateway-experimentalChannel" title="#opt-providers-kubernetesGateway-experimentalChannel">`providers.kubernetesGateway.experimentalChannel`</a> | Toggles support for the Experimental Channel resources ([Gateway API release channels documentation](https://gateway-api.sigs.k8s.io/concepts/versioning/#release-channels)).<br />(ex: `TCPRoute`) | false | No |
| <a id="opt-providers-kubernetesGateway-token" href="#opt-providers-kubernetesGateway-token" title="#opt-providers-kubernetesGateway-token">`providers.kubernetesGateway.token`</a> | Bearer token used for the Kubernetes client configuration. | "" | No |
| <a id="opt-providers-kubernetesGateway-certAuthFilePath" href="#opt-providers-kubernetesGateway-certAuthFilePath" title="#opt-providers-kubernetesGateway-certAuthFilePath">`providers.kubernetesGateway.certAuthFilePath`</a> | Path to the certificate authority file.<br />Used for the Kubernetes client configuration. | "" | No |
| <a id="opt-providers-kubernetesGateway-namespaces" href="#opt-providers-kubernetesGateway-namespaces" title="#opt-providers-kubernetesGateway-namespaces">`providers.kubernetesGateway.namespaces`</a> | Array of namespaces to watch.<br />If left empty, watch all namespaces. | [] | No |
| <a id="opt-providers-kubernetesGateway-labelselector" href="#opt-providers-kubernetesGateway-labelselector" title="#opt-providers-kubernetesGateway-labelselector">`providers.kubernetesGateway.labelselector`</a> | Allow filtering on `GatewayClass` only. If left empty, Traefik processes all GatewayClass objects in the configured namespaces.<br />See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details. | "" | No |
| <a id="opt-providers-kubernetesGateway-throttleDuration" href="#opt-providers-kubernetesGateway-throttleDuration" title="#opt-providers-kubernetesGateway-throttleDuration">`providers.kubernetesGateway.throttleDuration`</a> | Minimum amount of time to wait between two Kubernetes events before producing a new configuration.<br />This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration.<br />If empty, every event is caught. | 0s | No |
| <a id="opt-providers-kubernetesGateway-nativeLBByDefault" href="#opt-providers-kubernetesGateway-nativeLBByDefault" title="#opt-providers-kubernetesGateway-nativeLBByDefault">`providers.kubernetesGateway.nativeLBByDefault`</a> | Defines whether to use Native Kubernetes load-balancing mode by default. For more information, please check out the `traefik.io/service.nativelb` service annotation documentation. | false | No |
| <a id="opt-providers-kubernetesGateway-statusAddress-hostname" href="#opt-providers-kubernetesGateway-statusAddress-hostname" title="#opt-providers-kubernetesGateway-statusAddress-hostname">`providers.kubernetesGateway.`<br />`statusAddress.hostname`</a> | Hostname copied to the Gateway `status.addresses`. | "" | No |
| <a id="opt-providers-kubernetesGateway-statusAddress-ip" href="#opt-providers-kubernetesGateway-statusAddress-ip" title="#opt-providers-kubernetesGateway-statusAddress-ip">`providers.kubernetesGateway.`<br />`statusAddress.ip`</a> | IP address copied to the Gateway `status.addresses`, and currently only supports one IP value (IPv4 or IPv6). | "" | No |
| <a id="opt-providers-kubernetesGateway-statusAddress-service-namespace" href="#opt-providers-kubernetesGateway-statusAddress-service-namespace" title="#opt-providers-kubernetesGateway-statusAddress-service-namespace">`providers.kubernetesGateway.`<br />`statusAddress.service.namespace`</a> | The namespace of the Kubernetes service to copy status addresses from.<br />When using third parties tools like External-DNS, this option can be used to copy the service `loadbalancer.status` (containing the service's endpoints IPs) to the Gateway `status.addresses`. | "" | No |
| <a id="opt-providers-kubernetesGateway-statusAddress-service-name" href="#opt-providers-kubernetesGateway-statusAddress-service-name" title="#opt-providers-kubernetesGateway-statusAddress-service-name">`providers.kubernetesGateway.`<br />`statusAddress.service.name`</a> | The name of the Kubernetes service to copy status addresses from.<br />When using third parties tools like External-DNS, this option can be used to copy the service `loadbalancer.status` (containing the service's endpoints IPs) to the Gateway `status.addresses`. | "" | No |
| <a id="opt-providers-kubernetesGateway-crossProviderNamespaces" href="#opt-providers-kubernetesGateway-crossProviderNamespaces" title="#opt-providers-kubernetesGateway-crossProviderNamespaces">`providers.kubernetesGateway.crossProviderNamespaces`</a> | List of namespaces from which Gateway API routes (`HTTPRoute`, `TCPRoute`, `TLSRoute`) are allowed to declare a `backendRef` of kind `TraefikService`.<br />When unset, all namespaces are allowed. When set to `[]`, every such backendRef is rejected and the route is dropped. | [] | No |
| <a id="opt-providers-kubernetesgateway-qps" href="#opt-providers-kubernetesgateway-qps" title="#opt-providers-kubernetesgateway-qps">providers.kubernetesgateway.qps</a> | Defines the maximum QPS to the Kubernetes API server. Setting this to a negative value will disable client-side ratelimiting. | 50 | No |
| <a id="opt-providers-kubernetesgateway-burst" href="#opt-providers-kubernetesgateway-burst" title="#opt-providers-kubernetesgateway-burst">providers.kubernetesgateway.burst</a> | Defines the maximum burst of requests to the Kubernetes API server. | 100 | No |
<!-- markdownlint-enable MD013 -->
@@ -45,25 +45,27 @@ which in turn creates the resulting routers, services, handlers, etc.
<!-- markdownlint-disable MD013 -->
| Field | Description | Default | Required |
| :------------------------------------------------------------------ | :------------- | :------ | :------- |
| <a id="opt-providers-providersThrottleDuration" href="#opt-providers-providersThrottleDuration" title="#opt-providers-providersThrottleDuration">`providers.providersThrottleDuration`</a> | Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event.<br />If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded.<br />**This option cannot be set per provider, but the throttling algorithm applies to each of them independently.** | 2s | No |
| <a id="opt-providers-kubernetesIngress-endpoint" href="#opt-providers-kubernetesIngress-endpoint" title="#opt-providers-kubernetesIngress-endpoint">`providers.kubernetesIngress.endpoint`</a> | Server endpoint URL.<br />More information [here](#endpoint). | "" | No |
| <a id="opt-providers-kubernetesIngress-token" href="#opt-providers-kubernetesIngress-token" title="#opt-providers-kubernetesIngress-token">`providers.kubernetesIngress.token`</a> | Bearer token used for the Kubernetes client configuration. | "" | No |
| <a id="opt-providers-kubernetesIngress-certAuthFilePath" href="#opt-providers-kubernetesIngress-certAuthFilePath" title="#opt-providers-kubernetesIngress-certAuthFilePath">`providers.kubernetesIngress.certAuthFilePath`</a> | Path to the certificate authority file.<br />Used for the Kubernetes client configuration. | "" | No |
| <a id="opt-providers-kubernetesIngress-namespaces" href="#opt-providers-kubernetesIngress-namespaces" title="#opt-providers-kubernetesIngress-namespaces">`providers.kubernetesIngress.namespaces`</a> | Array of namespaces to watch.<br />If left empty, watch all namespaces. | | No |
| <a id="opt-providers-kubernetesIngress-labelselector" href="#opt-providers-kubernetesIngress-labelselector" title="#opt-providers-kubernetesIngress-labelselector">`providers.kubernetesIngress.labelselector`</a> | Allow filtering on `Ingress` objects using label selectors.<br />No effect on Kubernetes `Secrets`, `EndpointSlices` and `Services`.<br />See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details. | "" | No |
| <a id="opt-providers-kubernetesIngress-ingressClass" href="#opt-providers-kubernetesIngress-ingressClass" title="#opt-providers-kubernetesIngress-ingressClass">`providers.kubernetesIngress.ingressClass`</a> | The `IngressClass` resource name or the `kubernetes.io/ingress.class` annotation value that identifies resource objects to be processed.<br />If empty, resources missing the annotation, having an empty value, or the value `traefik` are processed. | "" | No |
| <a id="opt-providers-kubernetesIngress-disableIngressClassLookup" href="#opt-providers-kubernetesIngress-disableIngressClassLookup" title="#opt-providers-kubernetesIngress-disableIngressClassLookup">`providers.kubernetesIngress.disableIngressClassLookup`</a> | Prevent to discover IngressClasses in the cluster.<br />It alleviates the requirement of giving Traefik the rights to look IngressClasses up.<br />Ignore Ingresses with IngressClass.<br />Annotations are not affected by this option. | false | No |
| <a id="opt-providers-kubernetesIngress-ingressEndpoint-hostname" href="#opt-providers-kubernetesIngress-ingressEndpoint-hostname" title="#opt-providers-kubernetesIngress-ingressEndpoint-hostname">`providers.kubernetesIngress.`<br />`ingressEndpoint.hostname`</a> | Hostname used for Kubernetes Ingress endpoints. | "" | No |
| <a id="opt-providers-kubernetesIngress-ingressEndpoint-ip" href="#opt-providers-kubernetesIngress-ingressEndpoint-ip" title="#opt-providers-kubernetesIngress-ingressEndpoint-ip">`providers.kubernetesIngress.`<br />`ingressEndpoint.ip`</a> | This IP will get copied to the Ingress `status.loadbalancer.ip`, and currently only supports one IP value (IPv4 or IPv6). | "" | No |
| <a id="opt-providers-kubernetesIngress-ingressEndpoint-publishedService" href="#opt-providers-kubernetesIngress-ingressEndpoint-publishedService" title="#opt-providers-kubernetesIngress-ingressEndpoint-publishedService">`providers.kubernetesIngress.`<br />`ingressEndpoint.publishedService`</a> | The Kubernetes service to copy status from.<br />More information [here](#ingressendpointpublishedservice). | "" | No |
| <a id="opt-providers-kubernetesIngress-throttleDuration" href="#opt-providers-kubernetesIngress-throttleDuration" title="#opt-providers-kubernetesIngress-throttleDuration">`providers.kubernetesIngress.throttleDuration`</a> | Minimum amount of time to wait between two Kubernetes events before producing a new configuration.<br />This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration.<br />If empty, every event is caught. | 0s | No |
| <a id="opt-providers-kubernetesIngress-allowEmptyServices" href="#opt-providers-kubernetesIngress-allowEmptyServices" title="#opt-providers-kubernetesIngress-allowEmptyServices">`providers.kubernetesIngress.allowEmptyServices`</a> | Allows creating a route to reach a service that has no endpoint available.<br />It allows Traefik to handle the requests and responses targeting this service (applying middleware or observability operations) before returning a `503` HTTP Status. | false | No |
| <a id="opt-providers-kubernetesIngress-allowExternalNameServices" href="#opt-providers-kubernetesIngress-allowExternalNameServices" title="#opt-providers-kubernetesIngress-allowExternalNameServices">`providers.kubernetesIngress.allowExternalNameServices`</a> | Allows the `Ingress` to reference ExternalName services. | false | No |
| <a id="opt-providers-kubernetesIngress-nativeLBByDefault" href="#opt-providers-kubernetesIngress-nativeLBByDefault" title="#opt-providers-kubernetesIngress-nativeLBByDefault">`providers.kubernetesIngress.nativeLBByDefault`</a> | Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik for every `Ingress` by default.<br />It can be overridden in the [`Service`](../../../../reference/routing-configuration/kubernetes/crd/http/service.md#opt-nativeLB) | false | No |
| <a id="opt-providers-kubernetesIngress-disableClusterScopeResources" href="#opt-providers-kubernetesIngress-disableClusterScopeResources" title="#opt-providers-kubernetesIngress-disableClusterScopeResources">`providers.kubernetesIngress.disableClusterScopeResources`</a> | Prevent from discovering cluster scope resources (`IngressClass` and `Nodes`).<br />By doing so, it alleviates the requirement of giving Traefik the rights to look up for cluster resources.<br />Furthermore, Traefik will not handle Ingresses with IngressClass references, therefore such Ingresses will be ignored (please note that annotations are not affected by this option).<br />This will also prevent from using the `NodePortLB` options on services. | false | No |
| <a id="opt-providers-kubernetesIngress-strictPrefixMatching" href="#opt-providers-kubernetesIngress-strictPrefixMatching" title="#opt-providers-kubernetesIngress-strictPrefixMatching">`providers.kubernetesIngress.strictPrefixMatching`</a> | Make prefix matching strictly comply with the Kubernetes Ingress specification (path-element-wise matching instead of character-by-character string matching). For example, a PathPrefix of `/foo` will match `/foo`, `/foo/`, and `/foo/bar` but not `/foobar`. | false | No |
| Field | Description | Default | Required |
|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------|:---------|
| <a id="opt-providers-providersThrottleDuration" href="#opt-providers-providersThrottleDuration" title="#opt-providers-providersThrottleDuration">`providers.providersThrottleDuration`</a> | Minimum amount of time to wait for, after a configuration reload, before taking into account any new configuration refresh event.<br />If multiple events occur within this time, only the most recent one is taken into account, and all others are discarded.<br />**This option cannot be set per provider, but the throttling algorithm applies to each of them independently.** | 2s | No |
| <a id="opt-providers-kubernetesIngress-endpoint" href="#opt-providers-kubernetesIngress-endpoint" title="#opt-providers-kubernetesIngress-endpoint">`providers.kubernetesIngress.endpoint`</a> | Server endpoint URL.<br />More information [here](#endpoint). | "" | No |
| <a id="opt-providers-kubernetesIngress-token" href="#opt-providers-kubernetesIngress-token" title="#opt-providers-kubernetesIngress-token">`providers.kubernetesIngress.token`</a> | Bearer token used for the Kubernetes client configuration. | "" | No |
| <a id="opt-providers-kubernetesIngress-certAuthFilePath" href="#opt-providers-kubernetesIngress-certAuthFilePath" title="#opt-providers-kubernetesIngress-certAuthFilePath">`providers.kubernetesIngress.certAuthFilePath`</a> | Path to the certificate authority file.<br />Used for the Kubernetes client configuration. | "" | No |
| <a id="opt-providers-kubernetesIngress-namespaces" href="#opt-providers-kubernetesIngress-namespaces" title="#opt-providers-kubernetesIngress-namespaces">`providers.kubernetesIngress.namespaces`</a> | Array of namespaces to watch.<br />If left empty, watch all namespaces. | | No |
| <a id="opt-providers-kubernetesIngress-labelselector" href="#opt-providers-kubernetesIngress-labelselector" title="#opt-providers-kubernetesIngress-labelselector">`providers.kubernetesIngress.labelselector`</a> | Allow filtering on `Ingress` objects using label selectors.<br />No effect on Kubernetes `Secrets`, `EndpointSlices` and `Services`.<br />See [label-selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors) for details. | "" | No |
| <a id="opt-providers-kubernetesIngress-ingressClass" href="#opt-providers-kubernetesIngress-ingressClass" title="#opt-providers-kubernetesIngress-ingressClass">`providers.kubernetesIngress.ingressClass`</a> | The `IngressClass` resource name or the `kubernetes.io/ingress.class` annotation value that identifies resource objects to be processed.<br />If empty, resources missing the annotation, having an empty value, or the value `traefik` are processed. | "" | No |
| <a id="opt-providers-kubernetesIngress-disableIngressClassLookup" href="#opt-providers-kubernetesIngress-disableIngressClassLookup" title="#opt-providers-kubernetesIngress-disableIngressClassLookup">`providers.kubernetesIngress.disableIngressClassLookup`</a> | Prevent to discover IngressClasses in the cluster.<br />It alleviates the requirement of giving Traefik the rights to look IngressClasses up.<br />Ignore Ingresses with IngressClass.<br />Annotations are not affected by this option. | false | No |
| <a id="opt-providers-kubernetesIngress-ingressEndpoint-hostname" href="#opt-providers-kubernetesIngress-ingressEndpoint-hostname" title="#opt-providers-kubernetesIngress-ingressEndpoint-hostname">`providers.kubernetesIngress.`<br />`ingressEndpoint.hostname`</a> | Hostname used for Kubernetes Ingress endpoints. | "" | No |
| <a id="opt-providers-kubernetesIngress-ingressEndpoint-ip" href="#opt-providers-kubernetesIngress-ingressEndpoint-ip" title="#opt-providers-kubernetesIngress-ingressEndpoint-ip">`providers.kubernetesIngress.`<br />`ingressEndpoint.ip`</a> | This IP will get copied to the Ingress `status.loadbalancer.ip`, and currently only supports one IP value (IPv4 or IPv6). | "" | No |
| <a id="opt-providers-kubernetesIngress-ingressEndpoint-publishedService" href="#opt-providers-kubernetesIngress-ingressEndpoint-publishedService" title="#opt-providers-kubernetesIngress-ingressEndpoint-publishedService">`providers.kubernetesIngress.`<br />`ingressEndpoint.publishedService`</a> | The Kubernetes service to copy status from.<br />More information [here](#ingressendpointpublishedservice). | "" | No |
| <a id="opt-providers-kubernetesIngress-reportNodeInternalIPs" href="#opt-providers-kubernetesIngress-reportNodeInternalIPs" title="#opt-providers-kubernetesIngress-reportNodeInternalIPs">`providers.kubernetesIngress.reportNodeInternalIPs`</a> | Report node internal IPs in Ingress status.<br />Incompatible with `ingressEndpoint` and `disableClusterScopeResources`.<br />More information [here](#reportnodeinternalips). | false | No |
| <a id="opt-providers-kubernetesIngress-throttleDuration" href="#opt-providers-kubernetesIngress-throttleDuration" title="#opt-providers-kubernetesIngress-throttleDuration">`providers.kubernetesIngress.throttleDuration`</a> | Minimum amount of time to wait between two Kubernetes events before producing a new configuration.<br />This prevents a Kubernetes cluster that updates many times per second from continuously changing your Traefik configuration.<br />If empty, every event is caught. | 0s | No |
| <a id="opt-providers-kubernetesIngress-allowEmptyServices" href="#opt-providers-kubernetesIngress-allowEmptyServices" title="#opt-providers-kubernetesIngress-allowEmptyServices">`providers.kubernetesIngress.allowEmptyServices`</a> | Allows creating a route to reach a service that has no endpoint available.<br />It allows Traefik to handle the requests and responses targeting this service (applying middleware or observability operations) before returning a `503` HTTP Status. | false | No |
| <a id="opt-providers-kubernetesIngress-allowExternalNameServices" href="#opt-providers-kubernetesIngress-allowExternalNameServices" title="#opt-providers-kubernetesIngress-allowExternalNameServices">`providers.kubernetesIngress.allowExternalNameServices`</a> | Allows the `Ingress` to reference ExternalName services. | false | No |
| <a id="opt-providers-kubernetesIngress-crossProviderNamespaces" href="#opt-providers-kubernetesIngress-crossProviderNamespaces" title="#opt-providers-kubernetesIngress-crossProviderNamespaces">`providers.kubernetesIngress.crossProviderNamespaces`</a> | List of namespaces from which Ingresses or Services are allowed to use `traefik.ingress.kubernetes.io/router.middlewares`, `traefik.ingress.kubernetes.io/router.tls.options`, or `traefik.ingress.kubernetes.io/service.serverstransport` annotations.<br />When unset, all namespaces are allowed. When set to `[]`, every cross-provider reference is rejected. | [] | No |
| <a id="opt-providers-kubernetesIngress-nativeLBByDefault" href="#opt-providers-kubernetesIngress-nativeLBByDefault" title="#opt-providers-kubernetesIngress-nativeLBByDefault">`providers.kubernetesIngress.nativeLBByDefault`</a> | Allow using the Kubernetes Service load balancing between the pods instead of the one provided by Traefik for every `Ingress` by default.<br />It can be overridden in the [`Service`](../../../../reference/routing-configuration/kubernetes/crd/http/service.md#opt-nativeLB) | false | No |
| <a id="opt-providers-kubernetesIngress-disableClusterScopeResources" href="#opt-providers-kubernetesIngress-disableClusterScopeResources" title="#opt-providers-kubernetesIngress-disableClusterScopeResources">`providers.kubernetesIngress.disableClusterScopeResources`</a> | Prevent from discovering cluster scope resources (`IngressClass` and `Nodes`).<br />By doing so, it alleviates the requirement of giving Traefik the rights to look up for cluster resources.<br />Furthermore, Traefik will not handle Ingresses with IngressClass references, therefore such Ingresses will be ignored (please note that annotations are not affected by this option).<br />This will also prevent from using the `NodePortLB` options on services and is incompatible with `reportNodeInternalIPs`. | false | No |
| <a id="opt-providers-kubernetesIngress-strictPrefixMatching" href="#opt-providers-kubernetesIngress-strictPrefixMatching" title="#opt-providers-kubernetesIngress-strictPrefixMatching">`providers.kubernetesIngress.strictPrefixMatching`</a> | Make prefix matching strictly comply with the Kubernetes Ingress specification (path-element-wise matching instead of character-by-character string matching). For example, a PathPrefix of `/foo` will match `/foo`, `/foo/`, and `/foo/bar` but not `/foobar`. | false | No |
<!-- markdownlint-enable MD013 -->
@@ -137,6 +139,31 @@ providers:
--providers.kubernetesingress.ingressendpoint.publishedservice=namespace/foo-service
```
### `reportNodeInternalIPs`
When set to `true`, Traefik reports the internal IPs of all nodes in the cluster into the `status.loadBalancer.ingress` field of each managed Ingress resource.
This is the equivalent of ingress-nginx's `--report-node-internal-ip-address` flag and is the recommended approach for bare-metal Kubernetes deployments where Traefik runs as a DaemonSet without a cloud LoadBalancer or MetalLB.
This option requires cluster-scope access to Node resources and is mutually exclusive with `ingressEndpoint` and `disableClusterScopeResources`.
```yaml tab="File (YAML)"
providers:
kubernetesIngress:
reportNodeInternalIPs: true
# ...
```
```toml tab="File (TOML)"
[providers.kubernetesIngress]
reportNodeInternalIPs = true
# ...
```
```bash tab="CLI"
--providers.kubernetesingress.reportnodeinternalips=true
```
## Routing Configuration
See the dedicated section in [routing](../../../../reference/routing-configuration/kubernetes/ingress.md).
@@ -23,7 +23,11 @@ http:
- "/path/to/rootca2.pem"
maxIdleConnsPerHost: 100
disableHTTP2: true
peerCertURI: "spiffe://example.org/peer"
peerCertSANs:
- type: DNSName
value: foo.com
- type: URI
value: spiffe://example.org/peer
forwardingTimeouts:
dialTimeout: "30s"
responseHeaderTimeout: "10s"
@@ -50,7 +54,7 @@ http:
rootcas = ["/path/to/rootca1.pem", "/path/to/rootca2.pem"]
maxIdleConnsPerHost = 100
disableHTTP2 = true
peerCertURI = "spiffe://example.org/peer"
peerCertSANs = [{type = "DNSName", value = "foo.com"}, {type = "URI", value = "spiffe://example.org/peer"}]
cipherSuites = ["TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256","TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"]
minVersion = "VersionTLS12"
maxVersion = "VersionTLS12"
@@ -108,12 +112,14 @@ labels:
| <a id="opt-certificates" href="#opt-certificates" title="#opt-certificates">`certificates`</a> | Defines the list of certificates (as file paths, or data bytes) that will be set as client certificates for mTLS. | [] | No |
| <a id="opt-insecureSkipVerify" href="#opt-insecureSkipVerify" title="#opt-insecureSkipVerify">`insecureSkipVerify`</a> | Controls whether the server's certificate chain and host name is verified. | false | No |
| <a id="opt-rootcas" href="#opt-rootcas" title="#opt-rootcas">`rootcas`</a> | Set of root certificate authorities to use when verifying server certificates. (for mTLS connections). | [] | No |
| <a id="opt-cipherSuites" href="#opt-cipherSuites" title="#opt-cipherSuites">`cipherSuites`</a> | Defines the cipher suites to use when contacting backend servers. | [] | No |
| <a id="opt-minVersion" href="#opt-minVersion" title="#opt-minVersion">`minVersion`</a> | Defines the minimum TLS version to use when contacting backend servers. | "" | No |
| <a id="opt-maxVersion" href="#opt-maxVersion" title="#opt-maxVersion">`maxVersion`</a> | Defines the maximum TLS version to use when contacting backend servers. | "" | No |
| <a id="opt-cipherSuites" href="#opt-cipherSuites" title="#opt-cipherSuites">`cipherSuites`</a> | Defines the cipher suites to use when contacting backend servers. | [] | No |
| <a id="opt-minVersion" href="#opt-minVersion" title="#opt-minVersion">`minVersion`</a> | Defines the minimum TLS version to use when contacting backend servers. | "" | No |
| <a id="opt-maxVersion" href="#opt-maxVersion" title="#opt-maxVersion">`maxVersion`</a> | Defines the maximum TLS version to use when contacting backend servers. | "" | No |
| <a id="opt-maxIdleConnsPerHost" href="#opt-maxIdleConnsPerHost" title="#opt-maxIdleConnsPerHost">`maxIdleConnsPerHost`</a> | Maximum idle (keep-alive) connections to keep per-host. | 200 | No |
| <a id="opt-disableHTTP2" href="#opt-disableHTTP2" title="#opt-disableHTTP2">`disableHTTP2`</a> | Disables HTTP/2 for connections with servers. | false | No |
| <a id="opt-peerCertURI" href="#opt-peerCertURI" title="#opt-peerCertURI">`peerCertURI`</a> | Defines the URI used to match against SAN URIs during the server's certificate verification. | "" | No |
| <a id="opt-peerCertSANs" href="#opt-peerCertSANs" title="#opt-peerCertSANs">`peerCertSANs`</a> | Defines the SANs (Subject Alternative Names) used to match against SANs during the peer certificate verification. | [] | No |
| <a id="opt-peerCertSANs-type" href="#opt-peerCertSANs-type" title="#opt-peerCertSANs-type">`peerCertSANs[].type`</a> | Defines the SAN type (`URI` or `DNSName`) to match against the peer certificate's Subject Alternative Names. | "" | No |
| <a id="opt-peerCertSANs-value" href="#opt-peerCertSANs-value" title="#opt-peerCertSANs-value">`peerCertSANs[].value`</a> | Defines the SAN value to match against the peer certificate's Subject Alternative Names. | "" | No |
| <a id="opt-forwardingTimeouts-dialTimeout" href="#opt-forwardingTimeouts-dialTimeout" title="#opt-forwardingTimeouts-dialTimeout">`forwardingTimeouts.dialTimeout`</a> | Amount of time to wait until a connection to a server can be established.<br />0 = no timeout | 30s | No |
| <a id="opt-forwardingTimeouts-responseHeaderTimeout" href="#opt-forwardingTimeouts-responseHeaderTimeout" title="#opt-forwardingTimeouts-responseHeaderTimeout">`forwardingTimeouts.responseHeaderTimeout`</a> | Amount of time to wait for a server's response headers after fully writing the request (including its body, if any).<br />0 = no timeout | 0s | No |
| <a id="opt-forwardingTimeouts-idleConnTimeout" href="#opt-forwardingTimeouts-idleConnTimeout" title="#opt-forwardingTimeouts-idleConnTimeout">`forwardingTimeouts.idleConnTimeout`</a> | Maximum amount of time an idle (keep-alive) connection will remain idle before closing itself.<br />0 = no timeout | 90s | No |
@@ -62,7 +62,7 @@ spec:
| <a id="opt-authRequestHeaders" href="#opt-authRequestHeaders" title="#opt-authRequestHeaders">`authRequestHeaders`</a> | List of the headers to copy from the request to the authentication server. <br /> It allows filtering headers that should not be passed to the authentication server. <br /> If not set or empty, then all request headers are passed. | [] | No |
| <a id="opt-addAuthCookiesToResponse" href="#opt-addAuthCookiesToResponse" title="#opt-addAuthCookiesToResponse">`addAuthCookiesToResponse`</a> | List of cookies to copy from the authentication server to the response, replacing any existing conflicting cookie from the forwarded response.<br /> Please note that all backend cookies matching the configured list will not be added to the response. | [] | No |
| <a id="opt-forwardBody" href="#opt-forwardBody" title="#opt-forwardBody">`forwardBody`</a> | Sets the `forwardBody` option to `true` to send the Body. As body is read inside Traefik before forwarding, this breaks streaming. | false | No |
| <a id="opt-maxBodySize" href="#opt-maxBodySize" title="#opt-maxBodySize">`maxBodySize`</a> | Set the `maxBodySize` to limit the body size in bytes. If body is bigger than this, it returns a 401 (unauthorized). If left unset, the request body size is unrestricted which can have performance or security implications. < br/>More information [here](#maxbodysize). | -1 | No |
| <a id="opt-maxBodySize" href="#opt-maxBodySize" title="#opt-maxBodySize">`maxBodySize`</a> | Set the `maxBodySize` to limit the body size in bytes. If body is bigger than this, it returns a 401 (unauthorized). If left unset, the request body size is unrestricted which can have performance or security implications. <br/>More information [here](#maxbodysize). | -1 | No |
| <a id="opt-maxResponseBodySize" href="#opt-maxResponseBodySize" title="#opt-maxResponseBodySize">`maxResponseBodySize`</a> | Set the `maxResponseBodySize` to limit the response body size from the authentication server in bytes. If the response body exceeds this limit, it returns a 401 (unauthorized). If left unset, the response body size is unrestricted which can have performance or security implications. <br/>More information [here](#maxresponsebodysize).| -1 | No |
| <a id="opt-headerField" href="#opt-headerField" title="#opt-headerField">`headerField`</a> | Defines a header field to store the authenticated user. | "" | No |
| <a id="opt-preserveLocationHeader" href="#opt-preserveLocationHeader" title="#opt-preserveLocationHeader">`preserveLocationHeader`</a> | Defines whether to forward the Location header to the client as is or prefix it with the domain name of the authentication server. | false | No |
@@ -92,7 +92,7 @@ spec:
| <a id="opt-routesn-middlewares" href="#opt-routesn-middlewares" title="#opt-routesn-middlewares">`routes[n].middlewares`</a> | List of middlewares to attach to the IngressRoute. <br />More information [here](#middleware). | "" | No |
| <a id="opt-routesn-middlewaresm-name" href="#opt-routesn-middlewaresm-name" title="#opt-routesn-middlewaresm-name">`routes[n].`<br />`middlewares[m].`<br />`name`</a> | Middleware name.<br />The character `@` is not authorized. <br />More information [here](#middleware). | | Yes |
| <a id="opt-routesn-middlewaresm-namespace" href="#opt-routesn-middlewaresm-namespace" title="#opt-routesn-middlewaresm-namespace">`routes[n].`<br />`middlewares[m].`<br />`namespace`</a> | Middleware namespace.<br />Can be empty if the middleware belongs to the same namespace as the IngressRoute. <br />More information [here](#middleware). | | No |
| <a id="opt-routesn-observability-accesslogs" href="#opt-routesn-observability-accesslogs" title="#opt-routesn-observability-accesslogs">`routes[n].`<br />`observability.`<br />`accesslogs`</a> | Defines whether the route will produce [access-logs](../../../../install-configuration/observability/logs-and-accesslogs.md). See [here](../../../http/routing/observability.md) for more information. | false | No |
| <a id="opt-routesn-observability-accessLogs" href="#opt-routesn-observability-accessLogs" title="#opt-routesn-observability-accessLogs">`routes[n].`<br />`observability.`<br />`accessLogs`</a> | Defines whether the route will produce [access-logs](../../../../install-configuration/observability/logs-and-accesslogs.md). See [here](../../../http/routing/observability.md) for more information. | false | No |
| <a id="opt-routesn-observability-metrics" href="#opt-routesn-observability-metrics" title="#opt-routesn-observability-metrics">`routes[n].`<br />`observability.`<br />`metrics`</a> | Defines whether the route will produce [metrics](../../../../install-configuration/observability/metrics.md). See [here](../../../http/routing/observability.md) for more information. | false | No |
| <a id="opt-routesn-observability-tracing" href="#opt-routesn-observability-tracing" title="#opt-routesn-observability-tracing">`routes[n].`<br />`observability.`<br />`tracing`</a> | Defines whether the route will produce [traces](../../../../install-configuration/observability/tracing.md). See [here](../../../http/routing/observability.md) for more information. | false | No |
| <a id="opt-tls" href="#opt-tls" title="#opt-tls">`tls`</a> | TLS configuration.<br />Can be an empty value(`{}`):<br />A self signed is generated in such a case<br />(or the [default certificate](../tls/tlsstore.md) is used if it is defined.) | | No |
@@ -53,35 +53,25 @@ spec:
## Configuration Options
| Field | Description | Default | Required |
|:------|:----------------------------------------------------------|:---------------------|:---------|
| <a id="opt-serverstransport-serverName" href="#opt-serverstransport-serverName" title="#opt-serverstransport-serverName">`serverstransport.`<br />`serverName`</a> | Defines the server name that will be used for SNI. | | No |
| <a id="opt-serverstransport-insecureSkipVerify" href="#opt-serverstransport-insecureSkipVerify" title="#opt-serverstransport-insecureSkipVerify">`serverstransport.`<br />`insecureSkipVerify`</a> | Controls whether the server's certificate chain and host name is verified. | false | No |
| <a id="opt-serverstransport-rootcas" href="#opt-serverstransport-rootcas" title="#opt-serverstransport-rootcas">`serverstransport.`<br />`rootcas`</a> | Set of root certificate authorities to use when verifying server certificates. (for mTLS connections). | | No |
| <a id="opt-serverstransport-certificatesSecrets" href="#opt-serverstransport-certificatesSecrets" title="#opt-serverstransport-certificatesSecrets">`serverstransport.`<br />`certificatesSecrets`</a> | Certificates to present to the server for mTLS. | | No |
| <a id="opt-serverstransport-maxIdleConnsPerHost" href="#opt-serverstransport-maxIdleConnsPerHost" title="#opt-serverstransport-maxIdleConnsPerHost">`serverstransport.`<br />`maxIdleConnsPerHost`</a> | Maximum idle (keep-alive) connections to keep per-host. | 200 | No |
| <a id="opt-serverstransport-disableHTTP2" href="#opt-serverstransport-disableHTTP2" title="#opt-serverstransport-disableHTTP2">`serverstransport.`<br />`disableHTTP2`</a> | Disables HTTP/2 for connections with servers. | false | No |
| <a id="opt-serverstransport-peerCertURI" href="#opt-serverstransport-peerCertURI" title="#opt-serverstransport-peerCertURI">`serverstransport.`<br />`peerCertURI`</a> | Defines the URI used to match against SAN URIs during the server's certificate verification. | "" | No |
| <a id="opt-serverstransport-forwardingTimeouts-dialTimeout" href="#opt-serverstransport-forwardingTimeouts-dialTimeout" title="#opt-serverstransport-forwardingTimeouts-dialTimeout">`serverstransport.`<br />`forwardingTimeouts.dialTimeout`</a> | Amount of time to wait until a connection to a server can be established.<br />Zero means no timeout. | 30s | No |
| <a id="opt-serverstransport-forwardingTimeouts-responseHeaderTimeout" href="#opt-serverstransport-forwardingTimeouts-responseHeaderTimeout" title="#opt-serverstransport-forwardingTimeouts-responseHeaderTimeout">`serverstransport.`<br />`forwardingTimeouts.responseHeaderTimeout`</a> | Amount of time to wait for a server's response headers after fully writing the request (including its body, if any).<br />Zero means no timeout | 0s | No |
| <a id="opt-serverstransport-forwardingTimeouts-idleConnTimeout" href="#opt-serverstransport-forwardingTimeouts-idleConnTimeout" title="#opt-serverstransport-forwardingTimeouts-idleConnTimeout">`serverstransport.`<br />`forwardingTimeouts.idleConnTimeout`</a> | Maximum amount of time an idle (keep-alive) connection will remain idle before closing itself.<br />Zero means no timeout. | 90s | No |
| <a id="opt-serverstransport-spiffe-ids" href="#opt-serverstransport-spiffe-ids" title="#opt-serverstransport-spiffe-ids">`serverstransport.`<br />`spiffe.ids`</a> | Allow SPIFFE IDs.<br />This takes precedence over the SPIFFE TrustDomain. | | No |
| <a id="opt-serverstransport-spiffe-trustDomain" href="#opt-serverstransport-spiffe-trustDomain" title="#opt-serverstransport-spiffe-trustDomain">`serverstransport.`<br />`spiffe.trustDomain`</a> | Allow SPIFFE trust domain. | "" | No |
| <a id="opt-serverstransport-serverName-2" href="#opt-serverstransport-serverName-2" title="#opt-serverstransport-serverName-2">`serverstransport.`<br />`serverName`</a> | Defines the server name that will be used for SNI. | | No |
| <a id="opt-serverstransport-insecureSkipVerify-2" href="#opt-serverstransport-insecureSkipVerify-2" title="#opt-serverstransport-insecureSkipVerify-2">`serverstransport.`<br />`insecureSkipVerify`</a> | Controls whether the server's certificate chain and host name is verified. | false | No |
| <a id="opt-serverstransport-rootcas-2" href="#opt-serverstransport-rootcas-2" title="#opt-serverstransport-rootcas-2">`serverstransport.`<br />`rootcas`</a> | Set of root certificate authorities to use when verifying server certificates. (for mTLS connections). | | No |
| <a id="opt-serverstransport-certificatesSecrets-2" href="#opt-serverstransport-certificatesSecrets-2" title="#opt-serverstransport-certificatesSecrets-2">`serverstransport.`<br />`certificatesSecrets`</a> | Certificates to present to the server for mTLS. | | No |
| <a id="opt-serverstransport-cipherSuites" href="#opt-serverstransport-cipherSuites" title="#opt-serverstransport-cipherSuites">`serverstransport.`<br />`cipherSuites`</a> | Defines the cipher suites to use when contacting backend servers. | [] | No |
| <a id="opt-serverstransport-minVersion" href="#opt-serverstransport-minVersion" title="#opt-serverstransport-minVersion">`serverstransport.`<br />`minVersion`</a> | Defines the minimum TLS version to use when contacting backend servers. | "" | No |
| <a id="opt-serverstransport-maxVersion" href="#opt-serverstransport-maxVersion" title="#opt-serverstransport-maxVersion">`serverstransport.`<br />`maxVersion`</a> | Defines the maximum TLS version to use when contacting backend servers. | "" | No |
| <a id="opt-serverstransport-maxIdleConnsPerHost-2" href="#opt-serverstransport-maxIdleConnsPerHost-2" title="#opt-serverstransport-maxIdleConnsPerHost-2">`serverstransport.`<br />`maxIdleConnsPerHost`</a> | Maximum idle (keep-alive) connections to keep per-host. | 200 | No |
| <a id="opt-serverstransport-disableHTTP2-2" href="#opt-serverstransport-disableHTTP2-2" title="#opt-serverstransport-disableHTTP2-2">`serverstransport.`<br />`disableHTTP2`</a> | Disables HTTP/2 for connections with servers. | false | No |
| <a id="opt-serverstransport-peerCertURI-2" href="#opt-serverstransport-peerCertURI-2" title="#opt-serverstransport-peerCertURI-2">`serverstransport.`<br />`peerCertURI`</a> | Defines the URI used to match against SAN URIs during the server's certificate verification. | "" | No |
| <a id="opt-serverstransport-forwardingTimeouts-dialTimeout-2" href="#opt-serverstransport-forwardingTimeouts-dialTimeout-2" title="#opt-serverstransport-forwardingTimeouts-dialTimeout-2">`serverstransport.`<br />`forwardingTimeouts.dialTimeout`</a> | Amount of time to wait until a connection to a server can be established.<br />Zero means no timeout. | 30s | No |
| <a id="opt-serverstransport-forwardingTimeouts-responseHeaderTimeout-2" href="#opt-serverstransport-forwardingTimeouts-responseHeaderTimeout-2" title="#opt-serverstransport-forwardingTimeouts-responseHeaderTimeout-2">`serverstransport.`<br />`forwardingTimeouts.responseHeaderTimeout`</a> | Amount of time to wait for a server's response headers after fully writing the request (including its body, if any).<br />Zero means no timeout | 0s | No |
| <a id="opt-serverstransport-forwardingTimeouts-idleConnTimeout-2" href="#opt-serverstransport-forwardingTimeouts-idleConnTimeout-2" title="#opt-serverstransport-forwardingTimeouts-idleConnTimeout-2">`serverstransport.`<br />`forwardingTimeouts.idleConnTimeout`</a> | Maximum amount of time an idle (keep-alive) connection will remain idle before closing itself.<br />Zero means no timeout. | 90s | No |
| <a id="opt-serverstransport-spiffe-ids-2" href="#opt-serverstransport-spiffe-ids-2" title="#opt-serverstransport-spiffe-ids-2">`serverstransport.`<br />`spiffe.ids`</a> | Allow SPIFFE IDs.<br />This takes precedence over the SPIFFE TrustDomain. | | No |
| <a id="opt-serverstransport-spiffe-trustDomain-2" href="#opt-serverstransport-spiffe-trustDomain-2" title="#opt-serverstransport-spiffe-trustDomain-2">`serverstransport.`<br />`spiffe.trustDomain`</a> | Allow SPIFFE trust domain. | "" | No |
| Field | Description | Default | Required |
|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:----------------------------------------------------------|:--------|:---------|
| <a id="opt-serverstransport-serverName" href="#opt-serverstransport-serverName" title="#opt-serverstransport-serverName">`serverstransport.`<br />`serverName`</a> | Defines the server name that will be used for SNI. | | No |
| <a id="opt-serverstransport-insecureSkipVerify" href="#opt-serverstransport-insecureSkipVerify" title="#opt-serverstransport-insecureSkipVerify">`serverstransport.`<br />`insecureSkipVerify`</a> | Controls whether the server's certificate chain and host name is verified. | false | No |
| <a id="opt-serverstransport-rootcas" href="#opt-serverstransport-rootcas" title="#opt-serverstransport-rootcas">`serverstransport.`<br />`rootcas`</a> | Set of root certificate authorities to use when verifying server certificates. (for mTLS connections). | | No |
| <a id="opt-serverstransport-certificatesSecrets" href="#opt-serverstransport-certificatesSecrets" title="#opt-serverstransport-certificatesSecrets">`serverstransport.`<br />`certificatesSecrets`</a> | Certificates to present to the server for mTLS. | | No |
| <a id="opt-serverstransport-maxIdleConnsPerHost" href="#opt-serverstransport-maxIdleConnsPerHost" title="#opt-serverstransport-maxIdleConnsPerHost">`serverstransport.`<br />`maxIdleConnsPerHost`</a> | Maximum idle (keep-alive) connections to keep per-host. | 200 | No |
| <a id="opt-serverstransport-disableHTTP2" href="#opt-serverstransport-disableHTTP2" title="#opt-serverstransport-disableHTTP2">`serverstransport.`<br />`disableHTTP2`</a> | Disables HTTP/2 for connections with servers. | false | No |
| <a id="opt-serverstransport-peerCertSANs" href="#opt-serverstransport-peerCertSANs" title="#opt-serverstransport-peerCertSANs">`serverstransport.`<br />`peerCertSANs`</a> | Defines the SANs (Subject Alternative Names) used to match against SANs during the peer certificate verification. | [] | No |
| <a id="opt-serverstransport-peerCertSANs-type" href="#opt-serverstransport-peerCertSANs-type" title="#opt-serverstransport-peerCertSANs-type">`serverstransport.`<br />`peerCertSANs[].type`</a> | Defines the SAN type (`URI` or `DNSName`) to match against the peer certificate's Subject Alternative Names. | "" | No |
| <a id="opt-serverstransport-peerCertSANs-value" href="#opt-serverstransport-peerCertSANs-value" title="#opt-serverstransport-peerCertSANs-value">`serverstransport.`<br />`peerCertSANs[].value`</a> | Defines the SAN value to match against the peer certificate's Subject Alternative Names. | "" | No |
| <a id="opt-serverstransport-forwardingTimeouts-dialTimeout" href="#opt-serverstransport-forwardingTimeouts-dialTimeout" title="#opt-serverstransport-forwardingTimeouts-dialTimeout">`serverstransport.`<br />`forwardingTimeouts.dialTimeout`</a> | Amount of time to wait until a connection to a server can be established.<br />Zero means no timeout. | 30s | No |
| <a id="opt-serverstransport-forwardingTimeouts-responseHeaderTimeout" href="#opt-serverstransport-forwardingTimeouts-responseHeaderTimeout" title="#opt-serverstransport-forwardingTimeouts-responseHeaderTimeout">`serverstransport.`<br />`forwardingTimeouts.responseHeaderTimeout`</a> | Amount of time to wait for a server's response headers after fully writing the request (including its body, if any).<br />Zero means no timeout | 0s | No |
| <a id="opt-serverstransport-forwardingTimeouts-idleConnTimeout" href="#opt-serverstransport-forwardingTimeouts-idleConnTimeout" title="#opt-serverstransport-forwardingTimeouts-idleConnTimeout">`serverstransport.`<br />`forwardingTimeouts.idleConnTimeout`</a> | Maximum amount of time an idle (keep-alive) connection will remain idle before closing itself.<br />Zero means no timeout. | 90s | No |
| <a id="opt-serverstransport-spiffe-ids" href="#opt-serverstransport-spiffe-ids" title="#opt-serverstransport-spiffe-ids">`serverstransport.`<br />`spiffe.ids`</a> | Allow SPIFFE IDs.<br />This takes precedence over the SPIFFE TrustDomain. | | No |
| <a id="opt-serverstransport-spiffe-trustDomain" href="#opt-serverstransport-spiffe-trustDomain" title="#opt-serverstransport-spiffe-trustDomain">`serverstransport.`<br />`spiffe.trustDomain`</a> | Allow SPIFFE trust domain. | "" | No |
| <a id="opt-serverstransport-cipherSuites" href="#opt-serverstransport-cipherSuites" title="#opt-serverstransport-cipherSuites">`serverstransport.`<br />`cipherSuites`</a> | Defines the cipher suites to use when contacting backend servers. | [] | No |
| <a id="opt-serverstransport-minVersion" href="#opt-serverstransport-minVersion" title="#opt-serverstransport-minVersion">`serverstransport.`<br />`minVersion`</a> | Defines the minimum TLS version to use when contacting backend servers. | "" | No |
| <a id="opt-serverstransport-maxVersion" href="#opt-serverstransport-maxVersion" title="#opt-serverstransport-maxVersion">`serverstransport.`<br />`maxVersion`</a> | Defines the maximum TLS version to use when contacting backend servers. | "" | No |
!!! note "CA Secret"
The CA secret must contain a base64 encoded certificate under either a tls.ca or a ca.crt key.
@@ -48,7 +48,9 @@ spec:
| <a id="opt-terminationDelay" href="#opt-terminationDelay" title="#opt-terminationDelay">`terminationDelay`</a> | Defines the delay to wait before fully terminating the connection, after one connected peer has closed its writing capability. | 100ms | No |
| <a id="opt-tls-serverName" href="#opt-tls-serverName" title="#opt-tls-serverName">`tls.serverName`</a> | ServerName used to contact the server. | "" | No |
| <a id="opt-tls-insecureSkipVerify" href="#opt-tls-insecureSkipVerify" title="#opt-tls-insecureSkipVerify">`tls.insecureSkipVerify`</a> | Controls whether the server's certificate chain and host name is verified. | false | No |
| <a id="opt-tls-peerCertURI" href="#opt-tls-peerCertURI" title="#opt-tls-peerCertURI">`tls.peerCertURI`</a> | Defines the URI used to match against SAN URIs during the server's certificate verification. | "" | No |
| <a id="opt-tls-peerCertSANs" href="#opt-tls-peerCertSANs" title="#opt-tls-peerCertSANs">`tls.peerCertSANs`</a> | Defines the SANs (Subject Alternative Names) used to match against SANs during the peer certificate verification. | [] | No |
| <a id="opt-tls-peerCertSANs-type" href="#opt-tls-peerCertSANs-type" title="#opt-tls-peerCertSANs-type">`tls.peerCertSANs[].type`</a> | Defines the SAN type (`URI` or `DNSName`) to match against the peer certificate's Subject Alternative Names. | "" | No |
| <a id="opt-tls-peerCertSANs-value" href="#opt-tls-peerCertSANs-value" title="#opt-tls-peerCertSANs-value">`tls.peerCertSANs[].value`</a> | Defines the SAN value to match against the peer certificate's Subject Alternative Names. | "" | No |
| <a id="opt-tls-rootCAsSecrets" href="#opt-tls-rootCAsSecrets" title="#opt-tls-rootCAsSecrets">`tls.rootCAsSecrets`</a> | Defines the set of root certificate authorities to use when verifying server certificates.<br />The CA secret must contain a base64 encoded certificate under either a `tls.ca` or a `ca.crt` key. | "" | No |
| <a id="opt-tls-certificatesSecrets" href="#opt-tls-certificatesSecrets" title="#opt-tls-certificatesSecrets">`tls.certificatesSecrets`</a> | Certificates to present to the server for mTLS. | "" | No |
| <a id="opt-spiffe" href="#opt-spiffe" title="#opt-spiffe">`spiffe`</a> | Configures [SPIFFE](../../../../install-configuration/tls/spiffe.md) options. | "" | No |
@@ -41,6 +41,7 @@ creating the corresponding routers, services, middlewares, and other components
Important differences in default behaviors:
- **Request buffering**: NGINX enables `proxy-request-buffering` by default, while Traefik requires explicit opt-in via the provider's `proxyRequestBuffering` option.
- **Legacy scheme headers**: If your applications depend on `X-Forwarded-Scheme` or `X-Scheme`, enable `entryPoints.<name>.forwardedHeaders.addXForwardedSchemeHeaders=true` on the relevant entrypoints.
To ensure consistent behavior during migration,
review and configure Traefik's provider-level options to match your current NGINX ConfigMap settings.
@@ -280,6 +281,7 @@ The following annotations are organized by category for easier navigation.
| <a id="opt-nginx-ingress-kubernetes-ioauth-snippet" href="#opt-nginx-ingress-kubernetes-ioauth-snippet" title="#opt-nginx-ingress-kubernetes-ioauth-snippet">`nginx.ingress.kubernetes.io/auth-snippet`</a> | Supported directives: `proxy_method`, `more_set_headers`, `proxy_set_header`, `more_set_input_headers`, `set`, `if`, `return code [text]`. It supports minimal variable interpolation by using the following NGINX variables: `$scheme`, `$host`, `$http_*`, `$hostname`, `$request_uri`, `$request_method`, `$query_string`, `$args`, `$arg_*`, `$remote_addr`, `$uri`, `$document_uri`, `$server_name`, `$server_port`, `$content_type`, `$content_length`, `$cookie_*`, `$is_args`, `$best_http_host`, `$escaped_request_uri`, `$proxy_add_x_forwarded_for`. |
| <a id="opt-nginx-ingress-kubernetes-ioauth-method" href="#opt-nginx-ingress-kubernetes-ioauth-method" title="#opt-nginx-ingress-kubernetes-ioauth-method">`nginx.ingress.kubernetes.io/auth-method`</a> | This annotation uses the `proxy_method` directive in Nginx. Thus, it can't be defined on an ingress that already have an `auth-snippet` annotation with the `proxy_method` directive. |
| <a id="opt-nginx-ingress-kubernetes-ioauth-response-headers" href="#opt-nginx-ingress-kubernetes-ioauth-response-headers" title="#opt-nginx-ingress-kubernetes-ioauth-response-headers">`nginx.ingress.kubernetes.io/auth-response-headers`</a> | |
| <a id="opt-nginx-ingress-kubernetes-ioenable-global-auth" href="#opt-nginx-ingress-kubernetes-ioenable-global-auth" title="#opt-nginx-ingress-kubernetes-ioenable-global-auth">`nginx.ingress.kubernetes.io/enable-global-auth`</a> | |
### SSL/TLS
@@ -456,7 +458,6 @@ In practice, Traefik is slightly more lenient under bursty load, as it smooths o
| <a id="opt-nginx-ingress-kubernetes-ioauth-keepalive-requests" href="#opt-nginx-ingress-kubernetes-ioauth-keepalive-requests" title="#opt-nginx-ingress-kubernetes-ioauth-keepalive-requests">`nginx.ingress.kubernetes.io/auth-keepalive-requests`</a> | |
| <a id="opt-nginx-ingress-kubernetes-ioauth-keepalive-timeout" href="#opt-nginx-ingress-kubernetes-ioauth-keepalive-timeout" title="#opt-nginx-ingress-kubernetes-ioauth-keepalive-timeout">`nginx.ingress.kubernetes.io/auth-keepalive-timeout`</a> | |
| <a id="opt-nginx-ingress-kubernetes-ioauth-proxy-set-headers" href="#opt-nginx-ingress-kubernetes-ioauth-proxy-set-headers" title="#opt-nginx-ingress-kubernetes-ioauth-proxy-set-headers">`nginx.ingress.kubernetes.io/auth-proxy-set-headers`</a> | |
| <a id="opt-nginx-ingress-kubernetes-ioenable-global-auth" href="#opt-nginx-ingress-kubernetes-ioenable-global-auth" title="#opt-nginx-ingress-kubernetes-ioenable-global-auth">`nginx.ingress.kubernetes.io/enable-global-auth`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iodisable-proxy-intercept-errors" href="#opt-nginx-ingress-kubernetes-iodisable-proxy-intercept-errors" title="#opt-nginx-ingress-kubernetes-iodisable-proxy-intercept-errors">`nginx.ingress.kubernetes.io/disable-proxy-intercept-errors`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iolimit-rate-after" href="#opt-nginx-ingress-kubernetes-iolimit-rate-after" title="#opt-nginx-ingress-kubernetes-iolimit-rate-after">`nginx.ingress.kubernetes.io/limit-rate-after`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iolimit-rate" href="#opt-nginx-ingress-kubernetes-iolimit-rate" title="#opt-nginx-ingress-kubernetes-iolimit-rate">`nginx.ingress.kubernetes.io/limit-rate`</a> | |
@@ -1,26 +1,454 @@
---
title: "Traefik File Dynamic Configuration"
description: "This guide will provide you with the YAML and TOML files for dynamic configuration in Traefik Proxy. Read the technical documentation."
title: "Traefik File Routing Configuration"
description: "This guide will provide you with the reference for file-based routing configuration in Traefik Proxy. Read the technical documentation."
---
# Traefik File Routing Configuration
# Traefik and Configuration Files
The file provider lets you define routing configuration in YAML or TOML.
Use it to declare routers, services, middlewares, TCP and UDP routing, and TLS options that Traefik should load from a file or a directory.
!!! warning "Work In Progress"
To configure the file provider itself, see the [File provider install configuration](../../install-configuration/providers/others/file.md) page.
This page is still work in progress to provide a better documention of the routing options.
## Configuration Examples
It has been created to provide a centralized page with all the option in YAML and TOML format.
??? example "Configuring the File Provider and Exposing One HTTP Service"
Enabling the file provider:
```yaml tab="Structured (YAML)"
providers:
file:
filename: /etc/traefik/dynamic.yml
```
```toml tab="Structured (TOML)"
[providers.file]
filename = "/etc/traefik/dynamic.toml"
```
```bash tab="CLI"
--providers.file.filename=/etc/traefik/dynamic.yml
```
Declaring the dynamic HTTP configuration:
```yaml tab="Structured (YAML)"
http:
routers:
app:
rule: Host(`example.com`)
entryPoints:
- websecure
service: app
tls: {}
services:
app:
loadBalancer:
servers:
- url: http://127.0.0.1:8080
```
```toml tab="Structured (TOML)"
[http.routers.app]
rule = "Host(`example.com`)"
entryPoints = ["websecure"]
service = "app"
[http.routers.app.tls]
[http.services.app.loadBalancer]
[[http.services.app.loadBalancer.servers]]
url = "http://127.0.0.1:8080"
```
??? example "Specifying More Than One Router and Service"
Define each router and explicitly attach it to the service that should handle matching requests.
```yaml tab="Structured (YAML)"
http:
routers:
app:
rule: Host(`example-a.com`)
service: app
admin:
rule: Host(`example-b.com`)
service: admin
services:
app:
loadBalancer:
servers:
- url: http://127.0.0.1:8000
admin:
loadBalancer:
servers:
- url: http://127.0.0.1:9000
```
```toml tab="Structured (TOML)"
[http.routers.app]
rule = "Host(`example-a.com`)"
service = "app"
[http.routers.admin]
rule = "Host(`example-b.com`)"
service = "admin"
[http.services.app.loadBalancer]
[[http.services.app.loadBalancer.servers]]
url = "http://127.0.0.1:8000"
[http.services.admin.loadBalancer]
[[http.services.admin.loadBalancer.servers]]
url = "http://127.0.0.1:9000"
```
??? example "Declaring and Referencing Middlewares"
Middlewares declared by the file provider can be used by routers from the file provider or by routers from other providers.
When another provider references them, use the `@file` provider suffix.
```yaml tab="Structured (YAML)"
http:
routers:
app:
rule: Host(`secure.example.com`)
entryPoints:
- websecure
middlewares:
- secure-headers
service: app
tls:
options: modern
middlewares:
secure-headers:
headers:
stsSeconds: 31536000
forceSTSHeader: true
services:
app:
loadBalancer:
servers:
- url: http://127.0.0.1:8080
tls:
options:
modern:
minVersion: VersionTLS12
sniStrict: true
```
```toml tab="Structured (TOML)"
[http.routers.app]
rule = "Host(`secure.example.com`)"
entryPoints = ["websecure"]
middlewares = ["secure-headers"]
service = "app"
[http.routers.app.tls]
options = "modern"
[http.middlewares.secure-headers.headers]
stsSeconds = 31536000
forceSTSHeader = true
[http.services.app.loadBalancer]
[[http.services.app.loadBalancer.servers]]
url = "http://127.0.0.1:8080"
[tls.options.modern]
minVersion = "VersionTLS12"
sniStrict = true
```
??? example "Loading Multiple Dynamic Configuration Files"
Configure the file provider with a directory when you want to split dynamic configuration across multiple files.
```yaml tab="Structured (YAML)"
providers:
file:
directory: /etc/traefik/dynamic
watch: true
```
```toml tab="Structured (TOML)"
[providers.file]
directory = "/etc/traefik/dynamic"
watch = true
```
```bash tab="CLI"
--providers.file.directory=/etc/traefik/dynamic
--providers.file.watch=true
```
Example `/etc/traefik/dynamic/http.yml`:
```yaml
http:
routers:
app:
rule: Host(`example.com`)
service: app
services:
app:
loadBalancer:
servers:
- url: http://127.0.0.1:8080
```
Example `/etc/traefik/dynamic/tls.yml`:
```yaml
tls:
certificates:
- certFile: /certs/example.crt
keyFile: /certs/example.key
```
## Configuration Options
```yml tab="YAML"
--8<-- "content/reference/routing-configuration/other-providers/file.yaml"
```
### General
```toml tab="TOML"
--8<-- "content/reference/routing-configuration/other-providers/file.toml"
```
The file provider does not discover services automatically.
Define every router, service, middleware, and TLS resource explicitly in the routing configuration file.
When another provider references a resource declared by the file provider, append the `@file` provider suffix.
For example, a Docker label can reference a file-provider middleware with `secure-headers@file`.
The examples below use YAML-style field paths.
In TOML, use the equivalent table and array syntax, such as `[http.routers.<router_name>]` and `[[http.services.<service_name>.loadBalancer.servers]]`.
### HTTP
#### Routers
Define HTTP routers under `http.routers.<router_name>`.
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
| Field | Description | Value |
|------|-------------|-------|
| <a id="opt-http-routers-router-name-rule" href="#opt-http-routers-router-name-rule" title="#opt-http-routers-router-name-rule">`http.routers.<router_name>.rule`</a> | See [rule](../http/routing/rules-and-priority.md#rules) for more information. | ```Host(`example.com`)``` |
| <a id="opt-http-routers-router-name-ruleSyntax" href="#opt-http-routers-router-name-ruleSyntax" title="#opt-http-routers-router-name-ruleSyntax">`http.routers.<router_name>.ruleSyntax`</a> | See [ruleSyntax](../http/routing/rules-and-priority.md#rulesyntax) for more information.<br/>RuleSyntax is deprecated and will be removed in the next major version. | `v3` |
| <a id="opt-http-routers-router-name-entryPointsn" href="#opt-http-routers-router-name-entryPointsn" title="#opt-http-routers-router-name-entryPointsn">`http.routers.<router_name>.entryPoints[n]`</a> | See [entry points](../../install-configuration/entrypoints.md) for more information. | `websecure` |
| <a id="opt-http-routers-router-name-middlewaresn" href="#opt-http-routers-router-name-middlewaresn" title="#opt-http-routers-router-name-middlewaresn">`http.routers.<router_name>.middlewares[n]`</a> | See [middlewares overview](../http/middlewares/overview.md) for more information. | `secure-headers` |
| <a id="opt-http-routers-router-name-service" href="#opt-http-routers-router-name-service" title="#opt-http-routers-router-name-service">`http.routers.<router_name>.service`</a> | See [service](../http/load-balancing/service.md) for more information. | `app` |
| <a id="opt-http-routers-router-name-parentRefsn" href="#opt-http-routers-router-name-parentRefsn" title="#opt-http-routers-router-name-parentRefsn">`http.routers.<router_name>.parentRefs[n]`</a> | See [multi-layer routing](../http/routing/multi-layer-routing.md) for more information. | `parent-router@file` |
| <a id="opt-http-routers-router-name-tls" href="#opt-http-routers-router-name-tls" title="#opt-http-routers-router-name-tls">`http.routers.<router_name>.tls`</a> | See [TLS](../http/tls/overview.md) for more information. | `{}` |
| <a id="opt-http-routers-router-name-tls-certResolver" href="#opt-http-routers-router-name-tls-certResolver" title="#opt-http-routers-router-name-tls-certResolver">`http.routers.<router_name>.tls.certResolver`</a> | See [certResolver](../../install-configuration/tls/certificate-resolvers/overview.md) for more information. | `myresolver` |
| <a id="opt-http-routers-router-name-tls-domainsn-main" href="#opt-http-routers-router-name-tls-domainsn-main" title="#opt-http-routers-router-name-tls-domainsn-main">`http.routers.<router_name>.tls.domains[n].main`</a> | See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information. | `example.org` |
| <a id="opt-http-routers-router-name-tls-domainsn-sansn" href="#opt-http-routers-router-name-tls-domainsn-sansn" title="#opt-http-routers-router-name-tls-domainsn-sansn">`http.routers.<router_name>.tls.domains[n].sans[n]`</a> | See [domains](../../install-configuration/tls/certificate-resolvers/acme.md#domain-definition) for more information. | `www.example.org` |
| <a id="opt-http-routers-router-name-tls-options" href="#opt-http-routers-router-name-tls-options" title="#opt-http-routers-router-name-tls-options">`http.routers.<router_name>.tls.options`</a> | See [TLS options](../http/tls/tls-options.md) for more information. | `modern` |
| <a id="opt-http-routers-router-name-observability-accessLogs" href="#opt-http-routers-router-name-observability-accessLogs" title="#opt-http-routers-router-name-observability-accessLogs">`http.routers.<router_name>.observability.accessLogs`</a> | Enables or disables access logs for the router. | `true` |
| <a id="opt-http-routers-router-name-observability-metrics" href="#opt-http-routers-router-name-observability-metrics" title="#opt-http-routers-router-name-observability-metrics">`http.routers.<router_name>.observability.metrics`</a> | Enables or disables metrics for the router. | `true` |
| <a id="opt-http-routers-router-name-observability-tracing" href="#opt-http-routers-router-name-observability-tracing" title="#opt-http-routers-router-name-observability-tracing">`http.routers.<router_name>.observability.tracing`</a> | Enables or disables tracing for the router. | `true` |
| <a id="opt-http-routers-router-name-observability-traceVerbosity" href="#opt-http-routers-router-name-observability-traceVerbosity" title="#opt-http-routers-router-name-observability-traceVerbosity">`http.routers.<router_name>.observability.traceVerbosity`</a> | See [trace verbosity](../http/routing/observability.md#opt-traceVerbosity) for more information. | `minimal` |
| <a id="opt-http-routers-router-name-priority" href="#opt-http-routers-router-name-priority" title="#opt-http-routers-router-name-priority">`http.routers.<router_name>.priority`</a> | See [priority](../http/routing/rules-and-priority.md#priority-calculation) for more information. | `42` |
#### Services
Define HTTP services under `http.services.<service_name>`.
!!! warning "The character `@` is not authorized in the service name `<service_name>`."
| Field | Description | Value |
|------|-------------|-------|
| <a id="opt-http-services-service-name-loadBalancer-serversn-url" href="#opt-http-services-service-name-loadBalancer-serversn-url" title="#opt-http-services-service-name-loadBalancer-serversn-url">`http.services.<service_name>.loadBalancer.servers[n].url`</a> | See [servers](../http/load-balancing/service.md#servers) for more information. | `http://127.0.0.1:8080` |
| <a id="opt-http-services-service-name-loadBalancer-serversn-weight" href="#opt-http-services-service-name-loadBalancer-serversn-weight" title="#opt-http-services-service-name-loadBalancer-serversn-weight">`http.services.<service_name>.loadBalancer.servers[n].weight`</a> | See [servers](../http/load-balancing/service.md#servers) for more information. | `1` |
| <a id="opt-http-services-service-name-loadBalancer-serversn-preservePath" href="#opt-http-services-service-name-loadBalancer-serversn-preservePath" title="#opt-http-services-service-name-loadBalancer-serversn-preservePath">`http.services.<service_name>.loadBalancer.servers[n].preservePath`</a> | See [servers](../http/load-balancing/service.md#servers) for more information. | `true` |
| <a id="opt-http-services-service-name-loadBalancer-strategy" href="#opt-http-services-service-name-loadBalancer-strategy" title="#opt-http-services-service-name-loadBalancer-strategy">`http.services.<service_name>.loadBalancer.strategy`</a> | See [load balancing strategies](../http/load-balancing/service.md#load-balancing-strategies) for more information. | `wrr` |
| <a id="opt-http-services-service-name-loadBalancer-passHostHeader" href="#opt-http-services-service-name-loadBalancer-passHostHeader" title="#opt-http-services-service-name-loadBalancer-passHostHeader">`http.services.<service_name>.loadBalancer.passHostHeader`</a> | See [service load balancer](../http/load-balancing/service.md) for more information. | `true` |
| <a id="opt-http-services-service-name-loadBalancer-healthCheck" href="#opt-http-services-service-name-loadBalancer-healthCheck" title="#opt-http-services-service-name-loadBalancer-healthCheck">`http.services.<service_name>.loadBalancer.healthCheck.*`</a> | See [health check](../http/load-balancing/service.md#health-check) for more information. | `path: /health` |
| <a id="opt-http-services-service-name-loadBalancer-passiveHealthCheck" href="#opt-http-services-service-name-loadBalancer-passiveHealthCheck" title="#opt-http-services-service-name-loadBalancer-passiveHealthCheck">`http.services.<service_name>.loadBalancer.passiveHealthCheck.*`</a> | See [passive health check](../http/load-balancing/service.md#passive-health-check) for more information. | `maxFailedAttempts: 3` |
| <a id="opt-http-services-service-name-loadBalancer-sticky-cookie" href="#opt-http-services-service-name-loadBalancer-sticky-cookie" title="#opt-http-services-service-name-loadBalancer-sticky-cookie">`http.services.<service_name>.loadBalancer.sticky.cookie.*`</a> | See [sticky sessions](../http/load-balancing/service.md#sticky-sessions) for more information. | `name: app-cookie` |
| <a id="opt-http-services-service-name-loadBalancer-responseForwarding-flushInterval" href="#opt-http-services-service-name-loadBalancer-responseForwarding-flushInterval" title="#opt-http-services-service-name-loadBalancer-responseForwarding-flushInterval">`http.services.<service_name>.loadBalancer.responseForwarding.flushInterval`</a> | See [service load balancer](../http/load-balancing/service.md) for more information. | `100ms` |
| <a id="opt-http-services-service-name-loadBalancer-serversTransport" href="#opt-http-services-service-name-loadBalancer-serversTransport" title="#opt-http-services-service-name-loadBalancer-serversTransport">`http.services.<service_name>.loadBalancer.serversTransport`</a> | See [ServersTransport](../http/load-balancing/serverstransport.md) for more information. | `secure-transport` |
| <a id="opt-http-services-service-name-weighted-servicesn-name" href="#opt-http-services-service-name-weighted-servicesn-name" title="#opt-http-services-service-name-weighted-servicesn-name">`http.services.<service_name>.weighted.services[n].name`</a> | See [weighted round robin](../http/load-balancing/service.md#weighted-round-robin-wrr) for more information. | `app-v1` |
| <a id="opt-http-services-service-name-weighted-servicesn-weight" href="#opt-http-services-service-name-weighted-servicesn-weight" title="#opt-http-services-service-name-weighted-servicesn-weight">`http.services.<service_name>.weighted.services[n].weight`</a> | See [weighted round robin](../http/load-balancing/service.md#weighted-round-robin-wrr) for more information. | `3` |
| <a id="opt-http-services-service-name-weighted-sticky-cookie" href="#opt-http-services-service-name-weighted-sticky-cookie" title="#opt-http-services-service-name-weighted-sticky-cookie">`http.services.<service_name>.weighted.sticky.cookie.*`</a> | See [sticky sessions](../http/load-balancing/service.md#sticky-sessions) for more information. | `name: app-cookie` |
| <a id="opt-http-services-service-name-weighted-healthCheck" href="#opt-http-services-service-name-weighted-healthCheck" title="#opt-http-services-service-name-weighted-healthCheck">`http.services.<service_name>.weighted.healthCheck`</a> | See [weighted service health check](../http/load-balancing/service.md#health-check) for more information. | `{}` |
| <a id="opt-http-services-service-name-highestRandomWeight-servicesn-name" href="#opt-http-services-service-name-highestRandomWeight-servicesn-name" title="#opt-http-services-service-name-highestRandomWeight-servicesn-name">`http.services.<service_name>.highestRandomWeight.services[n].name`</a> | See [highest random weight](../http/load-balancing/service.md#highest-random-weight) for more information. | `app-v1` |
| <a id="opt-http-services-service-name-highestRandomWeight-servicesn-weight" href="#opt-http-services-service-name-highestRandomWeight-servicesn-weight" title="#opt-http-services-service-name-highestRandomWeight-servicesn-weight">`http.services.<service_name>.highestRandomWeight.services[n].weight`</a> | See [highest random weight](../http/load-balancing/service.md#highest-random-weight) for more information. | `3` |
| <a id="opt-http-services-service-name-highestRandomWeight-healthCheck" href="#opt-http-services-service-name-highestRandomWeight-healthCheck" title="#opt-http-services-service-name-highestRandomWeight-healthCheck">`http.services.<service_name>.highestRandomWeight.healthCheck`</a> | See [highest random weight](../http/load-balancing/service.md#highest-random-weight) for more information. | `{}` |
| <a id="opt-http-services-service-name-mirroring-service" href="#opt-http-services-service-name-mirroring-service" title="#opt-http-services-service-name-mirroring-service">`http.services.<service_name>.mirroring.service`</a> | See [mirroring](../http/load-balancing/service.md#mirroring) for more information. | `app-main` |
| <a id="opt-http-services-service-name-mirroring-mirrorBody" href="#opt-http-services-service-name-mirroring-mirrorBody" title="#opt-http-services-service-name-mirroring-mirrorBody">`http.services.<service_name>.mirroring.mirrorBody`</a> | See [mirroring](../http/load-balancing/service.md#mirroring) for more information. | `true` |
| <a id="opt-http-services-service-name-mirroring-maxBodySize" href="#opt-http-services-service-name-mirroring-maxBodySize" title="#opt-http-services-service-name-mirroring-maxBodySize">`http.services.<service_name>.mirroring.maxBodySize`</a> | See [mirroring](../http/load-balancing/service.md#mirroring) for more information. | `1048576` |
| <a id="opt-http-services-service-name-mirroring-mirrorsn-name" href="#opt-http-services-service-name-mirroring-mirrorsn-name" title="#opt-http-services-service-name-mirroring-mirrorsn-name">`http.services.<service_name>.mirroring.mirrors[n].name`</a> | See [mirroring](../http/load-balancing/service.md#mirroring) for more information. | `app-shadow` |
| <a id="opt-http-services-service-name-mirroring-mirrorsn-percent" href="#opt-http-services-service-name-mirroring-mirrorsn-percent" title="#opt-http-services-service-name-mirroring-mirrorsn-percent">`http.services.<service_name>.mirroring.mirrors[n].percent`</a> | See [mirroring](../http/load-balancing/service.md#mirroring) for more information. | `10` |
| <a id="opt-http-services-service-name-mirroring-healthCheck" href="#opt-http-services-service-name-mirroring-healthCheck" title="#opt-http-services-service-name-mirroring-healthCheck">`http.services.<service_name>.mirroring.healthCheck`</a> | See [mirroring](../http/load-balancing/service.md#mirroring) for more information. | `{}` |
| <a id="opt-http-services-service-name-failover-service" href="#opt-http-services-service-name-failover-service" title="#opt-http-services-service-name-failover-service">`http.services.<service_name>.failover.service`</a> | See [failover](../http/load-balancing/service.md#failover) for more information. | `app-main` |
| <a id="opt-http-services-service-name-failover-fallback" href="#opt-http-services-service-name-failover-fallback" title="#opt-http-services-service-name-failover-fallback">`http.services.<service_name>.failover.fallback`</a> | See [failover](../http/load-balancing/service.md#failover) for more information. | `app-backup` |
| <a id="opt-http-services-service-name-failover-healthCheck" href="#opt-http-services-service-name-failover-healthCheck" title="#opt-http-services-service-name-failover-healthCheck">`http.services.<service_name>.failover.healthCheck`</a> | See [failover](../http/load-balancing/service.md#failover) for more information. | `{}` |
| <a id="opt-http-services-service-name-failover-errors-maxRequestBodyBytes" href="#opt-http-services-service-name-failover-errors-maxRequestBodyBytes" title="#opt-http-services-service-name-failover-errors-maxRequestBodyBytes">`http.services.<service_name>.failover.errors.maxRequestBodyBytes`</a> | See [failover errors](../http/load-balancing/service.md#errors) for more information. | `1048576` |
| <a id="opt-http-services-service-name-failover-errors-statusn" href="#opt-http-services-service-name-failover-errors-statusn" title="#opt-http-services-service-name-failover-errors-statusn">`http.services.<service_name>.failover.errors.status[n]`</a> | See [failover errors](../http/load-balancing/service.md#errors) for more information. | `500-599` |
| <a id="opt-http-services-service-name-middlewaresn" href="#opt-http-services-service-name-middlewaresn" title="#opt-http-services-service-name-middlewaresn">`http.services.<service_name>.middlewares[n]`</a> | Adds middlewares to the service. | `service-ratelimit` |
#### Middlewares
Define HTTP middlewares under `http.middlewares.<middleware_name>`.
For example, to declare an [`AddPrefix`](../http/middlewares/addprefix.md) middleware named `add-api`, set `http.middlewares.add-api.addPrefix.prefix=/api`.
More information about available middlewares can be found in the dedicated [middlewares section](../http/middlewares/overview.md).
!!! warning "The character `@` is not authorized in the middleware name `<middleware_name>`."
!!! warning "Conflicts in Declaration"
If you declare multiple middlewares with the same name but different parameters, the middleware fails to be declared.
| Field | Description | Value |
|------|-------------|-------|
| <a id="opt-http-middlewares-middleware-name-middleware-type-middleware-option" href="#opt-http-middlewares-middleware-name-middleware-type-middleware-option" title="#opt-http-middlewares-middleware-name-middleware-type-middleware-option">`http.middlewares.<middleware_name>.<middleware_type>.<middleware_option>`</a> | With `middleware_type` the middleware type, such as `addPrefix` or `headers`, and `middleware_option` the option to set. | `prefix: /api` |
#### ServersTransports
Define HTTP ServersTransports under `http.serversTransports.<servers_transport_name>`.
| Field | Description | Value |
|------|-------------|-------|
| <a id="opt-http-serversTransports-servers-transport-name" href="#opt-http-serversTransports-servers-transport-name" title="#opt-http-serversTransports-servers-transport-name">`http.serversTransports.<servers_transport_name>.*`</a> | See [ServersTransport](../http/load-balancing/serverstransport.md) for more information. | `serverName: example.org` |
### TCP
You can declare TCP routers, services, middlewares, and ServersTransports with the file provider.
#### TCP Routers
Define TCP routers under `tcp.routers.<router_name>`.
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
| Field | Description | Value |
|------|-------------|-------|
| <a id="opt-tcp-routers-router-name-entryPointsn" href="#opt-tcp-routers-router-name-entryPointsn" title="#opt-tcp-routers-router-name-entryPointsn">`tcp.routers.<router_name>.entryPoints[n]`</a> | See [entry points](../../install-configuration/entrypoints.md) for more information. | `websecure` |
| <a id="opt-tcp-routers-router-name-rule" href="#opt-tcp-routers-router-name-rule" title="#opt-tcp-routers-router-name-rule">`tcp.routers.<router_name>.rule`</a> | See [rule](../tcp/routing/rules-and-priority.md#rules) for more information. | ```HostSNI(`example.com`)``` |
| <a id="opt-tcp-routers-router-name-ruleSyntax" href="#opt-tcp-routers-router-name-ruleSyntax" title="#opt-tcp-routers-router-name-ruleSyntax">`tcp.routers.<router_name>.ruleSyntax`</a> | Configures the rule syntax to use for parsing the rule on a per-router basis.<br/>RuleSyntax is deprecated and will be removed in the next major version. | `v3` |
| <a id="opt-tcp-routers-router-name-middlewaresn" href="#opt-tcp-routers-router-name-middlewaresn" title="#opt-tcp-routers-router-name-middlewaresn">`tcp.routers.<router_name>.middlewares[n]`</a> | See [TCP middlewares overview](../tcp/middlewares/overview.md) for more information. | `ip-allowlist` |
| <a id="opt-tcp-routers-router-name-service" href="#opt-tcp-routers-router-name-service" title="#opt-tcp-routers-router-name-service">`tcp.routers.<router_name>.service`</a> | See [service](../tcp/service.md) for more information. | `tcp-app` |
| <a id="opt-tcp-routers-router-name-tls" href="#opt-tcp-routers-router-name-tls" title="#opt-tcp-routers-router-name-tls">`tcp.routers.<router_name>.tls`</a> | See [TLS](../tcp/tls.md) for more information. | `{}` |
| <a id="opt-tcp-routers-router-name-tls-certResolver" href="#opt-tcp-routers-router-name-tls-certResolver" title="#opt-tcp-routers-router-name-tls-certResolver">`tcp.routers.<router_name>.tls.certResolver`</a> | See [certResolver](../tcp/tls.md#configuration-options) for more information. | `myresolver` |
| <a id="opt-tcp-routers-router-name-tls-domainsn-main" href="#opt-tcp-routers-router-name-tls-domainsn-main" title="#opt-tcp-routers-router-name-tls-domainsn-main">`tcp.routers.<router_name>.tls.domains[n].main`</a> | See [TLS](../tcp/tls.md) for more information. | `example.org` |
| <a id="opt-tcp-routers-router-name-tls-domainsn-sansn" href="#opt-tcp-routers-router-name-tls-domainsn-sansn" title="#opt-tcp-routers-router-name-tls-domainsn-sansn">`tcp.routers.<router_name>.tls.domains[n].sans[n]`</a> | See [TLS](../tcp/tls.md) for more information. | `www.example.org` |
| <a id="opt-tcp-routers-router-name-tls-options" href="#opt-tcp-routers-router-name-tls-options" title="#opt-tcp-routers-router-name-tls-options">`tcp.routers.<router_name>.tls.options`</a> | See [TLS](../tcp/tls.md) for more information. | `modern` |
| <a id="opt-tcp-routers-router-name-tls-passthrough" href="#opt-tcp-routers-router-name-tls-passthrough" title="#opt-tcp-routers-router-name-tls-passthrough">`tcp.routers.<router_name>.tls.passthrough`</a> | See [Passthrough](../tcp/tls.md#opt-passthrough) for more information. | `true` |
| <a id="opt-tcp-routers-router-name-priority" href="#opt-tcp-routers-router-name-priority" title="#opt-tcp-routers-router-name-priority">`tcp.routers.<router_name>.priority`</a> | See [priority](../tcp/routing/rules-and-priority.md#priority-calculation) for more information. | `42` |
#### TCP Services
Define TCP services under `tcp.services.<service_name>`.
!!! warning "The character `@` is not authorized in the service name `<service_name>`."
| Field | Description | Value |
|------|-------------|-------|
| <a id="opt-tcp-services-service-name-loadBalancer-serversn-address" href="#opt-tcp-services-service-name-loadBalancer-serversn-address" title="#opt-tcp-services-service-name-loadBalancer-serversn-address">`tcp.services.<service_name>.loadBalancer.servers[n].address`</a> | See [servers load balancer](../tcp/service.md#servers-load-balancer) for more information. | `127.0.0.1:9000` |
| <a id="opt-tcp-services-service-name-loadBalancer-serversn-tls" href="#opt-tcp-services-service-name-loadBalancer-serversn-tls" title="#opt-tcp-services-service-name-loadBalancer-serversn-tls">`tcp.services.<service_name>.loadBalancer.servers[n].tls`</a> | Determines whether to use TLS when dialing the backend server. | `true` |
| <a id="opt-tcp-services-service-name-loadBalancer-serversTransport" href="#opt-tcp-services-service-name-loadBalancer-serversTransport" title="#opt-tcp-services-service-name-loadBalancer-serversTransport">`tcp.services.<service_name>.loadBalancer.serversTransport`</a> | See [TCP ServersTransport](../tcp/serverstransport.md) for more information. | `secure-tcp` |
| <a id="opt-tcp-services-service-name-loadBalancer-proxyProtocol-version" href="#opt-tcp-services-service-name-loadBalancer-proxyProtocol-version" title="#opt-tcp-services-service-name-loadBalancer-proxyProtocol-version">`tcp.services.<service_name>.loadBalancer.proxyProtocol.version`</a> | Enables Proxy Protocol for backend connections. | `2` |
| <a id="opt-tcp-services-service-name-loadBalancer-terminationDelay" href="#opt-tcp-services-service-name-loadBalancer-terminationDelay" title="#opt-tcp-services-service-name-loadBalancer-terminationDelay">`tcp.services.<service_name>.loadBalancer.terminationDelay`</a> | Defines the delay before terminating connections. | `100` |
| <a id="opt-tcp-services-service-name-loadBalancer-healthCheck" href="#opt-tcp-services-service-name-loadBalancer-healthCheck" title="#opt-tcp-services-service-name-loadBalancer-healthCheck">`tcp.services.<service_name>.loadBalancer.healthCheck.*`</a> | See [TCP service health check](../tcp/service.md#health-check) for more information. | `interval: 10s` |
| <a id="opt-tcp-services-service-name-weighted-servicesn-name" href="#opt-tcp-services-service-name-weighted-servicesn-name" title="#opt-tcp-services-service-name-weighted-servicesn-name">`tcp.services.<service_name>.weighted.services[n].name`</a> | See [weighted round robin](../tcp/service.md#weighted-round-robin) for more information. | `tcp-v1` |
| <a id="opt-tcp-services-service-name-weighted-servicesn-weight" href="#opt-tcp-services-service-name-weighted-servicesn-weight" title="#opt-tcp-services-service-name-weighted-servicesn-weight">`tcp.services.<service_name>.weighted.services[n].weight`</a> | See [weighted round robin](../tcp/service.md#weighted-round-robin) for more information. | `3` |
| <a id="opt-tcp-services-service-name-weighted-healthCheck" href="#opt-tcp-services-service-name-weighted-healthCheck" title="#opt-tcp-services-service-name-weighted-healthCheck">`tcp.services.<service_name>.weighted.healthCheck`</a> | See [weighted round robin](../tcp/service.md#weighted-round-robin) for more information. | `{}` |
#### TCP Middlewares
Define TCP middlewares under `tcp.middlewares.<middleware_name>`.
For example, to declare an [`InFlightConn`](../tcp/middlewares/inflightconn.md) middleware named `limit`, set `tcp.middlewares.limit.inFlightConn.amount=10`.
More information about available middlewares is available in the dedicated [TCP middlewares section](../tcp/middlewares/overview.md).
!!! warning "The character `@` is not authorized in the middleware name `<middleware_name>`."
!!! warning "Conflicts in Declaration"
If you declare multiple middlewares with the same name but different parameters, the middleware fails to be declared.
| Field | Description | Value |
|------|-------------|-------|
| <a id="opt-tcp-middlewares-middleware-name-middleware-type-middleware-option" href="#opt-tcp-middlewares-middleware-name-middleware-type-middleware-option" title="#opt-tcp-middlewares-middleware-name-middleware-type-middleware-option">`tcp.middlewares.<middleware_name>.<middleware_type>.<middleware_option>`</a> | With `middleware_type` the middleware type, such as `inFlightConn`, and `middleware_option` the option to set. | `amount: 10` |
#### TCP ServersTransports
Define TCP ServersTransports under `tcp.serversTransports.<servers_transport_name>`.
| Field | Description | Value |
|------|-------------|-------|
| <a id="opt-tcp-serversTransports-servers-transport-name" href="#opt-tcp-serversTransports-servers-transport-name" title="#opt-tcp-serversTransports-servers-transport-name">`tcp.serversTransports.<servers_transport_name>.*`</a> | See [TCP ServersTransport](../tcp/serverstransport.md) for more information. | `dialTimeout: 30s` |
### UDP
You can declare UDP routers and services with the file provider.
#### UDP Routers
Define UDP routers under `udp.routers.<router_name>`.
!!! warning "The character `@` is not authorized in the router name `<router_name>`."
| Field | Description | Value |
|------|-------------|-------|
| <a id="opt-udp-routers-router-name-entryPointsn" href="#opt-udp-routers-router-name-entryPointsn" title="#opt-udp-routers-router-name-entryPointsn">`udp.routers.<router_name>.entryPoints[n]`</a> | See [UDP router entrypoints](../udp/routing/rules-priority.md#entrypoints) for more information. | `dns` |
| <a id="opt-udp-routers-router-name-service" href="#opt-udp-routers-router-name-service" title="#opt-udp-routers-router-name-service">`udp.routers.<router_name>.service`</a> | See [UDP router configuration](../udp/routing/rules-priority.md#configuration-example) for more information. | `dns-service` |
#### UDP Services
Define UDP services under `udp.services.<service_name>`.
!!! warning "The character `@` is not authorized in the service name `<service_name>`."
| Field | Description | Value |
|------|-------------|-------|
| <a id="opt-udp-services-service-name-loadBalancer-serversn-address" href="#opt-udp-services-service-name-loadBalancer-serversn-address" title="#opt-udp-services-service-name-loadBalancer-serversn-address">`udp.services.<service_name>.loadBalancer.servers[n].address`</a> | See [UDP service](../udp/service.md) for more information. | `127.0.0.1:5353` |
| <a id="opt-udp-services-service-name-weighted-servicesn-name" href="#opt-udp-services-service-name-weighted-servicesn-name" title="#opt-udp-services-service-name-weighted-servicesn-name">`udp.services.<service_name>.weighted.services[n].name`</a> | See [UDP service](../udp/service.md) for more information. | `dns-v1` |
| <a id="opt-udp-services-service-name-weighted-servicesn-weight" href="#opt-udp-services-service-name-weighted-servicesn-weight" title="#opt-udp-services-service-name-weighted-servicesn-weight">`udp.services.<service_name>.weighted.services[n].weight`</a> | See [UDP service](../udp/service.md) for more information. | `3` |
### TLS
You can declare TLS certificates, options, and stores with the file provider.
#### Certificates
| Field | Description | Value |
|------|-------------|-------|
| <a id="opt-tls-certificatesn-certFile" href="#opt-tls-certificatesn-certFile" title="#opt-tls-certificatesn-certFile">`tls.certificates[n].certFile`</a> | See [TLS certificates](../http/tls/tls-certificates.md) for more information. | `/certs/example.crt` |
| <a id="opt-tls-certificatesn-keyFile" href="#opt-tls-certificatesn-keyFile" title="#opt-tls-certificatesn-keyFile">`tls.certificates[n].keyFile`</a> | See [TLS certificates](../http/tls/tls-certificates.md) for more information. | `/certs/example.key` |
| <a id="opt-tls-certificatesn-storesn" href="#opt-tls-certificatesn-storesn" title="#opt-tls-certificatesn-storesn">`tls.certificates[n].stores[n]`</a> | See [certificate stores](../http/tls/tls-certificates.md#certificates-stores) for more information. | `default` |
#### TLS Options
| Field | Description | Value |
|------|-------------|-------|
| <a id="opt-tls-options-options-name-minVersion" href="#opt-tls-options-options-name-minVersion" title="#opt-tls-options-options-name-minVersion">`tls.options.<options_name>.minVersion`</a> | See [TLS options](../http/tls/tls-options.md) for more information. | `VersionTLS12` |
| <a id="opt-tls-options-options-name-maxVersion" href="#opt-tls-options-options-name-maxVersion" title="#opt-tls-options-options-name-maxVersion">`tls.options.<options_name>.maxVersion`</a> | See [TLS options](../http/tls/tls-options.md) for more information. | `VersionTLS13` |
| <a id="opt-tls-options-options-name-cipherSuitesn" href="#opt-tls-options-options-name-cipherSuitesn" title="#opt-tls-options-options-name-cipherSuitesn">`tls.options.<options_name>.cipherSuites[n]`</a> | See [TLS options](../http/tls/tls-options.md) for more information. | `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` |
| <a id="opt-tls-options-options-name-curvePreferencesn" href="#opt-tls-options-options-name-curvePreferencesn" title="#opt-tls-options-options-name-curvePreferencesn">`tls.options.<options_name>.curvePreferences[n]`</a> | See [TLS options](../http/tls/tls-options.md) for more information. | `CurveP256` |
| <a id="opt-tls-options-options-name-clientAuth-caFilesn" href="#opt-tls-options-options-name-clientAuth-caFilesn" title="#opt-tls-options-options-name-clientAuth-caFilesn">`tls.options.<options_name>.clientAuth.caFiles[n]`</a> | See [client authentication](../http/tls/tls-options.md#client-authentication-mtls) for more information. | `/certs/client-ca.crt` |
| <a id="opt-tls-options-options-name-clientAuth-clientAuthType" href="#opt-tls-options-options-name-clientAuth-clientAuthType" title="#opt-tls-options-options-name-clientAuth-clientAuthType">`tls.options.<options_name>.clientAuth.clientAuthType`</a> | See [client authentication](../http/tls/tls-options.md#client-authentication-mtls) for more information. | `RequireAndVerifyClientCert` |
| <a id="opt-tls-options-options-name-sniStrict" href="#opt-tls-options-options-name-sniStrict" title="#opt-tls-options-options-name-sniStrict">`tls.options.<options_name>.sniStrict`</a> | See [strict SNI checking](../http/tls/tls-options.md#strict-sni-checking) for more information. | `true` |
| <a id="opt-tls-options-options-name-alpnProtocolsn" href="#opt-tls-options-options-name-alpnProtocolsn" title="#opt-tls-options-options-name-alpnProtocolsn">`tls.options.<options_name>.alpnProtocols[n]`</a> | See [TLS options](../http/tls/tls-options.md) for more information. | `h2` |
| <a id="opt-tls-options-options-name-disableSessionTickets" href="#opt-tls-options-options-name-disableSessionTickets" title="#opt-tls-options-options-name-disableSessionTickets">`tls.options.<options_name>.disableSessionTickets`</a> | See [TLS options](../http/tls/tls-options.md) for more information. | `true` |
| <a id="opt-tls-options-options-name-preferServerCipherSuites" href="#opt-tls-options-options-name-preferServerCipherSuites" title="#opt-tls-options-options-name-preferServerCipherSuites">`tls.options.<options_name>.preferServerCipherSuites`</a> | See [TLS options](../http/tls/tls-options.md) for more information. | `true` |
#### TLS Stores
| Field | Description | Value |
|------|-------------|-------|
| <a id="opt-tls-stores-store-name-defaultCertificate-certFile" href="#opt-tls-stores-store-name-defaultCertificate-certFile" title="#opt-tls-stores-store-name-defaultCertificate-certFile">`tls.stores.<store_name>.defaultCertificate.certFile`</a> | See [default certificate](../http/tls/tls-certificates.md#default-certificate) for more information. | `/certs/default.crt` |
| <a id="opt-tls-stores-store-name-defaultCertificate-keyFile" href="#opt-tls-stores-store-name-defaultCertificate-keyFile" title="#opt-tls-stores-store-name-defaultCertificate-keyFile">`tls.stores.<store_name>.defaultCertificate.keyFile`</a> | See [default certificate](../http/tls/tls-certificates.md#default-certificate) for more information. | `/certs/default.key` |
| <a id="opt-tls-stores-store-name-defaultGeneratedCert-resolver" href="#opt-tls-stores-store-name-defaultGeneratedCert-resolver" title="#opt-tls-stores-store-name-defaultGeneratedCert-resolver">`tls.stores.<store_name>.defaultGeneratedCert.resolver`</a> | See [ACME default certificate](../http/tls/tls-certificates.md#acme-default-certificate) for more information. | `myresolver` |
| <a id="opt-tls-stores-store-name-defaultGeneratedCert-domain-main" href="#opt-tls-stores-store-name-defaultGeneratedCert-domain-main" title="#opt-tls-stores-store-name-defaultGeneratedCert-domain-main">`tls.stores.<store_name>.defaultGeneratedCert.domain.main`</a> | See [ACME default certificate](../http/tls/tls-certificates.md#acme-default-certificate) for more information. | `example.org` |
| <a id="opt-tls-stores-store-name-defaultGeneratedCert-domain-sansn" href="#opt-tls-stores-store-name-defaultGeneratedCert-domain-sansn" title="#opt-tls-stores-store-name-defaultGeneratedCert-domain-sansn">`tls.stores.<store_name>.defaultGeneratedCert.domain.sans[n]`</a> | See [ACME default certificate](../http/tls/tls-certificates.md#acme-default-certificate) for more information. | `www.example.org` |
## Go Templating
@@ -69,7 +497,7 @@ To illustrate, it is possible to easily define multiple routers, services, and T
{{ range $i, $e := until 10 }}
- certFile: "/etc/traefik/cert-{{ $e }}.pem"
keyFile: "/etc/traefik/cert-{{ $e }}.key"
store:
stores:
- "my-store-foo-{{ $e }}"
- "my-store-bar-{{ $e }}"
{{end}}
@@ -101,7 +529,7 @@ To illustrate, it is possible to easily define multiple routers, services, and T
[tcp.services]
{{ range $i, $e := until 100 }}
[http.services.service{{ $e }}]
[tcp.services.service{{ $e }}]
# ...
{{ end }}
@@ -112,9 +540,9 @@ To illustrate, it is possible to easily define multiple routers, services, and T
stores = ["my-store-foo-{{ $e }}", "my-store-bar-{{ $e }}"]
{{ end }}
[tls.config]
[tls.options]
{{ range $i, $e := until 10 }}
[tls.config.TLS{{ $e }}]
[tls.options.TLS{{ $e }}]
# ...
{{ end }}
```
@@ -1,667 +0,0 @@
## CODE GENERATED AUTOMATICALLY
## THIS FILE MUST NOT BE EDITED BY HAND
[http]
[http.routers]
[http.routers.Router0]
entryPoints = ["foobar", "foobar"]
middlewares = ["foobar", "foobar"]
service = "foobar"
rule = "foobar"
parentRefs = ["foobar", "foobar"]
ruleSyntax = "foobar"
priority = 42
[http.routers.Router0.tls]
options = "foobar"
certResolver = "foobar"
[[http.routers.Router0.tls.domains]]
main = "foobar"
sans = ["foobar", "foobar"]
[[http.routers.Router0.tls.domains]]
main = "foobar"
sans = ["foobar", "foobar"]
[http.routers.Router0.observability]
accessLogs = true
metrics = true
tracing = true
traceVerbosity = "foobar"
[http.routers.Router1]
entryPoints = ["foobar", "foobar"]
middlewares = ["foobar", "foobar"]
service = "foobar"
rule = "foobar"
parentRefs = ["foobar", "foobar"]
ruleSyntax = "foobar"
priority = 42
[http.routers.Router1.tls]
options = "foobar"
certResolver = "foobar"
[[http.routers.Router1.tls.domains]]
main = "foobar"
sans = ["foobar", "foobar"]
[[http.routers.Router1.tls.domains]]
main = "foobar"
sans = ["foobar", "foobar"]
[http.routers.Router1.observability]
accessLogs = true
metrics = true
tracing = true
traceVerbosity = "foobar"
[http.services]
[http.services.Service01]
[http.services.Service01.failover]
service = "foobar"
fallback = "foobar"
[http.services.Service01.failover.healthCheck]
[http.services.Service01.failover.errors]
maxRequestBodyBytes = 42
status = ["foobar", "foobar"]
[http.services.Service02]
[http.services.Service02.highestRandomWeight]
[[http.services.Service02.highestRandomWeight.services]]
name = "foobar"
weight = 42
[[http.services.Service02.highestRandomWeight.services]]
name = "foobar"
weight = 42
[http.services.Service02.highestRandomWeight.healthCheck]
[http.services.Service03]
[http.services.Service03.loadBalancer]
strategy = "foobar"
passHostHeader = true
serversTransport = "foobar"
[http.services.Service03.loadBalancer.sticky]
[http.services.Service03.loadBalancer.sticky.cookie]
name = "foobar"
secure = true
httpOnly = true
sameSite = "foobar"
maxAge = 42
path = "foobar"
domain = "foobar"
[[http.services.Service03.loadBalancer.servers]]
url = "foobar"
weight = 42
preservePath = true
[[http.services.Service03.loadBalancer.servers]]
url = "foobar"
weight = 42
preservePath = true
[http.services.Service03.loadBalancer.healthCheck]
scheme = "foobar"
mode = "foobar"
path = "foobar"
method = "foobar"
status = 42
port = 42
interval = "42s"
unhealthyInterval = "42s"
timeout = "42s"
hostname = "foobar"
followRedirects = true
[http.services.Service03.loadBalancer.healthCheck.headers]
name0 = "foobar"
name1 = "foobar"
[http.services.Service03.loadBalancer.passiveHealthCheck]
failureWindow = "42s"
maxFailedAttempts = 42
[http.services.Service03.loadBalancer.responseForwarding]
flushInterval = "42s"
[http.services.Service04]
middlewares = ["foobar", "foobar"]
[http.services.Service05]
[http.services.Service05.mirroring]
service = "foobar"
mirrorBody = true
maxBodySize = 42
[[http.services.Service05.mirroring.mirrors]]
name = "foobar"
percent = 42
[[http.services.Service05.mirroring.mirrors]]
name = "foobar"
percent = 42
[http.services.Service05.mirroring.healthCheck]
[http.services.Service06]
[http.services.Service06.weighted]
[[http.services.Service06.weighted.services]]
name = "foobar"
weight = 42
[[http.services.Service06.weighted.services]]
name = "foobar"
weight = 42
[http.services.Service06.weighted.sticky]
[http.services.Service06.weighted.sticky.cookie]
name = "foobar"
secure = true
httpOnly = true
sameSite = "foobar"
maxAge = 42
path = "foobar"
domain = "foobar"
[http.services.Service06.weighted.healthCheck]
[http.middlewares]
[http.middlewares.Middleware01]
[http.middlewares.Middleware01.addPrefix]
prefix = "foobar"
[http.middlewares.Middleware02]
[http.middlewares.Middleware02.basicAuth]
users = ["foobar", "foobar"]
usersFile = "foobar"
realm = "foobar"
removeHeader = true
headerField = "foobar"
[http.middlewares.Middleware03]
[http.middlewares.Middleware03.buffering]
maxRequestBodyBytes = 42
memRequestBodyBytes = 42
maxResponseBodyBytes = 42
memResponseBodyBytes = 42
retryExpression = "foobar"
[http.middlewares.Middleware04]
[http.middlewares.Middleware04.chain]
middlewares = ["foobar", "foobar"]
[http.middlewares.Middleware05]
[http.middlewares.Middleware05.circuitBreaker]
expression = "foobar"
checkPeriod = "42s"
fallbackDuration = "42s"
recoveryDuration = "42s"
responseCode = 42
[http.middlewares.Middleware06]
[http.middlewares.Middleware06.compress]
excludedContentTypes = ["foobar", "foobar"]
includedContentTypes = ["foobar", "foobar"]
minResponseBodyBytes = 42
encodings = ["foobar", "foobar"]
defaultEncoding = "foobar"
[http.middlewares.Middleware07]
[http.middlewares.Middleware07.contentType]
autoDetect = true
[http.middlewares.Middleware08]
[http.middlewares.Middleware08.digestAuth]
users = ["foobar", "foobar"]
usersFile = "foobar"
removeHeader = true
realm = "foobar"
headerField = "foobar"
[http.middlewares.Middleware09]
[http.middlewares.Middleware09.encodedCharacters]
allowEncodedSlash = true
allowEncodedBackSlash = true
allowEncodedNullCharacter = true
allowEncodedSemicolon = true
allowEncodedPercent = true
allowEncodedQuestionMark = true
allowEncodedHash = true
[http.middlewares.Middleware10]
[http.middlewares.Middleware10.errors]
status = ["foobar", "foobar"]
service = "foobar"
query = "foobar"
errorRequestHeaders = ["foobar", "foobar"]
[http.middlewares.Middleware10.errors.statusRewrites]
name0 = 42
name1 = 42
[http.middlewares.Middleware11]
[http.middlewares.Middleware11.forwardAuth]
address = "foobar"
trustForwardHeader = true
authResponseHeaders = ["foobar", "foobar"]
authResponseHeadersRegex = "foobar"
authRequestHeaders = ["foobar", "foobar"]
maxResponseBodySize = 42
addAuthCookiesToResponse = ["foobar", "foobar"]
headerField = "foobar"
forwardBody = true
maxBodySize = 42
preserveLocationHeader = true
preserveRequestMethod = true
authSigninURL = "foobar"
[http.middlewares.Middleware11.forwardAuth.tls]
ca = "foobar"
cert = "foobar"
key = "foobar"
insecureSkipVerify = true
caOptional = true
[http.middlewares.Middleware12]
[http.middlewares.Middleware12.grpcWeb]
allowOrigins = ["foobar", "foobar"]
[http.middlewares.Middleware13]
[http.middlewares.Middleware13.headers]
accessControlAllowCredentials = true
accessControlAllowHeaders = ["foobar", "foobar"]
accessControlAllowMethods = ["foobar", "foobar"]
accessControlAllowOriginList = ["foobar", "foobar"]
accessControlAllowOriginListRegex = ["foobar", "foobar"]
accessControlExposeHeaders = ["foobar", "foobar"]
accessControlMaxAge = 42
addVaryHeader = true
allowedHosts = ["foobar", "foobar"]
hostsProxyHeaders = ["foobar", "foobar"]
stsSeconds = 42
stsIncludeSubdomains = true
stsPreload = true
forceSTSHeader = true
frameDeny = true
customFrameOptionsValue = "foobar"
contentTypeNosniff = true
browserXssFilter = true
customBrowserXSSValue = "foobar"
contentSecurityPolicy = "foobar"
contentSecurityPolicyReportOnly = "foobar"
publicKey = "foobar"
referrerPolicy = "foobar"
permissionsPolicy = "foobar"
isDevelopment = true
featurePolicy = "foobar"
sslRedirect = true
sslTemporaryRedirect = true
sslHost = "foobar"
sslForceHost = true
[http.middlewares.Middleware13.headers.customRequestHeaders]
name0 = "foobar"
name1 = "foobar"
[http.middlewares.Middleware13.headers.customResponseHeaders]
name0 = "foobar"
name1 = "foobar"
[http.middlewares.Middleware13.headers.sslProxyHeaders]
name0 = "foobar"
name1 = "foobar"
[http.middlewares.Middleware14]
[http.middlewares.Middleware14.ipAllowList]
sourceRange = ["foobar", "foobar"]
rejectStatusCode = 42
[http.middlewares.Middleware14.ipAllowList.ipStrategy]
depth = 42
excludedIPs = ["foobar", "foobar"]
ipv6Subnet = 42
[http.middlewares.Middleware15]
[http.middlewares.Middleware15.ipWhiteList]
sourceRange = ["foobar", "foobar"]
[http.middlewares.Middleware15.ipWhiteList.ipStrategy]
depth = 42
excludedIPs = ["foobar", "foobar"]
ipv6Subnet = 42
[http.middlewares.Middleware16]
[http.middlewares.Middleware16.inFlightReq]
amount = 42
[http.middlewares.Middleware16.inFlightReq.sourceCriterion]
requestHeaderName = "foobar"
requestHost = true
[http.middlewares.Middleware16.inFlightReq.sourceCriterion.ipStrategy]
depth = 42
excludedIPs = ["foobar", "foobar"]
ipv6Subnet = 42
[http.middlewares.Middleware17]
[http.middlewares.Middleware17.passTLSClientCert]
pem = true
[http.middlewares.Middleware17.passTLSClientCert.info]
notAfter = true
notBefore = true
sans = true
serialNumber = true
[http.middlewares.Middleware17.passTLSClientCert.info.subject]
country = true
province = true
locality = true
organization = true
organizationalUnit = true
commonName = true
serialNumber = true
domainComponent = true
[http.middlewares.Middleware17.passTLSClientCert.info.issuer]
country = true
province = true
locality = true
organization = true
commonName = true
serialNumber = true
domainComponent = true
[http.middlewares.Middleware18]
[http.middlewares.Middleware18.plugin]
[http.middlewares.Middleware18.plugin.PluginConf0]
name0 = "foobar"
name1 = "foobar"
[http.middlewares.Middleware18.plugin.PluginConf1]
name0 = "foobar"
name1 = "foobar"
[http.middlewares.Middleware19]
[http.middlewares.Middleware19.rateLimit]
average = 42
period = "42s"
burst = 42
[http.middlewares.Middleware19.rateLimit.sourceCriterion]
requestHeaderName = "foobar"
requestHost = true
[http.middlewares.Middleware19.rateLimit.sourceCriterion.ipStrategy]
depth = 42
excludedIPs = ["foobar", "foobar"]
ipv6Subnet = 42
[http.middlewares.Middleware19.rateLimit.redis]
endpoints = ["foobar", "foobar"]
username = "foobar"
password = "foobar"
db = 42
poolSize = 42
minIdleConns = 42
maxActiveConns = 42
readTimeout = "42s"
writeTimeout = "42s"
dialTimeout = "42s"
[http.middlewares.Middleware19.rateLimit.redis.tls]
ca = "foobar"
cert = "foobar"
key = "foobar"
insecureSkipVerify = true
[http.middlewares.Middleware20]
[http.middlewares.Middleware20.redirectRegex]
regex = "foobar"
replacement = "foobar"
permanent = true
[http.middlewares.Middleware21]
[http.middlewares.Middleware21.redirectScheme]
scheme = "foobar"
port = "foobar"
permanent = true
[http.middlewares.Middleware22]
[http.middlewares.Middleware22.replacePath]
path = "foobar"
[http.middlewares.Middleware23]
[http.middlewares.Middleware23.replacePathRegex]
regex = "foobar"
replacement = "foobar"
[http.middlewares.Middleware24]
[http.middlewares.Middleware24.retry]
attempts = 42
timeout = "42s"
initialInterval = "42s"
maxRequestBodyBytes = 42
status = ["foobar", "foobar"]
disableRetryOnNetworkError = true
retryNonIdempotentMethod = true
[http.middlewares.Middleware25]
[http.middlewares.Middleware25.stripPrefix]
prefixes = ["foobar", "foobar"]
forceSlash = true
[http.middlewares.Middleware26]
[http.middlewares.Middleware26.stripPrefixRegex]
regex = ["foobar", "foobar"]
[http.serversTransports]
[http.serversTransports.ServersTransport0]
serverName = "foobar"
insecureSkipVerify = true
rootCAs = ["foobar", "foobar"]
cipherSuites = ["foobar", "foobar"]
minVersion = "foobar"
maxVersion = "foobar"
maxIdleConnsPerHost = 42
disableHTTP2 = true
peerCertURI = "foobar"
[[http.serversTransports.ServersTransport0.certificates]]
certFile = "foobar"
keyFile = "foobar"
[[http.serversTransports.ServersTransport0.certificates]]
certFile = "foobar"
keyFile = "foobar"
[http.serversTransports.ServersTransport0.forwardingTimeouts]
dialTimeout = "42s"
responseHeaderTimeout = "42s"
idleConnTimeout = "42s"
readIdleTimeout = "42s"
pingTimeout = "42s"
[http.serversTransports.ServersTransport0.spiffe]
ids = ["foobar", "foobar"]
trustDomain = "foobar"
[http.serversTransports.ServersTransport1]
serverName = "foobar"
insecureSkipVerify = true
rootCAs = ["foobar", "foobar"]
cipherSuites = ["foobar", "foobar"]
minVersion = "foobar"
maxVersion = "foobar"
maxIdleConnsPerHost = 42
disableHTTP2 = true
peerCertURI = "foobar"
[[http.serversTransports.ServersTransport1.certificates]]
certFile = "foobar"
keyFile = "foobar"
[[http.serversTransports.ServersTransport1.certificates]]
certFile = "foobar"
keyFile = "foobar"
[http.serversTransports.ServersTransport1.forwardingTimeouts]
dialTimeout = "42s"
responseHeaderTimeout = "42s"
idleConnTimeout = "42s"
readIdleTimeout = "42s"
pingTimeout = "42s"
[http.serversTransports.ServersTransport1.spiffe]
ids = ["foobar", "foobar"]
trustDomain = "foobar"
[tcp]
[tcp.routers]
[tcp.routers.TCPRouter0]
entryPoints = ["foobar", "foobar"]
middlewares = ["foobar", "foobar"]
service = "foobar"
rule = "foobar"
ruleSyntax = "foobar"
priority = 42
[tcp.routers.TCPRouter0.tls]
passthrough = true
options = "foobar"
certResolver = "foobar"
[[tcp.routers.TCPRouter0.tls.domains]]
main = "foobar"
sans = ["foobar", "foobar"]
[[tcp.routers.TCPRouter0.tls.domains]]
main = "foobar"
sans = ["foobar", "foobar"]
[tcp.routers.TCPRouter1]
entryPoints = ["foobar", "foobar"]
middlewares = ["foobar", "foobar"]
service = "foobar"
rule = "foobar"
ruleSyntax = "foobar"
priority = 42
[tcp.routers.TCPRouter1.tls]
passthrough = true
options = "foobar"
certResolver = "foobar"
[[tcp.routers.TCPRouter1.tls.domains]]
main = "foobar"
sans = ["foobar", "foobar"]
[[tcp.routers.TCPRouter1.tls.domains]]
main = "foobar"
sans = ["foobar", "foobar"]
[tcp.services]
[tcp.services.TCPService01]
[tcp.services.TCPService01.loadBalancer]
serversTransport = "foobar"
terminationDelay = 42
[[tcp.services.TCPService01.loadBalancer.servers]]
address = "foobar"
tls = true
[[tcp.services.TCPService01.loadBalancer.servers]]
address = "foobar"
tls = true
[tcp.services.TCPService01.loadBalancer.proxyProtocol]
version = 42
[tcp.services.TCPService01.loadBalancer.healthCheck]
port = 42
send = "foobar"
expect = "foobar"
interval = "42s"
unhealthyInterval = "42s"
timeout = "42s"
[tcp.services.TCPService02]
[tcp.services.TCPService02.weighted]
[[tcp.services.TCPService02.weighted.services]]
name = "foobar"
weight = 42
[[tcp.services.TCPService02.weighted.services]]
name = "foobar"
weight = 42
[tcp.services.TCPService02.weighted.healthCheck]
[tcp.middlewares]
[tcp.middlewares.TCPMiddleware01]
[tcp.middlewares.TCPMiddleware01.ipAllowList]
sourceRange = ["foobar", "foobar"]
[tcp.middlewares.TCPMiddleware02]
[tcp.middlewares.TCPMiddleware02.ipWhiteList]
sourceRange = ["foobar", "foobar"]
[tcp.middlewares.TCPMiddleware03]
[tcp.middlewares.TCPMiddleware03.inFlightConn]
amount = 42
[tcp.serversTransports]
[tcp.serversTransports.TCPServersTransport0]
dialKeepAlive = "42s"
dialTimeout = "42s"
terminationDelay = "42s"
[tcp.serversTransports.TCPServersTransport0.proxyProtocol]
version = 42
[tcp.serversTransports.TCPServersTransport0.tls]
serverName = "foobar"
insecureSkipVerify = true
rootCAs = ["foobar", "foobar"]
peerCertURI = "foobar"
[[tcp.serversTransports.TCPServersTransport0.tls.certificates]]
certFile = "foobar"
keyFile = "foobar"
[[tcp.serversTransports.TCPServersTransport0.tls.certificates]]
certFile = "foobar"
keyFile = "foobar"
[tcp.serversTransports.TCPServersTransport0.tls.spiffe]
ids = ["foobar", "foobar"]
trustDomain = "foobar"
[tcp.serversTransports.TCPServersTransport1]
dialKeepAlive = "42s"
dialTimeout = "42s"
terminationDelay = "42s"
[tcp.serversTransports.TCPServersTransport1.proxyProtocol]
version = 42
[tcp.serversTransports.TCPServersTransport1.tls]
serverName = "foobar"
insecureSkipVerify = true
rootCAs = ["foobar", "foobar"]
peerCertURI = "foobar"
[[tcp.serversTransports.TCPServersTransport1.tls.certificates]]
certFile = "foobar"
keyFile = "foobar"
[[tcp.serversTransports.TCPServersTransport1.tls.certificates]]
certFile = "foobar"
keyFile = "foobar"
[tcp.serversTransports.TCPServersTransport1.tls.spiffe]
ids = ["foobar", "foobar"]
trustDomain = "foobar"
[udp]
[udp.routers]
[udp.routers.UDPRouter0]
entryPoints = ["foobar", "foobar"]
service = "foobar"
[udp.routers.UDPRouter1]
entryPoints = ["foobar", "foobar"]
service = "foobar"
[udp.services]
[udp.services.UDPService01]
[udp.services.UDPService01.loadBalancer]
[[udp.services.UDPService01.loadBalancer.servers]]
address = "foobar"
[[udp.services.UDPService01.loadBalancer.servers]]
address = "foobar"
[udp.services.UDPService02]
[udp.services.UDPService02.weighted]
[[udp.services.UDPService02.weighted.services]]
name = "foobar"
weight = 42
[[udp.services.UDPService02.weighted.services]]
name = "foobar"
weight = 42
[tls]
[[tls.certificates]]
certFile = "foobar"
keyFile = "foobar"
stores = ["foobar", "foobar"]
[[tls.certificates]]
certFile = "foobar"
keyFile = "foobar"
stores = ["foobar", "foobar"]
[tls.options]
[tls.options.Options0]
minVersion = "foobar"
maxVersion = "foobar"
cipherSuites = ["foobar", "foobar"]
curvePreferences = ["foobar", "foobar"]
sniStrict = true
alpnProtocols = ["foobar", "foobar"]
disableSessionTickets = true
preferServerCipherSuites = true
[tls.options.Options0.clientAuth]
caFiles = ["foobar", "foobar"]
clientAuthType = "foobar"
[tls.options.Options1]
minVersion = "foobar"
maxVersion = "foobar"
cipherSuites = ["foobar", "foobar"]
curvePreferences = ["foobar", "foobar"]
sniStrict = true
alpnProtocols = ["foobar", "foobar"]
disableSessionTickets = true
preferServerCipherSuites = true
[tls.options.Options1.clientAuth]
caFiles = ["foobar", "foobar"]
clientAuthType = "foobar"
[tls.stores]
[tls.stores.Store0]
[tls.stores.Store0.defaultCertificate]
certFile = "foobar"
keyFile = "foobar"
[tls.stores.Store0.defaultGeneratedCert]
resolver = "foobar"
[tls.stores.Store0.defaultGeneratedCert.domain]
main = "foobar"
sans = ["foobar", "foobar"]
[tls.stores.Store1]
[tls.stores.Store1.defaultCertificate]
certFile = "foobar"
keyFile = "foobar"
[tls.stores.Store1.defaultGeneratedCert]
resolver = "foobar"
[tls.stores.Store1.defaultGeneratedCert.domain]
main = "foobar"
sans = ["foobar", "foobar"]
@@ -1,763 +0,0 @@
## CODE GENERATED AUTOMATICALLY
## THIS FILE MUST NOT BE EDITED BY HAND
http:
routers:
Router0:
entryPoints:
- foobar
- foobar
middlewares:
- foobar
- foobar
service: foobar
rule: foobar
parentRefs:
- foobar
- foobar
ruleSyntax: foobar
priority: 42
tls:
options: foobar
certResolver: foobar
domains:
- main: foobar
sans:
- foobar
- foobar
- main: foobar
sans:
- foobar
- foobar
observability:
accessLogs: true
metrics: true
tracing: true
traceVerbosity: foobar
Router1:
entryPoints:
- foobar
- foobar
middlewares:
- foobar
- foobar
service: foobar
rule: foobar
parentRefs:
- foobar
- foobar
ruleSyntax: foobar
priority: 42
tls:
options: foobar
certResolver: foobar
domains:
- main: foobar
sans:
- foobar
- foobar
- main: foobar
sans:
- foobar
- foobar
observability:
accessLogs: true
metrics: true
tracing: true
traceVerbosity: foobar
services:
Service01:
failover:
service: foobar
fallback: foobar
healthCheck: {}
errors:
maxRequestBodyBytes: 42
status:
- foobar
- foobar
Service02:
highestRandomWeight:
services:
- name: foobar
weight: 42
- name: foobar
weight: 42
healthCheck: {}
Service03:
loadBalancer:
sticky:
cookie:
name: foobar
secure: true
httpOnly: true
sameSite: foobar
maxAge: 42
path: foobar
domain: foobar
servers:
- url: foobar
weight: 42
preservePath: true
- url: foobar
weight: 42
preservePath: true
strategy: foobar
healthCheck:
scheme: foobar
mode: foobar
path: foobar
method: foobar
status: 42
port: 42
interval: 42s
unhealthyInterval: 42s
timeout: 42s
hostname: foobar
followRedirects: true
headers:
name0: foobar
name1: foobar
passiveHealthCheck:
failureWindow: 42s
maxFailedAttempts: 42
passHostHeader: true
responseForwarding:
flushInterval: 42s
serversTransport: foobar
Service04:
middlewares:
- foobar
- foobar
Service05:
mirroring:
service: foobar
mirrorBody: true
maxBodySize: 42
mirrors:
- name: foobar
percent: 42
- name: foobar
percent: 42
healthCheck: {}
Service06:
weighted:
services:
- name: foobar
weight: 42
- name: foobar
weight: 42
sticky:
cookie:
name: foobar
secure: true
httpOnly: true
sameSite: foobar
maxAge: 42
path: foobar
domain: foobar
healthCheck: {}
middlewares:
Middleware01:
addPrefix:
prefix: foobar
Middleware02:
basicAuth:
users:
- foobar
- foobar
usersFile: foobar
realm: foobar
removeHeader: true
headerField: foobar
Middleware03:
buffering:
maxRequestBodyBytes: 42
memRequestBodyBytes: 42
maxResponseBodyBytes: 42
memResponseBodyBytes: 42
retryExpression: foobar
Middleware04:
chain:
middlewares:
- foobar
- foobar
Middleware05:
circuitBreaker:
expression: foobar
checkPeriod: 42s
fallbackDuration: 42s
recoveryDuration: 42s
responseCode: 42
Middleware06:
compress:
excludedContentTypes:
- foobar
- foobar
includedContentTypes:
- foobar
- foobar
minResponseBodyBytes: 42
encodings:
- foobar
- foobar
defaultEncoding: foobar
Middleware07:
contentType:
autoDetect: true
Middleware08:
digestAuth:
users:
- foobar
- foobar
usersFile: foobar
removeHeader: true
realm: foobar
headerField: foobar
Middleware09:
encodedCharacters:
allowEncodedSlash: true
allowEncodedBackSlash: true
allowEncodedNullCharacter: true
allowEncodedSemicolon: true
allowEncodedPercent: true
allowEncodedQuestionMark: true
allowEncodedHash: true
Middleware10:
errors:
status:
- foobar
- foobar
statusRewrites:
name0: 42
name1: 42
service: foobar
query: foobar
errorRequestHeaders:
- foobar
- foobar
Middleware11:
forwardAuth:
address: foobar
tls:
ca: foobar
cert: foobar
key: foobar
insecureSkipVerify: true
caOptional: true
trustForwardHeader: true
authResponseHeaders:
- foobar
- foobar
authResponseHeadersRegex: foobar
authRequestHeaders:
- foobar
- foobar
maxResponseBodySize: 42
addAuthCookiesToResponse:
- foobar
- foobar
headerField: foobar
forwardBody: true
maxBodySize: 42
preserveLocationHeader: true
preserveRequestMethod: true
authSigninURL: foobar
Middleware12:
grpcWeb:
allowOrigins:
- foobar
- foobar
Middleware13:
headers:
customRequestHeaders:
name0: foobar
name1: foobar
customResponseHeaders:
name0: foobar
name1: foobar
accessControlAllowCredentials: true
accessControlAllowHeaders:
- foobar
- foobar
accessControlAllowMethods:
- foobar
- foobar
accessControlAllowOriginList:
- foobar
- foobar
accessControlAllowOriginListRegex:
- foobar
- foobar
accessControlExposeHeaders:
- foobar
- foobar
accessControlMaxAge: 42
addVaryHeader: true
allowedHosts:
- foobar
- foobar
hostsProxyHeaders:
- foobar
- foobar
sslProxyHeaders:
name0: foobar
name1: foobar
stsSeconds: 42
stsIncludeSubdomains: true
stsPreload: true
forceSTSHeader: true
frameDeny: true
customFrameOptionsValue: foobar
contentTypeNosniff: true
browserXssFilter: true
customBrowserXSSValue: foobar
contentSecurityPolicy: foobar
contentSecurityPolicyReportOnly: foobar
publicKey: foobar
referrerPolicy: foobar
permissionsPolicy: foobar
isDevelopment: true
featurePolicy: foobar
sslRedirect: true
sslTemporaryRedirect: true
sslHost: foobar
sslForceHost: true
Middleware14:
ipAllowList:
sourceRange:
- foobar
- foobar
ipStrategy:
depth: 42
excludedIPs:
- foobar
- foobar
ipv6Subnet: 42
rejectStatusCode: 42
Middleware15:
ipWhiteList:
sourceRange:
- foobar
- foobar
ipStrategy:
depth: 42
excludedIPs:
- foobar
- foobar
ipv6Subnet: 42
Middleware16:
inFlightReq:
amount: 42
sourceCriterion:
ipStrategy:
depth: 42
excludedIPs:
- foobar
- foobar
ipv6Subnet: 42
requestHeaderName: foobar
requestHost: true
Middleware17:
passTLSClientCert:
pem: true
info:
notAfter: true
notBefore: true
sans: true
serialNumber: true
subject:
country: true
province: true
locality: true
organization: true
organizationalUnit: true
commonName: true
serialNumber: true
domainComponent: true
issuer:
country: true
province: true
locality: true
organization: true
commonName: true
serialNumber: true
domainComponent: true
Middleware18:
plugin:
PluginConf0:
name0: foobar
name1: foobar
PluginConf1:
name0: foobar
name1: foobar
Middleware19:
rateLimit:
average: 42
period: 42s
burst: 42
sourceCriterion:
ipStrategy:
depth: 42
excludedIPs:
- foobar
- foobar
ipv6Subnet: 42
requestHeaderName: foobar
requestHost: true
redis:
endpoints:
- foobar
- foobar
tls:
ca: foobar
cert: foobar
key: foobar
insecureSkipVerify: true
username: foobar
password: foobar
db: 42
poolSize: 42
minIdleConns: 42
maxActiveConns: 42
readTimeout: 42s
writeTimeout: 42s
dialTimeout: 42s
Middleware20:
redirectRegex:
regex: foobar
replacement: foobar
permanent: true
Middleware21:
redirectScheme:
scheme: foobar
port: foobar
permanent: true
Middleware22:
replacePath:
path: foobar
Middleware23:
replacePathRegex:
regex: foobar
replacement: foobar
Middleware24:
retry:
attempts: 42
timeout: 42s
initialInterval: 42s
maxRequestBodyBytes: 42
status:
- foobar
- foobar
disableRetryOnNetworkError: true
retryNonIdempotentMethod: true
Middleware25:
stripPrefix:
prefixes:
- foobar
- foobar
forceSlash: true
Middleware26:
stripPrefixRegex:
regex:
- foobar
- foobar
serversTransports:
ServersTransport0:
serverName: foobar
insecureSkipVerify: true
rootCAs:
- foobar
- foobar
certificates:
- certFile: foobar
keyFile: foobar
- certFile: foobar
keyFile: foobar
cipherSuites:
- foobar
- foobar
minVersion: foobar
maxVersion: foobar
maxIdleConnsPerHost: 42
forwardingTimeouts:
dialTimeout: 42s
responseHeaderTimeout: 42s
idleConnTimeout: 42s
readIdleTimeout: 42s
pingTimeout: 42s
disableHTTP2: true
peerCertURI: foobar
spiffe:
ids:
- foobar
- foobar
trustDomain: foobar
ServersTransport1:
serverName: foobar
insecureSkipVerify: true
rootCAs:
- foobar
- foobar
certificates:
- certFile: foobar
keyFile: foobar
- certFile: foobar
keyFile: foobar
cipherSuites:
- foobar
- foobar
minVersion: foobar
maxVersion: foobar
maxIdleConnsPerHost: 42
forwardingTimeouts:
dialTimeout: 42s
responseHeaderTimeout: 42s
idleConnTimeout: 42s
readIdleTimeout: 42s
pingTimeout: 42s
disableHTTP2: true
peerCertURI: foobar
spiffe:
ids:
- foobar
- foobar
trustDomain: foobar
tcp:
routers:
TCPRouter0:
entryPoints:
- foobar
- foobar
middlewares:
- foobar
- foobar
service: foobar
rule: foobar
ruleSyntax: foobar
priority: 42
tls:
passthrough: true
options: foobar
certResolver: foobar
domains:
- main: foobar
sans:
- foobar
- foobar
- main: foobar
sans:
- foobar
- foobar
TCPRouter1:
entryPoints:
- foobar
- foobar
middlewares:
- foobar
- foobar
service: foobar
rule: foobar
ruleSyntax: foobar
priority: 42
tls:
passthrough: true
options: foobar
certResolver: foobar
domains:
- main: foobar
sans:
- foobar
- foobar
- main: foobar
sans:
- foobar
- foobar
services:
TCPService01:
loadBalancer:
servers:
- address: foobar
tls: true
- address: foobar
tls: true
serversTransport: foobar
proxyProtocol:
version: 42
terminationDelay: 42
healthCheck:
port: 42
send: foobar
expect: foobar
interval: 42s
unhealthyInterval: 42s
timeout: 42s
TCPService02:
weighted:
services:
- name: foobar
weight: 42
- name: foobar
weight: 42
healthCheck: {}
middlewares:
TCPMiddleware01:
ipAllowList:
sourceRange:
- foobar
- foobar
TCPMiddleware02:
ipWhiteList:
sourceRange:
- foobar
- foobar
TCPMiddleware03:
inFlightConn:
amount: 42
serversTransports:
TCPServersTransport0:
dialKeepAlive: 42s
dialTimeout: 42s
proxyProtocol:
version: 42
terminationDelay: 42s
tls:
serverName: foobar
insecureSkipVerify: true
rootCAs:
- foobar
- foobar
certificates:
- certFile: foobar
keyFile: foobar
- certFile: foobar
keyFile: foobar
peerCertURI: foobar
spiffe:
ids:
- foobar
- foobar
trustDomain: foobar
TCPServersTransport1:
dialKeepAlive: 42s
dialTimeout: 42s
proxyProtocol:
version: 42
terminationDelay: 42s
tls:
serverName: foobar
insecureSkipVerify: true
rootCAs:
- foobar
- foobar
certificates:
- certFile: foobar
keyFile: foobar
- certFile: foobar
keyFile: foobar
peerCertURI: foobar
spiffe:
ids:
- foobar
- foobar
trustDomain: foobar
udp:
routers:
UDPRouter0:
entryPoints:
- foobar
- foobar
service: foobar
UDPRouter1:
entryPoints:
- foobar
- foobar
service: foobar
services:
UDPService01:
loadBalancer:
servers:
- address: foobar
- address: foobar
UDPService02:
weighted:
services:
- name: foobar
weight: 42
- name: foobar
weight: 42
tls:
certificates:
- certFile: foobar
keyFile: foobar
stores:
- foobar
- foobar
- certFile: foobar
keyFile: foobar
stores:
- foobar
- foobar
options:
Options0:
minVersion: foobar
maxVersion: foobar
cipherSuites:
- foobar
- foobar
curvePreferences:
- foobar
- foobar
clientAuth:
caFiles:
- foobar
- foobar
clientAuthType: foobar
sniStrict: true
alpnProtocols:
- foobar
- foobar
disableSessionTickets: true
preferServerCipherSuites: true
Options1:
minVersion: foobar
maxVersion: foobar
cipherSuites:
- foobar
- foobar
curvePreferences:
- foobar
- foobar
clientAuth:
caFiles:
- foobar
- foobar
clientAuthType: foobar
sniStrict: true
alpnProtocols:
- foobar
- foobar
disableSessionTickets: true
preferServerCipherSuites: true
stores:
Store0:
defaultCertificate:
certFile: foobar
keyFile: foobar
defaultGeneratedCert:
resolver: foobar
domain:
main: foobar
sans:
- foobar
- foobar
Store1:
defaultCertificate:
certFile: foobar
keyFile: foobar
defaultGeneratedCert:
resolver: foobar
domain:
main: foobar
sans:
- foobar
- foobar
@@ -24,7 +24,11 @@ tcp:
insecureSkipVerify: true
rootcas:
- "/path/to/rootca.pem"
peerCertURI: "spiffe://example.org/peer"
peerCertSANs:
- type: DNSName
value: foo.com
- type: URI
value: spiffe://example.org/peer
spiffe:
ids:
- "spiffe://example.org/id1"
@@ -43,7 +47,7 @@ tcp:
certificates = ["/path/to/cert1.pem", "/path/to/cert2.pem"]
insecureSkipVerify = true
rootcas = ["/path/to/rootca.pem"]
peerCertURI = "spiffe://example.org/peer"
peerCertSANs = [{type = "DNSName", value = "foo.com"}, {type = "URI", value = "spiffe://example.org/peer"}]
[tcp.serversTransports.mytransport.spiffe]
ids = ["spiffe://example.org/id1", "spiffe://example.org/id2"]
@@ -96,7 +100,9 @@ labels:
| <a id="opt-serverstransport-tls-certificates" href="#opt-serverstransport-tls-certificates" title="#opt-serverstransport-tls-certificates">`serverstransport.`<br />`tls`<br />`.certificates`</a> | Defines the list of certificates (as file paths, or data bytes) that will be set as client certificates for mTLS. | | No |
| <a id="opt-serverstransport-tls-insecureSkipVerify" href="#opt-serverstransport-tls-insecureSkipVerify" title="#opt-serverstransport-tls-insecureSkipVerify">`serverstransport.`<br />`tls`<br />`.insecureSkipVerify`</a> | Controls whether the server's certificate chain and host name is verified. | false | No |
| <a id="opt-serverstransport-tls-rootcas" href="#opt-serverstransport-tls-rootcas" title="#opt-serverstransport-tls-rootcas">`serverstransport.`<br />`tls`<br />`.rootcas`</a> | Defines the root certificate authorities to use when verifying server certificates. (for mTLS connections). | | No |
| <a id="opt-serverstransport-tls-peerCertURI" href="#opt-serverstransport-tls-peerCertURI" title="#opt-serverstransport-tls-peerCertURI">`serverstransport.`<br />`tls.`<br />`peerCertURI`</a> | Defines the URI used to match against SAN URIs during the server's certificate verification. | false | No |
| <a id="opt-serverstransport-tls-peerCertSANs" href="#opt-serverstransport-tls-peerCertSANs" title="#opt-serverstransport-tls-peerCertSANs">`serverstransport.`<br />`tls.`<br />`peerCertSANs`</a> | Defines the SANs (Subject Alternative Names) used to match against SANs during the peer certificate verification. | [] | No |
| <a id="opt-serverstransport-tls-peerCertSANs-type" href="#opt-serverstransport-tls-peerCertSANs-type" title="#opt-serverstransport-tls-peerCertSANs-type">`serverstransport.`<br />`tls.`<br />`peerCertSANs[].type`</a> | Defines the SAN type (`URI` or `DNSName`) to match against the peer certificate's Subject Alternative Names. | "" | No |
| <a id="opt-serverstransport-tls-peerCertSANs-value" href="#opt-serverstransport-tls-peerCertSANs-value" title="#opt-serverstransport-tls-peerCertSANs-value">`serverstransport.`<br />`tls.`<br />`peerCertSANs[].value`</a> | Defines the SAN value to match against the peer certificate's Subject Alternative Names. | "" | No |
| <a id="opt-serverstransport-spiffe" href="#opt-serverstransport-spiffe" title="#opt-serverstransport-spiffe">`serverstransport.`<br />`spiffe`</a> | Defines the SPIFFE configuration. An empty `spiffe` section enables SPIFFE (that allows any SPIFFE ID). | | No |
| <a id="opt-serverstransport-spiffe-ids" href="#opt-serverstransport-spiffe-ids" title="#opt-serverstransport-spiffe-ids">`serverstransport.`<br />`spiffe`<br />`.ids`</a> | Allow SPIFFE IDs.<br />This takes precedence over the SPIFFE TrustDomain. | | No |
| <a id="opt-serverstransport-spiffe-trustDomain" href="#opt-serverstransport-spiffe-trustDomain" title="#opt-serverstransport-spiffe-trustDomain">`serverstransport.`<br />`spiffe`<br />`.trustDomain`</a> | Allow SPIFFE trust domain. | "" | No |
@@ -50,6 +50,7 @@
insecure = true
trustedIPs = ["foobar", "foobar"]
connection = ["foobar", "foobar"]
addXForwardedSchemeHeaders = true
[entryPoints.EntryPoint0.http]
middlewares = ["foobar", "foobar"]
encodeQuerySemicolons = true
@@ -61,6 +61,7 @@ entryPoints:
connection:
- foobar
- foobar
addXForwardedSchemeHeaders: true
http:
redirections:
entryPoint:
Generated
+7 -44
View File
@@ -1,37 +1,16 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1772963539,
"narHash": "sha256-9jVDGZnvCckTGdYT53d/EfznygLskyLQXYwJLKMPsZs=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9dcb002ca1690658be4a04645215baea8b95f31d",
"type": "github"
"lastModified": 1778036283,
"narHash": "sha256-GW2cEd/cLcVbbCes8iQuoY2qGIeCA7UiaD351hpkXfI=",
"rev": "ed67bc86e84e51d4a88e73c7fd36006dc876476f",
"type": "tarball",
"url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.05pre993032.ed67bc86e84e/nixexprs.tar.xz"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
"type": "tarball",
"url": "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz"
}
},
"nixpkgs-golangci": {
@@ -68,26 +47,10 @@
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"nixpkgs-golangci": "nixpkgs-golangci",
"nixpkgs-kct": "nixpkgs-kct"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
+26 -25
View File
@@ -3,7 +3,7 @@
inputs = {
# Main nixpkgs (used for gnused)
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs.url = "https://channels.nixos.org/nixpkgs-unstable/nixexprs.tar.xz";
# Pinned nixpkgs for kubernetes-controller-tools
# Search: https://www.nixhub.io/packages/kubernetes-controller-tools
@@ -12,33 +12,34 @@
# Pinned nixpkgs for golangci-lint
# Search: https://www.nixhub.io/packages/golangci-lint
nixpkgs-golangci.url = "github:NixOS/nixpkgs/80d901ec0377e19ac3f7bb8c035201e2e098cc97";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, nixpkgs-kct, nixpkgs-golangci, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
};
outputs =
{
nixpkgs,
nixpkgs-kct,
nixpkgs-golangci,
...
}:
let
inherit (nixpkgs.lib) genAttrs;
forEachSystem = genAttrs nixpkgs.lib.systems.flakeExposed;
pkgs-kct = import nixpkgs-kct {
inherit system;
};
pkgs-golangci = import nixpkgs-golangci {
inherit system;
};
in
{
devShells.default = pkgs.mkShell {
pkgsForEach = nixpkgs.legacyPackages;
pkgsKctForEach = nixpkgs-kct.legacyPackages;
pkgsGolangCiForEach = nixpkgs-golangci.legacyPackages;
in
{
devShells = forEachSystem (system: {
default = pkgsForEach.${system}.mkShell {
packages = [
pkgs-kct.kubernetes-controller-tools
pkgs.gnused
pkgs-golangci.golangci-lint
pkgsForEach.${system}.gnused
pkgsKctForEach.${system}.kubernetes-controller-tools
pkgsGolangCiForEach.${system}.golangci-lint
];
};
}
);
}
});
formatter = forEachSystem (system: pkgsForEach.${system}.nixfmt);
};
}
+10 -11
View File
@@ -22,7 +22,7 @@ require (
github.com/docker/cli v29.4.0+incompatible
github.com/docker/go-connections v0.6.0
github.com/fatih/structs v1.1.0
github.com/fsnotify/fsnotify v1.9.0
github.com/fsnotify/fsnotify v1.10.1
github.com/go-acme/lego/v4 v4.35.2
github.com/go-kit/kit v0.13.0
github.com/go-kit/log v0.2.1
@@ -53,11 +53,11 @@ require (
github.com/moby/moby/api v1.54.1
github.com/moby/moby/client v0.4.0
github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/pires/go-proxyproto v0.8.1
github.com/pires/go-proxyproto v0.12.0
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // No tag on the repo.
github.com/prometheus/client_golang v1.23.2
github.com/prometheus/client_model v0.6.2
github.com/quic-go/quic-go v0.59.0
github.com/quic-go/quic-go v0.59.1
github.com/redis/go-redis/v9 v9.8.0
github.com/rs/zerolog v1.33.0
github.com/sirupsen/logrus v1.9.4
@@ -99,12 +99,12 @@ require (
go.opentelemetry.io/otel/sdk/log v0.19.0
go.opentelemetry.io/otel/sdk/metric v1.43.0
go.opentelemetry.io/otel/trace v1.43.0
golang.org/x/crypto v0.50.0
golang.org/x/crypto v0.52.0
golang.org/x/mod v0.35.0
golang.org/x/net v0.53.0
golang.org/x/net v0.55.0
golang.org/x/sync v0.20.0
golang.org/x/sys v0.43.0
golang.org/x/text v0.36.0
golang.org/x/sys v0.45.0
golang.org/x/text v0.37.0
golang.org/x/time v0.15.0
golang.org/x/tools v0.44.0
google.golang.org/grpc v1.80.0
@@ -182,7 +182,7 @@ require (
github.com/blendle/zapdriver v1.3.1 // indirect
github.com/bodgit/tsig v1.2.2 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/bytedance/sonic v1.12.0 // indirect
github.com/bytedance/sonic v1.15.1 // indirect
github.com/cenkalti/backoff/v5 v5.0.3 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
@@ -274,7 +274,6 @@ require (
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.13-0.20220915233716-71ac16282d12 // indirect
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect
github.com/kylelemons/godebug v1.1.0 // indirect
github.com/labbsr0x/bindman-dns-webhook v1.0.2 // indirect
@@ -298,7 +297,7 @@ require (
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/go-archive v0.2.0 // indirect
github.com/moby/patternmatcher v0.6.1 // indirect
github.com/moby/spdystream v0.5.0 // indirect
github.com/moby/spdystream v0.5.1 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
@@ -401,7 +400,7 @@ require (
golang.org/x/arch v0.4.0 // indirect
golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect
golang.org/x/oauth2 v0.36.0 // indirect
golang.org/x/term v0.42.0 // indirect
golang.org/x/term v0.43.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect
google.golang.org/api v0.276.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 // indirect
+28 -28
View File
@@ -835,10 +835,12 @@ github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/bytedance/sonic v1.12.0 h1:YGPgxF9xzaCNvd/ZKdQ28yRovhfMFZQjuk6fKBzZ3ls=
github.com/bytedance/sonic v1.12.0/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
github.com/bytedance/sonic v1.15.1 h1:nJD5PmM0vY7J8CT6MxoqbVAAMhkSmV2HgRAUrrpLoOw=
github.com/bytedance/sonic v1.15.1/go.mod h1:mT2NbXunuaEbnZ+mRIX/vYqKISmgEuHFDI4UzmKx2SA=
github.com/bytedance/sonic/loader v0.5.1 h1:Ygpfa9zwRCCKSlrp5bBP/b/Xzc3VxsAW+5NIYXrOOpI=
github.com/bytedance/sonic/loader v0.5.1/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY=
github.com/casbin/casbin/v2 v2.37.0/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
@@ -866,10 +868,8 @@ github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5P
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -1004,8 +1004,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
@@ -1467,8 +1467,8 @@ github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHU
github.com/klauspost/compress v1.18.5 h1:/h1gH5Ce+VWNLSWqPzOVn6XBO+vJbCNGvjoaGBFW2IE=
github.com/klauspost/compress v1.18.5/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b h1:udzkj9S/zlT5X367kqJis0QP7YMxobob6zhzq6Yre00=
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b/go.mod h1:pcaDhQK0/NJZEvtCO0qQPPropqV0sJOJ6YW7X+9kRwM=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -1629,8 +1629,8 @@ github.com/moby/moby/client v0.4.0 h1:S+2XegzHQrrvTCvF6s5HFzcrywWQmuVnhOXe2kiWjI
github.com/moby/moby/client v0.4.0/go.mod h1:QWPbvWchQbxBNdaLSpoKpCdf5E+WxFAgNHogCWDoa7g=
github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/spdystream v0.5.1 h1:9sNYeYZUcci9R6/w7KDaFWEWeV4LStVG78Mpyq/Zm/Y=
github.com/moby/spdystream v0.5.1/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
@@ -1748,8 +1748,8 @@ github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaASJgp0=
github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU=
github.com/pires/go-proxyproto v0.12.0 h1:TTCxD66dU898tahivkqc3hoceZp7P44FnorWyo9d5vM=
github.com/pires/go-proxyproto v0.12.0/go.mod h1:qUvfqUMEoX7T8g0q7TQLDnhMjdTrxnG0hvpMn+7ePNI=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
@@ -1811,8 +1811,8 @@ github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05Zp
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/quic-go/quic-go v0.59.1 h1:0Gmua0HW1Tv7ANR7hUYwRyD0MG5OJfgvYSZasGZzBic=
github.com/quic-go/quic-go v0.59.1/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.8.0 h1:q3nRvjrlge/6UD7eTu/DSg2uYiU2mCL0G/uzBWqhicI=
@@ -2239,8 +2239,8 @@ golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDf
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -2391,8 +2391,8 @@ golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA=
golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs=
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -2572,8 +2572,8 @@ golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -2595,8 +2595,8 @@ golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY=
golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY=
golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4=
golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -2618,8 +2618,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -8,6 +8,7 @@
[entryPoints.websecure]
address = ":4443"
[entryPoints.websecure.http3]
[api]
insecure = true
@@ -33,6 +34,35 @@
[http.routers.router3.tls]
options = "mytls"
[http.routers.router4]
rule = "Host(`site4.www.snitest.com`)"
service = "service4"
[http.routers.router4.tls]
[http.routers.router4path]
rule = "Host(`site4.www.snitest.com`) && PathPrefix(`/foo`)"
service = "service4"
[http.routers.router4path.tls]
options = "mytls"
[http.routers.router5]
rule = "Host(`site5.www.snitest.com`)"
service = "service5"
[http.routers.router5.tls]
options = "mytls"
[http.routers.router5path]
rule = "Host(`site5.www.snitest.com`) && PathPrefix(`/bar`)"
service = "service5"
[http.routers.router5path.tls]
options = "mytls"
[http.routers.router6]
rule = "Host(`site6.www.snitest.com.`)"
service = "service6"
[http.routers.router6.tls]
options = "mytls"
[http.services.service1]
[[http.services.service1.loadBalancer.servers]]
url = "http://127.0.0.1:9010"
@@ -45,10 +75,22 @@
[[http.services.service3.loadBalancer.servers]]
url = "http://127.0.0.1:9030"
[http.services.service4]
[[http.services.service4.loadBalancer.servers]]
url = "http://127.0.0.1:9040"
[http.services.service5]
[[http.services.service5.loadBalancer.servers]]
url = "http://127.0.0.1:9050"
[http.services.service6]
[[http.services.service6.loadBalancer.servers]]
url = "http://127.0.0.1:9060"
[[tls.certificates]]
certFile = "fixtures/https/wildcard.www.snitest.com.cert"
keyFile = "fixtures/https/wildcard.www.snitest.com.key"
[tls.options]
[tls.options.mytls]
maxVersion = "VersionTLS12"
maxVersion = "VersionTLS13"
@@ -0,0 +1,53 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
[entryPoints]
[entryPoints.websecure]
address = ":4443"
[entryPoints.websecure.http.tls]
[entryPoints.websecure-options]
address = ":4444"
[entryPoints.websecure-options.http.tls]
options = "foo"
[api]
insecure = true
[providers.file]
filename = "{{ .SelfFilename }}"
## dynamic configuration ##
[http.routers]
[http.routers.router1]
entryPoints = ["websecure"]
service = "service1"
rule = "Host(`snitest.com`)"
[http.routers.router2]
entryPoints = ["websecure-options"]
service = "service1"
rule = "Host(`snitest.org`)"
[http.services]
[http.services.service1]
[http.services.service1.loadBalancer]
[[http.services.service1.loadBalancer.servers]]
url = "http://127.0.0.1:9010"
[[tls.certificates]]
certFile = "fixtures/https/snitest.com.cert"
keyFile = "fixtures/https/snitest.com.key"
[[tls.certificates]]
certFile = "fixtures/https/snitest.org.cert"
keyFile = "fixtures/https/snitest.org.key"
[tls.options]
[tls.options.foo]
maxVersion = "VersionTLS12"
@@ -0,0 +1,101 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
[entryPoints.websecure]
address = ":4443"
[entryPoints.websecure2]
address = ":4444"
[api]
insecure = true
[providers.file]
filename = "{{ .SelfFilename }}"
## dynamic configuration ##
# --- Same host, same options, same entryPoint: no conflict, the options are applied. ---
[http.routers.same-1]
rule = "Host(`same.www.snitest.com`)"
entryPoints = ["websecure"]
service = "service1"
[http.routers.same-1.tls]
options = "tls12"
[http.routers.same-2]
rule = "Host(`same.www.snitest.com`) && PathPrefix(`/same`)"
entryPoints = ["websecure"]
service = "service1"
[http.routers.same-2.tls]
options = "tls12"
# --- Same host, different options, same entryPoint: conflict, fallback to default options. ---
[http.routers.conflict-1]
rule = "Host(`conflict.www.snitest.com`)"
entryPoints = ["websecure"]
service = "service1"
[http.routers.conflict-1.tls]
options = "tls12"
[http.routers.conflict-2]
rule = "Host(`conflict.www.snitest.com`) && PathPrefix(`/conflict`)"
entryPoints = ["websecure"]
service = "service1"
[http.routers.conflict-2.tls]
options = "tls13"
# --- Same host, different options, different entryPoints: no conflict, each entryPoint keeps its own options. ---
[http.routers.cross-ep1]
rule = "Host(`cross.www.snitest.com`)"
entryPoints = ["websecure"]
service = "service1"
[http.routers.cross-ep1.tls]
options = "tls12"
[http.routers.cross-ep2]
rule = "Host(`cross.www.snitest.com`)"
entryPoints = ["websecure2"]
service = "service1"
[http.routers.cross-ep2.tls]
options = "tls13"
# --- Domain fronting (Host header != SNI): same options follow the header, different options are rejected. ---
[http.routers.df-a]
rule = "Host(`df-a.www.snitest.com`)"
entryPoints = ["websecure"]
service = "service1"
[http.routers.df-a.tls]
options = "tls12"
[http.routers.df-b]
rule = "Host(`df-b.www.snitest.com`)"
entryPoints = ["websecure"]
service = "service1"
[http.routers.df-b.tls]
options = "tls12"
[http.routers.df-c]
rule = "Host(`df-c.www.snitest.com`)"
entryPoints = ["websecure"]
service = "service1"
[http.routers.df-c.tls]
options = "tls13"
[http.services.service1]
[[http.services.service1.loadBalancer.servers]]
url = "http://127.0.0.1:9010"
[[tls.certificates]]
certFile = "fixtures/https/wildcard.www.snitest.com.cert"
keyFile = "fixtures/https/wildcard.www.snitest.com.key"
[tls.options]
[tls.options.tls12]
maxVersion = "VersionTLS12"
[tls.options.tls13]
minVersion = "VersionTLS13"
+35 -3
View File
@@ -2494,9 +2494,25 @@ spec:
description: MinVersion defines the minimum TLS version to use when
contacting backend servers.
type: string
peerCertSANs:
description: PeerCertSANs defines the peer cert Subject Alternative
Names used to match against SAN during the peer certificate verification.
items:
description: SAN represents a Subject Alternative Name.
properties:
type:
description: SANType is the type of the Subject Alternative
Name.
type: string
value:
type: string
type: object
type: array
peerCertURI:
description: PeerCertURI defines the peer cert URI used to match against
SAN URI during the peer certificate verification.
description: |-
PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
type: string
rootCAs:
description: RootCAs defines a list of CA certificate Secrets or ConfigMaps
@@ -2648,10 +2664,26 @@ spec:
insecureSkipVerify:
description: InsecureSkipVerify disables TLS certificate verification.
type: boolean
peerCertSANs:
description: PeerCertSANs defines the peer cert Subject Alternative
Names used to match against SAN during the peer certificate
verification.
items:
description: SAN represents a Subject Alternative Name.
properties:
type:
description: SANType is the type of the Subject Alternative
Name.
type: string
value:
type: string
type: object
type: array
peerCertURI:
description: |-
MaxIdleConnsPerHost controls the maximum idle (keep-alive) to keep per-host.
PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
type: string
rootCAs:
description: RootCAs defines a list of CA certificate Secrets
@@ -30,10 +30,11 @@ profiles:
result: success
statistics:
Failed: 0
Passed: 20
Passed: 21
Skipped: 0
supportedFeatures:
- BackendTLSPolicy
- BackendTLSPolicySANValidation
- GatewayPort8080
- HTTPRouteBackendProtocolH2C
- HTTPRouteBackendProtocolWebSocket
@@ -48,7 +49,6 @@ profiles:
- HTTPRouteResponseHeaderModification
- HTTPRouteSchemeRedirect
unsupportedFeatures:
- BackendTLSPolicySANValidation
- GatewayAddressEmpty
- GatewayBackendClientCertificate
- GatewayFrontendClientCertificateValidation
+246 -24
View File
@@ -13,6 +13,7 @@ import (
"time"
"github.com/BurntSushi/toml"
"github.com/quic-go/quic-go/http3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
@@ -149,7 +150,69 @@ func (s *HTTPSSuite) TestWithSNIConfigRoute() {
require.NoError(s.T(), err)
}
// TestWithTLSOptions verifies that traefik routes the requests with the associated tls options.
// TestWithEntryPointTLSConfig verifies that a router relying on the entry point
// TLS configuration (without an explicit router TLS section) is served over HTTPS,
// including when the entry point references user-defined TLS options.
// Regression test for https://github.com/traefik/traefik/issues/13289.
func (s *HTTPSSuite) TestWithEntryPointTLSConfig() {
file := s.adaptFile("fixtures/https/https_entrypoint_tls.toml", struct{}{})
s.traefikCmd(withConfigFile(file))
// wait for Traefik
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`snitest.com`)"))
require.NoError(s.T(), err)
backend := startTestServer("9010", http.StatusNoContent, "")
defer backend.Close()
err = try.GetRequest(backend.URL, 1*time.Second, try.StatusCodeIs(http.StatusNoContent))
require.NoError(s.T(), err)
tr := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
ServerName: "snitest.com",
},
}
req, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:4443/", nil)
require.NoError(s.T(), err)
req.Host = tr.TLSClientConfig.ServerName
req.Header.Set("Host", tr.TLSClientConfig.ServerName)
req.Header.Set("Accept", "*/*")
err = try.RequestWithTransport(req, 30*time.Second, tr, try.HasCn(tr.TLSClientConfig.ServerName), try.StatusCodeIs(http.StatusNoContent))
require.NoError(s.T(), err)
// The websecure-options entry point references the user-defined "foo" TLS options (maxVersion VersionTLS12).
// A request with no router-level TLS must still have these options resolved and applied.
trOptions := &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
ServerName: "snitest.org",
},
}
req, err = http.NewRequest(http.MethodGet, "https://127.0.0.1:4444/", nil)
require.NoError(s.T(), err)
req.Host = trOptions.TLSClientConfig.ServerName
req.Header.Set("Host", trOptions.TLSClientConfig.ServerName)
req.Header.Set("Accept", "*/*")
err = try.RequestWithTransport(req, 30*time.Second, trOptions, try.HasCn(trOptions.TLSClientConfig.ServerName), try.StatusCodeIs(http.StatusNoContent))
require.NoError(s.T(), err)
// A TLS 1.3-only client must fail the handshake, proving the "foo" options
// (resolved from the entry point) are effectively enforced.
_, err = tls.Dial("tcp", "127.0.0.1:4444", &tls.Config{
InsecureSkipVerify: true,
ServerName: "snitest.org",
MinVersion: tls.VersionTLS13,
})
assert.Error(s.T(), err)
}
// TestWithTLSOptions verifies that traefik routes the requests with the associated tls options.
func (s *HTTPSSuite) TestWithTLSOptions() {
file := s.adaptFile("fixtures/https/https_tls_options.toml", struct{}{})
s.traefikCmd(withConfigFile(file))
@@ -352,7 +415,7 @@ func (s *HTTPSSuite) TestWithConflictingTLSOptions() {
assert.ErrorContains(s.T(), err, "tls: no supported versions satisfy MinVersion and MaxVersion")
// with unknown tls option
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains(fmt.Sprintf("found different TLS options for routers on the same host %v, so using the default TLS options instead", tr4.TLSClientConfig.ServerName)))
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("router's TLSOptions configuration is conflicting with other routers on the same entrypoint and host, default TLS options will be used instead"))
require.NoError(s.T(), err)
}
@@ -1083,19 +1146,20 @@ func (s *HTTPSSuite) TestWithDomainFronting() {
defer backend2.Close()
backend3 := startTestServer("9030", http.StatusOK, "server3")
defer backend3.Close()
backend5 := startTestServer("9050", http.StatusOK, "server5")
defer backend5.Close()
file := s.adaptFile("fixtures/https/https_domain_fronting.toml", struct{}{})
s.traefikCmd(withConfigFile(file))
// wait for Traefik
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 500*time.Millisecond, try.BodyContains("Host(`site1.www.snitest.com`)"))
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1000*time.Millisecond, try.BodyContains("Host(`site1.www.snitest.com`)"))
require.NoError(s.T(), err)
testCases := []struct {
desc string
hostHeader string
serverName string
expectedError bool
expectedContent string
expectedStatusCode int
}{
@@ -1113,14 +1177,6 @@ func (s *HTTPSSuite) TestWithDomainFronting() {
expectedContent: "server3",
expectedStatusCode: http.StatusOK,
},
{
desc: "Spaces after the host header",
hostHeader: "site3.www.snitest.com ",
serverName: "site3.www.snitest.com",
expectedError: true,
expectedContent: "server3",
expectedStatusCode: http.StatusOK,
},
{
desc: "Spaces after the servername",
hostHeader: "site3.www.snitest.com",
@@ -1128,14 +1184,6 @@ func (s *HTTPSSuite) TestWithDomainFronting() {
expectedContent: "server3",
expectedStatusCode: http.StatusOK,
},
{
desc: "Spaces after the servername and host header",
hostHeader: "site3.www.snitest.com ",
serverName: "site3.www.snitest.com ",
expectedError: true,
expectedContent: "server3",
expectedStatusCode: http.StatusOK,
},
{
desc: "Domain Fronting with same tlsOptions should follow header",
hostHeader: "site1.www.snitest.com",
@@ -1171,6 +1219,34 @@ func (s *HTTPSSuite) TestWithDomainFronting() {
expectedContent: "server1",
expectedStatusCode: http.StatusOK,
},
{
desc: "Domain Fronting with ambiguous TLS options should produce a 421",
hostHeader: "site4.www.snitest.com",
serverName: "site3.www.snitest.com",
expectedContent: "",
expectedStatusCode: http.StatusMisdirectedRequest,
},
{
desc: "Domain Fronting with same non-default TLS options should not produce a 421",
hostHeader: "site5.www.snitest.com",
serverName: "site3.www.snitest.com",
expectedContent: "server5",
expectedStatusCode: http.StatusOK,
},
{
desc: "FQDN host header with empty SNI to non-default TLS options route should produce a 421",
hostHeader: "site3.www.snitest.com.",
serverName: "",
expectedContent: "",
expectedStatusCode: http.StatusMisdirectedRequest,
},
{
desc: "Non-FQDN host header with empty SNI matching FQDN route rule should produce a 421",
hostHeader: "site6.www.snitest.com",
serverName: "",
expectedContent: "",
expectedStatusCode: http.StatusMisdirectedRequest,
},
}
for _, test := range testCases {
@@ -1179,11 +1255,157 @@ func (s *HTTPSSuite) TestWithDomainFronting() {
req.Host = test.hostHeader
err = try.RequestWithTransport(req, 500*time.Millisecond, &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true, ServerName: test.serverName}}, try.StatusCodeIs(test.expectedStatusCode), try.BodyContains(test.expectedContent))
if test.expectedError {
assert.Error(s.T(), err)
} else {
require.NoError(s.T(), err)
assert.NoError(s.T(), err, "test %s failed with: %v", test.desc, err)
err = try.RequestWithTransport(req, 500*time.Millisecond, &http3.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true, ServerName: test.serverName}}, try.StatusCodeIs(test.expectedStatusCode), try.BodyContains(test.expectedContent))
assert.NoError(s.T(), err, "test %s failed with: %v", test.desc, err)
}
}
// TestWithTLSOptionsConflict checks how TLS options are resolved when several routers
// target the same host (SNI), across the different conflict situations:
// - same options on the same entryPoint: no conflict, the options are applied;
// - different options on the same entryPoint: conflict, fallback to the default options;
// - different options on different entryPoints: no conflict, each entryPoint keeps its
// own options (they are selected independently on each listener);
// - domain fronting (Host header != SNI): allowed when both resolve to the same options,
// rejected with a 421 otherwise.
//
// The effective TLS options are probed through the negotiated TLS version: the "tls12"
// options cap the version to TLS 1.2, while the "tls13" options require at least TLS 1.3.
func (s *HTTPSSuite) TestWithTLSOptionsConflict() {
backend := startTestServer("9010", http.StatusOK, "server1")
defer backend.Close()
file := s.adaptFile("fixtures/https/https_tls_options_conflict.toml", struct{}{})
s.traefikCmd(withConfigFile(file))
// wait for Traefik
err := try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.BodyContains("Host(`cross.www.snitest.com`)"))
require.NoError(s.T(), err)
testCases := []struct {
desc string
addr string // entryPoint address to reach
hostHeader string
serverName string // SNI
minVersion uint16 // 0 means the crypto/tls library default
maxVersion uint16 // 0 means the crypto/tls library default
// expectHandshakeError is set when the TLS handshake itself is expected to fail
// (i.e. the probed options reject the client's TLS version). Otherwise
// expectedStatusCode is asserted on the HTTP response.
expectHandshakeError bool
expectedStatusCode int
}{
// Same host, same options, same entryPoint: no conflict, the "tls12" options are applied.
{
desc: "same options / same entryPoint: TLS 1.2 client is accepted",
addr: "127.0.0.1:4443",
hostHeader: "same.www.snitest.com",
serverName: "same.www.snitest.com",
maxVersion: tls.VersionTLS12,
expectedStatusCode: http.StatusOK,
},
{
desc: "same options / same entryPoint: TLS 1.3 client is rejected (maxVersion TLS1.2 enforced)",
addr: "127.0.0.1:4443",
hostHeader: "same.www.snitest.com",
serverName: "same.www.snitest.com",
minVersion: tls.VersionTLS13,
expectHandshakeError: true,
},
// Same host, different options, same entryPoint: conflict, both routers fall back to the default options.
{
desc: "conflicting options / same entryPoint: TLS 1.3 client is accepted (default options used)",
addr: "127.0.0.1:4443",
hostHeader: "conflict.www.snitest.com",
serverName: "conflict.www.snitest.com",
minVersion: tls.VersionTLS13,
expectedStatusCode: http.StatusOK,
},
{
desc: "conflicting options / same entryPoint: TLS 1.2 client is accepted (default options used)",
addr: "127.0.0.1:4443",
hostHeader: "conflict.www.snitest.com",
serverName: "conflict.www.snitest.com",
maxVersion: tls.VersionTLS12,
expectedStatusCode: http.StatusOK,
},
// Same host, different options, different entryPoints: no conflict, each entryPoint keeps its own options.
{
desc: "different entryPoints: websecure keeps tls12, TLS 1.2 client is accepted",
addr: "127.0.0.1:4443",
hostHeader: "cross.www.snitest.com",
serverName: "cross.www.snitest.com",
maxVersion: tls.VersionTLS12,
expectedStatusCode: http.StatusOK,
},
{
desc: "different entryPoints: websecure keeps tls12, TLS 1.3 client is rejected",
addr: "127.0.0.1:4443",
hostHeader: "cross.www.snitest.com",
serverName: "cross.www.snitest.com",
minVersion: tls.VersionTLS13,
expectHandshakeError: true,
},
{
desc: "different entryPoints: websecure2 keeps tls13, TLS 1.3 client is accepted",
addr: "127.0.0.1:4444",
hostHeader: "cross.www.snitest.com",
serverName: "cross.www.snitest.com",
minVersion: tls.VersionTLS13,
expectedStatusCode: http.StatusOK,
},
{
desc: "different entryPoints: websecure2 keeps tls13, TLS 1.2 client is rejected",
addr: "127.0.0.1:4444",
hostHeader: "cross.www.snitest.com",
serverName: "cross.www.snitest.com",
maxVersion: tls.VersionTLS12,
expectHandshakeError: true,
},
// Domain fronting (Host header != SNI) on the same entryPoint.
{
desc: "domain fronting / same options: request follows the Host header (200)",
addr: "127.0.0.1:4443",
hostHeader: "df-a.www.snitest.com",
serverName: "df-b.www.snitest.com",
maxVersion: tls.VersionTLS12,
expectedStatusCode: http.StatusOK,
},
{
desc: "domain fronting / different options: request is misdirected (421)",
addr: "127.0.0.1:4443",
hostHeader: "df-a.www.snitest.com",
serverName: "df-c.www.snitest.com",
minVersion: tls.VersionTLS13,
expectedStatusCode: http.StatusMisdirectedRequest,
},
}
for _, test := range testCases {
tlsConfig := &tls.Config{
InsecureSkipVerify: true,
ServerName: test.serverName,
MinVersion: test.minVersion,
MaxVersion: test.maxVersion,
}
req, err := http.NewRequest(http.MethodGet, "https://"+test.addr+"/", nil)
require.NoError(s.T(), err)
req.Host = test.hostHeader
if test.expectHandshakeError {
_, err = (&http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}}).Do(req)
assert.ErrorContains(s.T(), err, "tls:", "test %q should fail the TLS handshake", test.desc)
continue
}
err = try.RequestWithTransport(req, 2*time.Second, &http.Transport{TLSClientConfig: tlsConfig}, try.StatusCodeIs(test.expectedStatusCode))
assert.NoError(s.T(), err, "test %q failed with: %v", test.desc, err)
}
}
+3 -3
View File
@@ -949,7 +949,7 @@ func (s *SimpleSuite) TestRouterConfigErrors() {
s.traefikCmd(withConfigFile(file))
// All errors
err := try.GetRequest("http://127.0.0.1:8080/api/http/routers", 1000*time.Millisecond, try.BodyContains(`["middleware \"unknown@file\" does not exist","found different TLS options for routers on the same host snitest.net, so using the default TLS options instead"]`))
err := try.GetRequest("http://127.0.0.1:8080/api/http/routers", 1000*time.Millisecond, try.BodyContains(`["middleware \"unknown@file\" does not exist","router's TLSOptions configuration is conflicting with other routers on the same entrypoint and host, default TLS options will be used instead"]`))
require.NoError(s.T(), err)
// router3 has an error because it uses an unknown entrypoint
@@ -957,11 +957,11 @@ func (s *SimpleSuite) TestRouterConfigErrors() {
require.NoError(s.T(), err)
// router4 is enabled, but in warning state because its tls options conf was messed up
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router4@file", 1000*time.Millisecond, try.BodyContains(`"status":"warning"`))
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/websecure-conflicted-router4@file", 1000*time.Millisecond, try.BodyContains(`"status":"warning"`))
require.NoError(s.T(), err)
// router5 is disabled because its middleware conf is broken
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/router5@file", 1000*time.Millisecond, try.BodyContains())
err = try.GetRequest("http://127.0.0.1:8080/api/http/routers/websecure-conflicted-router5@file", 1000*time.Millisecond, try.BodyContains())
require.NoError(s.T(), err)
}
+3 -3
View File
@@ -76,7 +76,7 @@ func Request(req *http.Request, timeout time.Duration, conditions ...ResponseCon
// the condition on the response.
// ResponseCondition may be nil, in which case only the request against the URL must
// succeed.
func RequestWithTransport(req *http.Request, timeout time.Duration, transport *http.Transport, conditions ...ResponseCondition) error {
func RequestWithTransport(req *http.Request, timeout time.Duration, transport http.RoundTripper, conditions ...ResponseCondition) error {
resp, err := doTryRequest(req, timeout, transport, conditions...)
if resp != nil && resp.Body != nil {
@@ -140,12 +140,12 @@ func doTryRequest(request *http.Request, timeout time.Duration, transport http.R
func doRequest(action timedAction, timeout time.Duration, request *http.Request, transport http.RoundTripper, conditions ...ResponseCondition) (*http.Response, error) {
var resp *http.Response
return resp, action(timeout, func() error {
var err error
client := http.DefaultClient
var client http.Client
if transport != nil {
client.Transport = transport
}
var err error
resp, err = client.Do(request)
if err != nil {
return err
-109
View File
@@ -1,131 +1,22 @@
package main
import (
"bytes"
"fmt"
"io"
"os"
"reflect"
"sort"
"strings"
"github.com/BurntSushi/toml"
"github.com/rs/zerolog/log"
"github.com/traefik/paerser/flag"
"github.com/traefik/paerser/generator"
"github.com/traefik/traefik/v3/cmd"
"github.com/traefik/traefik/v3/pkg/collector/hydratation"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
"gopkg.in/yaml.v3"
)
var commentGenerated = `## CODE GENERATED AUTOMATICALLY
## THIS FILE MUST NOT BE EDITED BY HAND
`
func main() {
genRoutingConfDoc()
genInstallConfDoc()
genAnchors()
}
// Generate the Routing Configuration YAML and TOML files.
func genRoutingConfDoc() {
logger := log.With().Logger()
dynConf := &dynamic.Configuration{}
err := hydratation.Hydrate(dynConf)
if err != nil {
logger.Fatal().Err(err).Send()
}
dynConf.HTTP.Models = map[string]*dynamic.Model{}
clean(dynConf.HTTP.Middlewares)
clean(dynConf.TCP.Middlewares)
clean(dynConf.HTTP.Services)
clean(dynConf.TCP.Services)
clean(dynConf.UDP.Services)
err = tomlWrite("./docs/content/reference/routing-configuration/other-providers/file.toml", dynConf)
if err != nil {
logger.Fatal().Err(err).Send()
}
err = yamlWrite("./docs/content/reference/routing-configuration/other-providers/file.yaml", dynConf)
if err != nil {
logger.Fatal().Err(err).Send()
}
}
func yamlWrite(outputFile string, element any) error {
file, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666)
if err != nil {
return err
}
defer file.Close()
// Write the comment at the beginning of the file.
if _, err := file.WriteString(commentGenerated); err != nil {
return err
}
buf := new(bytes.Buffer)
encoder := yaml.NewEncoder(buf)
encoder.SetIndent(2)
err = encoder.Encode(element)
if err != nil {
return err
}
_, err = file.Write(buf.Bytes())
return err
}
func tomlWrite(outputFile string, element any) error {
file, err := os.OpenFile(outputFile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o666)
if err != nil {
return err
}
defer file.Close()
// Write the comment at the beginning of the file.
if _, err := file.WriteString(commentGenerated); err != nil {
return err
}
return toml.NewEncoder(file).Encode(element)
}
func clean(element any) {
valSvcs := reflect.ValueOf(element)
key := valSvcs.MapKeys()[0]
valueSvcRoot := valSvcs.MapIndex(key).Elem()
var svcFieldNames []string
for i := range valueSvcRoot.NumField() {
field := valueSvcRoot.Type().Field(i)
// do not create empty node for hidden config.
if field.Tag.Get("file") == "-" && field.Tag.Get("kv") == "-" && field.Tag.Get("label") == "-" {
continue
}
svcFieldNames = append(svcFieldNames, field.Name)
}
sort.Strings(svcFieldNames)
for i, fieldName := range svcFieldNames {
v := reflect.New(valueSvcRoot.Type())
v.Elem().FieldByName(fieldName).Set(valueSvcRoot.FieldByName(fieldName))
valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s%.2d", valueSvcRoot.Type().Name(), i+1)), v)
}
valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s0", valueSvcRoot.Type().Name())), reflect.Value{})
valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s1", valueSvcRoot.Type().Name())), reflect.Value{})
}
// Generate the Install Configuration in a table.
func genInstallConfDoc() {
outputFile := "./docs/content/reference/install-configuration/configuration-options.md"
+8 -5
View File
@@ -149,9 +149,10 @@ func (r *RouterDeniedEncodedPathCharacters) Map() map[string]struct{} {
// RouterTLSConfig holds the TLS configuration for a router.
type RouterTLSConfig struct {
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty" export:"true"`
CertResolver string `json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty" export:"true"`
Domains []types.Domain `json:"domains,omitempty" toml:"domains,omitempty" yaml:"domains,omitempty" export:"true"`
Options string `json:"options,omitempty" toml:"options,omitempty" yaml:"options,omitempty" export:"true"`
ResolvedOptions string `json:"-" toml:"-" yaml:"-" label:"-" file:"-" kv:"-" export:"false"`
CertResolver string `json:"certResolver,omitempty" toml:"certResolver,omitempty" yaml:"certResolver,omitempty" export:"true"`
Domains []types.Domain `json:"domains,omitempty" toml:"domains,omitempty" yaml:"domains,omitempty" export:"true"`
}
// +k8s:deepcopy-gen=true
@@ -536,8 +537,10 @@ type ServersTransport struct {
MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used. If negative, disables connection reuse." json:"maxIdleConnsPerHost,omitempty" toml:"maxIdleConnsPerHost,omitempty" yaml:"maxIdleConnsPerHost,omitempty" export:"true"`
ForwardingTimeouts *ForwardingTimeouts `description:"Defines the timeouts for requests forwarded to the backend servers." json:"forwardingTimeouts,omitempty" toml:"forwardingTimeouts,omitempty" yaml:"forwardingTimeouts,omitempty" export:"true"`
DisableHTTP2 bool `description:"Disables HTTP/2 for connections with backend servers." json:"disableHTTP2,omitempty" toml:"disableHTTP2,omitempty" yaml:"disableHTTP2,omitempty" export:"true"`
PeerCertURI string `description:"Defines the URI used to match against SAN URI during the peer certificate verification." json:"peerCertURI,omitempty" toml:"peerCertURI,omitempty" yaml:"peerCertURI,omitempty" export:"true"`
Spiffe *Spiffe `description:"Defines the SPIFFE configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
// Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
PeerCertURI string `description:"Defines the URI used to match against SAN URI during the peer certificate verification." json:"peerCertURI,omitempty" toml:"peerCertURI,omitempty" yaml:"peerCertURI,omitempty"`
PeerCertSANs []traefiktls.SAN `description:"Defines the SANs (Subject Alternative Names) used to match against SANs during the peer certificate verification." json:"peerCertSANs,omitempty" toml:"peerCertSANs,omitempty" yaml:"peerCertSANs,omitempty"`
Spiffe *Spiffe `description:"Defines the SPIFFE configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// +k8s:deepcopy-gen=true
+4 -2
View File
@@ -207,8 +207,10 @@ type TLSClientConfig struct {
InsecureSkipVerify bool `description:"Disables SSL certificate verification." json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
RootCAs []types.FileOrContent `description:"Defines a list of CA certificates used to validate server certificates." json:"rootCAs,omitempty" toml:"rootCAs,omitempty" yaml:"rootCAs,omitempty"`
Certificates traefiktls.Certificates `description:"Defines a list of client certificates for mTLS." json:"certificates,omitempty" toml:"certificates,omitempty" yaml:"certificates,omitempty" export:"true"`
PeerCertURI string `description:"Defines the URI used to match against SAN URI during the peer certificate verification." json:"peerCertURI,omitempty" toml:"peerCertURI,omitempty" yaml:"peerCertURI,omitempty" export:"true"`
Spiffe *Spiffe `description:"Defines the SPIFFE TLS configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
// Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
PeerCertURI string `description:"Defines the URI used to match against SAN URI during the peer certificate verification." json:"peerCertURI,omitempty" toml:"peerCertURI,omitempty" yaml:"peerCertURI,omitempty"`
PeerCertSANs []traefiktls.SAN `description:"Defines the SANs (Subject Alternative Names) used to match against SANs during the peer certificate verification." json:"peerCertSANs,omitempty" toml:"peerCertSANs,omitempty" yaml:"peerCertSANs,omitempty"`
Spiffe *Spiffe `description:"Defines the SPIFFE TLS configuration." json:"spiffe,omitempty" toml:"spiffe,omitempty" yaml:"spiffe,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// +k8s:deepcopy-gen=true
@@ -1855,6 +1855,11 @@ func (in *ServersTransport) DeepCopyInto(out *ServersTransport) {
*out = new(ForwardingTimeouts)
**out = **in
}
if in.PeerCertSANs != nil {
in, out := &in.PeerCertSANs, &out.PeerCertSANs
*out = make([]tls.SAN, len(*in))
copy(*out, *in)
}
if in.Spiffe != nil {
in, out := &in.Spiffe, &out.Spiffe
*out = new(Spiffe)
@@ -2522,6 +2527,11 @@ func (in *TLSClientConfig) DeepCopyInto(out *TLSClientConfig) {
*out = make(tls.Certificates, len(*in))
copy(*out, *in)
}
if in.PeerCertSANs != nil {
in, out := &in.PeerCertSANs, &out.PeerCertSANs
*out = make([]tls.SAN, len(*in))
copy(*out, *in)
}
if in.Spiffe != nil {
in, out := &in.Spiffe, &out.Spiffe
*out = new(Spiffe)
+5 -4
View File
@@ -150,10 +150,11 @@ type TLSConfig struct {
// ForwardedHeaders Trust client forwarding headers.
type ForwardedHeaders struct {
Insecure bool `description:"Trust all forwarded headers." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"`
TrustedIPs []string `description:"Trust only forwarded headers from selected IPs." json:"trustedIPs,omitempty" toml:"trustedIPs,omitempty" yaml:"trustedIPs,omitempty"`
Connection []string `description:"List of Connection headers that are allowed to pass through the middleware chain before being removed." json:"connection,omitempty" toml:"connection,omitempty" yaml:"connection,omitempty"`
NotAppendXForwardedFor bool `description:"Disable appending RemoteAddr to X-Forwarded-For header. Defaults to false (appending is enabled)." json:"notAppendXForwardedFor,omitempty" toml:"notAppendXForwardedFor,omitempty" yaml:"notAppendXForwardedFor,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
Insecure bool `description:"Trust all forwarded headers." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"`
TrustedIPs []string `description:"Trust only forwarded headers from selected IPs." json:"trustedIPs,omitempty" toml:"trustedIPs,omitempty" yaml:"trustedIPs,omitempty"`
Connection []string `description:"List of Connection headers that are allowed to pass through the middleware chain before being removed." json:"connection,omitempty" toml:"connection,omitempty" yaml:"connection,omitempty"`
NotAppendXForwardedFor bool `description:"Disable appending RemoteAddr to X-Forwarded-For header. Defaults to false (appending is enabled)." json:"notAppendXForwardedFor,omitempty" toml:"notAppendXForwardedFor,omitempty" yaml:"notAppendXForwardedFor,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
AddXForwardedSchemeHeaders bool `description:"Add the X-Forwarded-Scheme and X-Scheme headers." json:"addXForwardedSchemeHeaders,omitempty" toml:"addXForwardedSchemeHeaders,omitempty" yaml:"addXForwardedSchemeHeaders,omitempty" export:"true"`
}
// ProxyProtocol contains Proxy-Protocol configuration.
+8 -2
View File
@@ -230,12 +230,18 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request, next http
core[RequestAddr] = req.Host
core[RequestHost], core[RequestPort] = silentSplitHostPort(req.Host)
}
queryParameters := ""
if h.config.Fields.KeepQueryParameters() {
queryParameters = req.URL.RawQuery
}
// copy the URL without the scheme, hostname etc
urlCopy := &url.URL{
Path: req.URL.Path,
RawPath: req.URL.RawPath,
RawQuery: req.URL.RawQuery,
ForceQuery: req.URL.ForceQuery,
RawQuery: queryParameters,
ForceQuery: req.URL.ForceQuery && h.config.Fields.KeepQueryParameters(),
Fragment: req.URL.Fragment,
}
urlCopyString := urlCopy.String()
@@ -3,6 +3,7 @@ package accesslog
import (
"bytes"
"fmt"
"strings"
"time"
"github.com/sirupsen/logrus"
@@ -108,7 +109,7 @@ func toLogEntry(s, defaultValue string, quote bool) string {
}
if quote {
return `"` + s + `"`
return `"` + strings.ReplaceAll(s, `"`, `\"`) + `"`
}
return s
}
@@ -79,6 +79,27 @@ func TestCommonLogFormatter_Format(t *testing.T) {
ServiceURL: "http://10.0.0.2/toto",
},
expectedLog: `10.0.0.1 - Client [10/Nov/2009:14:00:00 -0900] "GET /foo http" 123 132 "referer" "agent" - "foo" "http://10.0.0.2/toto" 123000ms
`,
},
{
name: "user-agent with double quote is escaped",
data: map[string]any{
StartUTC: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
Duration: 1 * time.Millisecond,
ClientHost: "10.0.0.1",
ClientUsername: "-",
RequestMethod: http.MethodGet,
RequestPath: "/",
RequestProtocol: "HTTP/1.1",
DownstreamStatus: 200,
DownstreamContentSize: 0,
RequestRefererHeader: "-",
RequestUserAgentHeader: `foo " bar`,
RequestCount: 1,
RouterName: "test@file",
ServiceURL: "http://127.0.0.1:8080",
},
expectedLog: `10.0.0.1 - - [10/Nov/2009:23:00:00 +0000] "GET / HTTP/1.1" 200 0 "-" "foo \" bar" 1 "test@file" "http://127.0.0.1:8080" 1ms
`,
},
}
@@ -221,6 +242,16 @@ func Test_toLog(t *testing.T) {
quoted: true,
expectedLog: `"foo"`,
},
{
desc: "Should escape double quotes in quoted string",
fields: logrus.Fields{
"Powpow": `foo " bar`,
},
fieldName: "Powpow",
defaultValue: defaultValue,
quoted: true,
expectedLog: `"foo \" bar"`,
},
{
desc: "Should return defaultValue if fieldName does not exist",
fields: logrus.Fields{
+158 -32
View File
@@ -39,23 +39,25 @@ import (
const delta float64 = 1e-10
var (
logFileNameSuffix = "/traefik/logger/test.log"
testContent = "Hello, World"
testServiceName = "http://127.0.0.1/testService"
testRouterName = "testRouter"
testStatus = 123
testContentSize int64 = 12
testHostname = "TestHost"
testUsername = "TestUser"
testPath = "testpath"
testPort = 8181
testProto = "HTTP/0.0"
testScheme = "http"
testMethod = http.MethodPost
testReferer = "testReferer"
testUserAgent = "testUserAgent"
testRetryAttempts = 2
testStart = time.Now()
logFileNameSuffix = "/traefik/logger/test.log"
testContent = "Hello, World"
testServiceName = "http://127.0.0.1/testService"
testRouterName = "testRouter"
testStatus = 123
testContentSize int64 = 12
testHostname = "TestHost"
testUsername = "TestUser"
testPath = "testpath"
testQueryParams = "param1=test1&param2=test2"
testPathWithQueryParams = testPath + "?" + testQueryParams
testPort = 8181
testProto = "HTTP/0.0"
testScheme = "http"
testMethod = http.MethodPost
testReferer = "testReferer"
testUserAgent = "testUserAgent"
testRetryAttempts = 2
testStart = time.Now()
)
func TestOTelAccessLogWithBodyAndDualOutput(t *testing.T) {
@@ -458,7 +460,7 @@ func TestCommonLogger(t *testing.T) {
logData, err := os.ReadFile(logFilePath)
require.NoError(t, err)
expectedLog := ` TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent" 1 "testRouter" "http://127.0.0.1/testService" 1ms`
expectedLog := ` TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath?param1=test1&param2=test2 HTTP/0.0" 123 12 "testReferer" "testUserAgent" 1 "testRouter" "http://127.0.0.1/testService" 1ms`
assertValidCommonLogData(t, expectedLog, logData)
}
@@ -473,6 +475,23 @@ func TestCommonLoggerWithBufferingSize(t *testing.T) {
logData, err := os.ReadFile(logFilePath)
require.NoError(t, err)
expectedLog := ` TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath?param1=test1&param2=test2 HTTP/0.0" 123 12 "testReferer" "testUserAgent" 1 "testRouter" "http://127.0.0.1/testService" 1ms`
assertValidCommonLogData(t, expectedLog, logData)
}
func TestCommonLoggerDropQueryParameters(t *testing.T) {
logFilePath := filepath.Join(t.TempDir(), logFileNameSuffix)
fieldConfig := &otypes.AccessLogFields{
QueryParameters: &otypes.FieldQueryParameters{
DefaultMode: "drop",
},
}
config := &otypes.AccessLog{FilePath: logFilePath, Format: CommonFormat, Fields: fieldConfig}
doLogging(t, config, false, false)
logData, err := os.ReadFile(logFilePath)
require.NoError(t, err)
expectedLog := ` TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent" 1 "testRouter" "http://127.0.0.1/testService" 1ms`
assertValidCommonLogData(t, expectedLog, logData)
}
@@ -485,7 +504,7 @@ func TestLoggerGenericCLF(t *testing.T) {
logData, err := os.ReadFile(logFilePath)
require.NoError(t, err)
expectedLog := ` TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent"`
expectedLog := ` TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath?param1=test1&param2=test2 HTTP/0.0" 123 12 "testReferer" "testUserAgent"`
assertValidGenericCLFLogData(t, expectedLog, logData)
}
@@ -500,6 +519,23 @@ func TestLoggerGenericCLFWithBufferingSize(t *testing.T) {
logData, err := os.ReadFile(logFilePath)
require.NoError(t, err)
expectedLog := ` TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath?param1=test1&param2=test2 HTTP/0.0" 123 12 "testReferer" "testUserAgent"`
assertValidGenericCLFLogData(t, expectedLog, logData)
}
func TestLoggerGenericCLFDropQueryParameters(t *testing.T) {
logFilePath := filepath.Join(t.TempDir(), logFileNameSuffix)
fieldConfig := &otypes.AccessLogFields{
QueryParameters: &otypes.FieldQueryParameters{
DefaultMode: "drop",
},
}
config := &otypes.AccessLog{FilePath: logFilePath, Format: GenericCLFFormat, Fields: fieldConfig}
doLogging(t, config, false, false)
logData, err := os.ReadFile(logFilePath)
require.NoError(t, err)
expectedLog := ` TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent"`
assertValidGenericCLFLogData(t, expectedLog, logData)
}
@@ -556,7 +592,7 @@ func TestLoggerJSON(t *testing.T) {
RequestHost: assertString(testHostname),
RequestAddr: assertString(testHostname),
RequestMethod: assertString(testMethod),
RequestPath: assertString(testPath),
RequestPath: assertString(testPathWithQueryParams),
RequestProtocol: assertString(testProto),
RequestScheme: assertString(testScheme),
RequestPort: assertString("-"),
@@ -596,7 +632,7 @@ func TestLoggerJSON(t *testing.T) {
RequestHost: assertString(testHostname),
RequestAddr: assertString(testHostname),
RequestMethod: assertString(testMethod),
RequestPath: assertString(testPath),
RequestPath: assertString(testPathWithQueryParams),
RequestProtocol: assertString(testProto),
RequestScheme: assertString(testScheme),
RequestPort: assertString("-"),
@@ -640,7 +676,7 @@ func TestLoggerJSON(t *testing.T) {
RequestHost: assertString(testHostname),
RequestAddr: assertString(testHostname),
RequestMethod: assertString(testMethod),
RequestPath: assertString(testPath),
RequestPath: assertString(testPath + "?param1=test1&param2=test2"),
RequestProtocol: assertString(testProto),
RequestScheme: assertString(testScheme),
RequestPort: assertString("-"),
@@ -684,7 +720,7 @@ func TestLoggerJSON(t *testing.T) {
RequestHost: assertString(testHostname),
RequestAddr: assertString(testHostname),
RequestMethod: assertString(testMethod),
RequestPath: assertString(testPath),
RequestPath: assertString(testPathWithQueryParams),
RequestProtocol: assertString(testProto),
RequestScheme: assertString("https"),
RequestPort: assertString("-"),
@@ -824,6 +860,94 @@ func TestLoggerJSON(t *testing.T) {
RequestRefererHeader: assertString(testReferer),
},
},
{
desc: "default config, drop query parameters",
config: &otypes.AccessLog{
FilePath: "",
Format: JSONFormat,
Fields: &otypes.AccessLogFields{
QueryParameters: &otypes.FieldQueryParameters{
DefaultMode: "drop",
},
},
},
expected: map[string]func(t *testing.T, value any){
RequestContentSize: assertFloat64(0),
RequestHost: assertString(testHostname),
RequestAddr: assertString(testHostname),
RequestMethod: assertString(testMethod),
RequestPath: assertString(testPath),
RequestProtocol: assertString(testProto),
RequestScheme: assertString(testScheme),
RequestPort: assertString("-"),
DownstreamStatus: assertFloat64(float64(testStatus)),
DownstreamContentSize: assertFloat64(float64(len(testContent))),
OriginContentSize: assertFloat64(float64(len(testContent))),
OriginStatus: assertFloat64(float64(testStatus)),
RequestRefererHeader: assertString(testReferer),
RequestUserAgentHeader: assertString(testUserAgent),
RouterName: assertString(testRouterName),
ServiceURL: assertString(testServiceName),
ClientUsername: assertString(testUsername),
ClientHost: assertString(testHostname),
ClientPort: assertString(strconv.Itoa(testPort)),
ClientAddr: assertString(fmt.Sprintf("%s:%d", testHostname, testPort)),
"level": assertString("info"),
"msg": assertString(""),
"downstream_Content-Type": assertString("text/plain; charset=utf-8"),
RequestCount: assertFloat64NotZero(),
Duration: assertFloat64NotZero(),
Overhead: assertFloat64NotZero(),
RetryAttempts: assertFloat64(float64(testRetryAttempts)),
"time": assertNotEmpty(),
"StartLocal": assertNotEmpty(),
"StartUTC": assertNotEmpty(),
},
},
{
desc: "default config, keep query parameters",
config: &otypes.AccessLog{
FilePath: "",
Format: JSONFormat,
Fields: &otypes.AccessLogFields{
QueryParameters: &otypes.FieldQueryParameters{
DefaultMode: "keep",
},
},
},
expected: map[string]func(t *testing.T, value any){
RequestContentSize: assertFloat64(0),
RequestHost: assertString(testHostname),
RequestAddr: assertString(testHostname),
RequestMethod: assertString(testMethod),
RequestPath: assertString(testPathWithQueryParams),
RequestProtocol: assertString(testProto),
RequestScheme: assertString(testScheme),
RequestPort: assertString("-"),
DownstreamStatus: assertFloat64(float64(testStatus)),
DownstreamContentSize: assertFloat64(float64(len(testContent))),
OriginContentSize: assertFloat64(float64(len(testContent))),
OriginStatus: assertFloat64(float64(testStatus)),
RequestRefererHeader: assertString(testReferer),
RequestUserAgentHeader: assertString(testUserAgent),
RouterName: assertString(testRouterName),
ServiceURL: assertString(testServiceName),
ClientUsername: assertString(testUsername),
ClientHost: assertString(testHostname),
ClientPort: assertString(strconv.Itoa(testPort)),
ClientAddr: assertString(fmt.Sprintf("%s:%d", testHostname, testPort)),
"level": assertString("info"),
"msg": assertString(""),
"downstream_Content-Type": assertString("text/plain; charset=utf-8"),
RequestCount: assertFloat64NotZero(),
Duration: assertFloat64NotZero(),
Overhead: assertFloat64NotZero(),
RetryAttempts: assertFloat64(float64(testRetryAttempts)),
"time": assertNotEmpty(),
"StartLocal": assertNotEmpty(),
"StartUTC": assertNotEmpty(),
},
},
}
for _, test := range testCases {
@@ -925,7 +1049,7 @@ func TestNewLogHandlerOutputStdout(t *testing.T) {
FilePath: "",
Format: CommonFormat,
},
expectedLog: `TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
expectedLog: `TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath?param1=test1&param2=test2 HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
},
{
desc: "default config with empty filters",
@@ -934,7 +1058,7 @@ func TestNewLogHandlerOutputStdout(t *testing.T) {
Format: CommonFormat,
Filters: &otypes.AccessLogFilters{},
},
expectedLog: `TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
expectedLog: `TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath?param1=test1&param2=test2 HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
},
{
desc: "Status code filter not matching",
@@ -956,7 +1080,7 @@ func TestNewLogHandlerOutputStdout(t *testing.T) {
StatusCodes: []string{"123"},
},
},
expectedLog: `TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
expectedLog: `TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath?param1=test1&param2=test2 HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
},
{
desc: "Duration filter not matching",
@@ -978,7 +1102,7 @@ func TestNewLogHandlerOutputStdout(t *testing.T) {
MinDuration: ptypes.Duration(1 * time.Millisecond),
},
},
expectedLog: `TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
expectedLog: `TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath?param1=test1&param2=test2 HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
},
{
desc: "Retry attempts filter matching",
@@ -989,7 +1113,7 @@ func TestNewLogHandlerOutputStdout(t *testing.T) {
RetryAttempts: true,
},
},
expectedLog: `TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
expectedLog: `TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath?param1=test1&param2=test2 HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
},
{
desc: "Default mode keep",
@@ -1000,7 +1124,7 @@ func TestNewLogHandlerOutputStdout(t *testing.T) {
DefaultMode: "keep",
},
},
expectedLog: `TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
expectedLog: `TestHost - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath?param1=test1&param2=test2 HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
},
{
desc: "Default mode keep with override",
@@ -1014,7 +1138,7 @@ func TestNewLogHandlerOutputStdout(t *testing.T) {
},
},
},
expectedLog: `- - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
expectedLog: `- - TestUser [13/Apr/2016:07:14:19 -0700] "POST testpath?param1=test1&param2=test2 HTTP/0.0" 123 12 "testReferer" "testUserAgent" 23 "testRouter" "http://127.0.0.1/testService" 1ms`,
},
{
desc: "Default mode drop",
@@ -1220,8 +1344,10 @@ func doLoggingTLSOpt(t *testing.T, config *otypes.AccessLog, enableTLS, tracing,
Method: testMethod,
RemoteAddr: fmt.Sprintf("%s:%d", testHostname, testPort),
URL: &url.URL{
User: url.UserPassword(testUsername, ""),
Path: testPath,
User: url.UserPassword(testUsername, ""),
Path: testPath,
RawQuery: testQueryParams,
ForceQuery: true,
},
Body: io.NopCloser(bytes.NewReader([]byte("bar"))),
}
+4
View File
@@ -43,6 +43,10 @@ func NewBasic(ctx context.Context, next http.Handler, authConfig dynamic.BasicAu
return nil, err
}
if len(users) == 0 {
return nil, fmt.Errorf("no users found in %s", authConfig.UsersFile)
}
// To prevent timing attacks, we need to compute a hash even if the user is not found.
// We assume it to be safe only when the users hashes are all from the same algorithm,
// so we can pick the first one as a random hash to compute.
+9
View File
@@ -16,6 +16,15 @@ import (
"github.com/traefik/traefik/v3/pkg/testhelpers"
)
func TestNewBasicEmpty(t *testing.T) {
auth := dynamic.BasicAuth{
Users: []string{},
}
_, err := NewBasic(t.Context(), nil, auth, "authName")
require.Error(t, err)
}
func TestNewBasicNotFoundSecretIsSet(t *testing.T) {
auth := dynamic.BasicAuth{
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
@@ -18,12 +18,14 @@ const (
XForwardedFor = "X-Forwarded-For"
XForwardedHost = "X-Forwarded-Host"
XForwardedPort = "X-Forwarded-Port"
xForwardedScheme = "X-Forwarded-Scheme"
xForwardedServer = "X-Forwarded-Server"
XForwardedURI = "X-Forwarded-Uri"
XForwardedMethod = "X-Forwarded-Method"
XForwardedPrefix = "X-Forwarded-Prefix"
xForwardedTLSClientCert = "X-Forwarded-Tls-Client-Cert"
xForwardedTLSClientCertInfo = "X-Forwarded-Tls-Client-Cert-Info"
xScheme = "X-Scheme"
xRealIP = "X-Real-Ip"
connection = "Connection"
upgrade = "Upgrade"
@@ -34,6 +36,7 @@ const (
// that Go's HTTP server preserves (e.g. X_Forwarded_Proto).
var XHeadersSet = map[string]struct{}{
XForwardedProto: {},
xForwardedScheme: {},
XForwardedFor: {},
XForwardedHost: {},
XForwardedPort: {},
@@ -43,6 +46,7 @@ var XHeadersSet = map[string]struct{}{
XForwardedPrefix: {},
xForwardedTLSClientCert: {},
xForwardedTLSClientCertInfo: {},
xScheme: {},
xRealIP: {},
}
@@ -70,17 +74,18 @@ func isManagedXHeader(key string) bool {
// Unless insecure is set,
// it first removes all the existing values for those headers if the remote address is not one of the trusted ones.
type XForwarded struct {
insecure bool
trustedIPs []string
connectionHeaders []string
notAppendXForwardedFor bool
ipChecker *ip.Checker
next http.Handler
hostname string
insecure bool
trustedIPs []string
connectionHeaders []string
notAppendXForwardedFor bool
addXForwardedSchemeHeaders bool
ipChecker *ip.Checker
next http.Handler
hostname string
}
// NewXForwarded creates a new XForwarded.
func NewXForwarded(insecure bool, trustedIPs []string, connectionHeaders []string, notAppendXForwardedFor bool, next http.Handler) (*XForwarded, error) {
func NewXForwarded(insecure bool, trustedIPs []string, connectionHeaders []string, notAppendXForwardedFor bool, addXForwardedSchemeHeaders bool, next http.Handler) (*XForwarded, error) {
var ipChecker *ip.Checker
if len(trustedIPs) > 0 {
var err error
@@ -101,13 +106,14 @@ func NewXForwarded(insecure bool, trustedIPs []string, connectionHeaders []strin
}
return &XForwarded{
insecure: insecure,
trustedIPs: trustedIPs,
connectionHeaders: canonicalConnectionHeaders,
notAppendXForwardedFor: notAppendXForwardedFor,
ipChecker: ipChecker,
next: next,
hostname: hostname,
insecure: insecure,
trustedIPs: trustedIPs,
connectionHeaders: canonicalConnectionHeaders,
notAppendXForwardedFor: notAppendXForwardedFor,
addXForwardedSchemeHeaders: addXForwardedSchemeHeaders,
ipChecker: ipChecker,
next: next,
hostname: hostname,
}, nil
}
@@ -168,6 +174,12 @@ func (x *XForwarded) rewrite(outreq *http.Request) {
unsafeHeader(outreq.Header).Set(XForwardedPort, forwardedPort(outreq))
}
if x.addXForwardedSchemeHeaders {
scheme := unsafeHeader(outreq.Header).Get(XForwardedProto)
unsafeHeader(outreq.Header).Set(xForwardedScheme, scheme)
unsafeHeader(outreq.Header).Set(xScheme, scheme)
}
if xfHost := unsafeHeader(outreq.Header).Get(XForwardedHost); xfHost == "" && outreq.Host != "" {
unsafeHeader(outreq.Header).Set(XForwardedHost, outreq.Host)
}
@@ -17,12 +17,14 @@ func TestServeHTTP(t *testing.T) {
insecure bool
trustedIps []string
connectionHeaders []string
addSchemeHeaders bool
incomingHeaders map[string][]string
remoteAddr string
expectedHeaders map[string]string
tls bool
websocket bool
host string
absentHeaders []string
}{
{
desc: "all Empty",
@@ -230,6 +232,24 @@ func TestServeHTTP(t *testing.T) {
XForwardedProto: "https",
},
},
{
desc: "xForwardedScheme headers with tls",
tls: true,
addSchemeHeaders: true,
expectedHeaders: map[string]string{
XForwardedProto: "https",
xForwardedScheme: "https",
xScheme: "https",
},
},
{
desc: "xForwardedScheme headers disabled keeps legacy headers absent",
tls: true,
expectedHeaders: map[string]string{
XForwardedProto: "https",
},
absentHeaders: []string{xForwardedScheme, xScheme},
},
{
desc: "xForwardedProto with websocket",
tls: false,
@@ -238,6 +258,16 @@ func TestServeHTTP(t *testing.T) {
XForwardedProto: "ws",
},
},
{
desc: "xForwardedScheme headers with websocket",
websocket: true,
addSchemeHeaders: true,
expectedHeaders: map[string]string{
XForwardedProto: "ws",
xForwardedScheme: "ws",
xScheme: "ws",
},
},
{
desc: "xForwardedProto with websocket and tls",
tls: true,
@@ -246,6 +276,17 @@ func TestServeHTTP(t *testing.T) {
XForwardedProto: "wss",
},
},
{
desc: "xForwardedScheme headers with websocket and tls",
tls: true,
websocket: true,
addSchemeHeaders: true,
expectedHeaders: map[string]string{
XForwardedProto: "wss",
xForwardedScheme: "wss",
xScheme: "wss",
},
},
{
desc: "xForwardedProto with websocket and tls and already x-forwarded-proto with wss",
tls: true,
@@ -257,6 +298,21 @@ func TestServeHTTP(t *testing.T) {
XForwardedProto: "wss",
},
},
{
desc: "xForwardedScheme headers overwrite in insecure mode",
insecure: true,
addSchemeHeaders: true,
incomingHeaders: map[string][]string{
XForwardedProto: {"https"},
xForwardedScheme: {"external-https"},
xScheme: {"external-https"},
},
expectedHeaders: map[string]string{
XForwardedProto: "https",
xForwardedScheme: "https",
xScheme: "https",
},
},
{
desc: "xForwardedPort with explicit port",
host: "foo.com:8080",
@@ -643,7 +699,7 @@ func TestServeHTTP(t *testing.T) {
}
}
m, err := NewXForwarded(test.insecure, test.trustedIps, test.connectionHeaders, false,
m, err := NewXForwarded(test.insecure, test.trustedIps, test.connectionHeaders, false, test.addSchemeHeaders,
http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {}))
require.NoError(t, err)
@@ -656,6 +712,10 @@ func TestServeHTTP(t *testing.T) {
for k, v := range test.expectedHeaders {
assert.Equal(t, v, req.Header.Get(k))
}
for _, header := range test.absentHeaders {
assert.NotContains(t, req.Header, http.CanonicalHeaderKey(header))
}
})
}
}
@@ -782,7 +842,7 @@ func TestConnection(t *testing.T) {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
forwarded, err := NewXForwarded(true, nil, test.connectionHeaders, false, nil)
forwarded, err := NewXForwarded(true, nil, test.connectionHeaders, false, false, nil)
require.NoError(t, err)
req := httptest.NewRequest(http.MethodGet, "https://localhost", nil)
@@ -65,6 +65,10 @@ func (p *authTLSPassCertificateToUpstream) ServeHTTP(rw http.ResponseWriter, req
if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
logger.Debug().Msg("Tried to extract a certificate on a request without mutual TLS")
req.Header.Set(sslClientVerify, "NONE")
// Prevent client-supplied values from reaching the upstream on the no-mTLS path.
req.Header.Del(sslClientCert)
req.Header.Del(sslClientSubjectDN)
req.Header.Del(sslClientIssuerDN)
p.next.ServeHTTP(rw, req)
return
}
@@ -360,6 +360,26 @@ func TestAuthTLSPassCertificateToUpstream(t *testing.T) {
}
}
func TestAuthTLSNoMTLSClearsCertHeaders(t *testing.T) {
config := dynamic.AuthTLSPassCertificateToUpstream{
ClientAuthType: tls.VerifyClientCertIfGiven,
}
handler, err := NewAuthTLSPassCertificateToUpstream(t.Context(), next, config, "test")
require.NoError(t, err)
req := testhelpers.MustNewRequest(http.MethodGet, "http://example.com/foo", nil)
req.Header.Set(sslClientCert, "client-cert")
req.Header.Set(sslClientSubjectDN, "CN=client")
req.Header.Set(sslClientIssuerDN, "CN=client-CA")
handler.ServeHTTP(httptest.NewRecorder(), req)
assert.Equal(t, "NONE", req.Header.Get(sslClientVerify))
assert.Empty(t, req.Header.Get(sslClientCert))
assert.Empty(t, req.Header.Get(sslClientSubjectDN))
assert.Empty(t, req.Header.Get(sslClientIssuerDN))
}
func buildTLSWith(certContents []string) *cryptoTLS.ConnectionState {
var peerCertificates []*x509.Certificate
@@ -393,7 +393,7 @@ func createProxySetHeaderAction(d config.IDirective) (action, error) {
return nil, errors.New("proxy_set_header directive requires 2 parameters (header and value)")
}
key := params[0].String()
key := trimQuote(params[0].String())
val := trimQuote(params[1].String())
return func(rw http.ResponseWriter, req *http.Request, ctx *actionContext) (bool, error) {
@@ -399,6 +399,15 @@ proxy_set_header Accept-Encoding "";
"Accept-Encoding",
},
},
{
desc: "proxy_set_header with quoted header name",
configurationSnippet: `
proxy_set_header "X-Custom-Header" "my-value";
`,
expectedRequestHeaders: map[string]string{
"X-Custom-Header": "my-value",
},
},
{
desc: "set directive creates variable",
configurationSnippet: `
@@ -52,8 +52,6 @@ func TestSemConvServerMetrics(t *testing.T) {
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
var cfg otypes.OTLP
(&cfg).SetDefaults()
cfg.AddRoutersLabels = true
+1 -1
View File
@@ -49,7 +49,7 @@ func newRedisLimiter(ctx context.Context, rate rate.Limit, burst int64, maxDelay
}
if config.Redis.WriteTimeout != nil {
if *config.Redis.ReadTimeout > 0 {
if *config.Redis.WriteTimeout > 0 {
options.WriteTimeout = time.Duration(*config.Redis.WriteTimeout)
} else {
options.WriteTimeout = -1
+19 -82
View File
@@ -1,24 +1,26 @@
package snicheck
import (
"net"
"net/http"
"strings"
"github.com/rs/zerolog/log"
"github.com/traefik/traefik/v3/pkg/middlewares/requestdecorator"
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
"github.com/traefik/traefik/v3/pkg/tcp"
)
// SNICheck is an HTTP handler that checks whether the TLS configuration for the server name is the same as for the host header.
type SNICheck struct {
next http.Handler
tlsOptionsForHost map[string]string
next http.Handler
routerName string
tlsOptionsName string
}
// New creates a new SNICheck.
func New(tlsOptionsForHost map[string]string, next http.Handler) *SNICheck {
return &SNICheck{next: next, tlsOptionsForHost: tlsOptionsForHost}
func New(routerName, tlsOptionsName string, next http.Handler) *SNICheck {
return &SNICheck{
next: next,
routerName: routerName,
tlsOptionsName: tlsOptionsName,
}
}
func (s SNICheck) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
@@ -27,81 +29,16 @@ func (s SNICheck) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
return
}
host := getHost(req)
serverName := strings.TrimSpace(req.TLS.ServerName)
// Domain Fronting
if !strings.EqualFold(host, serverName) {
tlsOptionHeader := findTLSOptionName(s.tlsOptionsForHost, host, true)
tlsOptionSNI := findTLSOptionName(s.tlsOptionsForHost, serverName, false)
if tlsOptionHeader != tlsOptionSNI {
log.Debug().
Str("host", host).
Str("req.Host", req.Host).
Str("req.TLS.ServerName", req.TLS.ServerName).
Msgf("TLS options difference: SNI:%s, Header:%s", tlsOptionSNI, tlsOptionHeader)
http.Error(rw, http.StatusText(http.StatusMisdirectedRequest), http.StatusMisdirectedRequest)
return
}
tlsOptionsNameUsed := tcp.GetTLSOptionsName(req.Context())
if s.tlsOptionsName != tlsOptionsNameUsed {
log.Debug().
Str("routerName", s.routerName).
Str("req.Host", req.Host).
Str("req.TLS.ServerName", req.TLS.ServerName).
Msgf("TLS options difference: SNI:%s, Header:%s", tlsOptionsNameUsed, s.tlsOptionsName)
http.Error(rw, http.StatusText(http.StatusMisdirectedRequest), http.StatusMisdirectedRequest)
return
}
s.next.ServeHTTP(rw, req)
}
func getHost(req *http.Request) string {
h := requestdecorator.GetCNAMEFlatten(req.Context())
if h != "" {
return h
}
h = requestdecorator.GetCanonicalHost(req.Context())
if h != "" {
return h
}
host, _, err := net.SplitHostPort(req.Host)
if err != nil {
host = req.Host
}
return strings.TrimSpace(host)
}
func findTLSOptionName(tlsOptionsForHost map[string]string, host string, fqdn bool) string {
name := findTLSOptName(tlsOptionsForHost, host, fqdn)
if name != "" {
return name
}
name = findTLSOptName(tlsOptionsForHost, strings.ToLower(host), fqdn)
if name != "" {
return name
}
return traefiktls.DefaultTLSConfigName
}
func findTLSOptName(tlsOptionsForHost map[string]string, host string, fqdn bool) string {
if tlsOptions, ok := tlsOptionsForHost[host]; ok {
return tlsOptions
}
if !fqdn {
return ""
}
if last := len(host) - 1; last >= 0 && host[last] == '.' {
if tlsOptions, ok := tlsOptionsForHost[host[:last]]; ok {
return tlsOptions
}
return ""
}
if tlsOptions, ok := tlsOptionsForHost[host+"."]; ok {
return tlsOptions
}
return ""
}
-59
View File
@@ -1,59 +0,0 @@
package snicheck
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestSNICheck_ServeHTTP(t *testing.T) {
testCases := []struct {
desc string
tlsOptionsForHost map[string]string
host string
expected int
}{
{
desc: "no TLS options",
expected: http.StatusOK,
},
{
desc: "with TLS options",
tlsOptionsForHost: map[string]string{
"example.com": "foo",
},
expected: http.StatusOK,
},
{
desc: "server name and host doesn't have the same TLS configuration",
tlsOptionsForHost: map[string]string{
"example.com": "foo",
},
host: "example.com",
expected: http.StatusMisdirectedRequest,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {})
sniCheck := New(test.tlsOptionsForHost, next)
req := httptest.NewRequest(http.MethodGet, "https://localhost", nil)
if test.host != "" {
req.Host = test.host
}
recorder := httptest.NewRecorder()
sniCheck.ServeHTTP(recorder, req)
assert.Equal(t, test.expected, recorder.Code)
})
}
}
+11 -1
View File
@@ -54,6 +54,8 @@ func (s *stripPrefix) GetTracingInformation() (string, string) {
}
func (s *stripPrefix) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := middlewares.GetLogger(req.Context(), s.name, typeName)
for _, prefix := range s.prefixes {
if strings.HasPrefix(req.URL.Path, prefix) {
req.URL.Path = s.getPathStripped(req.URL.Path, prefix)
@@ -64,10 +66,18 @@ func (s *stripPrefix) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
// Here we are sanitizing the URL when the path is not empty,
// as the JoinPath method is adding a leading slash if the path is empty
// to be aligned with ensureLeadingSlash behavior.
if req.URL.Path != "" {
path := req.URL.Path
if path != "" {
req.URL = req.URL.JoinPath()
}
// Stop here if the normalization of the path produces a different path.
if path != req.URL.Path {
logger.Debug().Msgf("Rejecting request, sanitized path: %q is not equivalent to stripped path: %q", path, req.URL.Path)
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
req.Header.Add(ForwardedPrefixHeader, prefix)
req.RequestURI = req.URL.RequestURI()
break
@@ -148,10 +148,7 @@ func TestStripPrefix(t *testing.T) {
Prefixes: []string{"/api"},
},
path: "/api./foo",
expectedStatusCode: http.StatusOK,
expectedPath: "/foo",
expectedRawPath: "",
expectedHeader: "/api",
expectedStatusCode: http.StatusBadRequest,
},
{
desc: "multiple dots in the path not stripped by the prefix",
@@ -159,10 +156,7 @@ func TestStripPrefix(t *testing.T) {
Prefixes: []string{"/api"},
},
path: "/api../foo",
expectedStatusCode: http.StatusOK,
expectedPath: "/foo",
expectedRawPath: "",
expectedHeader: "/api",
expectedStatusCode: http.StatusBadRequest,
},
{
desc: "multiple dots in the path not stripped by the prefix with forceSlash",
@@ -171,10 +165,7 @@ func TestStripPrefix(t *testing.T) {
ForceSlash: ptr.To(true),
},
path: "/api../foo",
expectedStatusCode: http.StatusOK,
expectedPath: "/foo",
expectedRawPath: "",
expectedHeader: "/api",
expectedStatusCode: http.StatusBadRequest,
},
}
@@ -204,6 +195,10 @@ func TestStripPrefix(t *testing.T) {
handler.ServeHTTP(resp, req)
assert.Equal(t, test.expectedStatusCode, resp.Code, "Unexpected status code.")
if test.expectedStatusCode != http.StatusOK {
return
}
assert.Equal(t, test.expectedPath, actualPath, "Unexpected path.")
assert.Equal(t, test.expectedRawPath, actualRawPath, "Unexpected raw path.")
assert.Equal(t, test.expectedHeader, actualHeader, "Unexpected '%s' header.", ForwardedPrefixHeader)
@@ -47,6 +47,8 @@ func (s *stripPrefixRegex) GetTracingInformation() (string, string) {
}
func (s *stripPrefixRegex) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
logger := middlewares.GetLogger(req.Context(), s.name, typeName)
for _, exp := range s.expressions {
parts := exp.FindStringSubmatch(req.URL.Path)
if len(parts) > 0 && len(parts[0]) > 0 {
@@ -65,10 +67,18 @@ func (s *stripPrefixRegex) ServeHTTP(rw http.ResponseWriter, req *http.Request)
// Here we are sanitizing the URL when the path is not empty,
// as the JoinPath method is adding a leading slash if the path is empty
// to be aligned with ensureLeadingSlash behavior.
if req.URL.Path != "" {
path := req.URL.Path
if path != "" {
req.URL = req.URL.JoinPath()
}
// Stop here if the normalization of the path produces a different path.
if path != req.URL.Path {
logger.Debug().Msgf("Rejecting request, sanitized path: %q is not equivalent to stripped path: %q", path, req.URL.Path)
http.Error(rw, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
return
}
req.RequestURI = req.URL.RequestURI()
break
}
@@ -201,21 +201,13 @@ func TestStripPrefixRegex(t *testing.T) {
desc: "/api./foo",
config: dynamic.StripPrefixRegex{Regex: []string{"/api"}},
path: "/api./foo",
expectedStatusCode: http.StatusOK,
expectedPath: "/foo",
expectedRawPath: "",
expectedRequestURI: "/foo",
expectedHeader: "/api",
expectedStatusCode: http.StatusBadRequest,
},
{
desc: "/api../foo",
config: dynamic.StripPrefixRegex{Regex: []string{"/api"}},
path: "/api../foo",
expectedStatusCode: http.StatusOK,
expectedPath: "/foo",
expectedRawPath: "",
expectedRequestURI: "/foo",
expectedHeader: "/api",
expectedStatusCode: http.StatusBadRequest,
},
}
+1 -1
View File
@@ -491,7 +491,7 @@ func Test_addTCPRouteV2(t *testing.T) {
remoteAddr: fakeAddr{addr: addr},
}
connData, err := NewConnData(test.serverName, conn, test.protos)
connData, err := NewConnData(test.serverName, conn.RemoteAddr(), test.protos)
require.NoError(t, err)
matchingHandler, _ := router.Match(connData)
+3 -3
View File
@@ -22,10 +22,10 @@ type ConnData struct {
}
// NewConnData builds a connData struct from the given parameters.
func NewConnData(serverName string, conn tcp.WriteCloser, alpnProtos []string) (ConnData, error) {
remoteIP, _, err := net.SplitHostPort(conn.RemoteAddr().String())
func NewConnData(serverName string, remoteAddr net.Addr, alpnProtos []string) (ConnData, error) {
remoteIP, _, err := net.SplitHostPort(remoteAddr.String())
if err != nil {
return ConnData{}, fmt.Errorf("error while parsing remote address %q: %w", conn.RemoteAddr().String(), err)
return ConnData{}, fmt.Errorf("parsing remote address %q: %w", remoteAddr.String(), err)
}
return ConnData{
+1 -1
View File
@@ -293,7 +293,7 @@ func Test_addTCPRoute(t *testing.T) {
remoteAddr: fakeAddr{addr: addr},
}
connData, err := NewConnData(test.serverName, conn, test.protos)
connData, err := NewConnData(test.serverName, conn.RemoteAddr(), test.protos)
require.NoError(t, err)
matchingHandler, _ := router.Match(connData)
+21 -3
View File
@@ -93,9 +93,15 @@ type FieldHeaders struct {
// AccessLogFields holds configuration for access log fields.
type AccessLogFields struct {
DefaultMode string `description:"Default mode for fields: keep | drop" json:"defaultMode,omitempty" toml:"defaultMode,omitempty" yaml:"defaultMode,omitempty" export:"true"`
Names map[string]string `description:"Override mode for fields" json:"names,omitempty" toml:"names,omitempty" yaml:"names,omitempty" export:"true"`
Headers *FieldHeaders `description:"Headers to keep, drop or redact" json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty" export:"true"`
DefaultMode string `description:"Default mode for fields: keep | drop" json:"defaultMode,omitempty" toml:"defaultMode,omitempty" yaml:"defaultMode,omitempty" export:"true"`
Names map[string]string `description:"Override mode for fields" json:"names,omitempty" toml:"names,omitempty" yaml:"names,omitempty" export:"true"`
Headers *FieldHeaders `description:"Headers to keep, drop or redact" json:"headers,omitempty" toml:"headers,omitempty" yaml:"headers,omitempty" export:"true"`
QueryParameters *FieldQueryParameters `description:"Keep or drop all query parameters" json:"queryParameters,omitempty" toml:"queryParameters,omitempty" yaml:"queryParameters,omitempty" export:"true"`
}
// FieldQueryParameters holds configuration for access log query parameters.
type FieldQueryParameters struct {
DefaultMode string `description:"Default mode for query parameters: keep | drop" json:"defaultMode,omitempty" toml:"defaultMode,omitempty" yaml:"defaultMode,omitempty" export:"true"`
}
// SetDefaults sets the default values.
@@ -104,6 +110,9 @@ func (f *AccessLogFields) SetDefaults() {
f.Headers = &FieldHeaders{
DefaultMode: AccessLogDrop,
}
f.QueryParameters = &FieldQueryParameters{
DefaultMode: AccessLogKeep,
}
}
// Keep check if the field need to be kept or dropped.
@@ -132,6 +141,15 @@ func (f *AccessLogFields) KeepHeader(header string) string {
return defaultValue
}
// KeepQueryParameters checks if the query parameters need to be kept or dropped.
func (f *AccessLogFields) KeepQueryParameters() bool {
defaultKeep := true
if f == nil || f.QueryParameters == nil {
return defaultKeep
}
return checkFieldValue(f.QueryParameters.DefaultMode, defaultKeep)
}
func checkFieldValue(value string, defaultKeep bool) bool {
switch value {
case AccessLogKeep:
+24 -4
View File
@@ -462,7 +462,12 @@ func Test_buildConfiguration(t *testing.T) {
KeyFile: "key",
},
},
PeerCertURI: "spiffe:///ns/ns/dc/dc1/svc/dev/Test",
PeerCertSANs: []tls.SAN{
{
Type: tls.SANURIType,
Value: "spiffe:///ns/ns/dc/dc1/svc/dev/Test",
},
},
},
},
},
@@ -557,7 +562,12 @@ func Test_buildConfiguration(t *testing.T) {
KeyFile: "key",
},
},
PeerCertURI: "spiffe:///ns/ns/dc/dc1/svc/dev/Test",
PeerCertSANs: []tls.SAN{
{
Type: tls.SANURIType,
Value: "spiffe:///ns/ns/dc/dc1/svc/dev/Test",
},
},
},
},
},
@@ -2626,7 +2636,12 @@ func Test_buildConfiguration(t *testing.T) {
KeyFile: "key",
},
},
PeerCertURI: "spiffe:///ns/ns/dc/dc1/svc/Test",
PeerCertSANs: []tls.SAN{
{
Type: tls.SANURIType,
Value: "spiffe:///ns/ns/dc/dc1/svc/Test",
},
},
},
},
},
@@ -3279,7 +3294,12 @@ func Test_buildConfiguration(t *testing.T) {
KeyFile: "key",
},
},
PeerCertURI: "spiffe:///ns/ns/dc/dc1/svc/Test",
PeerCertSANs: []tls.SAN{
{
Type: tls.SANURIType,
Value: "spiffe:///ns/ns/dc/dc1/svc/Test",
},
},
},
},
},
+12 -2
View File
@@ -69,7 +69,12 @@ func (c *connectCert) serversTransport(item itemData) *dynamic.ServersTransport
Certificates: traefiktls.Certificates{
c.getLeaf(),
},
PeerCertURI: spiffeID,
PeerCertSANs: []traefiktls.SAN{
{
Type: traefiktls.SANURIType,
Value: spiffeID,
},
},
}
}
@@ -91,7 +96,12 @@ func (c *connectCert) tcpServersTransport(item itemData) *dynamic.TCPServersTran
Certificates: traefiktls.Certificates{
c.getLeaf(),
},
PeerCertURI: spiffeID,
PeerCertSANs: []traefiktls.SAN{
{
Type: traefiktls.SANURIType,
Value: spiffeID,
},
},
},
}
}
+21 -5
View File
@@ -72,9 +72,16 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
// ignore sub-dir
continue
}
if !isFileSupported(entry.Name()) {
// ignore unsupported file extension
continue
}
watchItems = append(watchItems, path.Join(p.Directory, entry.Name()))
}
case len(p.Filename) > 0:
if !isFileSupported(p.Filename) {
return fmt.Errorf("unsupported file extension for file %s", p.Filename)
}
watchItems = append(watchItems, filepath.Dir(p.Filename), p.Filename)
default:
return errors.New("error using file configuration provider, neither filename nor directory is defined")
@@ -169,7 +176,7 @@ func (p *Provider) addWatcher(pool *safe.Pool, items []string, configurationChan
log.Debug().Msgf("add watcher on: %s", item)
err = watcher.Add(item)
if err != nil {
return fmt.Errorf("error adding file watcher: %w", err)
return fmt.Errorf("error adding file watcher for %s: %w", item, err)
}
}
@@ -392,6 +399,8 @@ func (p *Provider) collectFileConfigs(ctx context.Context, directory, prefix str
}
for _, item := range fileList {
logger := log.Ctx(ctx).With().Str("filename", item.Name()).Logger()
itemPath := filepath.Join(directory, item.Name())
filename := item.Name()
if prefix != "" {
@@ -407,10 +416,8 @@ func (p *Provider) collectFileConfigs(ctx context.Context, directory, prefix str
continue
}
switch strings.ToLower(filepath.Ext(item.Name())) {
case ".toml", ".yaml", ".yml":
// noop
default:
if !isFileSupported(item.Name()) {
logger.Debug().Msg("Skipping file, unsupported extension")
continue
}
@@ -500,3 +507,12 @@ func readFile(filename string) (string, error) {
}
return "", fmt.Errorf("invalid filename: %s", filename)
}
func isFileSupported(filename string) bool {
switch strings.ToLower(filepath.Ext(filename)) {
case ".toml", ".yaml", ".yml":
return true
default:
return false
}
}
+32
View File
@@ -197,6 +197,38 @@ func TestProvideWithWatch(t *testing.T) {
}
}
func TestProvideWatchWithNonConfigDanglingSymlink(t *testing.T) {
tempDir := t.TempDir()
err := copyFile("./fixtures/yaml/simple_file_01.yml", filepath.Join(tempDir, "simple_file_01.yml"))
require.NoError(t, err)
err = os.Symlink(filepath.Join(tempDir, "non_existent_file.txt"), filepath.Join(tempDir, "dangling_symlink.txt"))
require.NoError(t, err)
provider := &Provider{
Directory: tempDir,
Watch: true,
}
configChan := make(chan dynamic.Message)
go func() {
err := provider.Provide(configChan, safe.NewPool(t.Context()))
assert.NoError(t, err)
}()
timeout := time.After(time.Second)
select {
case conf := <-configChan:
require.NotNil(t, conf.Configuration.HTTP)
numServices := len(conf.Configuration.HTTP.Services) + len(conf.Configuration.TCP.Services) + len(conf.Configuration.UDP.Services)
numRouters := len(conf.Configuration.HTTP.Routers) + len(conf.Configuration.TCP.Routers) + len(conf.Configuration.UDP.Routers)
assert.Equal(t, 6, numServices)
assert.Equal(t, 3, numRouters)
case <-timeout:
t.Errorf("timeout while waiting for config")
}
}
func getTestCases() []ProvideTestCase {
return []ProvideTestCase{
{
+4 -4
View File
@@ -177,7 +177,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
}
for _, ns := range namespaces {
factoryCrd := traefikinformers.NewSharedInformerFactoryWithOptions(c.csCrd, resyncPeriod, traefikinformers.WithNamespace(ns), traefikinformers.WithTweakListOptions(matchesLabelSelector))
factoryCrd := traefikinformers.NewSharedInformerFactoryWithOptions(c.csCrd, resyncPeriod, traefikinformers.WithNamespace(ns), traefikinformers.WithTweakListOptions(matchesLabelSelector), traefikinformers.WithTransform(k8s.StripManagedFields))
_, err := factoryCrd.Traefik().V1alpha1().IngressRoutes().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@@ -219,7 +219,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
return nil, err
}
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns))
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@@ -233,7 +233,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
return nil, err
}
factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm))
factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factorySecret.Core().V1().Secrets().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@@ -271,7 +271,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
}
if !c.disableClusterScopeInformer {
c.clusterScopeFactory = kinformers.NewSharedInformerFactory(c.csKube, resyncPeriod)
c.clusterScopeFactory = kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithTransform(k8s.StripManagedFields))
_, err := c.clusterScopeFactory.Core().V1().Nodes().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@@ -0,0 +1,19 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRouteTCP
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- foo
routes:
- match: HostSNI(`foo.com`)
services:
- name: whoamitcp
port: 8000
tls:
options:
name: foo@file
@@ -141,6 +141,11 @@ spec:
maxIdleConnsPerHost: 42
disableHTTP2: true
peerCertURI: foo://bar
peerCertSANs:
- type: DNSName
value: foo.com
- type: URI
value: foo://bar
rootCAsSecrets:
- root-ca0
- root-ca1
@@ -0,0 +1,18 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`foo.com`) && PathPrefix(`/bar`)
kind: Rule
priority: 12
services:
- name: whoami
port: 80
serversTransport: foo@file
@@ -0,0 +1,70 @@
---
apiVersion: traefik.io/v1alpha1
kind: TraefikService
metadata:
name: mirror-cp
namespace: foo
spec:
mirroring:
name: external-main@file
kind: TraefikService
mirrors:
- name: external-mirror@file
kind: TraefikService
percent: 50
---
apiVersion: traefik.io/v1alpha1
kind: TraefikService
metadata:
name: weighted-cp
namespace: bar
spec:
weighted:
services:
- name: external-a@file
kind: TraefikService
weight: 1
- name: external-b@file
kind: TraefikService
weight: 1
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: ir-mirror
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`mirror.example.com`)
kind: Rule
services:
- name: mirror-cp
namespace: foo
kind: TraefikService
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: ir-weighted
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`weighted.example.com`)
kind: Rule
services:
- name: weighted-cp
namespace: bar
kind: TraefikService
@@ -0,0 +1,21 @@
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: test.route
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`foo.com`) && PathPrefix(`/bar`)
kind: Rule
priority: 12
services:
- name: whoami
port: 80
tls:
options:
name: foo@file
@@ -28,6 +28,7 @@ package v1alpha1
import (
dynamic "github.com/traefik/traefik/v3/pkg/config/dynamic"
tls "github.com/traefik/traefik/v3/pkg/tls"
)
// ServersTransportSpecApplyConfiguration represents a declarative configuration of the ServersTransportSpec type for use
@@ -60,7 +61,11 @@ type ServersTransportSpecApplyConfiguration struct {
// DisableHTTP2 disables HTTP/2 for connections with backend servers.
DisableHTTP2 *bool `json:"disableHTTP2,omitempty"`
// PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
//
// Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
PeerCertURI *string `json:"peerCertURI,omitempty"`
// PeerCertSANs defines the peer cert Subject Alternative Names used to match against SAN during the peer certificate verification.
PeerCertSANs []tls.SAN `json:"peerCertSANs,omitempty"`
// Spiffe defines the SPIFFE configuration.
Spiffe *dynamic.Spiffe `json:"spiffe,omitempty"`
}
@@ -178,6 +183,16 @@ func (b *ServersTransportSpecApplyConfiguration) WithPeerCertURI(value string) *
return b
}
// WithPeerCertSANs adds the given value to the PeerCertSANs field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the PeerCertSANs field.
func (b *ServersTransportSpecApplyConfiguration) WithPeerCertSANs(values ...tls.SAN) *ServersTransportSpecApplyConfiguration {
for i := range values {
b.PeerCertSANs = append(b.PeerCertSANs, values[i])
}
return b
}
// WithSpiffe sets the Spiffe field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Spiffe field is set to the value of the last call.
@@ -28,6 +28,7 @@ package v1alpha1
import (
dynamic "github.com/traefik/traefik/v3/pkg/config/dynamic"
tls "github.com/traefik/traefik/v3/pkg/tls"
)
// TLSClientConfigApplyConfiguration represents a declarative configuration of the TLSClientConfig type for use
@@ -47,9 +48,12 @@ type TLSClientConfigApplyConfiguration struct {
RootCAsSecrets []string `json:"rootCAsSecrets,omitempty"`
// CertificatesSecrets defines a list of secret storing client certificates for mTLS.
CertificatesSecrets []string `json:"certificatesSecrets,omitempty"`
// MaxIdleConnsPerHost controls the maximum idle (keep-alive) to keep per-host.
// PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
//
// Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
PeerCertURI *string `json:"peerCertURI,omitempty"`
// PeerCertSANs defines the peer cert Subject Alternative Names used to match against SAN during the peer certificate verification.
PeerCertSANs []tls.SAN `json:"peerCertSANs,omitempty"`
// Spiffe defines the SPIFFE configuration.
Spiffe *dynamic.Spiffe `json:"spiffe,omitempty"`
}
@@ -117,6 +121,16 @@ func (b *TLSClientConfigApplyConfiguration) WithPeerCertURI(value string) *TLSCl
return b
}
// WithPeerCertSANs adds the given value to the PeerCertSANs field in the declarative configuration
// and returns the receiver, so that objects can be build by chaining "With" function invocations.
// If called multiple times, values provided by each call will be appended to the PeerCertSANs field.
func (b *TLSClientConfigApplyConfiguration) WithPeerCertSANs(values ...tls.SAN) *TLSClientConfigApplyConfiguration {
for i := range values {
b.PeerCertSANs = append(b.PeerCertSANs, values[i])
}
return b
}
// WithSpiffe sets the Spiffe field in the declarative configuration to the given value
// and returns the receiver, so that objects can be built by chaining "With" function invocations.
// If called multiple times, the Spiffe field is set to the value of the last call.
+65 -38
View File
@@ -57,6 +57,7 @@ type Provider struct {
Namespaces []string `description:"Kubernetes namespaces." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" export:"true"`
AllowCrossNamespace bool `description:"Allow cross namespace resource reference." json:"allowCrossNamespace,omitempty" toml:"allowCrossNamespace,omitempty" yaml:"allowCrossNamespace,omitempty" export:"true"`
AllowExternalNameServices bool `description:"Allow ExternalName services." json:"allowExternalNameServices,omitempty" toml:"allowExternalNameServices,omitempty" yaml:"allowExternalNameServices,omitempty" export:"true"`
CrossProviderNamespaces []string `description:"List of namespaces from which IngressRoute, IngressRouteTCP, IngressRouteUDP, and TraefikService are allowed to declare cross-provider references." json:"crossProviderNamespaces,omitempty" toml:"crossProviderNamespaces,omitempty" yaml:"crossProviderNamespaces,omitempty" export:"true"`
LabelSelector string `description:"Kubernetes label selector to use." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`
IngressClass string `description:"Value of ingressClassName field or kubernetes.io/ingress.class annotation to watch for." json:"ingressClass,omitempty" toml:"ingressClass,omitempty" yaml:"ingressClass,omitempty" export:"true"`
ThrottleDuration ptypes.Duration `description:"Ingress refresh throttle duration" json:"throttleDuration,omitempty" toml:"throttleDuration,omitempty" yaml:"throttleDuration,omitempty" export:"true"`
@@ -93,6 +94,10 @@ func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.
logger.Info().Msg("ExternalName service loading is enabled, please ensure that this is expected (see AllowExternalNameServices option)")
}
if p.CrossProviderNamespaces != nil {
logger.Warn().Msgf("Cross-provider references are restricted to namespaces %v (see CrossProviderNamespaces option)", p.CrossProviderNamespaces)
}
pool.GoCtx(func(ctxPool context.Context) {
operation := func() error {
eventsChan, err := k8sClient.WatchAll(p.Namespaces, ctxPool.Done())
@@ -307,7 +312,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
continue
}
chain, err := createChainMiddleware(ctxMid, middleware.Namespace, middleware.Spec.Chain, p.AllowCrossNamespace)
chain, err := p.createChainMiddleware(ctxMid, middleware.Namespace, middleware.Spec.Chain)
if err != nil {
logger.Error().Err(err).Msg("Error while reading chain middleware")
continue
@@ -358,6 +363,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
allowCrossNamespace: p.AllowCrossNamespace,
allowExternalNameServices: p.AllowExternalNameServices,
allowEmptyServices: p.AllowEmptyServices,
crossProviderNamespaces: p.CrossProviderNamespaces,
}
for _, service := range client.GetTraefikServices() {
@@ -535,6 +541,7 @@ func (p *Provider) loadConfigurationFromCRD(ctx context.Context, client Client)
MaxIdleConnsPerHost: serversTransport.Spec.MaxIdleConnsPerHost,
ForwardingTimeouts: forwardingTimeout,
PeerCertURI: serversTransport.Spec.PeerCertURI,
PeerCertSANs: serversTransport.Spec.PeerCertSANs,
Spiffe: serversTransport.Spec.Spiffe,
}
}
@@ -666,6 +673,7 @@ func (p *Provider) createErrorPageMiddleware(ctx context.Context, client Client,
allowCrossNamespace: p.AllowCrossNamespace,
allowExternalNameServices: p.AllowExternalNameServices,
allowEmptyServices: p.AllowEmptyServices,
crossProviderNamespaces: p.CrossProviderNamespaces,
}
balancerName, balancerServerHTTP, err := cb.nameAndService(ctx, namespace, errorPage.Service.LoadBalancerSpec)
@@ -680,6 +688,26 @@ func (p *Provider) createErrorPageMiddleware(ctx context.Context, client Client,
}, balancerServerHTTP, nil
}
func (p *Provider) createChainMiddleware(ctx context.Context, parentNamespace string, chain *traefikv1alpha1.Chain) (*dynamic.Chain, error) {
if chain == nil {
return nil, nil
}
var mds []string
for _, mi := range chain.Middlewares {
ctxMid := log.Ctx(ctx).With().Str("middlewareRef", mi.Namespace+"/"+mi.Name).Logger().WithContext(ctx)
middlewareRef, err := resolveReference(ctxMid, parentNamespace, mi.Namespace, mi.Name, p.CrossProviderNamespaces, p.AllowCrossNamespace)
if err != nil {
return nil, fmt.Errorf("invalid reference to middleware %s: %w", mi.Name, err)
}
mds = append(mds, middlewareRef)
}
return &dynamic.Chain{Middlewares: mds}, nil
}
// getServicePort always returns a valid port, an error otherwise.
func getServicePort(svc *corev1.Service, port intstr.IntOrString) (*corev1.ServicePort, error) {
if svc == nil {
@@ -1280,43 +1308,6 @@ func loadAuthCredentials(secret *corev1.Secret) ([]string, error) {
return credentials, nil
}
func createChainMiddleware(ctx context.Context, parentNamespace string, chain *traefikv1alpha1.Chain, allowCrossNamespace bool) (*dynamic.Chain, error) {
if chain == nil {
return nil, nil
}
var mds []string
for _, mi := range chain.Middlewares {
if !allowCrossNamespace && strings.HasSuffix(mi.Name, providerNamespaceSeparator+ProviderName) {
// Since we are not able to know if another namespace is in the name (namespace-name@kubernetescrd),
// if the provider namespace kubernetescrd is used,
// we don't allow this format to avoid cross-namespace references.
return nil, fmt.Errorf("invalid reference to middleware %s: when allowCrossNamespace is disabled @kubernetescrd provider references are disallowed", mi.Name)
}
if strings.Contains(mi.Name, providerNamespaceSeparator) {
if len(mi.Namespace) > 0 {
log.Ctx(ctx).Warn().Msgf("namespace %q is ignored in cross-provider context", mi.Namespace)
}
mds = append(mds, mi.Name)
continue
}
ns := parentNamespace
if len(mi.Namespace) > 0 {
if !isNamespaceAllowed(allowCrossNamespace, parentNamespace, mi.Namespace) {
return nil, fmt.Errorf("middleware %s/%s is not in the chain namespace %s", mi.Namespace, mi.Name, parentNamespace)
}
ns = mi.Namespace
}
mds = append(mds, makeID(ns, mi.Name))
}
return &dynamic.Chain{Middlewares: mds}, nil
}
func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options {
tlsOptionsCRDs := client.GetTLSOptions()
var tlsOptions map[string]tls.Options
@@ -1659,3 +1650,39 @@ func isNamespaceAllowed(allowCrossNamespace bool, parentNamespace, namespace str
// If allowCrossNamespace option is not defined the default behavior is to allow cross namespace references.
return allowCrossNamespace || parentNamespace == namespace
}
// isCrossProviderNamespaceAllowed reports whether the given namespace is allowed to declare direct references to Traefik resources.
// A nil allowList means references are unrestricted, and an empty allowList disables them entirely.
func isCrossProviderNamespaceAllowed(allowList []string, namespace string) bool {
if allowList == nil {
return true
}
return slices.Contains(allowList, namespace)
}
func resolveReference(ctx context.Context, parentNs, ns, name string, crossProviderNamespaces []string, allowCrossNamespace bool) (string, error) {
if strings.Contains(name, providerNamespaceSeparator) {
if !allowCrossNamespace && strings.HasSuffix(name, providerNamespaceSeparator+ProviderName) {
return "", errors.New("when allowCrossNamespace is disabled, @kubernetescrd references are disallowed")
}
if !isCrossProviderNamespaceAllowed(crossProviderNamespaces, parentNs) {
return "", fmt.Errorf("namespace %q is not in crossProviderNamespaces", parentNs)
}
if ns != "" {
log.Ctx(ctx).Warn().Msgf("Namespace %q is ignored in cross-provider context", ns)
}
return name, nil
}
ns = namespaceOrParentNamespace(ns, parentNs)
if !isNamespaceAllowed(allowCrossNamespace, parentNs, ns) {
return "", errors.New("allowCrossNamespace is disabled, cross-namespace are disallowed")
}
return provider.Normalize(ns + "-" + name), nil
}
+42 -63
View File
@@ -61,6 +61,7 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
allowEmptyServices: p.AllowEmptyServices,
nativeLBByDefault: p.NativeLBByDefault,
disableClusterScopeResources: p.DisableClusterScopeResources,
crossProviderNamespaces: p.CrossProviderNamespaces,
}
parentRouterNames, err := resolveParentRouterNames(client, ingressRoute, p.AllowCrossNamespace)
@@ -82,7 +83,7 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
serviceKey := makeServiceKey(route.Match, ingressName)
mds, err := makeMiddlewareKeys(ctx, ingressRoute.Namespace, route.Middlewares, p.AllowCrossNamespace)
mds, err := makeMiddlewareKeys(ctx, ingressRoute.Namespace, route.Middlewares, p.CrossProviderNamespaces, p.AllowCrossNamespace)
if err != nil {
logger.Error().Err(err).Msg("Failed to create middleware keys")
continue
@@ -147,27 +148,14 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
}
if ingressRoute.Spec.TLS.Options != nil && len(ingressRoute.Spec.TLS.Options.Name) > 0 {
tlsOptionsName := ingressRoute.Spec.TLS.Options.Name
// Is a Kubernetes CRD reference, (i.e. not a cross-provider reference)
ns := ingressRoute.Spec.TLS.Options.Namespace
if !strings.Contains(tlsOptionsName, providerNamespaceSeparator) {
if len(ns) == 0 {
ns = ingressRoute.Namespace
}
tlsOptionsName = makeID(ns, tlsOptionsName)
} else if len(ns) > 0 {
logger.
Warn().Str("TLSOption", ingressRoute.Spec.TLS.Options.Name).
Msgf("Namespace %q is ignored in cross-provider context", ns)
}
tlsOptions := ingressRoute.Spec.TLS.Options
ctxTLSOption := log.Ctx(ctx).With().Str("TLSOption", tlsOptions.Name).Logger().WithContext(ctx)
if !isNamespaceAllowed(p.AllowCrossNamespace, ingressRoute.Namespace, ns) {
logger.Error().Msgf("TLSOption %s/%s is not in the IngressRoute namespace %s",
ns, ingressRoute.Spec.TLS.Options.Name, ingressRoute.Namespace)
r.TLS.Options, err = resolveReference(ctxTLSOption, ingressRoute.Namespace, tlsOptions.Namespace, tlsOptions.Name, p.CrossProviderNamespaces, p.AllowCrossNamespace)
if err != nil {
logger.Error().Err(err).Msgf("Invalid reference to TLSOption %q", ingressRoute.Spec.TLS.Options.Name)
continue
}
r.TLS.Options = tlsOptionsName
}
}
@@ -180,40 +168,18 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
return conf
}
func makeMiddlewareKeys(ctx context.Context, namespace string, middlewares []traefikv1alpha1.MiddlewareRef, allowCrossNamespace bool) ([]string, error) {
func makeMiddlewareKeys(ctx context.Context, ingRouteNamespace string, middlewares []traefikv1alpha1.MiddlewareRef, crossProviderNamespaces []string, allowCrossNamespace bool) ([]string, error) {
var mds []string
for _, mi := range middlewares {
name := mi.Name
ctxMid := log.Ctx(ctx).With().Str(logs.MiddlewareName, mi.Name).Logger().WithContext(ctx)
if !allowCrossNamespace && strings.HasSuffix(mi.Name, providerNamespaceSeparator+ProviderName) {
// Since we are not able to know if another namespace is in the name (namespace-name@kubernetescrd),
// if the provider namespace kubernetescrd is used,
// we don't allow this format to avoid cross-namespace references.
return nil, fmt.Errorf("invalid reference to middleware %s: when allowCrossNamespace is disabled @kubernetescrd provider references are disallowed", mi.Name)
middlewareRef, err := resolveReference(ctxMid, ingRouteNamespace, mi.Namespace, mi.Name, crossProviderNamespaces, allowCrossNamespace)
if err != nil {
return nil, fmt.Errorf("invalid reference to middleware %s: %w", mi.Name, err)
}
if strings.Contains(name, providerNamespaceSeparator) {
if len(mi.Namespace) > 0 {
log.Ctx(ctx).
Warn().Str(logs.MiddlewareName, mi.Name).
Msgf("namespace %q is ignored in cross-provider context", mi.Namespace)
}
mds = append(mds, name)
continue
}
ns := namespace
if len(mi.Namespace) > 0 {
if !isNamespaceAllowed(allowCrossNamespace, namespace, mi.Namespace) {
return nil, fmt.Errorf("middleware %s/%s is not in the parent namespace %s", mi.Namespace, mi.Name, namespace)
}
ns = mi.Namespace
}
mds = append(mds, provider.Normalize(makeID(ns, name)))
mds = append(mds, middlewareRef)
}
return mds, nil
@@ -270,6 +236,7 @@ type configBuilder struct {
allowEmptyServices bool
nativeLBByDefault bool
disableClusterScopeResources bool
crossProviderNamespaces []string
}
// buildTraefikService creates the configuration for the traefik service defined in tService,
@@ -514,7 +481,7 @@ func (c configBuilder) buildServersLB(ctx context.Context, svc traefikv1alpha1.L
service := &dynamic.Service{LoadBalancer: lb}
if len(svc.Middlewares) > 0 {
mds, err := makeMiddlewareKeys(ctx, svc.Namespace, svc.Middlewares, c.allowCrossNamespace)
mds, err := makeMiddlewareKeys(ctx, svc.Namespace, svc.Middlewares, c.crossProviderNamespaces, c.allowCrossNamespace)
if err != nil {
return nil, fmt.Errorf("could not create middleware keys: %w", err)
}
@@ -529,14 +496,18 @@ func (c configBuilder) makeServersTransportKey(parentNamespace string, serversTr
return "", nil
}
if !c.allowCrossNamespace && strings.HasSuffix(serversTransportName, providerNamespaceSeparator+ProviderName) {
// Since we are not able to know if another namespace is in the name (namespace-name@kubernetescrd),
// if the provider namespace kubernetescrd is used,
// we don't allow this format to avoid cross namespace references.
return "", fmt.Errorf("invalid reference to serversTransport %s: namespace-name@kubernetescrd format is not allowed when crossnamespace is disallowed", serversTransportName)
}
if strings.Contains(serversTransportName, providerNamespaceSeparator) {
if !c.allowCrossNamespace && strings.HasSuffix(serversTransportName, providerNamespaceSeparator+ProviderName) {
// Since we are not able to know if another namespace is in the name (namespace-name@kubernetescrd),
// if the provider namespace kubernetescrd is used,
// we don't allow this format to avoid cross namespace references.
return "", fmt.Errorf("invalid reference to serversTransport %s: namespace-name@kubernetescrd format is not allowed when crossnamespace is disallowed", serversTransportName)
}
if !isCrossProviderNamespaceAllowed(c.crossProviderNamespaces, parentNamespace) {
return "", fmt.Errorf("serversTransport %q reference is not allowed: namespace %q is not in crossProviderNamespaces", serversTransportName, parentNamespace)
}
return serversTransportName, nil
}
@@ -691,11 +662,17 @@ func (c configBuilder) loadServers(svc traefikv1alpha1.LoadBalancerSpec) ([]dyna
func (c configBuilder) nameAndService(ctx context.Context, parentNamespace string, service traefikv1alpha1.LoadBalancerSpec) (string, *dynamic.Service, error) {
svcCtx := log.Ctx(ctx).With().Str(logs.ServiceName, service.Name).Logger().WithContext(ctx)
service = *service.DeepCopy()
service.Namespace = namespaceOrFallback(service, parentNamespace)
if !strings.Contains(service.Name, providerNamespaceSeparator) {
service = *service.DeepCopy()
service.Namespace = namespaceOrParentNamespace(service.Namespace, parentNamespace)
if !isNamespaceAllowed(c.allowCrossNamespace, parentNamespace, service.Namespace) {
return "", nil, fmt.Errorf("service %s/%s not in the parent resource namespace %s", service.Namespace, service.Name, parentNamespace)
if !isNamespaceAllowed(c.allowCrossNamespace, parentNamespace, service.Namespace) {
return "", nil, fmt.Errorf("service %s/%s not in the parent resource namespace %s", service.Namespace, service.Name, parentNamespace)
}
}
if !isCrossProviderNamespaceAllowed(c.crossProviderNamespaces, parentNamespace) && strings.Contains(service.Name, providerNamespaceSeparator) {
return "", nil, fmt.Errorf("service %q reference is not allowed: namespace %q is not in crossProviderNamespaces", service.Name, parentNamespace)
}
switch service.Kind {
@@ -811,11 +788,12 @@ func fullServiceName(ctx context.Context, service traefikv1alpha1.LoadBalancerSp
return provider.Normalize(name) + providerNamespaceSeparator + pName
}
func namespaceOrFallback(lb traefikv1alpha1.LoadBalancerSpec, fallback string) string {
if lb.Namespace != "" {
return lb.Namespace
func namespaceOrParentNamespace(namespace, parentNamespace string) string {
if namespace != "" {
return namespace
}
return fallback
return parentNamespace
}
// getTLSHTTP mutates tlsConfigs.
@@ -823,6 +801,7 @@ func getTLSHTTP(ctx context.Context, ingressRoute *traefikv1alpha1.IngressRoute,
if ingressRoute.Spec.TLS == nil {
return nil
}
if ingressRoute.Spec.TLS.SecretName == "" {
log.Ctx(ctx).Debug().Msg("No secret name provided")
return nil
+14 -42
View File
@@ -114,27 +114,14 @@ func (p *Provider) loadIngressRouteTCPConfiguration(ctx context.Context, client
}
if ingressRouteTCP.Spec.TLS.Options != nil && len(ingressRouteTCP.Spec.TLS.Options.Name) > 0 {
tlsOptionsName := ingressRouteTCP.Spec.TLS.Options.Name
// Is a Kubernetes CRD reference (i.e. not a cross-provider reference)
ns := ingressRouteTCP.Spec.TLS.Options.Namespace
if !strings.Contains(tlsOptionsName, providerNamespaceSeparator) {
if len(ns) == 0 {
ns = ingressRouteTCP.Namespace
}
tlsOptionsName = makeID(ns, tlsOptionsName)
} else if len(ns) > 0 {
logger.Warn().
Str("TLSOption", ingressRouteTCP.Spec.TLS.Options.Name).
Msgf("Namespace %q is ignored in cross-provider context", ns)
}
tlsOptions := ingressRouteTCP.Spec.TLS.Options
ctxTLSOption := log.Ctx(ctx).With().Str("TLSOption", tlsOptions.Name).Logger().WithContext(ctx)
if !isNamespaceAllowed(p.AllowCrossNamespace, ingressRouteTCP.Namespace, ns) {
logger.Error().Msgf("TLSOption %s/%s is not in the IngressRouteTCP namespace %s",
ns, ingressRouteTCP.Spec.TLS.Options.Name, ingressRouteTCP.Namespace)
r.TLS.Options, err = resolveReference(ctxTLSOption, ingressRouteTCP.Namespace, tlsOptions.Namespace, tlsOptions.Name, p.CrossProviderNamespaces, p.AllowCrossNamespace)
if err != nil {
logger.Error().Err(err).Msgf("Invalid reference to TLSOption %q", ingressRouteTCP.Spec.TLS.Options.Name)
continue
}
r.TLS.Options = tlsOptionsName
}
}
@@ -149,39 +136,24 @@ func (p *Provider) makeMiddlewareTCPKeys(ctx context.Context, ingRouteTCPNamespa
var mds []string
for _, mi := range middlewares {
if strings.Contains(mi.Name, providerNamespaceSeparator) {
if len(mi.Namespace) > 0 {
log.Ctx(ctx).Warn().
Str(logs.MiddlewareName, mi.Name).
Msgf("Namespace %q is ignored in cross-provider context", mi.Namespace)
}
mds = append(mds, mi.Name)
continue
ctxMid := log.Ctx(ctx).With().Str(logs.MiddlewareName, mi.Name).Logger().WithContext(ctx)
middlewareRef, err := resolveReference(ctxMid, ingRouteTCPNamespace, mi.Namespace, mi.Name, p.CrossProviderNamespaces, p.AllowCrossNamespace)
if err != nil {
return nil, fmt.Errorf("invalid reference to middleware %s: %w", mi.Name, err)
}
ns := ingRouteTCPNamespace
if len(mi.Namespace) > 0 {
if !isNamespaceAllowed(p.AllowCrossNamespace, ingRouteTCPNamespace, mi.Namespace) {
return nil, fmt.Errorf("middleware %s/%s is not in the IngressRouteTCP namespace %s", mi.Namespace, mi.Name, ingRouteTCPNamespace)
}
ns = mi.Namespace
}
mds = append(mds, provider.Normalize(makeID(ns, mi.Name)))
mds = append(mds, middlewareRef)
}
return mds, nil
}
func (p *Provider) createLoadBalancerServerTCP(client Client, parentNamespace string, service traefikv1alpha1.ServiceTCP) (*dynamic.TCPService, error) {
ns := parentNamespace
if len(service.Namespace) > 0 {
if !isNamespaceAllowed(p.AllowCrossNamespace, parentNamespace, service.Namespace) {
return nil, fmt.Errorf("tcp service %s/%s is not in the parent resource namespace %s", service.Namespace, service.Name, parentNamespace)
}
ns := namespaceOrParentNamespace(service.Namespace, parentNamespace)
ns = service.Namespace
if !isNamespaceAllowed(p.AllowCrossNamespace, parentNamespace, ns) {
return nil, fmt.Errorf("tcp service %s/%s is not in the parent resource namespace %s", ns, service.Name, parentNamespace)
}
servers, err := p.loadTCPServers(client, ns, service)
+409 -10
View File
@@ -259,7 +259,7 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
},
{
desc: "Simple Ingress Route, with foo entrypoint and crossprovider middleware",
paths: []string{"tcp/services.yml", "tcp/with_middleware_crossprovider.yml"},
paths: []string{"tcp/services.yml", "tcp/with_middleware_cross_provider.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
@@ -1813,12 +1813,13 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
func TestLoadIngressRoutes(t *testing.T) {
testCases := []struct {
desc string
ingressClass string
paths []string
expected *dynamic.Configuration
allowCrossNamespace bool
allowEmptyServices bool
desc string
ingressClass string
paths []string
expected *dynamic.Configuration
allowCrossNamespace bool
allowEmptyServices bool
crossProviderNamespaces []string
}{
{
desc: "Empty",
@@ -2104,9 +2105,10 @@ func TestLoadIngressRoutes(t *testing.T) {
},
},
{
desc: "Simple Ingress Route with middleware crossprovider",
allowCrossNamespace: true,
paths: []string{"services.yml", "with_middleware_crossprovider.yml"},
desc: "Simple Ingress Route with middleware crossprovider",
crossProviderNamespaces: []string{"default"},
allowCrossNamespace: true,
paths: []string{"services.yml", "with_middleware_cross_provider.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
@@ -5470,6 +5472,16 @@ func TestLoadIngressRoutes(t *testing.T) {
PingTimeout: ptypes.Duration(42 * time.Second),
},
PeerCertURI: "foo://bar",
PeerCertSANs: []tls.SAN{
{
Type: tls.SANDNSNameType,
Value: "foo.com",
},
{
Type: tls.SANURIType,
Value: "foo://bar",
},
},
Spiffe: &dynamic.Spiffe{
IDs: []string{
"spiffe://foo/buz",
@@ -6389,6 +6401,7 @@ func TestLoadIngressRoutes(t *testing.T) {
AllowCrossNamespace: test.allowCrossNamespace,
AllowExternalNameServices: true,
AllowEmptyServices: test.allowEmptyServices,
CrossProviderNamespaces: test.crossProviderNamespaces,
}
conf := p.loadConfigurationFromCRD(t.Context(), client)
@@ -8676,6 +8689,392 @@ func TestCrossNamespace(t *testing.T) {
}
}
func Test_isCrossProviderNamespaceAllowed(t *testing.T) {
testCases := []struct {
desc string
allowList []string
namespace string
want bool
}{
{desc: "nil allowList allows any namespace", allowList: nil, namespace: "ns-a", want: true},
{desc: "empty allowList denies every namespace", allowList: []string{}, namespace: "ns-a", want: false},
{desc: "namespace in allowList is accepted", allowList: []string{"ns-a"}, namespace: "ns-a", want: true},
{desc: "namespace not in allowList is rejected", allowList: []string{"ns-b"}, namespace: "ns-a", want: false},
{desc: "namespace among multiple allowed entries is accepted", allowList: []string{"ns-a", "ns-b"}, namespace: "ns-b", want: true},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
got := isCrossProviderNamespaceAllowed(test.allowList, test.namespace)
assert.Equal(t, test.want, got)
})
}
}
// TestCrossProviderNamespaces_HTTPMiddleware verifies that the
// CrossProviderNamespaces option gates middleware references.
// Plain in-namespace middleware references are not affected.
func TestCrossProviderNamespaces_HTTPMiddleware(t *testing.T) {
testCases := []struct {
desc string
crossProviderNamespaces []string
wantMiddlewares []string
wantRouterDropped bool
}{
{
desc: "nil: cross-provider middleware refs are accepted (backward compatible)",
crossProviderNamespaces: nil,
wantMiddlewares: []string{"default-stripprefix", "foo-addprefix", "basicauth@file", "redirect@file"},
},
{
desc: "empty list: cross-provider middleware refs are rejected, IngressRoute is dropped",
crossProviderNamespaces: []string{},
wantRouterDropped: true,
},
{
desc: "namespace allowed: cross-provider middleware refs are accepted",
crossProviderNamespaces: []string{"default"},
wantMiddlewares: []string{"default-stripprefix", "foo-addprefix", "basicauth@file", "redirect@file"},
},
{
desc: "namespace not allowed: cross-provider middleware refs are rejected, IngressRoute is dropped",
crossProviderNamespaces: []string{"other"},
wantRouterDropped: true,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
k8sObjects, crdObjects := readResources(t, []string{"services.yml", "with_middleware_cross_provider.yml"})
kubeClient := kubefake.NewClientset(k8sObjects...)
crdClient := traefikcrdfake.NewClientset(crdObjects...)
client := newClientImpl(kubeClient, crdClient)
stopCh := make(chan struct{})
eventCh, err := client.WatchAll(nil, stopCh)
require.NoError(t, err)
if k8sObjects != nil || crdObjects != nil {
// just wait for the first event
<-eventCh
}
p := Provider{
AllowCrossNamespace: true,
CrossProviderNamespaces: test.crossProviderNamespaces,
}
conf := p.loadConfigurationFromCRD(t.Context(), client)
router, ok := conf.HTTP.Routers["default-test2-route-23c7f4c450289ee29016"]
if test.wantRouterDropped {
assert.False(t, ok)
return
}
assert.True(t, ok)
assert.Equal(t, test.wantMiddlewares, router.Middlewares)
})
}
}
// TestCrossProviderNamespaces_HTTPServiceTransitivity verifies that the option for a TraefikService chain
// (here: IngressRoute -> Mirror / Weighted TraefikService -> @file service).
func TestCrossProviderNamespaces_HTTPServiceTransitivity(t *testing.T) {
testCases := []struct {
desc string
crossProviderNamespaces []string
wantMirrorService bool
wantWeightedService bool
}{
{
desc: "nil: cross-provider service refs accepted (backward compatible)",
crossProviderNamespaces: nil,
wantMirrorService: true,
wantWeightedService: true,
},
{
desc: "empty list: both Mirror and Weighted TraefikServices are rejected",
crossProviderNamespaces: []string{},
wantMirrorService: false,
wantWeightedService: false,
},
{
desc: "only the Mirror's namespace is allowed: Weighted is still rejected",
crossProviderNamespaces: []string{"foo"},
wantMirrorService: true,
wantWeightedService: false,
},
{
desc: "only the Weighted's namespace is allowed: Mirror is still rejected",
crossProviderNamespaces: []string{"bar"},
wantMirrorService: false,
wantWeightedService: true,
},
{
desc: "both namespaces allowed: both TraefikServices are accepted",
crossProviderNamespaces: []string{"foo", "bar"},
wantMirrorService: true,
wantWeightedService: true,
},
{
desc: "originating IngressRoute namespace alone is not enough: TraefikService namespace must also be allowed",
crossProviderNamespaces: []string{"default"},
wantMirrorService: false,
wantWeightedService: false,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
k8sObjects, crdObjects := readResources(t, []string{"services.yml", "with_service_cross_provider.yml"})
kubeClient := kubefake.NewClientset(k8sObjects...)
crdClient := traefikcrdfake.NewClientset(crdObjects...)
client := newClientImpl(kubeClient, crdClient)
stopCh := make(chan struct{})
eventCh, err := client.WatchAll(nil, stopCh)
require.NoError(t, err)
if k8sObjects != nil || crdObjects != nil {
// just wait for the first event
<-eventCh
}
p := Provider{
AllowCrossNamespace: true,
CrossProviderNamespaces: test.crossProviderNamespaces,
}
conf := p.loadConfigurationFromCRD(t.Context(), client)
_, mirrorOK := conf.HTTP.Services["foo-mirror-cp"]
_, weightedOK := conf.HTTP.Services["bar-weighted-cp"]
assert.Equal(t, test.wantMirrorService, mirrorOK)
assert.Equal(t, test.wantWeightedService, weightedOK)
})
}
}
// TestCrossProviderNamespaces_HTTPTLSOption verifies that the
// CrossProviderNamespaces option gates @file references in IngressRoute tls.options.
func TestCrossProviderNamespaces_HTTPTLSOption(t *testing.T) {
testCases := []struct {
desc string
crossProviderNamespaces []string
wantRouterDropped bool
}{
{
desc: "nil: cross-provider TLSOption ref is accepted (backward compatible)",
crossProviderNamespaces: nil,
},
{
desc: "empty list: cross-provider TLSOption ref is rejected, IngressRoute is dropped",
crossProviderNamespaces: []string{},
wantRouterDropped: true,
},
{
desc: "namespace allowed: cross-provider TLSOption ref is accepted",
crossProviderNamespaces: []string{"default"},
},
{
desc: "namespace not allowed: cross-provider TLSOption ref is rejected, IngressRoute is dropped",
crossProviderNamespaces: []string{"other"},
wantRouterDropped: true,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
k8sObjects, crdObjects := readResources(t, []string{"services.yml", "with_tls_option_cross_provider.yml"})
kubeClient := kubefake.NewClientset(k8sObjects...)
crdClient := traefikcrdfake.NewClientset(crdObjects...)
client := newClientImpl(kubeClient, crdClient)
stopCh := make(chan struct{})
eventCh, err := client.WatchAll(nil, stopCh)
require.NoError(t, err)
if k8sObjects != nil || crdObjects != nil {
// just wait for the first event
<-eventCh
}
p := Provider{
AllowCrossNamespace: true,
CrossProviderNamespaces: test.crossProviderNamespaces,
}
conf := p.loadConfigurationFromCRD(t.Context(), client)
router, ok := conf.HTTP.Routers["default-test-route-6b204d94623b3df4370c"]
if test.wantRouterDropped {
assert.False(t, ok)
return
}
require.True(t, ok)
require.NotNil(t, router.TLS)
assert.Equal(t, "foo@file", router.TLS.Options)
})
}
}
// TestCrossProviderNamespaces_TCPTLSOption verifies that the
// CrossProviderNamespaces option gates @file references in IngressRouteTCP tls.options.
func TestCrossProviderNamespaces_TCPTLSOption(t *testing.T) {
testCases := []struct {
desc string
crossProviderNamespaces []string
wantRouterDropped bool
}{
{
desc: "nil: cross-provider TLSOption ref is accepted (backward compatible)",
crossProviderNamespaces: nil,
},
{
desc: "empty list: cross-provider TLSOption ref is rejected, IngressRouteTCP is dropped",
crossProviderNamespaces: []string{},
wantRouterDropped: true,
},
{
desc: "namespace allowed: cross-provider TLSOption ref is accepted",
crossProviderNamespaces: []string{"default"},
},
{
desc: "namespace not allowed: cross-provider TLSOption ref is rejected, IngressRouteTCP is dropped",
crossProviderNamespaces: []string{"other"},
wantRouterDropped: true,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
k8sObjects, crdObjects := readResources(t, []string{"tcp/services.yml", "tcp/with_tls_options_cross_provider.yml"})
kubeClient := kubefake.NewClientset(k8sObjects...)
crdClient := traefikcrdfake.NewClientset(crdObjects...)
client := newClientImpl(kubeClient, crdClient)
stopCh := make(chan struct{})
eventCh, err := client.WatchAll(nil, stopCh)
require.NoError(t, err)
if k8sObjects != nil || crdObjects != nil {
// just wait for the first event
<-eventCh
}
p := Provider{
AllowCrossNamespace: true,
CrossProviderNamespaces: test.crossProviderNamespaces,
}
conf := p.loadConfigurationFromCRD(t.Context(), client)
router, ok := conf.TCP.Routers["default-test.route-fdd3e9338e47a45efefc"]
if test.wantRouterDropped {
assert.False(t, ok)
return
}
require.True(t, ok)
require.NotNil(t, router.TLS)
assert.Equal(t, "foo@file", router.TLS.Options)
})
}
}
// TestCrossProviderNamespaces_HTTPServersTransport verifies that the
// CrossProviderNamespaces option gates @file references in service.serversTransport.
func TestCrossProviderNamespaces_HTTPServersTransport(t *testing.T) {
testCases := []struct {
desc string
crossProviderNamespaces []string
wantServiceDropped bool
}{
{
desc: "nil: cross-provider ServersTransport ref is accepted (backward compatible)",
crossProviderNamespaces: nil,
},
{
desc: "empty list: cross-provider ServersTransport ref is rejected, service is dropped",
crossProviderNamespaces: []string{},
wantServiceDropped: true,
},
{
desc: "namespace allowed: cross-provider ServersTransport ref is accepted",
crossProviderNamespaces: []string{"default"},
},
{
desc: "namespace not allowed: cross-provider ServersTransport ref is rejected, service is dropped",
crossProviderNamespaces: []string{"other"},
wantServiceDropped: true,
},
}
for _, test := range testCases {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
k8sObjects, crdObjects := readResources(t, []string{"services.yml", "with_servers_transport_cross_provider.yml"})
kubeClient := kubefake.NewClientset(k8sObjects...)
crdClient := traefikcrdfake.NewClientset(crdObjects...)
client := newClientImpl(kubeClient, crdClient)
stopCh := make(chan struct{})
eventCh, err := client.WatchAll(nil, stopCh)
require.NoError(t, err)
if k8sObjects != nil || crdObjects != nil {
// just wait for the first event
<-eventCh
}
p := Provider{
AllowCrossNamespace: true,
CrossProviderNamespaces: test.crossProviderNamespaces,
}
conf := p.loadConfigurationFromCRD(t.Context(), client)
service, ok := conf.HTTP.Services["default-test-route-6b204d94623b3df4370c"]
if test.wantServiceDropped {
assert.False(t, ok)
return
}
require.True(t, ok)
require.NotNil(t, service.LoadBalancer)
assert.Equal(t, "foo@file", service.LoadBalancer.ServersTransport)
})
}
}
func TestExternalNameService(t *testing.T) {
testCases := []struct {
desc string
@@ -2,6 +2,7 @@ package v1alpha1
import (
"github.com/traefik/traefik/v3/pkg/config/dynamic"
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
@@ -53,7 +54,11 @@ type ServersTransportSpec struct {
// DisableHTTP2 disables HTTP/2 for connections with backend servers.
DisableHTTP2 bool `json:"disableHTTP2,omitempty"`
// PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
//
// Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
PeerCertURI string `json:"peerCertURI,omitempty"`
// PeerCertSANs defines the peer cert Subject Alternative Names used to match against SAN during the peer certificate verification.
PeerCertSANs []traefiktls.SAN `json:"peerCertSANs,omitempty"`
// Spiffe defines the SPIFFE configuration.
Spiffe *dynamic.Spiffe `json:"spiffe,omitempty"`
}
@@ -2,6 +2,7 @@ package v1alpha1
import (
"github.com/traefik/traefik/v3/pkg/config/dynamic"
traefiktls "github.com/traefik/traefik/v3/pkg/tls"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
@@ -59,9 +60,12 @@ type TLSClientConfig struct {
RootCAsSecrets []string `json:"rootCAsSecrets,omitempty"`
// CertificatesSecrets defines a list of secret storing client certificates for mTLS.
CertificatesSecrets []string `json:"certificatesSecrets,omitempty"`
// MaxIdleConnsPerHost controls the maximum idle (keep-alive) to keep per-host.
// PeerCertURI defines the peer cert URI used to match against SAN URI during the peer certificate verification.
//
// Deprecated: PeerCertURI is deprecated, please use the PeerCertSANs option instead.
PeerCertURI string `json:"peerCertURI,omitempty"`
// PeerCertSANs defines the peer cert Subject Alternative Names used to match against SAN during the peer certificate verification.
PeerCertSANs []traefiktls.SAN `json:"peerCertSANs,omitempty"`
// Spiffe defines the SPIFFE configuration.
Spiffe *dynamic.Spiffe `json:"spiffe,omitempty"`
}
@@ -1618,6 +1618,11 @@ func (in *ServersTransportSpec) DeepCopyInto(out *ServersTransportSpec) {
*out = new(ForwardingTimeouts)
(*in).DeepCopyInto(*out)
}
if in.PeerCertSANs != nil {
in, out := &in.PeerCertSANs, &out.PeerCertSANs
*out = make([]tls.SAN, len(*in))
copy(*out, *in)
}
if in.Spiffe != nil {
in, out := &in.Spiffe, &out.Spiffe
*out = new(dynamic.Spiffe)
@@ -1871,6 +1876,11 @@ func (in *TLSClientConfig) DeepCopyInto(out *TLSClientConfig) {
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.PeerCertSANs != nil {
in, out := &in.PeerCertSANs, &out.PeerCertSANs
*out = make([]tls.SAN, len(*in))
copy(*out, *in)
}
if in.Spiffe != nil {
in, out := &in.Spiffe, &out.Spiffe
*out = new(dynamic.Spiffe)
+17 -15
View File
@@ -49,7 +49,10 @@ type clientWrapper struct {
experimentalChannel bool
}
func createClientFromConfig(c *rest.Config) (*clientWrapper, error) {
func createClientFromConfig(c *rest.Config, qps, burst int) (*clientWrapper, error) {
c.QPS = float32(qps)
c.Burst = burst
csGateway, err := gateclientset.NewForConfig(c)
if err != nil {
return nil, err
@@ -75,7 +78,7 @@ func newClientImpl(csKube kclientset.Interface, csGateway gateclientset.Interfac
// newInClusterClient returns a new Provider client that is expected to run
// inside the cluster.
func newInClusterClient(endpoint string) (*clientWrapper, error) {
func newInClusterClient(endpoint string, qps, burst int) (*clientWrapper, error) {
config, err := rest.InClusterConfig()
if err != nil {
return nil, fmt.Errorf("failed to create in-cluster configuration: %w", err)
@@ -85,20 +88,20 @@ func newInClusterClient(endpoint string) (*clientWrapper, error) {
config.Host = endpoint
}
return createClientFromConfig(config)
return createClientFromConfig(config, qps, burst)
}
func newExternalClusterClientFromFile(file string) (*clientWrapper, error) {
func newExternalClusterClientFromFile(file string, qps, burst int) (*clientWrapper, error) {
configFromFlags, err := clientcmd.BuildConfigFromFlags("", file)
if err != nil {
return nil, err
}
return createClientFromConfig(configFromFlags)
return createClientFromConfig(configFromFlags, qps, burst)
}
// newExternalClusterClient returns a new Provider client that may run outside of the cluster.
// The endpoint parameter must not be empty.
func newExternalClusterClient(endpoint, caFilePath string, token types.FileOrContent) (*clientWrapper, error) {
func newExternalClusterClient(endpoint, caFilePath string, token types.FileOrContent, qps, burst int) (*clientWrapper, error) {
if endpoint == "" {
return nil, errors.New("endpoint missing for external cluster client")
}
@@ -122,7 +125,7 @@ func newExternalClusterClient(endpoint, caFilePath string, token types.FileOrCon
config.TLSClientConfig = rest.TLSClientConfig{CAData: caData}
}
return createClientFromConfig(config)
return createClientFromConfig(config, qps, burst)
}
// WatchAll starts namespace-specific controllers for all relevant kinds.
@@ -145,20 +148,20 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
options.LabelSelector = c.labelSelector
}
c.factoryNamespace = kinformers.NewSharedInformerFactory(c.csKube, resyncPeriod)
c.factoryNamespace = kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithTransform(k8s.StripManagedFields))
_, err := c.factoryNamespace.Core().V1().Namespaces().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
}
c.factoryGatewayClass = gateinformers.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, gateinformers.WithTweakListOptions(labelSelectorOptions))
c.factoryGatewayClass = gateinformers.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, gateinformers.WithTweakListOptions(labelSelectorOptions), gateinformers.WithTransform(k8s.StripManagedFields))
_, err = c.factoryGatewayClass.Gateway().V1().GatewayClasses().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
}
for _, ns := range namespaces {
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns))
factoryKube := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factoryKube.Core().V1().Services().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@@ -168,7 +171,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
return nil, err
}
factoryGateway := gateinformers.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, gateinformers.WithNamespace(ns))
factoryGateway := gateinformers.NewSharedInformerFactoryWithOptions(c.csGateway, resyncPeriod, gateinformers.WithNamespace(ns), gateinformers.WithTransform(k8s.StripManagedFields))
_, err = factoryGateway.Gateway().V1().Gateways().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@@ -206,7 +209,7 @@ func (c *clientWrapper) WatchAll(namespaces []string, stopCh <-chan struct{}) (<
}
}
factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm))
factorySecret := kinformers.NewSharedInformerFactoryWithOptions(c.csKube, resyncPeriod, kinformers.WithNamespace(ns), kinformers.WithTweakListOptions(notOwnedByHelm), kinformers.WithTransform(k8s.StripManagedFields))
_, err = factorySecret.Core().V1().Secrets().Informer().AddEventHandler(eventHandler)
if err != nil {
return nil, err
@@ -718,9 +721,8 @@ func (c *clientWrapper) UpdateBackendTLSPolicyStatus(ctx context.Context, policy
ancestorStatuses := make([]gatev1.PolicyAncestorStatus, len(status.Ancestors))
copy(ancestorStatuses, status.Ancestors)
// keep statuses added by other gateway controllers,
// and statuses for Traefik gateway controller but not for the same Gateway as the one in parameter (AncestorRef).
for _, ancestorStatus := range currentPolicy.Status.Ancestors {
// Keep statuses added by other gateway controllers.
if ancestorStatus.ControllerName != controllerName {
ancestorStatuses = append(ancestorStatuses, ancestorStatus)
continue
@@ -731,7 +733,7 @@ func (c *clientWrapper) UpdateBackendTLSPolicyStatus(ctx context.Context, policy
return fmt.Errorf("failed to update BackendTLSPolicy %s/%s status: PolicyAncestor statuses count exceeds 16", policy.Namespace, policy.Name)
}
// do not update status when nothing has changed.
// Do not update status when nothing has changed.
if policyAncestorStatusesEqual(currentPolicy.Status.Ancestors, ancestorStatuses) {
return nil
}
@@ -15,6 +15,7 @@ var SupportedFeatures = sync.OnceValue(func() []features.FeatureName {
Insert(features.HTTPRouteExtendedFeatures.Intersection(extendedHTTPRouteFeatures()).UnsortedList()...).
Insert(features.ReferenceGrantCoreFeatures.UnsortedList()...).
Insert(features.BackendTLSPolicyCoreFeatures.UnsortedList()...).
Insert(features.BackendTLSPolicyExtendedFeatures.Intersection(extendedBackendTLSPolicyFeatures()).UnsortedList()...).
Insert(features.GRPCRouteCoreFeatures.UnsortedList()...).
Insert(features.TLSRouteCoreFeatures.UnsortedList()...).
Insert(features.TLSRouteExtendedFeatures.Intersection(extendedTLSRouteFeatures()).UnsortedList()...)
@@ -56,3 +57,10 @@ func extendedHTTPRouteFeatures() sets.Set[features.Feature] {
features.HTTPRouteBackendRequestHeaderModificationFeature,
)
}
// extendedBackendTLSPolicyFeatures returns the supported extended BackendTLSPolicy features.
func extendedBackendTLSPolicyFeatures() sets.Set[features.Feature] {
return sets.New(
features.BackendTLSPolicySanValidationFeature,
)
}
@@ -0,0 +1,108 @@
---
kind: GatewayClass
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: my-gateway-class
spec:
controllerName: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- name: web
protocol: HTTP
port: 80
allowedRoutes:
kinds:
- kind: GRPCRoute
group: gateway.networking.k8s.io
namespaces:
from: Same
---
kind: GRPCRoute
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: grpc-app-1
namespace: default
spec:
parentRefs:
- name: my-gateway
kind: Gateway
group: gateway.networking.k8s.io
hostnames:
- foo.com
rules:
- backendRefs:
- name: whoami
port: 80
weight: 1
---
kind: BackendTLSPolicy
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: backend-tls-policy
namespace: default
spec:
targetRefs:
- group: ""
kind: Service
name: whoami
validation:
hostname: whoami
caCertificateRefs:
- group: ""
kind: ConfigMap
name: ca-file
- group: core
kind: ConfigMap
name: ca-file-2
- group: ""
kind: Secret
name: ca-file
- group: core
kind: Secret
name: ca-file-2
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ca-file
namespace: default
data:
ca.crt: "CA1"
---
apiVersion: v1
kind: ConfigMap
metadata:
name: ca-file-2
namespace: default
data:
ca.crt: "CA2"
---
apiVersion: v1
kind: Secret
metadata:
name: ca-file
namespace: default
data:
ca.crt: Q0ExLXNlY3JldA==
---
apiVersion: v1
kind: Secret
metadata:
name: ca-file-2
namespace: default
data:
ca.crt: Q0EyLXNlY3JldA==
@@ -0,0 +1,64 @@
---
kind: GatewayClass
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: my-gateway-class
spec:
controllerName: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- name: web
protocol: HTTP
port: 80
allowedRoutes:
kinds:
- kind: GRPCRoute
group: gateway.networking.k8s.io
namespaces:
from: Same
---
kind: GRPCRoute
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: grpc-app-1
namespace: default
spec:
parentRefs:
- name: my-gateway
kind: Gateway
group: gateway.networking.k8s.io
hostnames:
- foo.com
rules:
- backendRefs:
- name: whoami
port: 80
weight: 1
---
kind: BackendTLSPolicy
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: backend-tls-policy
namespace: default
spec:
targetRefs:
- group: ""
kind: Service
name: whoami
validation:
hostname: whoami
subjectAltNames:
- type: Hostname
hostname: whoami.default.svc.cluster.local
- type: URI
uri: spiffe://cluster.local/ns/default/sa/whoami
@@ -0,0 +1,60 @@
---
kind: GatewayClass
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: my-gateway-class
spec:
controllerName: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- name: http
protocol: HTTP
port: 80
allowedRoutes:
kinds:
- kind: GRPCRoute
group: gateway.networking.k8s.io
namespaces:
from: Same
---
kind: GRPCRoute
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: grpc-app-1
namespace: default
spec:
parentRefs:
- name: my-gateway
kind: Gateway
group: gateway.networking.k8s.io
hostnames:
- foo.com
rules:
- backendRefs:
- name: whoami
port: 80
weight: 1
---
kind: BackendTLSPolicy
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: backend-tls-policy
namespace: default
spec:
targetRefs:
- group: core
kind: Service
name: whoami
validation:
hostname: whoami
wellKnownCACertificates: System
@@ -0,0 +1,55 @@
---
kind: GatewayClass
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: my-gateway-class
spec:
controllerName: traefik.io/gateway-controller
---
kind: Gateway
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: my-gateway-class
listeners: # Use GatewayClass defaults for listener definition.
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same
---
kind: HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
metadata:
name: http-app-1
namespace: default
spec:
parentRefs:
- name: my-gateway
kind: Gateway
group: gateway.networking.k8s.io
hostnames:
- "foo.com"
rules:
- matches:
- path:
type: Exact
value: /bar
backendRefs:
- weight: 1
group: traefik.io
kind: TraefikService
name: service@file
namespace: bar
port: 80
- name: whoami
port: 80
weight: 1
group: ""
kind: Service

Some files were not shown because too many files have changed in this diff Show More