diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c5e1a28c..43f9eb587 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,46 @@ +## [v2.11.1](https://github.com/traefik/traefik/tree/v2.11.1) (2024-04-10) +[All Commits](https://github.com/traefik/traefik/compare/v2.11.0...v2.11.1) + +**Bug fixes:** +- **[acme,tls]** Enforce handling of ACME-TLS/1 challenges ([#10536](https://github.com/traefik/traefik/pull/10536) by [rtribotte](https://github.com/rtribotte)) +- **[acme]** Update go-acme/lego to v4.16.1 ([#10508](https://github.com/traefik/traefik/pull/10508) by [ldez](https://github.com/ldez)) +- **[acme]** Close created file in ACME local store CheckFile func ([#10574](https://github.com/traefik/traefik/pull/10574) by [testwill](https://github.com/testwill)) +- **[docker,http3]** Update to quic-go v0.42.0 and docker/cli v24.0.9 ([#10572](https://github.com/traefik/traefik/pull/10572) by [mloiseleur](https://github.com/mloiseleur)) +- **[docker,marathon,rancher,ecs,tls,nomad]** Allow to configure TLSStore default generated certificate with labels ([#10439](https://github.com/traefik/traefik/pull/10439) by [kevinpollet](https://github.com/kevinpollet)) +- **[ecs]** Adjust ECS network interface detection logic ([#10550](https://github.com/traefik/traefik/pull/10550) by [amaxine](https://github.com/amaxine)) +- **[logs,tls]** Fix log when default TLSStore and TLSOptions are defined multiple times ([#10499](https://github.com/traefik/traefik/pull/10499) by [rtribotte](https://github.com/rtribotte)) +- **[middleware]** Allow empty replacement with ReplacePathRegex middleware ([#10538](https://github.com/traefik/traefik/pull/10538) by [rtribotte](https://github.com/rtribotte)) +- **[plugins]** Update Yaegi to v0.16.1 ([#10565](https://github.com/traefik/traefik/pull/10565) by [ldez](https://github.com/ldez)) +- **[provider,rules]** Don't allow routers higher than internal ones ([#10428](https://github.com/traefik/traefik/pull/10428) by [ldez](https://github.com/ldez)) +- **[rules]** Reserve priority range for internal routers ([#10541](https://github.com/traefik/traefik/pull/10541) by [youkoulayley](https://github.com/youkoulayley)) +- **[server,tcp]** Introduce Lingering Timeout ([#10569](https://github.com/traefik/traefik/pull/10569) by [rtribotte](https://github.com/rtribotte)) +- **[tcp]** Enforce failure for TCP HostSNI with hostname ([#10540](https://github.com/traefik/traefik/pull/10540) by [youkoulayley](https://github.com/youkoulayley)) +- **[tracing]** Bump Elastic APM to v2.4.8 ([#10512](https://github.com/traefik/traefik/pull/10512) by [rtribotte](https://github.com/rtribotte)) +- **[webui]** Fix dashboard exposition through a router ([#10518](https://github.com/traefik/traefik/pull/10518) by [mmatur](https://github.com/mmatur)) +- **[webui]** Display IPAllowlist middleware configuration in dashboard ([#10459](https://github.com/traefik/traefik/pull/10459) by [youkoulayley](https://github.com/youkoulayley)) +- **[webui]** Make text more readable in dark mode ([#10473](https://github.com/traefik/traefik/pull/10473) by [hood](https://github.com/hood)) +- **[webui]** Migrate to Quasar 2.x and Vue.js 3.x ([#10416](https://github.com/traefik/traefik/pull/10416) by [andsarr](https://github.com/andsarr)) +- **[webui]** Add a horizontal scroll for the mobile view ([#10480](https://github.com/traefik/traefik/pull/10480) by [framebassman](https://github.com/framebassman)) + +**Documentation:** +- **[acme]** Update gandiv5 env variable in providers table ([#10506](https://github.com/traefik/traefik/pull/10506) by [dominiwe](https://github.com/dominiwe)) +- **[acme]** Fix multiple dns provider documentation ([#10496](https://github.com/traefik/traefik/pull/10496) by [mmatur](https://github.com/mmatur)) +- **[docker]** Fix paragraph in entrypoints and Docker docs ([#10491](https://github.com/traefik/traefik/pull/10491) by [luigir-it](https://github.com/luigir-it)) +- **[k8s]** Improve middleware example ([#10532](https://github.com/traefik/traefik/pull/10532) by [mloiseleur](https://github.com/mloiseleur)) +- **[metrics]** Fix host header mention in prometheus metrics doc ([#10502](https://github.com/traefik/traefik/pull/10502) by [MorphBonehunter](https://github.com/MorphBonehunter)) +- **[metrics]** Fix typo in statsd metrics docs ([#10437](https://github.com/traefik/traefik/pull/10437) by [xpac1985](https://github.com/xpac1985)) +- **[middleware]** Improve excludedIPs example with IPWhiteList and IPAllowList middleware ([#10554](https://github.com/traefik/traefik/pull/10554) by [mloiseleur](https://github.com/mloiseleur)) +- **[nomad]** Improve documentation about Nomad ACL minimum rights ([#10482](https://github.com/traefik/traefik/pull/10482) by [Thadir](https://github.com/Thadir)) +- **[server]** Add specification for TCP TLS routers in documentation ([#10510](https://github.com/traefik/traefik/pull/10510) by [shivanipawar00](https://github.com/shivanipawar00)) +- **[tls]** Fix default value for peerCertURI option ([#10470](https://github.com/traefik/traefik/pull/10470) by [marcmognol](https://github.com/marcmognol)) +- Update releases page ([#10449](https://github.com/traefik/traefik/pull/10449) by [ldez](https://github.com/ldez)) +- Update releases page ([#10443](https://github.com/traefik/traefik/pull/10443) by [ldez](https://github.com/ldez)) +- Add youkoulayley to maintainers ([#10517](https://github.com/traefik/traefik/pull/10517) by [emilevauge](https://github.com/emilevauge)) +- Add sdelicata to maintainers ([#10515](https://github.com/traefik/traefik/pull/10515) by [emilevauge](https://github.com/emilevauge)) + +**Misc:** +- **[webui]** Modify the Hub Button ([#10583](https://github.com/traefik/traefik/pull/10583) by [mdeliatf](https://github.com/mdeliatf)) + ## [v3.0.0-rc3](https://github.com/traefik/traefik/tree/v3.0.0-rc3) (2024-03-13) [All Commits](https://github.com/traefik/traefik/compare/v3.0.0-rc2...v3.0.0-rc3) diff --git a/docs/content/middlewares/http/ipallowlist.md b/docs/content/middlewares/http/ipallowlist.md index d62e253bb..ec7d70e03 100644 --- a/docs/content/middlewares/http/ipallowlist.md +++ b/docs/content/middlewares/http/ipallowlist.md @@ -8,11 +8,11 @@ description: "Learn how to use IPAllowList in HTTP middleware for limiting clien Limiting Clients to Specific IPs {: .subtitle } -IPAllowList accepts / refuses requests based on the client IP. +IPAllowList limits allowed requests based on the client IP. ## Configuration Examples -```yaml tab="Docker & Swarm" +```yaml tab="Docker" # Accepts request from defined IP labels: - "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7" @@ -35,6 +35,18 @@ spec: - "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7" ``` +```json tab="Marathon" +"labels": { + "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange": "127.0.0.1/32,192.168.1.7" +} +``` + +```yaml tab="Rancher" +# Accepts request from defined IP +labels: + - "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7" +``` + ```yaml tab="File (YAML)" # Accepts request from defined IP http: @@ -57,6 +69,8 @@ http: ### `sourceRange` +_Required_ + The `sourceRange` option sets the allowed IPs (or ranges of allowed IPs by using CIDR notation). ### `ipStrategy` @@ -83,7 +97,7 @@ The `depth` option tells Traefik to use the `X-Forwarded-For` header and take th | `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `3` | `"11.0.0.1"` | | `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `5` | `""` | -```yaml tab="Docker & Swarm" +```yaml tab="Docker" # Allowlisting Based on `X-Forwarded-For` with `depth=2` labels: - "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7" @@ -111,6 +125,20 @@ spec: - "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.depth=2" ``` +```json tab="Marathon" +"labels": { + "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange": "127.0.0.1/32, 192.168.1.7", + "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.depth": "2" +} +``` + +```yaml tab="Rancher" +# Whitelisting Based on `X-Forwarded-For` with `depth=2` +labels: + - "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourcerange=127.0.0.1/32, 192.168.1.7" + - "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.depth=2" +``` + ```yaml tab="File (YAML)" # Allowlisting Based on `X-Forwarded-For` with `depth=2` http: @@ -149,9 +177,10 @@ http: | `"10.0.0.1,11.0.0.1,12.0.0.1,13.0.0.1"` | `"15.0.0.1,16.0.0.1"` | `"13.0.0.1"` | | `"10.0.0.1,11.0.0.1"` | `"10.0.0.1,11.0.0.1"` | `""` | -```yaml tab="Docker & Swarm" +```yaml tab="Docker" # Exclude from `X-Forwarded-For` labels: + - "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourceRange=127.0.0.1/32, 192.168.1.0/24" - "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7" ``` @@ -163,6 +192,9 @@ metadata: name: test-ipallowlist spec: ipAllowList: + sourceRange: + - 127.0.0.1/32 + - 192.168.1.0/24 ipStrategy: excludedIPs: - 127.0.0.1/32 @@ -171,25 +203,44 @@ spec: ```yaml tab="Consul Catalog" # Exclude from `X-Forwarded-For` +- "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourceRange=127.0.0.1/32, 192.168.1.0/24" - "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7" ``` +```json tab="Marathon" +"labels": { + "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourceRange=127.0.0.1/32, 192.168.1.0/24" + "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.excludedips": "127.0.0.1/32, 192.168.1.7" +} +``` + +```yaml tab="Rancher" +# Exclude from `X-Forwarded-For` +labels: + - "traefik.http.middlewares.test-ipallowlist.ipallowlist.sourceRange=127.0.0.1/32, 192.168.1.0/24" + - "traefik.http.middlewares.test-ipallowlist.ipallowlist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7" +``` + ```yaml tab="File (YAML)" # Exclude from `X-Forwarded-For` http: middlewares: test-ipallowlist: ipAllowList: + sourceRange: + - 127.0.0.1/32 + - 192.168.1.0/24 ipStrategy: excludedIPs: - - "127.0.0.1/32" - - "192.168.1.7" + - 127.0.0.1/32 + - 192.168.1.7 ``` ```toml tab="File (TOML)" # Exclude from `X-Forwarded-For` [http.middlewares] [http.middlewares.test-ipallowlist.ipAllowList] + sourceRange = ["127.0.0.1/32", "192.168.1.0/24"] [http.middlewares.test-ipallowlist.ipAllowList.ipStrategy] excludedIPs = ["127.0.0.1/32", "192.168.1.7"] ``` diff --git a/docs/content/middlewares/http/ipwhitelist.md b/docs/content/middlewares/http/ipwhitelist.md index e093ad0a9..f25960a52 100644 --- a/docs/content/middlewares/http/ipwhitelist.md +++ b/docs/content/middlewares/http/ipwhitelist.md @@ -10,7 +10,7 @@ Limiting Clients to Specific IPs ![IPWhiteList](../../assets/img/middleware/ipwhitelist.png) -IPWhiteList accepts / refuses requests based on the client IP. +IPWhiteList limits allowed requests based on the client IP. !!! warning @@ -63,6 +63,8 @@ http: ### `sourceRange` +_Required_ + The `sourceRange` option sets the allowed IPs (or ranges of allowed IPs by using CIDR notation). ### `ipStrategy` @@ -158,6 +160,7 @@ http: ```yaml tab="Docker" # Exclude from `X-Forwarded-For` labels: + - "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourceRange=127.0.0.1/32, 192.168.1.0/24" - "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7" ``` @@ -170,6 +173,9 @@ metadata: spec: ipWhiteList: ipStrategy: + sourceRange: + - 127.0.0.1/32 + - 192.168.1.0/24 excludedIPs: - 127.0.0.1/32 - 192.168.1.7 @@ -177,6 +183,7 @@ spec: ```yaml tab="Consul Catalog" # Exclude from `X-Forwarded-For` +- "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.sourceRange=127.0.0.1/32, 192.168.1.0/24" - "traefik.http.middlewares.test-ipwhitelist.ipwhitelist.ipstrategy.excludedips=127.0.0.1/32, 192.168.1.7" ``` @@ -186,16 +193,20 @@ http: middlewares: test-ipwhitelist: ipWhiteList: + sourceRange: + - 127.0.0.1/32 + - 192.168.1.0/24 ipStrategy: excludedIPs: - - "127.0.0.1/32" - - "192.168.1.7" + - 127.0.0.1/32 + - 192.168.1.7 ``` ```toml tab="File (TOML)" # Exclude from `X-Forwarded-For` [http.middlewares] [http.middlewares.test-ipwhitelist.ipWhiteList] + sourceRange = ["127.0.0.1/32", "192.168.1.0/24"] [http.middlewares.test-ipwhitelist.ipWhiteList.ipStrategy] excludedIPs = ["127.0.0.1/32", "192.168.1.7"] ``` diff --git a/docs/content/middlewares/tcp/ipallowlist.md b/docs/content/middlewares/tcp/ipallowlist.md index e8466b94e..39e014ef7 100644 --- a/docs/content/middlewares/tcp/ipallowlist.md +++ b/docs/content/middlewares/tcp/ipallowlist.md @@ -8,7 +8,7 @@ description: "Learn how to use IPAllowList in TCP middleware for limiting client Limiting Clients to Specific IPs {: .subtitle } -IPAllowList accepts / refuses connections based on the client IP. +IPAllowList limits allowed requests based on the client IP. ## Configuration Examples diff --git a/docs/content/migration/v2.md b/docs/content/migration/v2.md index 626e9da45..b4f1e9e15 100644 --- a/docs/content/migration/v2.md +++ b/docs/content/migration/v2.md @@ -580,3 +580,35 @@ the maximum user-defined router priority value is: - `(MaxInt32 - 1000)` for 32-bit platforms, - `(MaxInt64 - 1000)` for 64-bit platforms. + +### .Transport.RespondingTimeouts. + +Starting with `v2.11.1` the following timeout options are deprecated: + +- `.transport.respondingTimeouts.readTimeout` +- `.transport.respondingTimeouts.writeTimeout` +- `.transport.respondingTimeouts.idleTimeout` + +They have been replaced by: + +- `.transport.respondingTimeouts.http.readTimeout` +- `.transport.respondingTimeouts.http.writeTimeout` +- `.transport.respondingTimeouts.http.idleTimeout` + +### .Transport.RespondingTimeouts.TCP.LingeringTimeout + +Starting with `v2.11.1` a new `lingeringTimeout` entryPoints option has been introduced, with a default value of 2s. + +The lingering timeout defines the maximum duration between each TCP read operation on the connection. +As a layer 4 timeout, it applies during HTTP handling but respects the configured HTTP server `readTimeout`. + +This change avoids Traefik instances with the default configuration hanging while waiting for bytes to be read on the connection. + +We suggest to adapt this value accordingly to your situation. +The new default value is purposely narrowed and can close the connection too early. + +Increasing the `lingeringTimeout` value could be the solution notably if you are dealing with the following errors: + +- TCP: `Error while handling TCP connection: readfrom tcp X.X.X.X:X->X.X.X.X:X: read tcp X.X.X.X:X->X.X.X.X:X: i/o timeout` +- HTTP: `'499 Client Closed Request' caused by: context canceled` +- HTTP: `ReverseProxy read error during body copy: read tcp X.X.X.X:X->X.X.X.X:X: use of closed network connection` diff --git a/docs/content/providers/nomad.md b/docs/content/providers/nomad.md index 85b3ac033..62e973fb0 100644 --- a/docs/content/providers/nomad.md +++ b/docs/content/providers/nomad.md @@ -163,6 +163,7 @@ providers: _Optional, Default=""_ Token is used to provide a per-request ACL token, if Nomad ACLs are enabled. +The appropriate ACL privilege for this token is 'read-job', as outlined in the [Nomad documentation on ACL](https://developer.hashicorp.com/nomad/tutorials/access-control/access-control-policies). ```yaml tab="File (YAML)" providers: diff --git a/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml b/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml index a95cf1153..56257f335 100644 --- a/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml +++ b/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml @@ -1303,7 +1303,7 @@ spec: ipAllowList: description: |- IPAllowList holds the IP allowlist middleware configuration. - This middleware accepts / refuses requests based on the client IP. + This middleware limits allowed requests based on the client IP. More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipallowlist/ properties: ipStrategy: @@ -1357,7 +1357,7 @@ spec: type: object sourceRange: description: SourceRange defines the set of allowed IPs (or ranges - of allowed IPs by using CIDR notation). + of allowed IPs by using CIDR notation). Required. items: type: string type: array diff --git a/docs/content/reference/dynamic-configuration/traefik.containo.us_middlewares.yaml b/docs/content/reference/dynamic-configuration/traefik.containo.us_middlewares.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/docs/content/reference/dynamic-configuration/traefik.io_middlewares.yaml b/docs/content/reference/dynamic-configuration/traefik.io_middlewares.yaml index 4ef178a57..fb6ff1246 100644 --- a/docs/content/reference/dynamic-configuration/traefik.io_middlewares.yaml +++ b/docs/content/reference/dynamic-configuration/traefik.io_middlewares.yaml @@ -661,7 +661,7 @@ spec: ipAllowList: description: |- IPAllowList holds the IP allowlist middleware configuration. - This middleware accepts / refuses requests based on the client IP. + This middleware limits allowed requests based on the client IP. More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipallowlist/ properties: ipStrategy: @@ -715,7 +715,7 @@ spec: type: object sourceRange: description: SourceRange defines the set of allowed IPs (or ranges - of allowed IPs by using CIDR notation). + of allowed IPs by using CIDR notation). Required. items: type: string type: array diff --git a/docs/content/reference/static-configuration/cli-ref.md b/docs/content/reference/static-configuration/cli-ref.md index 6d49edb59..797c66da7 100644 --- a/docs/content/reference/static-configuration/cli-ref.md +++ b/docs/content/reference/static-configuration/cli-ref.md @@ -198,15 +198,27 @@ Duration to give active requests a chance to finish before Traefik stops. (Defau `--entrypoints..transport.lifecycle.requestacceptgracetimeout`: Duration to keep accepting requests before Traefik initiates the graceful shutdown procedure. (Default: ```0```) -`--entrypoints..transport.respondingtimeouts.idletimeout`: +`--entrypoints..transport.respondingtimeouts.http.idletimeout`: IdleTimeout is the maximum amount duration an idle (keep-alive) connection will remain idle before closing itself. If zero, no timeout is set. (Default: ```180```) -`--entrypoints..transport.respondingtimeouts.readtimeout`: +`--entrypoints..transport.respondingtimeouts.http.readtimeout`: ReadTimeout is the maximum duration for reading the entire request, including the body. If zero, no timeout is set. (Default: ```0```) -`--entrypoints..transport.respondingtimeouts.writetimeout`: +`--entrypoints..transport.respondingtimeouts.http.writetimeout`: WriteTimeout is the maximum duration before timing out writes of the response. If zero, no timeout is set. (Default: ```0```) +`--entrypoints..transport.respondingtimeouts.idletimeout`: +(Deprecated) IdleTimeout is the maximum amount duration an idle (keep-alive) connection will remain idle before closing itself. If zero, no timeout is set. (Default: ```0```) + +`--entrypoints..transport.respondingtimeouts.readtimeout`: +(Deprecated) ReadTimeout is the maximum duration for reading the entire request, including the body. If zero, no timeout is set. (Default: ```0```) + +`--entrypoints..transport.respondingtimeouts.tcp.lingeringtimeout`: +LingeringTimeout is the maximum duration between each TCP read operation on the connection. If zero, no timeout is set. (Default: ```2```) + +`--entrypoints..transport.respondingtimeouts.writetimeout`: +(Deprecated) WriteTimeout is the maximum duration before timing out writes of the response. If zero, no timeout is set. (Default: ```0```) + `--entrypoints..udp.timeout`: Timeout defines how long to wait on an idle session before releasing the related resources. (Default: ```3```) diff --git a/docs/content/reference/static-configuration/env-ref.md b/docs/content/reference/static-configuration/env-ref.md index cac42b39b..9b9486c3d 100644 --- a/docs/content/reference/static-configuration/env-ref.md +++ b/docs/content/reference/static-configuration/env-ref.md @@ -198,15 +198,27 @@ Duration to give active requests a chance to finish before Traefik stops. (Defau `TRAEFIK_ENTRYPOINTS__TRANSPORT_LIFECYCLE_REQUESTACCEPTGRACETIMEOUT`: Duration to keep accepting requests before Traefik initiates the graceful shutdown procedure. (Default: ```0```) -`TRAEFIK_ENTRYPOINTS__TRANSPORT_RESPONDINGTIMEOUTS_IDLETIMEOUT`: +`TRAEFIK_ENTRYPOINTS__TRANSPORT_RESPONDINGTIMEOUTS_HTTP_IDLETIMEOUT`: IdleTimeout is the maximum amount duration an idle (keep-alive) connection will remain idle before closing itself. If zero, no timeout is set. (Default: ```180```) -`TRAEFIK_ENTRYPOINTS__TRANSPORT_RESPONDINGTIMEOUTS_READTIMEOUT`: +`TRAEFIK_ENTRYPOINTS__TRANSPORT_RESPONDINGTIMEOUTS_HTTP_READTIMEOUT`: ReadTimeout is the maximum duration for reading the entire request, including the body. If zero, no timeout is set. (Default: ```0```) -`TRAEFIK_ENTRYPOINTS__TRANSPORT_RESPONDINGTIMEOUTS_WRITETIMEOUT`: +`TRAEFIK_ENTRYPOINTS__TRANSPORT_RESPONDINGTIMEOUTS_HTTP_WRITETIMEOUT`: WriteTimeout is the maximum duration before timing out writes of the response. If zero, no timeout is set. (Default: ```0```) +`TRAEFIK_ENTRYPOINTS__TRANSPORT_RESPONDINGTIMEOUTS_IDLETIMEOUT`: +(Deprecated) IdleTimeout is the maximum amount duration an idle (keep-alive) connection will remain idle before closing itself. If zero, no timeout is set. (Default: ```0```) + +`TRAEFIK_ENTRYPOINTS__TRANSPORT_RESPONDINGTIMEOUTS_READTIMEOUT`: +(Deprecated) ReadTimeout is the maximum duration for reading the entire request, including the body. If zero, no timeout is set. (Default: ```0```) + +`TRAEFIK_ENTRYPOINTS__TRANSPORT_RESPONDINGTIMEOUTS_TCP_LINGERINGTIMEOUT`: +LingeringTimeout is the maximum duration between each TCP read operation on the connection. If zero, no timeout is set. (Default: ```2```) + +`TRAEFIK_ENTRYPOINTS__TRANSPORT_RESPONDINGTIMEOUTS_WRITETIMEOUT`: +(Deprecated) WriteTimeout is the maximum duration before timing out writes of the response. If zero, no timeout is set. (Default: ```0```) + `TRAEFIK_ENTRYPOINTS__UDP_TIMEOUT`: Timeout defines how long to wait on an idle session before releasing the related resources. (Default: ```3```) diff --git a/docs/content/reference/static-configuration/file.toml b/docs/content/reference/static-configuration/file.toml index 9d796c4a6..13d913afd 100644 --- a/docs/content/reference/static-configuration/file.toml +++ b/docs/content/reference/static-configuration/file.toml @@ -42,6 +42,12 @@ readTimeout = "42s" writeTimeout = "42s" idleTimeout = "42s" + [entryPoints.EntryPoint0.transport.respondingTimeouts.http] + readTimeout = "42s" + writeTimeout = "42s" + idleTimeout = "42s" + [entryPoints.EntryPoint0.transport.respondingTimeouts.tcp] + lingeringTimeout = "42s" [entryPoints.EntryPoint0.proxyProtocol] insecure = true trustedIPs = ["foobar", "foobar"] diff --git a/docs/content/reference/static-configuration/file.yaml b/docs/content/reference/static-configuration/file.yaml index 477fa6b0e..b884b2aad 100644 --- a/docs/content/reference/static-configuration/file.yaml +++ b/docs/content/reference/static-configuration/file.yaml @@ -45,6 +45,12 @@ entryPoints: readTimeout: 42s writeTimeout: 42s idleTimeout: 42s + http: + readTimeout: 42s + writeTimeout: 42s + idleTimeout: 42s + tcp: + lingeringTimeout: 42s keepAliveMaxTime: 42s keepAliveMaxRequests: 42 proxyProtocol: diff --git a/docs/content/routing/entrypoints.md b/docs/content/routing/entrypoints.md index 67af1e9a2..060a1a3c3 100644 --- a/docs/content/routing/entrypoints.md +++ b/docs/content/routing/entrypoints.md @@ -504,10 +504,11 @@ You can configure Traefik to trust the forwarded headers information (`X-Forward #### `respondingTimeouts` -`respondingTimeouts` are timeouts for incoming requests to the Traefik instance. -Setting them has no effect for UDP entryPoints. +##### `http` -??? info "`transport.respondingTimeouts.readTimeout`" +`respondingTimeouts.http` are timeouts for incoming requests to the Traefik instance. + +??? info "`transport.respondingTimeouts.http.readTimeout`" _Optional, Default=0s_ @@ -524,7 +525,8 @@ Setting them has no effect for UDP entryPoints. address: ":8888" transport: respondingTimeouts: - readTimeout: 42 + http: + readTimeout: 42 ``` ```toml tab="File (TOML)" @@ -532,18 +534,17 @@ Setting them has no effect for UDP entryPoints. [entryPoints] [entryPoints.name] address = ":8888" - [entryPoints.name.transport] - [entryPoints.name.transport.respondingTimeouts] - readTimeout = 42 + [entryPoints.name.transport.respondingTimeouts.http] + readTimeout = 42 ``` ```bash tab="CLI" ## Static configuration --entryPoints.name.address=:8888 - --entryPoints.name.transport.respondingTimeouts.readTimeout=42 + --entryPoints.name.transport.respondingTimeouts.http.readTimeout=42 ``` -??? info "`transport.respondingTimeouts.writeTimeout`" +??? info "`transport.respondingTimeouts.http.writeTimeout`" _Optional, Default=0s_ @@ -561,7 +562,8 @@ Setting them has no effect for UDP entryPoints. address: ":8888" transport: respondingTimeouts: - writeTimeout: 42 + http: + writeTimeout: 42 ``` ```toml tab="File (TOML)" @@ -569,18 +571,17 @@ Setting them has no effect for UDP entryPoints. [entryPoints] [entryPoints.name] address = ":8888" - [entryPoints.name.transport] - [entryPoints.name.transport.respondingTimeouts] - writeTimeout = 42 + [entryPoints.name.transport.respondingTimeouts.http] + writeTimeout = 42 ``` ```bash tab="CLI" ## Static configuration --entryPoints.name.address=:8888 - --entryPoints.name.transport.respondingTimeouts.writeTimeout=42 + --entryPoints.name.transport.respondingTimeouts.http.writeTimeout=42 ``` -??? info "`transport.respondingTimeouts.idleTimeout`" +??? info "`transport.respondingTimeouts.http.idleTimeout`" _Optional, Default=180s_ @@ -597,7 +598,8 @@ Setting them has no effect for UDP entryPoints. address: ":8888" transport: respondingTimeouts: - idleTimeout: 42 + http: + idleTimeout: 42 ``` ```toml tab="File (TOML)" @@ -605,15 +607,54 @@ Setting them has no effect for UDP entryPoints. [entryPoints] [entryPoints.name] address = ":8888" - [entryPoints.name.transport] - [entryPoints.name.transport.respondingTimeouts] - idleTimeout = 42 + [entryPoints.name.transport.respondingTimeouts.http] + idleTimeout = 42 ``` ```bash tab="CLI" ## Static configuration --entryPoints.name.address=:8888 - --entryPoints.name.transport.respondingTimeouts.idleTimeout=42 + --entryPoints.name.transport.respondingTimeouts.http.idleTimeout=42 + +##### `tcp` + +`respondingTimeouts.tcp` are timeouts for client connections to the Traefik instance. + +??? info "`transport.respondingTimeouts.tcp.lingeringTimeout`" + + _Optional, Default=2s_ + + `lingeringTimeout` is the maximum duration between each TCP read operation on the connection. + As a layer 4 timeout, it also applies during HTTP handling, but respect the configured HTTP server `readTimeout`. + + If zero, the lingering is disabled. + Can be provided in a format supported by [time.ParseDuration](https://golang.org/pkg/time/#ParseDuration) or as raw values (digits). + If no units are provided, the value is parsed assuming seconds. + + ```yaml tab="File (YAML)" + ## Static configuration + entryPoints: + name: + address: ":8888" + transport: + respondingTimeouts: + tcp: + lingeringTimeout: 42 + ``` + + ```toml tab="File (TOML)" + ## Static configuration + [entryPoints] + [entryPoints.name] + address = ":8888" + [entryPoints.name.transport.respondingTimeouts.tcp] + lingeringTimeout = 42 + ``` + + ```bash tab="CLI" + ## Static configuration + --entryPoints.name.address=:8888 + --entryPoints.name.transport.respondingTimeouts.tcp.lingeringTimeout=42 ``` #### `lifeCycle` diff --git a/go.mod b/go.mod index 6c04b1d7c..c1352ee90 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,8 @@ require ( github.com/containous/alice v0.0.0-20181107144136-d83ebdd94cbd github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc - github.com/docker/cli v24.0.7+incompatible - github.com/docker/docker v24.0.7+incompatible + github.com/docker/cli v24.0.9+incompatible + github.com/docker/docker v24.0.9+incompatible github.com/docker/go-connections v0.4.0 github.com/fatih/structs v1.1.0 github.com/fsnotify/fsnotify v1.7.0 @@ -49,7 +49,7 @@ require ( github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 github.com/prometheus/client_golang v1.17.0 github.com/prometheus/client_model v0.5.0 - github.com/quic-go/quic-go v0.40.1 + github.com/quic-go/quic-go v0.42.0 github.com/rs/zerolog v1.29.0 github.com/sirupsen/logrus v1.9.3 github.com/spiffe/go-spiffe/v2 v2.1.1 @@ -79,12 +79,12 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.24.0 go.opentelemetry.io/otel/trace v1.24.0 golang.org/x/exp v0.0.0-20231006140011-7918f672742d - golang.org/x/mod v0.14.0 - golang.org/x/net v0.20.0 - golang.org/x/sys v0.17.0 + golang.org/x/mod v0.17.0 + golang.org/x/net v0.24.0 + golang.org/x/sys v0.19.0 golang.org/x/text v0.14.0 golang.org/x/time v0.5.0 - golang.org/x/tools v0.17.0 + golang.org/x/tools v0.20.0 google.golang.org/grpc v1.61.1 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.28.4 @@ -262,7 +262,7 @@ require ( github.com/nrdcg/porkbun v0.3.0 // indirect github.com/nzdjb/go-metaname v1.0.0 // indirect github.com/onsi/ginkgo v1.16.5 // indirect - github.com/onsi/ginkgo/v2 v2.11.0 // indirect + github.com/onsi/ginkgo/v2 v2.17.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc5 // indirect github.com/opencontainers/runc v1.1.7 // indirect @@ -276,7 +276,6 @@ require ( github.com/prometheus/common v0.45.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.4.1 // indirect github.com/redis/go-redis/v9 v9.2.1 // indirect github.com/rs/cors v1.7.0 // indirect github.com/sacloud/api-client-go v0.2.8 // indirect @@ -317,20 +316,21 @@ require ( go.opentelemetry.io/contrib/propagators/ot v1.24.0 // indirect go.opentelemetry.io/proto/otlp v1.1.0 // indirect go.uber.org/atomic v1.11.0 // indirect - go.uber.org/mock v0.3.0 // indirect + go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/arch v0.4.0 // indirect - golang.org/x/crypto v0.19.0 // indirect + golang.org/x/crypto v0.22.0 // indirect golang.org/x/oauth2 v0.16.0 // indirect - golang.org/x/term v0.17.0 // indirect + golang.org/x/sync v0.7.0 // indirect + golang.org/x/term v0.19.0 // indirect google.golang.org/api v0.149.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect - google.golang.org/protobuf v1.32.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect gopkg.in/h2non/gock.v1 v1.0.16 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 1faff9087..bff807738 100644 --- a/go.sum +++ b/go.sum @@ -265,12 +265,12 @@ github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dnsimple/dnsimple-go v1.2.0 h1:ddTGyLVKly5HKb5L65AkLqFqwZlWo3WnR0BlFZlIddM= github.com/dnsimple/dnsimple-go v1.2.0/go.mod h1:z/cs26v/eiRvUyXsHQBLd8lWF8+cD6GbmkPH84plM4U= -github.com/docker/cli v24.0.7+incompatible h1:wa/nIwYFW7BVTGa7SWPVyyXU9lgORqUb1xfI36MSkFg= -github.com/docker/cli v24.0.7+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v24.0.9+incompatible h1:OxbimnP/z+qVjDLpq9wbeFU3Nc30XhSe+LkwYQisD50= +github.com/docker/cli v24.0.9+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM= -github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v24.0.9+incompatible h1:HPGzNmwfLZWdxHqK9/II92pyi1EpYKsAqcl4G0Of9v0= +github.com/docker/docker v24.0.9+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -860,16 +860,16 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= -github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= +github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8= +github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= -github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= +github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= +github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= @@ -961,10 +961,8 @@ github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3c github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= -github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= -github.com/quic-go/quic-go v0.40.1 h1:X3AGzUNFs0jVuO3esAGnTfvdgvL4fq655WaOi1snv1Q= -github.com/quic-go/quic-go v0.40.1/go.mod h1:PeN7kuVJ4xZbxSv/4OX6S1USOX8MJvydwpTx31vx60c= +github.com/quic-go/quic-go v0.42.0 h1:uSfdap0eveIl8KXnipv9K7nlwZ5IqLlYOpJ58u5utpM= +github.com/quic-go/quic-go v0.42.0/go.mod h1:132kz4kL3F9vxhW3CtQJLDVwcFe5wdWeJXXijhsO57M= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/redis/go-redis/v9 v9.2.1 h1:WlYJg71ODF0dVspZZCpYmoF1+U1Jjk9Rwd7pq6QmlCg= github.com/redis/go-redis/v9 v9.2.1/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M= @@ -1207,8 +1205,8 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= -go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= @@ -1247,8 +1245,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= 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= @@ -1280,8 +1278,8 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0= -golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1323,8 +1321,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= 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= @@ -1342,8 +1340,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= -golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1417,8 +1415,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1427,8 +1425,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= +golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= 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= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -1488,8 +1486,8 @@ golang.org/x/tools v0.0.0-20210114065538-d78b04bdf963/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= -golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= +golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= +golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1573,8 +1571,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= +google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/integration/fixtures/k8s/01-traefik-crd.yml b/integration/fixtures/k8s/01-traefik-crd.yml index a95cf1153..56257f335 100644 --- a/integration/fixtures/k8s/01-traefik-crd.yml +++ b/integration/fixtures/k8s/01-traefik-crd.yml @@ -1303,7 +1303,7 @@ spec: ipAllowList: description: |- IPAllowList holds the IP allowlist middleware configuration. - This middleware accepts / refuses requests based on the client IP. + This middleware limits allowed requests based on the client IP. More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipallowlist/ properties: ipStrategy: @@ -1357,7 +1357,7 @@ spec: type: object sourceRange: description: SourceRange defines the set of allowed IPs (or ranges - of allowed IPs by using CIDR notation). + of allowed IPs by using CIDR notation). Required. items: type: string type: array diff --git a/pkg/api/handler_entrypoint_test.go b/pkg/api/handler_entrypoint_test.go index 768cd3dcd..9167146b8 100644 --- a/pkg/api/handler_entrypoint_test.go +++ b/pkg/api/handler_entrypoint_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + ptypes "github.com/traefik/paerser/types" "github.com/traefik/traefik/v3/pkg/config/runtime" "github.com/traefik/traefik/v3/pkg/config/static" ) @@ -55,9 +56,11 @@ func TestHandler_EntryPoints(t *testing.T) { GraceTimeOut: 2, }, RespondingTimeouts: &static.RespondingTimeouts{ - ReadTimeout: 3, - WriteTimeout: 4, - IdleTimeout: 5, + HTTP: &static.HTTPRespondingTimeouts{ + ReadTimeout: paerserDurationPtr(3), + WriteTimeout: paerserDurationPtr(4), + IdleTimeout: paerserDurationPtr(5), + }, }, }, ProxyProtocol: &static.ProxyProtocol{ @@ -77,9 +80,11 @@ func TestHandler_EntryPoints(t *testing.T) { GraceTimeOut: 20, }, RespondingTimeouts: &static.RespondingTimeouts{ - ReadTimeout: 30, - WriteTimeout: 40, - IdleTimeout: 50, + HTTP: &static.HTTPRespondingTimeouts{ + ReadTimeout: paerserDurationPtr(3), + WriteTimeout: paerserDurationPtr(4), + IdleTimeout: paerserDurationPtr(5), + }, }, }, ProxyProtocol: &static.ProxyProtocol{ @@ -263,3 +268,8 @@ func generateEntryPoints(nb int) map[string]*static.EntryPoint { return eps } + +func paerserDurationPtr(duration int) *ptypes.Duration { + d := ptypes.Duration(duration) + return &d +} diff --git a/pkg/api/testdata/entrypoints.json b/pkg/api/testdata/entrypoints.json index d93d07bfc..93f56a401 100644 --- a/pkg/api/testdata/entrypoints.json +++ b/pkg/api/testdata/entrypoints.json @@ -23,9 +23,11 @@ "requestAcceptGraceTimeout": "1ns" }, "respondingTimeouts": { - "idleTimeout": "5ns", - "readTimeout": "3ns", - "writeTimeout": "4ns" + "http": { + "idleTimeout": "5ns", + "readTimeout": "3ns", + "writeTimeout": "4ns" + } } } }, @@ -53,9 +55,11 @@ "requestAcceptGraceTimeout": "10ns" }, "respondingTimeouts": { - "idleTimeout": "50ns", - "readTimeout": "30ns", - "writeTimeout": "40ns" + "http": { + "idleTimeout": "5ns", + "readTimeout": "3ns", + "writeTimeout": "4ns" + } } } } diff --git a/pkg/config/dynamic/middlewares.go b/pkg/config/dynamic/middlewares.go index 6fbe2a0f5..59c91814b 100644 --- a/pkg/config/dynamic/middlewares.go +++ b/pkg/config/dynamic/middlewares.go @@ -423,11 +423,11 @@ func (s *IPStrategy) Get() (ip.Strategy, error) { // +k8s:deepcopy-gen=true // IPWhiteList holds the IP whitelist middleware configuration. -// This middleware accepts / refuses requests based on the client IP. +// This middleware limits allowed requests based on the client IP. // More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipwhitelist/ // Deprecated: please use IPAllowList instead. type IPWhiteList struct { - // SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation). + // SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation). Required. SourceRange []string `json:"sourceRange,omitempty" toml:"sourceRange,omitempty" yaml:"sourceRange,omitempty"` IPStrategy *IPStrategy `json:"ipStrategy,omitempty" toml:"ipStrategy,omitempty" yaml:"ipStrategy,omitempty" label:"allowEmpty" file:"allowEmpty" kv:"allowEmpty" export:"true"` } @@ -435,7 +435,7 @@ type IPWhiteList struct { // +k8s:deepcopy-gen=true // IPAllowList holds the IP allowlist middleware configuration. -// This middleware accepts / refuses requests based on the client IP. +// This middleware limits allowed requests based on the client IP. // More info: https://doc.traefik.io/traefik/v3.0/middlewares/http/ipallowlist/ type IPAllowList struct { // SourceRange defines the set of allowed IPs (or ranges of allowed IPs by using CIDR notation). diff --git a/pkg/config/dynamic/tcp_middlewares.go b/pkg/config/dynamic/tcp_middlewares.go index 4368dc334..3515b71eb 100644 --- a/pkg/config/dynamic/tcp_middlewares.go +++ b/pkg/config/dynamic/tcp_middlewares.go @@ -34,6 +34,8 @@ type TCPIPWhiteList struct { // +k8s:deepcopy-gen=true // TCPIPAllowList holds the TCP IPAllowList middleware configuration. +// This middleware limits allowed requests based on the client IP. +// More info: https://doc.traefik.io/traefik/v3.0/middlewares/tcp/ipallowlist/ type TCPIPAllowList struct { // SourceRange defines the allowed IPs (or ranges of allowed IPs by using CIDR notation). SourceRange []string `json:"sourceRange,omitempty" toml:"sourceRange,omitempty" yaml:"sourceRange,omitempty"` diff --git a/pkg/config/static/static_config.go b/pkg/config/static/static_config.go index 01144537e..5a9414b16 100644 --- a/pkg/config/static/static_config.go +++ b/pkg/config/static/static_config.go @@ -48,6 +48,9 @@ const ( // DefaultUDPTimeout defines how long to wait by default on an idle session, // before releasing all resources related to that session. DefaultUDPTimeout = 3 * time.Second + + // defaultLingeringTimeout defines the default maximum duration between each read operation on the connection. + defaultLingeringTimeout = 2 * time.Second ) // Configuration is the static configuration. @@ -155,16 +158,44 @@ func (a *API) SetDefaults() { a.Dashboard = true } -// RespondingTimeouts contains timeout configurations for incoming requests to the Traefik instance. +// RespondingTimeouts contains timeout configurations. type RespondingTimeouts struct { - ReadTimeout ptypes.Duration `description:"ReadTimeout is the maximum duration for reading the entire request, including the body. If zero, no timeout is set." json:"readTimeout,omitempty" toml:"readTimeout,omitempty" yaml:"readTimeout,omitempty" export:"true"` - WriteTimeout ptypes.Duration `description:"WriteTimeout is the maximum duration before timing out writes of the response. If zero, no timeout is set." json:"writeTimeout,omitempty" toml:"writeTimeout,omitempty" yaml:"writeTimeout,omitempty" export:"true"` - IdleTimeout ptypes.Duration `description:"IdleTimeout is the maximum amount duration an idle (keep-alive) connection will remain idle before closing itself. If zero, no timeout is set." json:"idleTimeout,omitempty" toml:"idleTimeout,omitempty" yaml:"idleTimeout,omitempty" export:"true"` + // Deprecated: please use `respondingTimeouts.http.readTimeout` instead. + ReadTimeout *ptypes.Duration `description:"(Deprecated) ReadTimeout is the maximum duration for reading the entire request, including the body. If zero, no timeout is set." json:"readTimeout,omitempty" toml:"readTimeout,omitempty" yaml:"readTimeout,omitempty" export:"true"` + // Deprecated: please use `respondingTimeouts.http.writeTimeout` instead. + WriteTimeout *ptypes.Duration `description:"(Deprecated) WriteTimeout is the maximum duration before timing out writes of the response. If zero, no timeout is set." json:"writeTimeout,omitempty" toml:"writeTimeout,omitempty" yaml:"writeTimeout,omitempty" export:"true"` + // Deprecated: please use `respondingTimeouts.http.idleTimeout` instead. + IdleTimeout *ptypes.Duration `description:"(Deprecated) IdleTimeout is the maximum amount duration an idle (keep-alive) connection will remain idle before closing itself. If zero, no timeout is set." json:"idleTimeout,omitempty" toml:"idleTimeout,omitempty" yaml:"idleTimeout,omitempty" export:"true"` + + HTTP *HTTPRespondingTimeouts `description:"Defines the HTTP responding timeouts." json:"http,omitempty" toml:"http,omitempty" yaml:"http,omitempty" export:"true"` + TCP *TCPRespondingTimeouts `description:"Defines the TCP responding timeouts." json:"tcp,omitempty" toml:"tcp,omitempty" yaml:"tcp,omitempty" export:"true"` +} + +// HTTPRespondingTimeouts contains HTTP timeout configurations for incoming requests to the Traefik instance. +type HTTPRespondingTimeouts struct { + ReadTimeout *ptypes.Duration `description:"ReadTimeout is the maximum duration for reading the entire request, including the body. If zero, no timeout is set." json:"readTimeout,omitempty" toml:"readTimeout,omitempty" yaml:"readTimeout,omitempty" export:"true"` + WriteTimeout *ptypes.Duration `description:"WriteTimeout is the maximum duration before timing out writes of the response. If zero, no timeout is set." json:"writeTimeout,omitempty" toml:"writeTimeout,omitempty" yaml:"writeTimeout,omitempty" export:"true"` + IdleTimeout *ptypes.Duration `description:"IdleTimeout is the maximum amount duration an idle (keep-alive) connection will remain idle before closing itself. If zero, no timeout is set." json:"idleTimeout,omitempty" toml:"idleTimeout,omitempty" yaml:"idleTimeout,omitempty" export:"true"` +} + +// TCPRespondingTimeouts contains TCP timeout configurations for client connections to the Traefik instance. +type TCPRespondingTimeouts struct { + LingeringTimeout ptypes.Duration `description:"LingeringTimeout is the maximum duration between each TCP read operation on the connection. If zero, no timeout is set." json:"lingeringTimeout,omitempty" toml:"lingeringTimeout,omitempty" yaml:"lingeringTimeout,omitempty" export:"true"` } // SetDefaults sets the default values. func (a *RespondingTimeouts) SetDefaults() { - a.IdleTimeout = ptypes.Duration(DefaultIdleTimeout) + noTimeout := ptypes.Duration(0) + defaultIdleTimeout := ptypes.Duration(DefaultIdleTimeout) + a.HTTP = &HTTPRespondingTimeouts{ + ReadTimeout: &noTimeout, + WriteTimeout: &noTimeout, + IdleTimeout: &defaultIdleTimeout, + } + + a.TCP = &TCPRespondingTimeouts{ + LingeringTimeout: ptypes.Duration(defaultLingeringTimeout), + } } // ForwardingTimeouts contains timeout configurations for forwarding requests to the backend servers. @@ -247,6 +278,39 @@ func (c *Configuration) SetEffectiveConfiguration() { c.EntryPoints["http"] = ep } + for _, entrypoint := range c.EntryPoints { + if entrypoint.Transport == nil || + entrypoint.Transport.RespondingTimeouts == nil { + continue + } + + respondingTimeouts := entrypoint.Transport.RespondingTimeouts + + if respondingTimeouts.ReadTimeout != nil && + respondingTimeouts.HTTP != nil && + respondingTimeouts.HTTP.ReadTimeout == nil { + log.Warn().Msg("Option `respondingTimeouts.readTimeout` is deprecated, please use `respondingTimeouts.http.readTimeout` instead.") + respondingTimeouts.HTTP.ReadTimeout = respondingTimeouts.ReadTimeout + respondingTimeouts.ReadTimeout = nil + } + + if respondingTimeouts.WriteTimeout != nil && + respondingTimeouts.HTTP != nil && + respondingTimeouts.HTTP.WriteTimeout == nil { + log.Warn().Msg("Option `respondingTimeouts.writeTimeout` is deprecated, please use `respondingTimeouts.http.writeTimeout` instead.") + respondingTimeouts.HTTP.WriteTimeout = respondingTimeouts.WriteTimeout + respondingTimeouts.WriteTimeout = nil + } + + if respondingTimeouts.IdleTimeout != nil && + respondingTimeouts.HTTP != nil && + respondingTimeouts.HTTP.IdleTimeout == nil { + log.Warn().Msg("Option `respondingTimeouts.idleTimeout` is deprecated, please use `respondingTimeouts.http.idleTimeout` instead.") + respondingTimeouts.HTTP.IdleTimeout = respondingTimeouts.IdleTimeout + respondingTimeouts.IdleTimeout = nil + } + } + // Creates the internal traefik entry point if needed if (c.API != nil && c.API.Insecure) || (c.Ping != nil && !c.Ping.ManualRouting && c.Ping.EntryPoint == DefaultInternalEntryPointName) || @@ -358,6 +422,31 @@ func (c *Configuration) ValidateConfiguration() error { } } + for epName, entrypoint := range c.EntryPoints { + if entrypoint.Transport == nil || + entrypoint.Transport.RespondingTimeouts == nil || + entrypoint.Transport.RespondingTimeouts.HTTP == nil { + continue + } + + respondingTimeouts := entrypoint.Transport.RespondingTimeouts + + if respondingTimeouts.ReadTimeout != nil && + respondingTimeouts.HTTP.ReadTimeout != nil { + return fmt.Errorf("entrypoint %q has `readTimeout` option is defined multiple times (`respondingTimeouts.readTimeout` is deprecated)", epName) + } + + if respondingTimeouts.WriteTimeout != nil && + respondingTimeouts.HTTP.WriteTimeout != nil { + return fmt.Errorf("entrypoint %q has `writeTimeout` option is defined multiple times (`respondingTimeouts.writeTimeout` is deprecated)", epName) + } + + if respondingTimeouts.IdleTimeout != nil && + respondingTimeouts.HTTP.IdleTimeout != nil { + return fmt.Errorf("entrypoint %q has `idleTimeout` option is defined multiple times (`respondingTimeouts.idleTimeout` is deprecated)", epName) + } + } + return nil } diff --git a/pkg/provider/acme/local_store_unix.go b/pkg/provider/acme/local_store_unix.go index f6d590536..163ecd7ae 100644 --- a/pkg/provider/acme/local_store_unix.go +++ b/pkg/provider/acme/local_store_unix.go @@ -11,14 +11,15 @@ import ( // CheckFile checks file permissions and content size. func CheckFile(name string) (bool, error) { f, err := os.Open(name) - if err != nil { - if os.IsNotExist(err) { - f, err = os.Create(name) - if err != nil { - return false, err - } - return false, f.Chmod(0o600) + if err != nil && os.IsNotExist(err) { + nf, err := os.Create(name) + if err != nil { + return false, err } + defer nf.Close() + return false, nf.Chmod(0o600) + } + if err != nil { return false, err } defer f.Close() diff --git a/pkg/provider/ecs/ecs.go b/pkg/provider/ecs/ecs.go index 2280f3605..26565bb16 100644 --- a/pkg/provider/ecs/ecs.go +++ b/pkg/provider/ecs/ecs.go @@ -319,7 +319,7 @@ func (p *Provider) listInstances(ctx context.Context, client *awsClient) ([]ecsI } var mach *machine - if len(task.Attachments) != 0 { + if aws.StringValue(taskDef.NetworkMode) == "awsvpc" && len(task.Attachments) != 0 { if len(container.NetworkInterfaces) == 0 { logger.Error().Msgf("Skip container %s: no network interfaces", aws.StringValue(container.Name)) continue diff --git a/pkg/redactor/redactor_config_test.go b/pkg/redactor/redactor_config_test.go index be179561a..f0a1543b8 100644 --- a/pkg/redactor/redactor_config_test.go +++ b/pkg/redactor/redactor_config_test.go @@ -511,6 +511,8 @@ func TestDo_staticConfiguration(t *testing.T) { SendAnonymousUsage: true, } + paerserDuration := ptypes.Duration(111 * time.Second) + config.EntryPoints = static.EntryPoints{ "foobar": &static.EntryPoint{ Address: "foo Address", @@ -520,9 +522,14 @@ func TestDo_staticConfiguration(t *testing.T) { GraceTimeOut: ptypes.Duration(111 * time.Second), }, RespondingTimeouts: &static.RespondingTimeouts{ - ReadTimeout: ptypes.Duration(111 * time.Second), - WriteTimeout: ptypes.Duration(111 * time.Second), - IdleTimeout: ptypes.Duration(111 * time.Second), + HTTP: &static.HTTPRespondingTimeouts{ + ReadTimeout: &paerserDuration, + WriteTimeout: &paerserDuration, + IdleTimeout: &paerserDuration, + }, + TCP: &static.TCPRespondingTimeouts{ + LingeringTimeout: ptypes.Duration(111 * time.Second), + }, }, }, ProxyProtocol: &static.ProxyProtocol{ diff --git a/pkg/redactor/testdata/anonymized-static-config.json b/pkg/redactor/testdata/anonymized-static-config.json index a1b7b19ec..e9986ccce 100644 --- a/pkg/redactor/testdata/anonymized-static-config.json +++ b/pkg/redactor/testdata/anonymized-static-config.json @@ -38,9 +38,14 @@ "graceTimeOut": "1m51s" }, "respondingTimeouts": { - "readTimeout": "1m51s", - "writeTimeout": "1m51s", - "idleTimeout": "1m51s" + "http": { + "readTimeout": "1m51s", + "writeTimeout": "1m51s", + "idleTimeout": "1m51s" + }, + "tcp": { + "lingeringTimeout": "1m51s" + } } }, "proxyProtocol": { diff --git a/pkg/server/router/tcp/router.go b/pkg/server/router/tcp/router.go index 4522a4532..3afbc931a 100644 --- a/pkg/server/router/tcp/router.go +++ b/pkg/server/router/tcp/router.go @@ -9,7 +9,6 @@ import ( "net" "net/http" "slices" - "time" "github.com/go-acme/lego/v4/challenge/tlsalpn01" "github.com/rs/zerolog/log" @@ -128,17 +127,6 @@ func (r *Router) ServeTCP(conn tcp.WriteCloser) { return } - // Remove read/write deadline and delegate this to underlying tcp server (for now only handled by HTTP Server) - err = conn.SetReadDeadline(time.Time{}) - if err != nil { - log.Error().Err(err).Msg("Error while setting read deadline") - } - - err = conn.SetWriteDeadline(time.Time{}) - if err != nil { - log.Error().Err(err).Msg("Error while setting write deadline") - } - connData, err := tcpmuxer.NewConnData(hello.serverName, conn, hello.protos) if err != nil { log.Error().Err(err).Msg("Error while reading TCP connection data") diff --git a/pkg/server/server_entrypoint_tcp.go b/pkg/server/server_entrypoint_tcp.go index 6a25953d4..735980004 100644 --- a/pkg/server/server_entrypoint_tcp.go +++ b/pkg/server/server_entrypoint_tcp.go @@ -249,24 +249,15 @@ func (e *TCPEntryPoint) Start(ctx context.Context) { panic(err) } + if e.transportConfiguration != nil && + e.transportConfiguration.RespondingTimeouts != nil && + e.transportConfiguration.RespondingTimeouts.TCP != nil && + e.transportConfiguration.RespondingTimeouts.TCP.LingeringTimeout > 0 { + lingeringTimeout := time.Duration(e.transportConfiguration.RespondingTimeouts.TCP.LingeringTimeout) + writeCloser = newLingeringConnection(writeCloser, lingeringTimeout) + } + safe.Go(func() { - // Enforce read/write deadlines at the connection level, - // because when we're peeking the first byte to determine whether we are doing TLS, - // the deadlines at the server level are not taken into account. - if e.transportConfiguration.RespondingTimeouts.ReadTimeout > 0 { - err := writeCloser.SetReadDeadline(time.Now().Add(time.Duration(e.transportConfiguration.RespondingTimeouts.ReadTimeout))) - if err != nil { - logger.Error().Err(err).Msg("Error while setting read deadline") - } - } - - if e.transportConfiguration.RespondingTimeouts.WriteTimeout > 0 { - err = writeCloser.SetWriteDeadline(time.Now().Add(time.Duration(e.transportConfiguration.RespondingTimeouts.WriteTimeout))) - if err != nil { - logger.Error().Err(err).Msg("Error while setting write deadline") - } - } - e.switcher.ServeTCP(newTrackedConnection(writeCloser, e.tracker)) }) } @@ -398,6 +389,55 @@ func writeCloser(conn net.Conn) (tcp.WriteCloser, error) { } } +// lingeringConn represents a writeCloser with lingeringTimeout handling. +type lingeringConn struct { + tcp.WriteCloser + + lingeringTimeout time.Duration + + rdlMu sync.RWMutex + // readDeadline is the current readDeadline set by an upper caller. + // In case of HTTP, the HTTP go server manipulates deadlines on the connection. + readDeadline time.Time +} + +// newLingeringConnection returns the given writeCloser augmented with lingeringTimeout handling. +func newLingeringConnection(conn tcp.WriteCloser, timeout time.Duration) tcp.WriteCloser { + return &lingeringConn{ + WriteCloser: conn, + lingeringTimeout: timeout, + } +} + +// Read reads data from the connection and postpones the connection readDeadline according to the lingeringTimeout config. +// It also ensures that the upper level set readDeadline is enforced. +func (l *lingeringConn) Read(b []byte) (int, error) { + if l.lingeringTimeout > 0 { + deadline := time.Now().Add(l.lingeringTimeout) + + l.rdlMu.RLock() + if !l.readDeadline.IsZero() && deadline.After(l.readDeadline) { + deadline = l.readDeadline + } + l.rdlMu.RUnlock() + + if err := l.WriteCloser.SetReadDeadline(deadline); err != nil { + return 0, err + } + } + + return l.WriteCloser.Read(b) +} + +// SetReadDeadline sets and save the read deadline. +func (l *lingeringConn) SetReadDeadline(t time.Time) error { + l.rdlMu.Lock() + l.readDeadline = t + l.rdlMu.Unlock() + + return l.WriteCloser.SetReadDeadline(t) +} + // tcpKeepAliveListener sets TCP keep-alive timeouts on accepted // connections. type tcpKeepAliveListener struct { @@ -425,7 +465,7 @@ func (ln tcpKeepAliveListener) Accept() (net.Conn, error) { } func buildProxyProtocolListener(ctx context.Context, entryPoint *static.EntryPoint, listener net.Listener) (net.Listener, error) { - timeout := entryPoint.Transport.RespondingTimeouts.ReadTimeout + timeout := *entryPoint.Transport.RespondingTimeouts.HTTP.ReadTimeout // proxyproto use 200ms if ReadHeaderTimeout is set to 0 and not no timeout if timeout == 0 { timeout = -1 @@ -608,9 +648,9 @@ func createHTTPServer(ctx context.Context, ln net.Listener, configuration *stati serverHTTP := &http.Server{ Handler: handler, ErrorLog: stdlog.New(logs.NoLevel(log.Logger, zerolog.DebugLevel), "", 0), - ReadTimeout: time.Duration(configuration.Transport.RespondingTimeouts.ReadTimeout), - WriteTimeout: time.Duration(configuration.Transport.RespondingTimeouts.WriteTimeout), - IdleTimeout: time.Duration(configuration.Transport.RespondingTimeouts.IdleTimeout), + ReadTimeout: time.Duration(*configuration.Transport.RespondingTimeouts.HTTP.ReadTimeout), + WriteTimeout: time.Duration(*configuration.Transport.RespondingTimeouts.HTTP.WriteTimeout), + IdleTimeout: time.Duration(*configuration.Transport.RespondingTimeouts.HTTP.IdleTimeout), } if debugConnection || (configuration.Transport != nil && (configuration.Transport.KeepAliveMaxTime > 0 || configuration.Transport.KeepAliveMaxRequests > 0)) { serverHTTP.ConnContext = func(ctx context.Context, c net.Conn) context.Context { diff --git a/pkg/server/server_entrypoint_tcp_test.go b/pkg/server/server_entrypoint_tcp_test.go index 9ec5d2686..a7ea0a431 100644 --- a/pkg/server/server_entrypoint_tcp_test.go +++ b/pkg/server/server_entrypoint_tcp_test.go @@ -69,8 +69,10 @@ func testShutdown(t *testing.T, router *tcprouter.Router) { epConfig.LifeCycle.RequestAcceptGraceTimeout = 0 epConfig.LifeCycle.GraceTimeOut = ptypes.Duration(5 * time.Second) - epConfig.RespondingTimeouts.ReadTimeout = ptypes.Duration(5 * time.Second) - epConfig.RespondingTimeouts.WriteTimeout = ptypes.Duration(5 * time.Second) + readTimeout := ptypes.Duration(5 * time.Second) + epConfig.RespondingTimeouts.HTTP.ReadTimeout = &readTimeout + writeTimeout := ptypes.Duration(5 * time.Second) + epConfig.RespondingTimeouts.HTTP.WriteTimeout = &writeTimeout entryPoint, err := NewTCPEntryPoint(context.Background(), &static.EntryPoint{ // We explicitly use an IPV4 address because on Alpine, with an IPV6 address @@ -157,7 +159,8 @@ func startEntrypoint(entryPoint *TCPEntryPoint, router *tcprouter.Router) (net.C func TestReadTimeoutWithoutFirstByte(t *testing.T) { epConfig := &static.EntryPointsTransport{} epConfig.SetDefaults() - epConfig.RespondingTimeouts.ReadTimeout = ptypes.Duration(2 * time.Second) + readTimeout := ptypes.Duration(2 * time.Second) + epConfig.RespondingTimeouts.HTTP.ReadTimeout = &readTimeout entryPoint, err := NewTCPEntryPoint(context.Background(), &static.EntryPoint{ Address: ":0", @@ -194,7 +197,84 @@ func TestReadTimeoutWithoutFirstByte(t *testing.T) { func TestReadTimeoutWithFirstByte(t *testing.T) { epConfig := &static.EntryPointsTransport{} epConfig.SetDefaults() - epConfig.RespondingTimeouts.ReadTimeout = ptypes.Duration(2 * time.Second) + readTimeout := ptypes.Duration(2 * time.Second) + epConfig.RespondingTimeouts.HTTP.ReadTimeout = &readTimeout + + entryPoint, err := NewTCPEntryPoint(context.Background(), &static.EntryPoint{ + Address: ":0", + Transport: epConfig, + ForwardedHeaders: &static.ForwardedHeaders{}, + HTTP2: &static.HTTP2Config{}, + }, nil, nil) + require.NoError(t, err) + + router := &tcprouter.Router{} + router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + rw.WriteHeader(http.StatusOK) + })) + + conn, err := startEntrypoint(entryPoint, router) + require.NoError(t, err) + + _, err = conn.Write([]byte("GET /some HTTP/1.1\r\n")) + require.NoError(t, err) + + errChan := make(chan error) + + go func() { + b := make([]byte, 2048) + _, err := conn.Read(b) + errChan <- err + }() + + select { + case err := <-errChan: + require.Equal(t, io.EOF, err) + case <-time.Tick(5 * time.Second): + t.Error("Timeout while read") + } +} + +func TestLingeringTimeoutWithoutFirstByte(t *testing.T) { + epConfig := &static.EntryPointsTransport{} + epConfig.SetDefaults() + + entryPoint, err := NewTCPEntryPoint(context.Background(), &static.EntryPoint{ + Address: ":0", + Transport: epConfig, + ForwardedHeaders: &static.ForwardedHeaders{}, + HTTP2: &static.HTTP2Config{}, + }, nil, nil) + require.NoError(t, err) + + router := &tcprouter.Router{} + router.SetHTTPHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + rw.WriteHeader(http.StatusOK) + })) + + conn, err := startEntrypoint(entryPoint, router) + require.NoError(t, err) + + errChan := make(chan error) + + go func() { + b := make([]byte, 2048) + _, err := conn.Read(b) + errChan <- err + }() + + select { + case err := <-errChan: + require.Equal(t, io.EOF, err) + case <-time.Tick(5 * time.Second): + t.Error("Timeout while read") + } +} + +func TestLingeringTimeoutWithFirstByte(t *testing.T) { + epConfig := &static.EntryPointsTransport{} + epConfig.SetDefaults() + epConfig.RespondingTimeouts.TCP.LingeringTimeout = ptypes.Duration(time.Second) entryPoint, err := NewTCPEntryPoint(context.Background(), &static.EntryPoint{ Address: ":0", diff --git a/webui/public/traefiklabs-hub-button-app/main-v1.js b/webui/public/traefiklabs-hub-button-app/main-v1.js index 9d36a8b62..2c912be53 100644 --- a/webui/public/traefiklabs-hub-button-app/main-v1.js +++ b/webui/public/traefiklabs-hub-button-app/main-v1.js @@ -1,3 +1,3 @@ /* eslint-disable */ -!function(){var e={110:function(e,t,n){"use strict";var r=n(441),a={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},l={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},o={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},i={};function u(e){return r.isMemo(e)?o:i[e.$$typeof]||a}i[r.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},i[r.Memo]=o;var s=Object.defineProperty,c=Object.getOwnPropertyNames,f=Object.getOwnPropertySymbols,d=Object.getOwnPropertyDescriptor,p=Object.getPrototypeOf,h=Object.prototype;e.exports=function e(t,n,r){if("string"!==typeof n){if(h){var a=p(n);a&&a!==h&&e(t,a,r)}var o=c(n);f&&(o=o.concat(f(n)));for(var i=u(t),m=u(n),g=0;g