diff --git a/CHANGELOG.md b/CHANGELOG.md index 31915fed5..4c1c4d84d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +## [v2.6.1](https://github.com/traefik/traefik/tree/v2.6.1) (2022-02-14) +[All Commits](https://github.com/traefik/traefik/compare/v2.6.0...v2.6.1) + +**Bug fixes:** +- **[acme]** Add domain to HTTP challenge errors ([#8740](https://github.com/traefik/traefik/pull/8740) by [ldez](https://github.com/ldez)) +- **[metrics]** Fix metrics bucket key high cardinality ([#8761](https://github.com/traefik/traefik/pull/8761) by [tomMoulard](https://github.com/tomMoulard)) +- **[middleware,tls]** Use CNAME for SNI check on host header ([#8773](https://github.com/traefik/traefik/pull/8773) by [ldez](https://github.com/ldez)) +- **[middleware,tracing]** Rename Datadog span tags ([#8323](https://github.com/traefik/traefik/pull/8323) by [luckielordie](https://github.com/luckielordie)) +- **[tls]** Apply the same approach as the rules system on the TLS configuration choice ([#8764](https://github.com/traefik/traefik/pull/8764) by [ldez](https://github.com/ldez)) + +**Documentation:** +- **[acme]** Add Hurricane Electric to acme documentation ([#8746](https://github.com/traefik/traefik/pull/8746) by [vladshub](https://github.com/vladshub)) +- **[acme]** Clarify that ACME challenge is mandatory ([#8739](https://github.com/traefik/traefik/pull/8739) by [mpl](https://github.com/mpl)) +- **[http3]** Explain a bit more around enabling HTTP3 ([#8731](https://github.com/traefik/traefik/pull/8731) by [SantoDE](https://github.com/SantoDE)) +- **[metrics]** Fix mixups in metrics documentation ([#8752](https://github.com/traefik/traefik/pull/8752) by [tomMoulard](https://github.com/tomMoulard)) +- **[middleware,k8s/crd]** Fix Kubernetes TCP examples ([#8759](https://github.com/traefik/traefik/pull/8759) by [sylr](https://github.com/sylr)) + ## [v2.6.0](https://github.com/traefik/traefik/tree/v2.6.0) (2022-01-24) [All Commits](https://github.com/traefik/traefik/compare/v2.5.0-rc1...v2.6.0) diff --git a/cmd/traefik/traefik.go b/cmd/traefik/traefik.go index f03480bc0..78b2d873e 100644 --- a/cmd/traefik/traefik.go +++ b/cmd/traefik/traefik.go @@ -190,7 +190,7 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err // Entrypoints - serverEntryPointsTCP, err := server.NewTCPEntryPoints(staticConfiguration.EntryPoints) + serverEntryPointsTCP, err := server.NewTCPEntryPoints(staticConfiguration.EntryPoints, staticConfiguration.HostResolver) if err != nil { return nil, err } diff --git a/docs/content/middlewares/tcp/inflightconn.md b/docs/content/middlewares/tcp/inflightconn.md index 73e9e0df0..036ca74e1 100644 --- a/docs/content/middlewares/tcp/inflightconn.md +++ b/docs/content/middlewares/tcp/inflightconn.md @@ -14,7 +14,7 @@ labels: ```yaml tab="Kubernetes" apiVersion: traefik.containo.us/v1alpha1 -kind: Middleware +kind: MiddlewareTCP metadata: name: test-inflightconn spec: diff --git a/docs/content/middlewares/tcp/overview.md b/docs/content/middlewares/tcp/overview.md index 1fd53a963..8fc5f4919 100644 --- a/docs/content/middlewares/tcp/overview.md +++ b/docs/content/middlewares/tcp/overview.md @@ -36,7 +36,7 @@ spec: --- apiVersion: traefik.containo.us/v1alpha1 -kind: Middleware +kind: MiddlewareTCP metadata: name: foo-ip-whitelist spec: @@ -47,7 +47,7 @@ spec: --- apiVersion: traefik.containo.us/v1alpha1 -kind: IngressRoute +kind: IngressRouteTCP metadata: name: ingressroute spec: diff --git a/docs/content/migration/v2.md b/docs/content/migration/v2.md index 1793ddd4c..95b3b636a 100644 --- a/docs/content/migration/v2.md +++ b/docs/content/migration/v2.md @@ -438,3 +438,17 @@ To enable HTTP/3 on an EntryPoint, please check out the [HTTP/3 configuration](. In `v2.6`, the [Kubernetes Gateway API provider](../providers/kubernetes-gateway.md) now only supports the version [v1alpha2](https://gateway-api.sigs.k8s.io/v1alpha2/guides/getting-started/) of the specification and [route namespaces](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.RouteNamespaces) selectors, which requires Traefik to fetch and watch the cluster namespaces. Therefore, the [RBAC](../reference/dynamic-configuration/kubernetes-gateway.md#rbac) and [CRD](../reference/dynamic-configuration/kubernetes-gateway.md#definitions) definitions must be updated. + +## v2.6.0 to v2.6.1 + +### Metrics + +In `v2.6.1`, the metrics system does not support any more custom HTTP method verbs to prevent potential metrics cardinality overhead. +In consequence, for metrics having the method label, +if the HTTP method verb of a request is not one defined in the set of common methods for [`HTTP/1.1`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) +or the [`PRI`](https://datatracker.ietf.org/doc/html/rfc7540#section-11.6) verb (for `HTTP/2`), +the value for the method label becomes `EXTENSION_METHOD`, instead of the request's one. + +### Tracing + +In `v2.6.1`, the Datadog tags added to a span changed from `service.name` to `traefik.service.name` and from `router.name` to `traefik.router.name`. diff --git a/docs/content/observability/metrics/overview.md b/docs/content/observability/metrics/overview.md index 002aa096a..184d47f2f 100644 --- a/docs/content/observability/metrics/overview.md +++ b/docs/content/observability/metrics/overview.md @@ -62,7 +62,7 @@ traefik_config_last_reload_success The expiration date of certificates. -Available labels: `cn`, `sans`, `serial`. +[Labels](#labels): `cn`, `sans`, `serial`. ```dd tab="Datadog" tls.certs.notAfterTimestamp @@ -94,7 +94,7 @@ traefik_tls_certs_not_after The total count of HTTP requests received by an entrypoint. -Available labels: `code`, `method`, `protocol`, `entrypoint`. +[Labels](#labels): `code`, `method`, `protocol`, `entrypoint`. ```dd tab="Datadog" entrypoint.request.total @@ -117,7 +117,7 @@ traefik_entrypoint_requests_total The total count of HTTPS requests received by an entrypoint. -Available labels: `tls_version`, `tls_cipher`, `entrypoint`. +[Labels](#labels): `tls_version`, `tls_cipher`, `entrypoint`. ```dd tab="Datadog" entrypoint.request.tls.total @@ -140,7 +140,7 @@ traefik_entrypoint_requests_tls_total Request processing duration histogram on an entrypoint. -Available labels: `code`, `method`, `protocol`, `entrypoint`. +[Labels](#labels): `code`, `method`, `protocol`, `entrypoint`. ```dd tab="Datadog" entrypoint.request.duration @@ -163,7 +163,7 @@ traefik_entrypoint_request_duration_seconds The current count of open connections on an entrypoint. -Available labels: `method`, `protocol`, `entrypoint`. +[Labels](#labels): `method`, `protocol`, `entrypoint`. ```dd tab="Datadog" entrypoint.connections.open @@ -195,7 +195,7 @@ traefik_entrypoint_open_connections The total count of HTTP requests handled by a router. -Available labels: `code`, `method`, `protocol`, `router`, `service`. +[Labels](#labels): `code`, `method`, `protocol`, `router`, `service`. ```dd tab="Datadog" router.request.total @@ -218,7 +218,7 @@ traefik_router_requests_total The total count of HTTPS requests handled by a router. -Available labels: `tls_version`, `tls_cipher`, `router`, `service`. +[Labels](#labels): `tls_version`, `tls_cipher`, `router`, `service`. ```dd tab="Datadog" router.request.tls.total @@ -241,7 +241,7 @@ traefik_router_requests_tls_total Request processing duration histogram on a router. -Available labels: `code`, `method`, `protocol`, `router`, `service`. +[Labels](#labels): `code`, `method`, `protocol`, `router`, `service`. ```dd tab="Datadog" router.request.duration @@ -264,7 +264,7 @@ traefik_router_request_duration_seconds The current count of open connections on a router. -Available labels: `method`, `protocol`, `router`, `service`. +[Labels](#labels): `method`, `protocol`, `router`, `service`. ```dd tab="Datadog" router.connections.open @@ -298,7 +298,7 @@ traefik_router_open_connections The total count of HTTP requests processed on a service. -Available labels: `code`, `method`, `protocol`, `service`. +[Labels](#labels): `code`, `method`, `protocol`, `service`. ```dd tab="Datadog" service.request.total @@ -321,7 +321,7 @@ traefik_service_requests_total The total count of HTTPS requests processed on a service. -Available labels: `tls_version`, `tls_cipher`, `service`. +[Labels](#labels): `tls_version`, `tls_cipher`, `service`. ```dd tab="Datadog" router.service.tls.total @@ -344,7 +344,7 @@ traefik_service_requests_tls_total Request processing duration histogram on a service. -Available labels: `code`, `method`, `protocol`, `service`. +[Labels](#labels): `code`, `method`, `protocol`, `service`. ```dd tab="Datadog" service.request.duration @@ -367,7 +367,7 @@ traefik_service_request_duration_seconds The current count of open connections on a service. -Available labels: `method`, `protocol`, `service`. +[Labels](#labels): `method`, `protocol`, `service`. ```dd tab="Datadog" service.connections.open @@ -390,7 +390,7 @@ traefik_service_open_connections The count of requests retries on a service. -Available labels: `service`. +[Labels](#labels): `service`. ```dd tab="Datadog" service.retries.total @@ -413,7 +413,7 @@ traefik_service_retries_total Current service's server status, described by a gauge with a value of 0 for a down server or a value of 1 for an up server. -Available labels: `service`, `url`. +[Labels](#labels): `service`, `url`. ```dd tab="Datadog" service.server.up @@ -431,3 +431,28 @@ traefik_service_server_up # Default prefix: "traefik" {prefix}.service.server.up ``` + +## Labels + +Here is a comprehensive list of labels that are provided by the metrics: + +| Label | Description | example | +|---------------|---------------------------------------|----------------------------| +| `cn` | Certificate Common Name | "example.com" | +| `code` | Request code | "200" | +| `entrypoint` | Entrypoint that handled the request | "example_entrypoint" | +| `method` | Request Method | "GET" | +| `protocol` | Request protocol | "http" | +| `router` | Router that handled the request | "example_router" | +| `sans` | Certificate Subject Alternative NameS | "example.com" | +| `serial` | Certificate Serial Number | "123..." | +| `service` | Service that handled the request | "example_service@provider" | +| `tls_cipher` | TLS cipher used for the request | "TLS_FALLBACK_SCSV" | +| `tls_version` | TLS version used for the request | "1.0" | +| `url` | Service server url | "http://example.com" | + +!!! info "`method` label value" + + If the HTTP method verb on a request is not one defined in the set of common methods for [`HTTP/1.1`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods) + or the [`PRI`](https://datatracker.ietf.org/doc/html/rfc7540#section-11.6) verb (for `HTTP/2`), + then the value for the method label becomes `EXTENSION_METHOD`. diff --git a/integration/fixtures/https/rootcas/https.toml b/integration/fixtures/https/rootcas/https.toml index 2525c7473..37e450fc9 100644 --- a/integration/fixtures/https/rootcas/https.toml +++ b/integration/fixtures/https/rootcas/https.toml @@ -9,18 +9,24 @@ # Use certificate in net/internal/testcert.go rootCAs = [ """ -----BEGIN CERTIFICATE----- -MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS +MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw -MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4 -iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul -rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO -BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw -AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA -AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9 -tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs -h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM -fblo6RBxUQ== +MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r +bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U +aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P +YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk +POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu +h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE +AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv +bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI +5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv +cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2 ++tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B +grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK +5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/ +WkBKOclmOV2xlTVuPw== -----END CERTIFICATE----- """] diff --git a/integration/fixtures/https/rootcas/local.crt b/integration/fixtures/https/rootcas/local.crt index 07457e03e..1b683072e 100644 --- a/integration/fixtures/https/rootcas/local.crt +++ b/integration/fixtures/https/rootcas/local.crt @@ -1,14 +1,20 @@ -----BEGIN CERTIFICATE----- -MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS +MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw -MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4 -iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul -rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO -BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw -AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA -AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9 -tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs -h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM -fblo6RBxUQ== +MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r +bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U +aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P +YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk +POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu +h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE +AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv +bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI +5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv +cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2 ++tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B +grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK +5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/ +WkBKOclmOV2xlTVuPw== -----END CERTIFICATE----- diff --git a/pkg/middlewares/metrics/metrics.go b/pkg/middlewares/metrics/metrics.go index 1f216393b..a491401cb 100644 --- a/pkg/middlewares/metrics/metrics.go +++ b/pkg/middlewares/metrics/metrics.go @@ -159,12 +159,27 @@ func containsHeader(req *http.Request, name, value string) bool { return false } +// getMethod returns the request's method. +// It checks whether the method is a valid UTF-8 string. +// To restrict the (potentially infinite) number of accepted values for the method, +// and avoid unbounded memory issues, +// values that are not part of the set of HTTP verbs are replaced with EXTENSION_METHOD. +// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods +// https://datatracker.ietf.org/doc/html/rfc2616/#section-5.1.1. func getMethod(r *http.Request) string { if !utf8.ValidString(r.Method) { - log.Warnf("Invalid HTTP method encoding: %s", r.Method) + log.WithoutContext().Warnf("Invalid HTTP method encoding: %s", r.Method) return "NON_UTF8_HTTP_METHOD" } - return r.Method + + switch r.Method { + case "HEAD", "GET", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", // https://datatracker.ietf.org/doc/html/rfc7231#section-4 + "PATCH", // https://datatracker.ietf.org/doc/html/rfc5789#section-2 + "PRI": // https://datatracker.ietf.org/doc/html/rfc7540#section-11.6 + return r.Method + default: + return "EXTENSION_METHOD" + } } type retryMetrics interface { diff --git a/pkg/middlewares/metrics/metrics_test.go b/pkg/middlewares/metrics/metrics_test.go index 596ac6abe..9390e49f5 100644 --- a/pkg/middlewares/metrics/metrics_test.go +++ b/pkg/middlewares/metrics/metrics_test.go @@ -4,6 +4,7 @@ import ( "net/http" "net/http/httptest" "reflect" + "strings" "testing" "github.com/go-kit/kit/metrics" @@ -98,3 +99,33 @@ func TestCloseNotifier(t *testing.T) { }) } } + +func Test_getMethod(t *testing.T) { + testCases := []struct { + method string + expected string + }{ + { + method: http.MethodGet, + expected: http.MethodGet, + }, + { + method: strings.ToLower(http.MethodGet), + expected: "EXTENSION_METHOD", + }, + { + method: "THIS_IS_NOT_A_VALID_METHOD", + expected: "EXTENSION_METHOD", + }, + } + + for _, test := range testCases { + test := test + t.Run(test.method, func(t *testing.T) { + t.Parallel() + + request := httptest.NewRequest(test.method, "http://example.com", nil) + assert.Equal(t, test.expected, getMethod(request)) + }) + } +} diff --git a/pkg/middlewares/snicheck/snicheck.go b/pkg/middlewares/snicheck/snicheck.go new file mode 100644 index 000000000..e18b605cb --- /dev/null +++ b/pkg/middlewares/snicheck/snicheck.go @@ -0,0 +1,107 @@ +package snicheck + +import ( + "net" + "net/http" + "strings" + + "github.com/traefik/traefik/v2/pkg/log" + "github.com/traefik/traefik/v2/pkg/middlewares/requestdecorator" + traefiktls "github.com/traefik/traefik/v2/pkg/tls" +) + +// SNICheck is an HTTP handler that checks whether the TLS configuration for the server name is the same as for the host header. +type SNICheck struct { + next http.Handler + tlsOptionsForHost map[string]string +} + +// New creates a new SNICheck. +func New(tlsOptionsForHost map[string]string, next http.Handler) *SNICheck { + return &SNICheck{next: next, tlsOptionsForHost: tlsOptionsForHost} +} + +func (s SNICheck) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + if req.TLS == nil { + s.next.ServeHTTP(rw, req) + return + } + + host := getHost(req) + serverName := strings.TrimSpace(req.TLS.ServerName) + + // Domain Fronting + if !strings.EqualFold(host, serverName) { + tlsOptionHeader := findTLSOptionName(s.tlsOptionsForHost, host, true) + tlsOptionSNI := findTLSOptionName(s.tlsOptionsForHost, serverName, false) + + if tlsOptionHeader != tlsOptionSNI { + log.WithoutContext(). + WithField("host", host). + WithField("req.Host", req.Host). + WithField("req.TLS.ServerName", req.TLS.ServerName). + Debugf("TLS options difference: SNI:%s, Header:%s", tlsOptionSNI, tlsOptionHeader) + http.Error(rw, http.StatusText(http.StatusMisdirectedRequest), http.StatusMisdirectedRequest) + return + } + } + + s.next.ServeHTTP(rw, req) +} + +func getHost(req *http.Request) string { + h := requestdecorator.GetCNAMEFlatten(req.Context()) + if h != "" { + return h + } + + h = requestdecorator.GetCanonizedHost(req.Context()) + if h != "" { + return h + } + + host, _, err := net.SplitHostPort(req.Host) + if err != nil { + host = req.Host + } + + return strings.TrimSpace(host) +} + +func findTLSOptionName(tlsOptionsForHost map[string]string, host string, fqdn bool) string { + name := findTLSOptName(tlsOptionsForHost, host, fqdn) + if name != "" { + return name + } + + name = findTLSOptName(tlsOptionsForHost, strings.ToLower(host), fqdn) + if name != "" { + return name + } + + return traefiktls.DefaultTLSConfigName +} + +func findTLSOptName(tlsOptionsForHost map[string]string, host string, fqdn bool) string { + if tlsOptions, ok := tlsOptionsForHost[host]; ok { + return tlsOptions + } + + if !fqdn { + return "" + } + + if last := len(host) - 1; last >= 0 && host[last] == '.' { + if tlsOptions, ok := tlsOptionsForHost[host[:last]]; ok { + return tlsOptions + } + + return "" + } + + if tlsOptions, ok := tlsOptionsForHost[host+"."]; ok { + return tlsOptions + } + + return "" +} diff --git a/pkg/middlewares/snicheck/snicheck_test.go b/pkg/middlewares/snicheck/snicheck_test.go new file mode 100644 index 000000000..a9d57bdf6 --- /dev/null +++ b/pkg/middlewares/snicheck/snicheck_test.go @@ -0,0 +1,60 @@ +package snicheck + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSNICheck_ServeHTTP(t *testing.T) { + testCases := []struct { + desc string + tlsOptionsForHost map[string]string + host string + expected int + }{ + { + desc: "no TLS options", + expected: http.StatusOK, + }, + { + desc: "with TLS options", + tlsOptionsForHost: map[string]string{ + "example.com": "foo", + }, + expected: http.StatusOK, + }, + { + desc: "server name and host doesn't have the same TLS configuration", + tlsOptionsForHost: map[string]string{ + "example.com": "foo", + }, + host: "example.com", + expected: http.StatusMisdirectedRequest, + }, + } + + for _, test := range testCases { + test := test + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {}) + + sniCheck := New(test.tlsOptionsForHost, next) + + req := httptest.NewRequest(http.MethodGet, "https://localhost", nil) + if test.host != "" { + req.Host = test.host + } + + recorder := httptest.NewRecorder() + + sniCheck.ServeHTTP(recorder, req) + + assert.Equal(t, test.expected, recorder.Code) + }) + } +} diff --git a/pkg/middlewares/tracing/forwarder.go b/pkg/middlewares/tracing/forwarder.go index c65d322e1..51c313f4c 100644 --- a/pkg/middlewares/tracing/forwarder.go +++ b/pkg/middlewares/tracing/forwarder.go @@ -43,8 +43,8 @@ func (f *forwarderMiddleware) ServeHTTP(rw http.ResponseWriter, req *http.Reques span, req, finish := tr.StartSpanf(req, ext.SpanKindRPCClientEnum, "forward", opParts, "/") defer finish() - span.SetTag("service.name", f.service) - span.SetTag("router.name", f.router) + span.SetTag("traefik.service.name", f.service) + span.SetTag("traefik.router.name", f.router) ext.HTTPMethod.Set(span, req.Method) ext.HTTPUrl.Set(span, req.URL.String()) span.SetTag("http.host", req.Host) diff --git a/pkg/middlewares/tracing/forwarder_test.go b/pkg/middlewares/tracing/forwarder_test.go index d8b1cbb99..1253412d3 100644 --- a/pkg/middlewares/tracing/forwarder_test.go +++ b/pkg/middlewares/tracing/forwarder_test.go @@ -36,12 +36,12 @@ func TestNewForwarder(t *testing.T) { router: "some-service.domain.tld", expected: expected{ Tags: map[string]interface{}{ - "http.host": "www.test.com", - "http.method": "GET", - "http.url": "http://www.test.com/toto", - "service.name": "some-service.domain.tld", - "router.name": "some-service.domain.tld", - "span.kind": ext.SpanKindRPCClientEnum, + "http.host": "www.test.com", + "http.method": "GET", + "http.url": "http://www.test.com/toto", + "traefik.service.name": "some-service.domain.tld", + "traefik.router.name": "some-service.domain.tld", + "span.kind": ext.SpanKindRPCClientEnum, }, OperationName: "forward some-service.domain.tld/some-service.domain.tld", }, @@ -56,12 +56,12 @@ func TestNewForwarder(t *testing.T) { router: "some-service-100.slug.namespace.environment.domain.tld", expected: expected{ Tags: map[string]interface{}{ - "http.host": "www.test.com", - "http.method": "GET", - "http.url": "http://www.test.com/toto", - "service.name": "some-service-100.slug.namespace.environment.domain.tld", - "router.name": "some-service-100.slug.namespace.environment.domain.tld", - "span.kind": ext.SpanKindRPCClientEnum, + "http.host": "www.test.com", + "http.method": "GET", + "http.url": "http://www.test.com/toto", + "traefik.service.name": "some-service-100.slug.namespace.environment.domain.tld", + "traefik.router.name": "some-service-100.slug.namespace.environment.domain.tld", + "span.kind": ext.SpanKindRPCClientEnum, }, OperationName: "forward some-service-100.slug.namespace.enviro.../some-service-100.slug.namespace.enviro.../bc4a0d48", }, @@ -76,12 +76,12 @@ func TestNewForwarder(t *testing.T) { router: "some-service1.namespace.environment.domain.tld", expected: expected{ Tags: map[string]interface{}{ - "http.host": "www.test.com", - "http.method": "GET", - "http.url": "http://www.test.com/toto", - "service.name": "some-service1.namespace.environment.domain.tld", - "router.name": "some-service1.namespace.environment.domain.tld", - "span.kind": ext.SpanKindRPCClientEnum, + "http.host": "www.test.com", + "http.method": "GET", + "http.url": "http://www.test.com/toto", + "traefik.service.name": "some-service1.namespace.environment.domain.tld", + "traefik.router.name": "some-service1.namespace.environment.domain.tld", + "span.kind": ext.SpanKindRPCClientEnum, }, OperationName: "forward some-service1.namespace.environment.domain.tld/some-service1.namespace.environment.domain.tld", }, @@ -96,12 +96,12 @@ func TestNewForwarder(t *testing.T) { router: "some-service1.backend.namespace.environment.domain.tld", expected: expected{ Tags: map[string]interface{}{ - "http.host": "www.test.com", - "http.method": "GET", - "http.url": "http://www.test.com/toto", - "service.name": "some-service1.frontend.namespace.environment.domain.tld", - "router.name": "some-service1.backend.namespace.environment.domain.tld", - "span.kind": ext.SpanKindRPCClientEnum, + "http.host": "www.test.com", + "http.method": "GET", + "http.url": "http://www.test.com/toto", + "traefik.service.name": "some-service1.frontend.namespace.environment.domain.tld", + "traefik.router.name": "some-service1.backend.namespace.environment.domain.tld", + "span.kind": ext.SpanKindRPCClientEnum, }, OperationName: "forward some-service1.frontend.namespace.envir.../some-service1.backend.namespace.enviro.../fa49dd23", }, diff --git a/pkg/server/middleware/chainbuilder.go b/pkg/server/middleware/chainbuilder.go index 1f7a70ef3..418bdfd14 100644 --- a/pkg/server/middleware/chainbuilder.go +++ b/pkg/server/middleware/chainbuilder.go @@ -9,7 +9,6 @@ import ( "github.com/traefik/traefik/v2/pkg/metrics" "github.com/traefik/traefik/v2/pkg/middlewares/accesslog" metricsmiddleware "github.com/traefik/traefik/v2/pkg/middlewares/metrics" - "github.com/traefik/traefik/v2/pkg/middlewares/requestdecorator" mTracing "github.com/traefik/traefik/v2/pkg/middlewares/tracing" "github.com/traefik/traefik/v2/pkg/tracing" "github.com/traefik/traefik/v2/pkg/tracing/jaeger" @@ -20,7 +19,6 @@ type ChainBuilder struct { metricsRegistry metrics.Registry accessLoggerMiddleware *accesslog.Handler tracer *tracing.Tracing - requestDecorator *requestdecorator.RequestDecorator } // NewChainBuilder Creates a new ChainBuilder. @@ -29,7 +27,6 @@ func NewChainBuilder(staticConfiguration static.Configuration, metricsRegistry m metricsRegistry: metricsRegistry, accessLoggerMiddleware: accessLoggerMiddleware, tracer: setupTracing(staticConfiguration.Tracing), - requestDecorator: requestdecorator.New(staticConfiguration.HostResolver), } } @@ -49,7 +46,7 @@ func (c *ChainBuilder) Build(ctx context.Context, entryPointName string) alice.C chain = chain.Append(metricsmiddleware.WrapEntryPointHandler(ctx, c.metricsRegistry, entryPointName)) } - return chain.Append(requestdecorator.WrapHandler(c.requestDecorator)) + return chain } // Close accessLogger and tracer. diff --git a/pkg/server/router/tcp/router.go b/pkg/server/router/tcp/router.go index abe31d180..0a97a10b3 100644 --- a/pkg/server/router/tcp/router.go +++ b/pkg/server/router/tcp/router.go @@ -5,12 +5,11 @@ import ( "crypto/tls" "errors" "fmt" - "net" "net/http" - "strings" "github.com/traefik/traefik/v2/pkg/config/runtime" "github.com/traefik/traefik/v2/pkg/log" + "github.com/traefik/traefik/v2/pkg/middlewares/snicheck" "github.com/traefik/traefik/v2/pkg/rules" "github.com/traefik/traefik/v2/pkg/server/provider" tcpservice "github.com/traefik/traefik/v2/pkg/server/service/tcp" @@ -161,38 +160,7 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string } } - sniCheck := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { - if req.TLS == nil { - handlerHTTPS.ServeHTTP(rw, req) - return - } - - host, _, err := net.SplitHostPort(req.Host) - if err != nil { - host = req.Host - } - - host = strings.TrimSpace(host) - serverName := strings.TrimSpace(req.TLS.ServerName) - - // Domain Fronting - if !strings.EqualFold(host, serverName) { - tlsOptionSNI := findTLSOptionName(tlsOptionsForHost, serverName) - tlsOptionHeader := findTLSOptionName(tlsOptionsForHost, host) - - if tlsOptionHeader != tlsOptionSNI { - log.WithoutContext(). - WithField("host", host). - WithField("req.Host", req.Host). - WithField("req.TLS.ServerName", req.TLS.ServerName). - Debugf("TLS options difference: SNI=%s, Header:%s", tlsOptionSNI, tlsOptionHeader) - http.Error(rw, http.StatusText(http.StatusMisdirectedRequest), http.StatusMisdirectedRequest) - return - } - } - - handlerHTTPS.ServeHTTP(rw, req) - }) + sniCheck := snicheck.New(tlsOptionsForHost, handlerHTTPS) router.HTTPSHandler(sniCheck, defaultTLSConf) @@ -321,17 +289,3 @@ func (m *Manager) buildTCPHandler(ctx context.Context, router *runtime.TCPRouter return tcp.NewChain().Extend(*mHandler).Then(sHandler) } - -func findTLSOptionName(tlsOptionsForHost map[string]string, host string) string { - tlsOptions, ok := tlsOptionsForHost[host] - if ok { - return tlsOptions - } - - tlsOptions, ok = tlsOptionsForHost[strings.ToLower(host)] - if ok { - return tlsOptions - } - - return traefiktls.DefaultTLSConfigName -} diff --git a/pkg/server/router/tcp/router_test.go b/pkg/server/router/tcp/router_test.go index 156721aa6..cdf7c3bbc 100644 --- a/pkg/server/router/tcp/router_test.go +++ b/pkg/server/router/tcp/router_test.go @@ -59,7 +59,6 @@ func TestRuntimeConfiguration(t *testing.T) { }, "bar": { TCPRouter: &dynamic.TCPRouter{ - EntryPoints: []string{"web"}, Service: "foo-service", Rule: "HostSNI(`foo.bar`)", @@ -136,7 +135,6 @@ func TestRuntimeConfiguration(t *testing.T) { }, "bar": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, Service: "foo-service", Rule: "Host(`bar.foo`) && PathPrefix(`/path`)", @@ -240,7 +238,6 @@ func TestRuntimeConfiguration(t *testing.T) { }, "bar": { TCPRouter: &dynamic.TCPRouter{ - EntryPoints: []string{"web"}, Service: "foo-service", Rule: "HostSNI(`foo.bar`)", @@ -340,9 +337,26 @@ func TestRuntimeConfiguration(t *testing.T) { } func TestDomainFronting(t *testing.T) { + tlsOptionsBase := map[string]traefiktls.Options{ + "default": { + MinVersion: "VersionTLS10", + }, + "host1@file": { + MinVersion: "VersionTLS12", + }, + "host1@crd": { + MinVersion: "VersionTLS12", + }, + } + + entryPoints := []string{"web"} + tests := []struct { desc string routers map[string]*runtime.RouterInfo + tlsOptions map[string]traefiktls.Options + host string + ServerName string expectedStatus int }{ { @@ -350,7 +364,7 @@ func TestDomainFronting(t *testing.T) { routers: map[string]*runtime.RouterInfo{ "router-1@file": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host1.local`)", TLS: &dynamic.RouterTLSConfig{ Options: "host1", @@ -359,12 +373,15 @@ func TestDomainFronting(t *testing.T) { }, "router-2@file": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host2.local`)", TLS: &dynamic.RouterTLSConfig{}, }, }, }, + tlsOptions: tlsOptionsBase, + host: "host1.local", + ServerName: "host2.local", expectedStatus: http.StatusMisdirectedRequest, }, { @@ -372,7 +389,7 @@ func TestDomainFronting(t *testing.T) { routers: map[string]*runtime.RouterInfo{ "router-1@file": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host1.local`)", TLS: &dynamic.RouterTLSConfig{ Options: "host1", @@ -381,7 +398,7 @@ func TestDomainFronting(t *testing.T) { }, "router-2@file": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host2.local`)", TLS: &dynamic.RouterTLSConfig{ Options: "host1", @@ -389,6 +406,9 @@ func TestDomainFronting(t *testing.T) { }, }, }, + tlsOptions: tlsOptionsBase, + host: "host1.local", + ServerName: "host2.local", expectedStatus: http.StatusOK, }, { @@ -396,7 +416,7 @@ func TestDomainFronting(t *testing.T) { routers: map[string]*runtime.RouterInfo{ "router-1@file": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host1.local`)", TLS: &dynamic.RouterTLSConfig{ Options: "host1", @@ -405,7 +425,7 @@ func TestDomainFronting(t *testing.T) { }, "router-2@file": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host1.local`) && PathPrefix(`/foo`)", TLS: &dynamic.RouterTLSConfig{ Options: "default", @@ -414,7 +434,7 @@ func TestDomainFronting(t *testing.T) { }, "router-3@file": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host2.local`)", TLS: &dynamic.RouterTLSConfig{ Options: "host1", @@ -422,6 +442,9 @@ func TestDomainFronting(t *testing.T) { }, }, }, + tlsOptions: tlsOptionsBase, + host: "host1.local", + ServerName: "host2.local", expectedStatus: http.StatusMisdirectedRequest, }, { @@ -429,7 +452,7 @@ func TestDomainFronting(t *testing.T) { routers: map[string]*runtime.RouterInfo{ "router-1@file": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host1.local`)", TLS: &dynamic.RouterTLSConfig{ Options: "host1", @@ -438,7 +461,7 @@ func TestDomainFronting(t *testing.T) { }, "router-2@file": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host1.local`) && PathPrefix(`/bar`)", TLS: &dynamic.RouterTLSConfig{ Options: "host1", @@ -447,7 +470,7 @@ func TestDomainFronting(t *testing.T) { }, "router-3@file": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host2.local`)", TLS: &dynamic.RouterTLSConfig{ Options: "host1", @@ -455,6 +478,9 @@ func TestDomainFronting(t *testing.T) { }, }, }, + tlsOptions: tlsOptionsBase, + host: "host1.local", + ServerName: "host2.local", expectedStatus: http.StatusOK, }, { @@ -462,7 +488,7 @@ func TestDomainFronting(t *testing.T) { routers: map[string]*runtime.RouterInfo{ "router-1@file": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host1.local`)", TLS: &dynamic.RouterTLSConfig{ Options: "host1", @@ -471,7 +497,7 @@ func TestDomainFronting(t *testing.T) { }, "router-2@crd": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host2.local`)", TLS: &dynamic.RouterTLSConfig{ Options: "host1", @@ -479,6 +505,9 @@ func TestDomainFronting(t *testing.T) { }, }, }, + tlsOptions: tlsOptionsBase, + host: "host1.local", + ServerName: "host2.local", expectedStatus: http.StatusMisdirectedRequest, }, { @@ -486,7 +515,7 @@ func TestDomainFronting(t *testing.T) { routers: map[string]*runtime.RouterInfo{ "router-1@file": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host1.local`)", TLS: &dynamic.RouterTLSConfig{ Options: "host1@crd", @@ -495,7 +524,7 @@ func TestDomainFronting(t *testing.T) { }, "router-2@crd": { Router: &dynamic.Router{ - EntryPoints: []string{"web"}, + EntryPoints: entryPoints, Rule: "Host(`host2.local`)", TLS: &dynamic.RouterTLSConfig{ Options: "host1@crd", @@ -503,25 +532,63 @@ func TestDomainFronting(t *testing.T) { }, }, }, + tlsOptions: tlsOptionsBase, + host: "host1.local", + ServerName: "host2.local", expectedStatus: http.StatusOK, }, + { + desc: "Request is misdirected when server name is empty and the host name is an FQDN, but router's rule is not", + routers: map[string]*runtime.RouterInfo{ + "router-1@file": { + Router: &dynamic.Router{ + EntryPoints: entryPoints, + Rule: "Host(`host1.local`)", + TLS: &dynamic.RouterTLSConfig{ + Options: "host1@file", + }, + }, + }, + }, + tlsOptions: map[string]traefiktls.Options{ + "default": { + MinVersion: "VersionTLS13", + }, + "host1@file": { + MinVersion: "VersionTLS12", + }, + }, + host: "host1.local.", + expectedStatus: http.StatusMisdirectedRequest, + }, + { + desc: "Request is misdirected when server name is empty and the host name is not FQDN, but router's rule is", + routers: map[string]*runtime.RouterInfo{ + "router-1@file": { + Router: &dynamic.Router{ + EntryPoints: entryPoints, + Rule: "Host(`host1.local.`)", + TLS: &dynamic.RouterTLSConfig{ + Options: "host1@file", + }, + }, + }, + }, + tlsOptions: map[string]traefiktls.Options{ + "default": { + MinVersion: "VersionTLS13", + }, + "host1@file": { + MinVersion: "VersionTLS12", + }, + }, + host: "host1.local", + expectedStatus: http.StatusMisdirectedRequest, + }, } for _, test := range tests { t.Run(test.desc, func(t *testing.T) { - entryPoints := []string{"web"} - tlsOptions := map[string]traefiktls.Options{ - "default": { - MinVersion: "VersionTLS10", - }, - "host1@file": { - MinVersion: "VersionTLS12", - }, - "host1@crd": { - MinVersion: "VersionTLS12", - }, - } - conf := &runtime.Configuration{ Routers: test.routers, } @@ -529,7 +596,7 @@ func TestDomainFronting(t *testing.T) { serviceManager := tcp.NewManager(conf) tlsManager := traefiktls.NewManager() - tlsManager.UpdateConfigs(context.Background(), map[string]traefiktls.Store{}, tlsOptions, []*traefiktls.CertAndStores{}) + tlsManager.UpdateConfigs(context.Background(), map[string]traefiktls.Store{}, test.tlsOptions, []*traefiktls.CertAndStores{}) httpsHandler := map[string]http.Handler{ "web": http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {}), @@ -545,9 +612,9 @@ func TestDomainFronting(t *testing.T) { require.True(t, ok) req := httptest.NewRequest(http.MethodGet, "/", nil) - req.Host = "host1.local" + req.Host = test.host req.TLS = &tls.ConnectionState{ - ServerName: "host2.local", + ServerName: test.ServerName, } rw := httptest.NewRecorder() diff --git a/pkg/server/server_entrypoint_tcp.go b/pkg/server/server_entrypoint_tcp.go index bf62b47eb..395720555 100644 --- a/pkg/server/server_entrypoint_tcp.go +++ b/pkg/server/server_entrypoint_tcp.go @@ -11,6 +11,7 @@ import ( "syscall" "time" + "github.com/containous/alice" "github.com/pires/go-proxyproto" "github.com/sirupsen/logrus" "github.com/traefik/traefik/v2/pkg/config/static" @@ -18,9 +19,11 @@ import ( "github.com/traefik/traefik/v2/pkg/log" "github.com/traefik/traefik/v2/pkg/middlewares" "github.com/traefik/traefik/v2/pkg/middlewares/forwardedheaders" + "github.com/traefik/traefik/v2/pkg/middlewares/requestdecorator" "github.com/traefik/traefik/v2/pkg/safe" "github.com/traefik/traefik/v2/pkg/server/router" "github.com/traefik/traefik/v2/pkg/tcp" + "github.com/traefik/traefik/v2/pkg/types" "golang.org/x/net/http2" "golang.org/x/net/http2/h2c" ) @@ -60,7 +63,7 @@ func (h *httpForwarder) Accept() (net.Conn, error) { type TCPEntryPoints map[string]*TCPEntryPoint // NewTCPEntryPoints creates a new TCPEntryPoints. -func NewTCPEntryPoints(entryPointsConfig static.EntryPoints) (TCPEntryPoints, error) { +func NewTCPEntryPoints(entryPointsConfig static.EntryPoints, hostResolverConfig *types.HostResolverConfig) (TCPEntryPoints, error) { serverEntryPointsTCP := make(TCPEntryPoints) for entryPointName, config := range entryPointsConfig { protocol, err := config.GetProtocol() @@ -74,7 +77,7 @@ func NewTCPEntryPoints(entryPointsConfig static.EntryPoints) (TCPEntryPoints, er ctx := log.With(context.Background(), log.Str(log.EntryPointName, entryPointName)) - serverEntryPointsTCP[entryPointName], err = NewTCPEntryPoint(ctx, config) + serverEntryPointsTCP[entryPointName], err = NewTCPEntryPoint(ctx, config, hostResolverConfig) if err != nil { return nil, fmt.Errorf("error while building entryPoint %s: %w", entryPointName, err) } @@ -130,7 +133,7 @@ type TCPEntryPoint struct { } // NewTCPEntryPoint creates a new TCPEntryPoint. -func NewTCPEntryPoint(ctx context.Context, configuration *static.EntryPoint) (*TCPEntryPoint, error) { +func NewTCPEntryPoint(ctx context.Context, configuration *static.EntryPoint, hostResolverConfig *types.HostResolverConfig) (*TCPEntryPoint, error) { tracker := newConnectionTracker() listener, err := buildListener(ctx, configuration) @@ -140,14 +143,16 @@ func NewTCPEntryPoint(ctx context.Context, configuration *static.EntryPoint) (*T rt := &tcp.Router{} - httpServer, err := createHTTPServer(ctx, listener, configuration, true) + reqDecorator := requestdecorator.New(hostResolverConfig) + + httpServer, err := createHTTPServer(ctx, listener, configuration, true, reqDecorator) if err != nil { return nil, fmt.Errorf("error preparing httpServer: %w", err) } rt.HTTPForwarder(httpServer.Forwarder) - httpsServer, err := createHTTPServer(ctx, listener, configuration, false) + httpsServer, err := createHTTPServer(ctx, listener, configuration, false, reqDecorator) if err != nil { return nil, fmt.Errorf("error preparing httpsServer: %w", err) } @@ -500,16 +505,19 @@ type httpServer struct { Switcher *middlewares.HTTPHandlerSwitcher } -func createHTTPServer(ctx context.Context, ln net.Listener, configuration *static.EntryPoint, withH2c bool) (*httpServer, error) { +func createHTTPServer(ctx context.Context, ln net.Listener, configuration *static.EntryPoint, withH2c bool, reqDecorator *requestdecorator.RequestDecorator) (*httpServer, error) { httpSwitcher := middlewares.NewHandlerSwitcher(router.BuildDefaultHTTPRouter()) + next, err := alice.New(requestdecorator.WrapHandler(reqDecorator)).Then(httpSwitcher) + if err != nil { + return nil, err + } + var handler http.Handler - var err error handler, err = forwardedheaders.NewXForwarded( configuration.ForwardedHeaders.Insecure, configuration.ForwardedHeaders.TrustedIPs, - httpSwitcher) - + next) if err != nil { return nil, err } diff --git a/pkg/server/server_entrypoint_tcp_http3_test.go b/pkg/server/server_entrypoint_tcp_http3_test.go index 480bdb713..b0759ef48 100644 --- a/pkg/server/server_entrypoint_tcp_http3_test.go +++ b/pkg/server/server_entrypoint_tcp_http3_test.go @@ -17,38 +17,57 @@ import ( // LocalhostCert is a PEM-encoded TLS cert with SAN IPs // "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT. // generated from src/crypto/tls: -// go run generate_cert.go --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h +// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h var ( localhostCert = traefiktls.FileOrContent(`-----BEGIN CERTIFICATE----- -MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS +MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw -MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4 -iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul -rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO -BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw -AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA -AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9 -tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs -h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM -fblo6RBxUQ== +MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r +bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U +aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P +YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk +POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu +h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE +AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv +bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI +5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv +cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2 ++tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B +grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK +5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/ +WkBKOclmOV2xlTVuPw== -----END CERTIFICATE-----`) // LocalhostKey is the private key for localhostCert. localhostKey = traefiktls.FileOrContent(`-----BEGIN RSA PRIVATE KEY----- -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 +ZboOWVe3icTy64BT3OQhmg== -----END RSA PRIVATE KEY-----`) ) @@ -72,7 +91,7 @@ func TestHTTP3AdvertisedPort(t *testing.T) { HTTP3: &static.HTTP3Config{ AdvertisedPort: 8080, }, - }) + }, nil) require.NoError(t, err) router := &tcp.Router{} diff --git a/pkg/server/server_entrypoint_tcp_test.go b/pkg/server/server_entrypoint_tcp_test.go index 6b461632c..ab49cd5a9 100644 --- a/pkg/server/server_entrypoint_tcp_test.go +++ b/pkg/server/server_entrypoint_tcp_test.go @@ -79,7 +79,7 @@ func testShutdown(t *testing.T, router *tcp.Router) { Address: "127.0.0.1:0", Transport: epConfig, ForwardedHeaders: &static.ForwardedHeaders{}, - }) + }, nil) require.NoError(t, err) conn, err := startEntrypoint(entryPoint, router) @@ -162,7 +162,7 @@ func TestReadTimeoutWithoutFirstByte(t *testing.T) { Address: ":0", Transport: epConfig, ForwardedHeaders: &static.ForwardedHeaders{}, - }) + }, nil) require.NoError(t, err) router := &tcp.Router{} @@ -198,7 +198,7 @@ func TestReadTimeoutWithFirstByte(t *testing.T) { Address: ":0", Transport: epConfig, ForwardedHeaders: &static.ForwardedHeaders{}, - }) + }, nil) require.NoError(t, err) router := &tcp.Router{} diff --git a/pkg/tls/tlsmanager_test.go b/pkg/tls/tlsmanager_test.go index 06b364ea1..63f13fe17 100644 --- a/pkg/tls/tlsmanager_test.go +++ b/pkg/tls/tlsmanager_test.go @@ -17,35 +17,54 @@ import ( // go run generate_cert.go --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h var ( localhostCert = FileOrContent(`-----BEGIN CERTIFICATE----- -MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS +MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw -MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB -iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4 -iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul -rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO -BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw -AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA -AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9 -tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs -h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM -fblo6RBxUQ== +MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r +bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U +aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P +YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk +POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu +h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE +AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv +bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI +5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv +cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2 ++tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B +grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK +5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/ +WkBKOclmOV2xlTVuPw== -----END CERTIFICATE-----`) // LocalhostKey is the private key for localhostCert. localhostKey = FileOrContent(`-----BEGIN RSA PRIVATE KEY----- -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 +ZboOWVe3icTy64BT3OQhmg== -----END RSA PRIVATE KEY-----`) ) diff --git a/script/gcg/traefik-bugfix.toml b/script/gcg/traefik-bugfix.toml index 83e4b4e09..84ee76471 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.5.7 -CurrentRef = "v2.5" -PreviousRef = "v2.5.6" -BaseBranch = "v2.5" -FutureCurrentRefName = "v2.5.7" +# example new bugfix v2.6.1 +CurrentRef = "v2.6" +PreviousRef = "v2.6.0" +BaseBranch = "v2.6" +FutureCurrentRefName = "v2.6.1" ThresholdPreviousRef = 10 ThresholdCurrentRef = 10