From c3e943658a5d5d01d1600ec1530a03714e23662b Mon Sep 17 00:00:00 2001 From: peacewalker122 Date: Tue, 23 Jul 2024 20:34:04 +0800 Subject: [PATCH 1/8] Modify certificatesDuration documentation --- docs/content/https/acme.md | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/content/https/acme.md b/docs/content/https/acme.md index c4eafafd8..62509b32c 100644 --- a/docs/content/https/acme.md +++ b/docs/content/https/acme.md @@ -606,9 +606,21 @@ docker run -v "/my/host/acme:/etc/traefik/acme" traefik _Optional, Default=2160_ -The `certificatesDuration` option defines the certificates' duration in hours. +`certificatesDuration` is used to calculate two durations: + +- `Renew Period`: the period before the end of the certificate duration, during which the certificate should be renewed. +- `Renew Interval`: the interval between renew attempts. + It defaults to `2160` (90 days) to follow Let's Encrypt certificates' duration. +| Certificate Duration | Renew Period | Renew Interval | +|----------------------|-------------------|-------------------------| +| >= 1 year | 4 months | 1 week | +| >= 90 days | 30 days | 1 day | +| >= 7 days | 1 day | 1 hour | +| >= 24 hours | 6 hours | 10 min | +| < 24 hours | 20 min | 1 min | + !!! warning "Traefik cannot manage certificates with a duration lower than 1 hour." ```yaml tab="File (YAML)" @@ -633,19 +645,6 @@ certificatesResolvers: # ... ``` -`certificatesDuration` is used to calculate two durations: - -- `Renew Period`: the period before the end of the certificate duration, during which the certificate should be renewed. -- `Renew Interval`: the interval between renew attempts. - -| Certificate Duration | Renew Period | Renew Interval | -|----------------------|-------------------|-------------------------| -| >= 1 year | 4 months | 1 week | -| >= 90 days | 30 days | 1 day | -| >= 7 days | 1 day | 1 hour | -| >= 24 hours | 6 hours | 10 min | -| < 24 hours | 20 min | 1 min | - ### `preferredChain` _Optional, Default=""_ From 70dd7cdc7195ef98b42934693e9a4973852f368c Mon Sep 17 00:00:00 2001 From: Romain Date: Tue, 23 Jul 2024 16:30:05 +0200 Subject: [PATCH 2/8] Enforce default cipher suites list Co-authored-by: Kevin Pollet --- pkg/provider/kubernetes/crd/kubernetes.go | 61 +++++---- .../kubernetes/crd/kubernetes_test.go | 120 ++++++++++++++++++ pkg/tls/tls.go | 1 + 3 files changed, 154 insertions(+), 28 deletions(-) diff --git a/pkg/provider/kubernetes/crd/kubernetes.go b/pkg/provider/kubernetes/crd/kubernetes.go index 0ef4d78ad..83f0b4846 100644 --- a/pkg/provider/kubernetes/crd/kubernetes.go +++ b/pkg/provider/kubernetes/crd/kubernetes.go @@ -876,64 +876,69 @@ func createChainMiddleware(ctx context.Context, namespace string, chain *traefik } func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options { - tlsOptionsCRD := client.GetTLSOptions() + tlsOptionsCRDs := client.GetTLSOptions() var tlsOptions map[string]tls.Options - if len(tlsOptionsCRD) == 0 { + if len(tlsOptionsCRDs) == 0 { return tlsOptions } tlsOptions = make(map[string]tls.Options) var nsDefault []string - for _, tlsOption := range tlsOptionsCRD { - logger := log.FromContext(log.With(ctx, log.Str("tlsOption", tlsOption.Name), log.Str("namespace", tlsOption.Namespace))) + for _, tlsOptionsCRD := range tlsOptionsCRDs { + logger := log.FromContext(log.With(ctx, log.Str("tlsOption", tlsOptionsCRD.Name), log.Str("namespace", tlsOptionsCRD.Namespace))) var clientCAs []tls.FileOrContent - for _, secretName := range tlsOption.Spec.ClientAuth.SecretNames { - secret, exists, err := client.GetSecret(tlsOption.Namespace, secretName) + for _, secretName := range tlsOptionsCRD.Spec.ClientAuth.SecretNames { + secret, exists, err := client.GetSecret(tlsOptionsCRD.Namespace, secretName) if err != nil { - logger.Errorf("Failed to fetch secret %s/%s: %v", tlsOption.Namespace, secretName, err) + logger.Errorf("Failed to fetch secret %s/%s: %v", tlsOptionsCRD.Namespace, secretName, err) continue } if !exists { - logger.Warnf("Secret %s/%s does not exist", tlsOption.Namespace, secretName) + logger.Warnf("Secret %s/%s does not exist", tlsOptionsCRD.Namespace, secretName) continue } - cert, err := getCABlocks(secret, tlsOption.Namespace, secretName) + cert, err := getCABlocks(secret, tlsOptionsCRD.Namespace, secretName) if err != nil { - logger.Errorf("Failed to extract CA from secret %s/%s: %v", tlsOption.Namespace, secretName, err) + logger.Errorf("Failed to extract CA from secret %s/%s: %v", tlsOptionsCRD.Namespace, secretName, err) continue } clientCAs = append(clientCAs, tls.FileOrContent(cert)) } - id := makeID(tlsOption.Namespace, tlsOption.Name) + id := makeID(tlsOptionsCRD.Namespace, tlsOptionsCRD.Name) // If the name is default, we override the default config. - if tlsOption.Name == tls.DefaultTLSConfigName { - id = tlsOption.Name - nsDefault = append(nsDefault, tlsOption.Namespace) + if tlsOptionsCRD.Name == tls.DefaultTLSConfigName { + id = tlsOptionsCRD.Name + nsDefault = append(nsDefault, tlsOptionsCRD.Namespace) } - alpnProtocols := tls.DefaultTLSOptions.ALPNProtocols - if len(tlsOption.Spec.ALPNProtocols) > 0 { - alpnProtocols = tlsOption.Spec.ALPNProtocols + tlsOption := tls.Options{} + tlsOption.SetDefaults() + + tlsOption.MinVersion = tlsOptionsCRD.Spec.MinVersion + tlsOption.MaxVersion = tlsOptionsCRD.Spec.MaxVersion + + if tlsOptionsCRD.Spec.CipherSuites != nil { + tlsOption.CipherSuites = tlsOptionsCRD.Spec.CipherSuites } - tlsOptions[id] = tls.Options{ - MinVersion: tlsOption.Spec.MinVersion, - MaxVersion: tlsOption.Spec.MaxVersion, - CipherSuites: tlsOption.Spec.CipherSuites, - CurvePreferences: tlsOption.Spec.CurvePreferences, - ClientAuth: tls.ClientAuth{ - CAFiles: clientCAs, - ClientAuthType: tlsOption.Spec.ClientAuth.ClientAuthType, - }, - SniStrict: tlsOption.Spec.SniStrict, - ALPNProtocols: alpnProtocols, + tlsOption.CurvePreferences = tlsOptionsCRD.Spec.CurvePreferences + tlsOption.ClientAuth = tls.ClientAuth{ + CAFiles: clientCAs, + ClientAuthType: tlsOptionsCRD.Spec.ClientAuth.ClientAuthType, } + tlsOption.SniStrict = tlsOptionsCRD.Spec.SniStrict + + if tlsOptionsCRD.Spec.ALPNProtocols != nil { + tlsOption.ALPNProtocols = tlsOptionsCRD.Spec.ALPNProtocols + } + + tlsOptions[id] = tlsOption } if len(nsDefault) > 1 { diff --git a/pkg/provider/kubernetes/crd/kubernetes_test.go b/pkg/provider/kubernetes/crd/kubernetes_test.go index 6724e5c63..1d9869d61 100644 --- a/pkg/provider/kubernetes/crd/kubernetes_test.go +++ b/pkg/provider/kubernetes/crd/kubernetes_test.go @@ -860,6 +860,21 @@ func TestLoadIngressRouteTCPs(t *testing.T) { "http/1.1", "acme-tls/1", }, + CipherSuites: []string{ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + }, }, }, }, @@ -915,6 +930,21 @@ func TestLoadIngressRouteTCPs(t *testing.T) { "http/1.1", "acme-tls/1", }, + CipherSuites: []string{ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + }, }, }, }, @@ -3063,6 +3093,21 @@ func TestLoadIngressRoutes(t *testing.T) { "http/1.1", "acme-tls/1", }, + CipherSuites: []string{ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + }, }, }, }, @@ -3121,6 +3166,21 @@ func TestLoadIngressRoutes(t *testing.T) { "http/1.1", "acme-tls/1", }, + CipherSuites: []string{ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + }, }, }, }, @@ -5511,6 +5571,21 @@ func TestCrossNamespace(t *testing.T) { "cross-ns-tls-options-cn": { MinVersion: "VersionTLS12", ALPNProtocols: []string{"h2", "http/1.1", "acme-tls/1"}, + CipherSuites: []string{ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + }, }, }, }, @@ -5555,6 +5630,21 @@ func TestCrossNamespace(t *testing.T) { "cross-ns-tls-options-cn": { MinVersion: "VersionTLS12", ALPNProtocols: []string{"h2", "http/1.1", "acme-tls/1"}, + CipherSuites: []string{ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + }, }, }, }, @@ -5803,6 +5893,21 @@ func TestCrossNamespace(t *testing.T) { "cross-ns-tls-options-cn": { MinVersion: "VersionTLS12", ALPNProtocols: []string{"h2", "http/1.1", "acme-tls/1"}, + CipherSuites: []string{ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + }, }, }, }, @@ -5846,6 +5951,21 @@ func TestCrossNamespace(t *testing.T) { "cross-ns-tls-options-cn": { MinVersion: "VersionTLS12", ALPNProtocols: []string{"h2", "http/1.1", "acme-tls/1"}, + CipherSuites: []string{ + "TLS_AES_128_GCM_SHA256", + "TLS_AES_256_GCM_SHA384", + "TLS_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", + "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", + "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", + "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", + "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + }, }, }, }, diff --git a/pkg/tls/tls.go b/pkg/tls/tls.go index bacc3e337..3bf366805 100644 --- a/pkg/tls/tls.go +++ b/pkg/tls/tls.go @@ -32,6 +32,7 @@ type Options struct { func (o *Options) SetDefaults() { // ensure http2 enabled o.ALPNProtocols = DefaultTLSOptions.ALPNProtocols + o.CipherSuites = DefaultTLSOptions.CipherSuites } // +k8s:deepcopy-gen=true From 0f4e72d522f32ffc0facea2ebf6f4ffeffc9443a Mon Sep 17 00:00:00 2001 From: Jesper Noordsij <45041769+jnoordsij@users.noreply.github.com> Date: Thu, 25 Jul 2024 15:14:04 +0200 Subject: [PATCH 3/8] Update the supported versions table for v3.1 release --- docs/content/deprecation/releases.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/content/deprecation/releases.md b/docs/content/deprecation/releases.md index 4ac402236..fa3387cda 100644 --- a/docs/content/deprecation/releases.md +++ b/docs/content/deprecation/releases.md @@ -6,7 +6,8 @@ Below is a non-exhaustive list of versions and their maintenance status: | Version | Release Date | Community Support | |---------|--------------|--------------------| -| 3.0 | Apr 29, 2024 | Yes | +| 3.1 | Jul 15, 2024 | Yes | +| 3.0 | Apr 29, 2024 | Ended Jul 15, 2024 | | 2.11 | Feb 12, 2024 | Ends Apr 29, 2025 | | 2.10 | Apr 24, 2023 | Ended Feb 12, 2024 | | 2.9 | Oct 03, 2022 | Ended Apr 24, 2023 | From 3ba53df00517ff5e01d4369e535b9776f16f62b6 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Mon, 29 Jul 2024 10:22:04 +0200 Subject: [PATCH 4/8] Document Docker port selection on multiple exposed ports --- docs/content/providers/docker.md | 10 ++++++---- docs/content/routing/providers/docker.md | 5 +++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/content/providers/docker.md b/docs/content/providers/docker.md index d47e9d78f..5202dfe32 100644 --- a/docs/content/providers/docker.md +++ b/docs/content/providers/docker.md @@ -117,12 +117,14 @@ When using Docker Compose, labels are specified by the directive Traefik retrieves the private IP and port of containers from the Docker API. -Port detection works as follows: +Port detection for private communication works as follows: - If a container [exposes](https://docs.docker.com/engine/reference/builder/#expose) a single port, - then Traefik uses this port for private communication. + then Traefik uses this port. - If a container [exposes](https://docs.docker.com/engine/reference/builder/#expose) multiple ports, - or does not expose any port, then you must manually specify which port Traefik should use for communication + then Traefik uses the lowest port. E.g. if `80` and `8080` are exposed, Traefik will use `80`. +- If a container does not expose any port, or the selection from multiple ports does not fit, + then you must manually specify which port Traefik should use for communication by using the label `traefik.http.services..loadbalancer.server.port` (Read more on this label in the dedicated section in [routing](../routing/providers/docker.md#port)). @@ -738,7 +740,7 @@ providers: _Optional, Default=false_ If the parameter is set to `true`, -any [servers load balancer](../routing/services/index.md#servers-load-balancer) defined for Docker containers is created +any [servers load balancer](../routing/services/index.md#servers-load-balancer) defined for Docker containers is created regardless of the [healthiness](https://docs.docker.com/engine/reference/builder/#healthcheck) of the corresponding containers. It also then stays alive and responsive even at times when it becomes empty, i.e. when all its children containers become unhealthy. diff --git a/docs/content/routing/providers/docker.md b/docs/content/routing/providers/docker.md index b120abbb7..1c30f7824 100644 --- a/docs/content/routing/providers/docker.md +++ b/docs/content/routing/providers/docker.md @@ -66,10 +66,11 @@ With Docker, Traefik can leverage labels attached to a container to generate rou ``` !!! important "Traefik Connecting to the Wrong Port: `HTTP/502 Gateway Error`" - By default, Traefik uses the first exposed port of a container. + By default, Traefik uses the lowest exposed port of a container as detailed in + [Port Detection](../providers/docker.md#port-detection) of the Docker provider. Setting the label `traefik.http.services.xxx.loadbalancer.server.port` - overrides that behavior. + overrides this behavior. ??? example "Specifying more than one router and service per container" From 5a70910dceeed4e57651128c1887f94f815c3153 Mon Sep 17 00:00:00 2001 From: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> Date: Mon, 29 Jul 2024 12:12:04 +0200 Subject: [PATCH 5/8] Improve explanation on API exposition --- docs/content/operations/api.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/content/operations/api.md b/docs/content/operations/api.md index 3b30993a5..f6786f6d5 100644 --- a/docs/content/operations/api.md +++ b/docs/content/operations/api.md @@ -16,13 +16,9 @@ including sensitive data. In production, it should be at least secured by authentication and authorizations. -A good sane default (non exhaustive) set of recommendations -would be to apply the following protection mechanisms: - -* At the transport level: - NOT publicly exposing the API's port, - keeping it restricted to internal networks - (as in the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege), applied to networks). +!!! info + It's recommended to NOT publicly exposing the API's port, keeping it restricted to internal networks + (as in the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege), applied to networks). ## Configuration From 898eab20ac8098e09b3bbc0409a3ff319f00de5b Mon Sep 17 00:00:00 2001 From: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> Date: Mon, 29 Jul 2024 15:39:06 +0200 Subject: [PATCH 6/8] Improve error and documentation on the needed link between router and service --- docs/content/providers/docker.md | 8 +- docs/content/routing/providers/docker.md | 121 +++++++++++++---------- go.mod | 2 +- pkg/provider/configuration.go | 7 +- 4 files changed, 78 insertions(+), 60 deletions(-) diff --git a/docs/content/providers/docker.md b/docs/content/providers/docker.md index 5202dfe32..2a11a2e7c 100644 --- a/docs/content/providers/docker.md +++ b/docs/content/providers/docker.md @@ -21,7 +21,7 @@ and [Docker Swarm Mode](https://docs.docker.com/engine/swarm/). ## Configuration Examples -??? example "Configuring Docker & Deploying / Exposing Services" +??? example "Configuring Docker & Deploying / Exposing one Service" Enabling the docker provider @@ -49,7 +49,7 @@ and [Docker Swarm Mode](https://docs.docker.com/engine/swarm/). - traefik.http.routers.my-container.rule=Host(`example.com`) ``` -??? example "Configuring Docker Swarm & Deploying / Exposing Services" +??? example "Configuring Docker Swarm & Deploying / Exposing one Service" Enabling the docker provider (Swarm Mode) @@ -80,7 +80,9 @@ and [Docker Swarm Mode](https://docs.docker.com/engine/swarm/). --providers.docker.swarmMode=true ``` - Attach labels to services (not to containers) while in Swarm mode (in your docker compose file) + Attach labels to a single service (not containers) while in Swarm mode (in your Docker compose file). + When there is only one service, and the router does not specify a service, + then that service is automatically assigned to the router. ```yaml version: "3" diff --git a/docs/content/routing/providers/docker.md b/docs/content/routing/providers/docker.md index 1c30f7824..e03e93dce 100644 --- a/docs/content/routing/providers/docker.md +++ b/docs/content/routing/providers/docker.md @@ -22,7 +22,7 @@ With Docker, Traefik can leverage labels attached to a container to generate rou ## Configuration Examples -??? example "Configuring Docker & Deploying / Exposing Services" +??? example "Configuring Docker & Deploying / Exposing one Service" Enabling the docker provider @@ -50,6 +50,56 @@ With Docker, Traefik can leverage labels attached to a container to generate rou - traefik.http.routers.my-container.rule=Host(`example.com`) ``` +??? example "Configuring Docker Swarm & Deploying / Exposing one Service" + + Enabling the docker provider (Swarm Mode) + + ```yaml tab="File (YAML)" + providers: + docker: + # swarm classic (1.12-) + # endpoint: "tcp://127.0.0.1:2375" + # docker swarm mode (1.12+) + endpoint: "tcp://127.0.0.1:2377" + swarmMode: true + ``` + + ```toml tab="File (TOML)" + [providers.docker] + # swarm classic (1.12-) + # endpoint = "tcp://127.0.0.1:2375" + # docker swarm mode (1.12+) + endpoint = "tcp://127.0.0.1:2377" + swarmMode = true + ``` + + ```bash tab="CLI" + # swarm classic (1.12-) + # --providers.docker.endpoint=tcp://127.0.0.1:2375 + # docker swarm mode (1.12+) + --providers.docker.endpoint=tcp://127.0.0.1:2377 + --providers.docker.swarmMode=true + ``` + + Attach labels to services (not containers) while in Swarm mode (in your Docker compose file). + When there is only one service, and the router does not specify a service, + then that service is automatically assigned to the router. + + ```yaml + version: "3" + services: + my-container: + deploy: + labels: + - traefik.http.routers.my-container.rule=Host(`example.com`) + - traefik.http.services.my-container-service.loadbalancer.server.port=8080 + ``` + + !!! important "Labels in Docker Swarm Mode" + While in Swarm Mode, Traefik uses labels found on services, not on individual containers. + Therefore, if you use a compose file with Swarm Mode, labels should be defined in the `deploy` part of your service. + This behavior is only enabled for docker-compose version 3+ ([Compose file reference](https://docs.docker.com/compose/compose-file/compose-file-v3/#labels-1)). + ??? example "Specify a Custom Port for the Container" Forward requests for `http://example.com` to `http://:12345`: @@ -61,6 +111,7 @@ With Docker, Traefik can leverage labels attached to a container to generate rou # ... labels: - traefik.http.routers.my-container.rule=Host(`example.com`) + - traefik.http.routers.my-container.service=my-service" # Tell Traefik to use the port 12345 to connect to `my-container` - traefik.http.services.my-service.loadbalancer.server.port=12345 ``` @@ -92,54 +143,6 @@ With Docker, Traefik can leverage labels attached to a container to generate rou - traefik.http.services.admin-service.loadbalancer.server.port=9000 ``` -??? example "Configuring Docker Swarm & Deploying / Exposing Services" - - Enabling the docker provider (Swarm Mode) - - ```yaml tab="File (YAML)" - providers: - docker: - # swarm classic (1.12-) - # endpoint: "tcp://127.0.0.1:2375" - # docker swarm mode (1.12+) - endpoint: "tcp://127.0.0.1:2377" - swarmMode: true - ``` - - ```toml tab="File (TOML)" - [providers.docker] - # swarm classic (1.12-) - # endpoint = "tcp://127.0.0.1:2375" - # docker swarm mode (1.12+) - endpoint = "tcp://127.0.0.1:2377" - swarmMode = true - ``` - - ```bash tab="CLI" - # swarm classic (1.12-) - # --providers.docker.endpoint=tcp://127.0.0.1:2375 - # docker swarm mode (1.12+) - --providers.docker.endpoint=tcp://127.0.0.1:2377 - --providers.docker.swarmMode=true - ``` - - Attach labels to services (not to containers) while in Swarm mode (in your docker compose file) - - ```yaml - version: "3" - services: - my-container: - deploy: - labels: - - traefik.http.routers.my-container.rule=Host(`example.com`) - - traefik.http.services.my-container-service.loadbalancer.server.port=8080 - ``` - - !!! important "Labels in Docker Swarm Mode" - While in Swarm Mode, Traefik uses labels found on services, not on individual containers. - Therefore, if you use a compose file with Swarm Mode, labels should be defined in the `deploy` part of your service. - This behavior is only enabled for docker-compose version 3+ ([Compose file reference](https://docs.docker.com/compose/compose-file/compose-file-v3/#labels-1)). - ## Routing Configuration !!! info "Labels" @@ -158,7 +161,7 @@ and the router automatically gets a rule defined by `defaultRule` (if no rule fo --8<-- "content/routing/providers/service-by-label.md" -??? example "Automatic service assignment with labels" +??? example "Automatic assignment with one Service" With labels in a compose file @@ -169,7 +172,7 @@ and the router automatically gets a rule defined by `defaultRule` (if no rule fo - "traefik.http.services.myservice.loadbalancer.server.port=80" ``` -??? example "Automatic service creation and assignment with labels" +??? example "Automatic service creation with one Router" With labels in a compose file @@ -180,6 +183,18 @@ and the router automatically gets a rule defined by `defaultRule` (if no rule fo - "traefik.http.routers.myproxy.rule=Host(`example.net`)" ``` +??? example "Explicit definition with one Service" + + With labels in a compose file + + ```yaml + labels: + - traefik.http.routers.www-router.rule=Host(`example-a.com`) + # Explicit link between the router and the service + - traefik.http.routers.www-router.service=www-service + - traefik.http.services.www-service.loadbalancer.server.port=8000 + ``` + ### Routers To update the configuration of the Router automatically attached to the container, @@ -469,7 +484,7 @@ More information about available middlewares in the dedicated [middlewares secti You can declare TCP Routers and/or Services using labels. -??? example "Declaring TCP Routers and Services" +??? example "Declaring TCP Routers with one Service" ```yaml services: @@ -598,7 +613,7 @@ You can declare TCP Routers and/or Services using labels. You can declare UDP Routers and/or Services using labels. -??? example "Declaring UDP Routers and Services" +??? example "Declaring UDP Routers with one Service" ```yaml services: diff --git a/go.mod b/go.mod index 1289bbcf7..88a3eb3f6 100644 --- a/go.mod +++ b/go.mod @@ -67,6 +67,7 @@ require ( github.com/vulcand/predicate v1.2.0 go.elastic.co/apm/module/apmot/v2 v2.4.8 go.elastic.co/apm/v2 v2.4.8 + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // No tag on the repo. golang.org/x/mod v0.18.0 golang.org/x/net v0.26.0 golang.org/x/text v0.16.0 @@ -326,7 +327,6 @@ require ( go4.org/intern v0.0.0-20230525184215-6c62f75575cb // indirect go4.org/unsafe/assume-no-moving-gc v0.0.0-20230525183740-e7c30c78aeb2 // indirect golang.org/x/crypto v0.24.0 // indirect - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/oauth2 v0.21.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.21.0 // indirect diff --git a/pkg/provider/configuration.go b/pkg/provider/configuration.go index ac1e4b54a..47a65c410 100644 --- a/pkg/provider/configuration.go +++ b/pkg/provider/configuration.go @@ -13,6 +13,7 @@ import ( "github.com/traefik/traefik/v2/pkg/config/dynamic" "github.com/traefik/traefik/v2/pkg/log" "github.com/traefik/traefik/v2/pkg/tls" + "golang.org/x/exp/maps" ) // Merge merges multiple configurations. @@ -383,7 +384,7 @@ func BuildTCPRouterConfiguration(ctx context.Context, configuration *dynamic.TCP if len(configuration.Services) > 1 { delete(configuration.Routers, routerName) loggerRouter. - Error("Could not define the service name for the router: too many services") + Errorf("Router %s cannot be linked automatically with multiple Services: %q", routerName, maps.Keys(configuration.Services)) continue } @@ -405,7 +406,7 @@ func BuildUDPRouterConfiguration(ctx context.Context, configuration *dynamic.UDP if len(configuration.Services) > 1 { delete(configuration.Routers, routerName) loggerRouter. - Error("Could not define the service name for the router: too many services") + Errorf("Router %s cannot be linked automatically with multiple Services: %q", routerName, maps.Keys(configuration.Services)) continue } @@ -452,7 +453,7 @@ func BuildRouterConfiguration(ctx context.Context, configuration *dynamic.HTTPCo if len(configuration.Services) > 1 { delete(configuration.Routers, routerName) loggerRouter. - Error("Could not define the service name for the router: too many services") + Errorf("Router %s cannot be linked automatically with multiple Services: %q", routerName, maps.Keys(configuration.Services)) continue } From ba6b4cbcc37ff7428672edc1bed07b2d88f338fa Mon Sep 17 00:00:00 2001 From: Michel Loiseleur <97035654+mloiseleur@users.noreply.github.com> Date: Mon, 29 Jul 2024 15:58:04 +0200 Subject: [PATCH 7/8] chore(ci): fix deprecation and optimization --- .github/workflows/build.yaml | 4 ++++ .github/workflows/documentation.yml | 2 +- .github/workflows/experimental.yaml | 4 ++-- .github/workflows/test-integration.yaml | 9 +++++---- .github/workflows/test-unit.yaml | 4 ++++ 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 95e921ebf..542cd056b 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -4,6 +4,10 @@ on: pull_request: branches: - '*' + paths-ignore: + - 'docs/**' + - '**.md' + - 'script/gcg/**' env: GO_VERSION: '1.22' diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 696237d59..c278889e4 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -24,7 +24,7 @@ jobs: fetch-depth: 0 - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/experimental.yaml b/.github/workflows/experimental.yaml index fa91bfda5..7d9e2e2ea 100644 --- a/.github/workflows/experimental.yaml +++ b/.github/workflows/experimental.yaml @@ -56,10 +56,10 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Build docker experimental image env: diff --git a/.github/workflows/test-integration.yaml b/.github/workflows/test-integration.yaml index cd157edad..c00cad272 100644 --- a/.github/workflows/test-integration.yaml +++ b/.github/workflows/test-integration.yaml @@ -4,9 +4,10 @@ on: pull_request: branches: - '*' - push: - branches: - - 'gh-actions' + paths-ignore: + - 'docs/**' + - '**.md' + - 'script/gcg/**' env: GO_VERSION: '1.22' @@ -63,7 +64,7 @@ jobs: - name: Generate go test Slice id: test_split - uses: hashicorp-forge/go-test-split-action@v1 + uses: hashicorp-forge/go-test-split-action@v2.0.0 with: packages: ./integration total: ${{ matrix.parallel }} diff --git a/.github/workflows/test-unit.yaml b/.github/workflows/test-unit.yaml index 43ea42853..a22dc4cda 100644 --- a/.github/workflows/test-unit.yaml +++ b/.github/workflows/test-unit.yaml @@ -4,6 +4,10 @@ on: pull_request: branches: - '*' + paths-ignore: + - 'docs/**' + - '**.md' + - 'script/gcg/**' env: GO_VERSION: '1.22' From 210400905fab19623fd7d032c87f3903c1bed579 Mon Sep 17 00:00:00 2001 From: Romain Date: Tue, 30 Jul 2024 14:14:03 +0200 Subject: [PATCH 8/8] Prepare release v2.11.7 --- CHANGELOG.md | 16 ++++++++++++++++ script/gcg/traefik-bugfix.toml | 6 +++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec0077e20..034af8320 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## [v2.11.7](https://github.com/traefik/traefik/tree/v2.11.7) (2024-07-30) +[All Commits](https://github.com/traefik/traefik/compare/v2.11.6...v2.11.7) + +**Bug fixes:** +- **[logs]** Make the log about new version more accurate ([#10903](https://github.com/traefik/traefik/pull/10903) by [jmcbri](https://github.com/jmcbri)) +- **[tls,k8s/crd,k8s]** Enforce default cipher suites list ([#10907](https://github.com/traefik/traefik/pull/10907) by [rtribotte](https://github.com/rtribotte)) + +**Documentation:** +- **[acme]** Modify certificatesDuration documentation ([#10920](https://github.com/traefik/traefik/pull/10920) by [peacewalker122](https://github.com/peacewalker122)) +- **[api]** Improve explanation on API exposition ([#10926](https://github.com/traefik/traefik/pull/10926) by [mloiseleur](https://github.com/mloiseleur)) +- **[docker,consul,rancher,ecs]** Improve doc on sensitive data stored into labels/tags ([#10873](https://github.com/traefik/traefik/pull/10873) by [emilevauge](https://github.com/emilevauge)) +- **[docker,logs]** Improve error and documentation on the needed link between router and service ([#10262](https://github.com/traefik/traefik/pull/10262) by [mloiseleur](https://github.com/mloiseleur)) +- **[docker]** Document Docker port selection on multiple exposed ports ([#10935](https://github.com/traefik/traefik/pull/10935) by [mbrodala](https://github.com/mbrodala)) +- Update the supported versions table for v3.1 release ([#10933](https://github.com/traefik/traefik/pull/10933) by [jnoordsij](https://github.com/jnoordsij)) +- Update PR approval process ([#10887](https://github.com/traefik/traefik/pull/10887) by [emilevauge](https://github.com/emilevauge)) + ## [v2.11.6](https://github.com/traefik/traefik/tree/v2.11.6) (2024-07-02) [All Commits](https://github.com/traefik/traefik/compare/v2.11.5...v2.11.6) diff --git a/script/gcg/traefik-bugfix.toml b/script/gcg/traefik-bugfix.toml index b582e5eb6..88a1fcee1 100644 --- a/script/gcg/traefik-bugfix.toml +++ b/script/gcg/traefik-bugfix.toml @@ -4,11 +4,11 @@ RepositoryName = "traefik" OutputType = "file" FileName = "traefik_changelog.md" -# example new bugfix v2.11.6 +# example new bugfix v2.11.7 CurrentRef = "v2.11" -PreviousRef = "v2.11.5" +PreviousRef = "v2.11.6" BaseBranch = "v2.11" -FutureCurrentRefName = "v2.11.6" +FutureCurrentRefName = "v2.11.7" ThresholdPreviousRef = 10 ThresholdCurrentRef = 10