diff --git a/.goreleaser.yml b/.goreleaser.yml index 545ca5281..44beb3025 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -38,6 +38,8 @@ builds: goarch: arm64 - goos: freebsd goarch: arm64 + - goos: darwin + goarch: arm64 changelog: skip: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 38e423977..383d5bf6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ +## [v2.4.5](https://github.com/traefik/traefik/tree/v2.4.5) (2021-02-18) +[All Commits](https://github.com/traefik/traefik/compare/v2.4.3...v2.4.5) + +**Bug fixes:** +- **[webui]** Only allow iframes to be loaded from our domain ([#7904](https://github.com/traefik/traefik/pull/7904) by [SantoDE](https://github.com/SantoDE)) + +## [v2.4.4](https://github.com/traefik/traefik/tree/v2.4.4) (2021-02-18) +[All Commits](https://github.com/traefik/traefik/compare/v2.4.3...v2.4.4) + +Release canceled. + ## [v2.4.3](https://github.com/traefik/traefik/tree/v2.4.3) (2021-02-15) [All Commits](https://github.com/traefik/traefik/compare/v2.4.2...v2.4.3) diff --git a/docs/content/providers/file.md b/docs/content/providers/file.md index ecf255d85..b393dd0c9 100644 --- a/docs/content/providers/file.md +++ b/docs/content/providers/file.md @@ -5,7 +5,7 @@ Good Old Configuration File The file provider lets you define the [dynamic configuration](./overview.md) in a TOML or YAML file. -It supports providing configuration through a [single configuration file]](#filename) or [multiple separate files](#directory). +It supports providing configuration through a [single configuration file](#filename) or [multiple separate files](#directory). !!! info diff --git a/docs/content/providers/kubernetes-gateway.md b/docs/content/providers/kubernetes-gateway.md index 761444ae3..0ba84abd6 100644 --- a/docs/content/providers/kubernetes-gateway.md +++ b/docs/content/providers/kubernetes-gateway.md @@ -6,7 +6,7 @@ The Kubernetes Gateway API, The Experimental Way. Gateway API is the evolution of Kubernetes APIs that relate to `Services`, such as `Ingress`. The Gateway API project is part of Kubernetes, working under SIG-NETWORK. -The Kubernetes Gateway provider is a Traefik implementation of the [Service APIs](https://kubernetes-sigs.github.io/gateway-api/) +The Kubernetes Gateway provider is a Traefik implementation of the [Gateway API](https://gateway-api.sigs.k8s.io/) specifications from the Kubernetes Special Interest Groups (SIGs). This provider is proposed as an experimental feature and partially supports the Service APIs [v0.1.0](https://github.com/kubernetes-sigs/service-apis/releases/tag/v0.1.0) specification. @@ -71,9 +71,9 @@ This provider is proposed as an experimental feature and partially supports the --8<-- "content/reference/dynamic-configuration/kubernetes-gateway-rbac.yml" ``` -The Kubernetes Service APIs project provides several [guides](https://kubernetes-sigs.github.io/gateway-api/guides/) on how to use the APIs. +The Kubernetes Gateway API project provides several [guides](https://gateway-api.sigs.k8s.io/guides/) on how to use the APIs. These guides can help you to go further than the example above. -The [getting started guide](https://kubernetes-sigs.github.io/gateway-api/getting-started/) details how to install the CRDs from their repository. +The [getting started guide](https://gateway-api.sigs.k8s.io/getting-started/) details how to install the CRDs from their repository. !!! note "" @@ -81,9 +81,9 @@ The [getting started guide](https://kubernetes-sigs.github.io/gateway-api/gettin For now, the Traefik Gateway Provider can be used while following the below guides: -* [Simple Gateway](https://kubernetes-sigs.github.io/gateway-api/simple-gateway/) -* [HTTP routing](https://kubernetes-sigs.github.io/gateway-api/http-routing/) -* [TLS](https://kubernetes-sigs.github.io/gateway-api/tls/) (Partial support: only on listeners with terminate mode) +* [Simple Gateway](https://gateway-api.sigs.k8s.io/simple-gateway/) +* [HTTP routing](https://gateway-api.sigs.k8s.io/http-routing/) +* [TLS](https://gateway-api.sigs.k8s.io/tls/) (Partial support: only on listeners with terminate mode) ## Resource Configuration @@ -91,7 +91,7 @@ When using Kubernetes Gateway API as a provider, Traefik uses Kubernetes [Custom Resource Definitions](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) to retrieve its routing configuration. -All concepts can be found in the official API concepts [documentation](https://kubernetes-sigs.github.io/gateway-api/api-overview/). +All concepts can be found in the official API concepts [documentation](https://gateway-api.sigs.k8s.io/api-overview/). Traefik implements the following resources: * `GatewayClass` defines a set of Gateways that share a common configuration and behaviour. diff --git a/docs/content/routing/providers/kubernetes-gateway.md b/docs/content/routing/providers/kubernetes-gateway.md index 25843fbd9..3c2b30c75 100644 --- a/docs/content/routing/providers/kubernetes-gateway.md +++ b/docs/content/routing/providers/kubernetes-gateway.md @@ -33,16 +33,16 @@ The Kubernetes Gateway API, The Experimental Way. You can find an excerpt of the supported Kubernetes Gateway API resources in the table below: -| Kind | Purpose | Concept Behind | -|------------------------------------|---------------------------------------------------------------------------|-------------------------------------------------------------------------------------------| -| [GatewayClass](#kind-gatewayclass) | Defines a set of Gateways that share a common configuration and behaviour | [GatewayClass](https://kubernetes-sigs.github.io/gateway-api/api-overview/#gatewayclass) | -| [Gateway](#kind-gateway) | Describes how traffic can be translated to Services within the cluster | [Gateway](https://kubernetes-sigs.github.io/gateway-api/api-overview/#gateway) | -| [HTTPRoute](#kind-httproute) | HTTP rules for mapping requests from a Gateway to Kubernetes Services | [Route](https://kubernetes-sigs.github.io/gateway-api/api-overview/#httptcpfooroute) | +| Kind | Purpose | Concept Behind | +|------------------------------------|---------------------------------------------------------------------------|-----------------------------------------------------------------------------| +| [GatewayClass](#kind-gatewayclass) | Defines a set of Gateways that share a common configuration and behaviour | [GatewayClass](https://gateway-api.sigs.k8s.io/api-overview/#gatewayclass) | +| [Gateway](#kind-gateway) | Describes how traffic can be translated to Services within the cluster | [Gateway](https://gateway-api.sigs.k8s.io/api-overview/#gateway) | +| [HTTPRoute](#kind-httproute) | HTTP rules for mapping requests from a Gateway to Kubernetes Services | [Route](https://gateway-api.sigs.k8s.io/api-overview/#httptcpfooroute) | ### Kind: `GatewayClass` `GatewayClass` is cluster-scoped resource defined by the infrastructure provider. This resource represents a class of Gateways that can be instantiated. -More details on the GatewayClass [official documentation](https://kubernetes-sigs.github.io/gateway-api/gatewayclass/). +More details on the GatewayClass [official documentation](https://gateway-api.sigs.k8s.io/gatewayclass/). The `GatewayClass` should be declared by the infrastructure provider, otherwise please register the `GatewayClass` [definition](../../reference/dynamic-configuration/kubernetes-gateway.md#definitions) in the Kubernetes cluster before @@ -65,7 +65,7 @@ creating `GatewayClass` objects. A `Gateway` is 1:1 with the life cycle of the configuration of infrastructure. When a user creates a Gateway, some load balancing infrastructure is provisioned or configured by the GatewayClass controller. -More details on the Gateway [official documentation](https://kubernetes-sigs.github.io/gateway-api/gateway/). +More details on the Gateway [official documentation](https://gateway-api.sigs.k8s.io/gateway/). Register the `Gateway` [definition](../../reference/dynamic-configuration/kubernetes-gateway.md#definitions) in the Kubernetes cluster before creating `Gateway` objects. diff --git a/pkg/api/dashboard.go b/pkg/api/dashboard.go index 3fe69b911..54b0423c5 100644 --- a/pkg/api/dashboard.go +++ b/pkg/api/dashboard.go @@ -33,6 +33,13 @@ func (g DashboardHandler) Append(router *mux.Router) { Handler(http.StripPrefix("/dashboard/", http.FileServer(g.Assets))) } +func (g DashboardHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // allow iframes from our domains only + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-src + w.Header().Set("Content-Security-Policy", "frame-src 'self' https://traefik.io https://*.traefik.io;") + http.FileServer(g.Assets).ServeHTTP(w, r) +} + func safePrefix(req *http.Request) string { prefix := req.Header.Get("X-Forwarded-Prefix") if prefix == "" { diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go index c945a7000..384071dfe 100644 --- a/pkg/api/dashboard_test.go +++ b/pkg/api/dashboard_test.go @@ -1,9 +1,12 @@ package api import ( + "fmt" "net/http" + "net/http/httptest" "testing" + assetfs "github.com/elazarl/go-bindata-assetfs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -52,3 +55,70 @@ func Test_safePrefix(t *testing.T) { }) } } + +func Test_ContentSecurityPolicy(t *testing.T) { + testCases := []struct { + desc string + handler DashboardHandler + expected int + }{ + { + desc: "OK", + handler: DashboardHandler{ + Assets: &assetfs.AssetFS{ + Asset: func(path string) ([]byte, error) { + return []byte{}, nil + }, + AssetDir: func(path string) ([]string, error) { + return []string{}, nil + }, + }, + }, + expected: http.StatusOK, + }, + { + desc: "Not found", + handler: DashboardHandler{ + Assets: &assetfs.AssetFS{ + Asset: func(path string) ([]byte, error) { + return []byte{}, fmt.Errorf("not found") + }, + AssetDir: func(path string) ([]string, error) { + return []string{}, fmt.Errorf("not found") + }, + }, + }, + expected: http.StatusNotFound, + }, + { + desc: "Internal server error", + handler: DashboardHandler{ + Assets: &assetfs.AssetFS{ + Asset: func(path string) ([]byte, error) { + return []byte{}, fmt.Errorf("oops") + }, + AssetDir: func(path string) ([]string, error) { + return []string{}, fmt.Errorf("oops") + }, + }, + }, + expected: http.StatusInternalServerError, + }, + } + + for _, test := range testCases { + test := test + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + req := httptest.NewRequest(http.MethodGet, "/foobar.html", nil) + + rw := httptest.NewRecorder() + + test.handler.ServeHTTP(rw, req) + + assert.Equal(t, test.expected, rw.Code) + assert.Equal(t, "frame-src 'self' https://traefik.io https://*.traefik.io;", rw.Result().Header.Get("Content-Security-Policy")) + }) + } +} diff --git a/pkg/server/service/managerfactory.go b/pkg/server/service/managerfactory.go index 438c089b2..172f956f9 100644 --- a/pkg/server/service/managerfactory.go +++ b/pkg/server/service/managerfactory.go @@ -39,7 +39,7 @@ func NewManagerFactory(staticConfiguration static.Configuration, routinesPool *s factory.api = api.NewBuilder(staticConfiguration) if staticConfiguration.API.Dashboard { - factory.dashboardHandler = http.FileServer(staticConfiguration.API.DashboardAssets) + factory.dashboardHandler = api.DashboardHandler{Assets: staticConfiguration.API.DashboardAssets} } } diff --git a/script/gcg/traefik-bugfix.toml b/script/gcg/traefik-bugfix.toml index 092f71413..c1dd907c5 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.4.3 +# example new bugfix v2.4.5 CurrentRef = "v2.4" -PreviousRef = "v2.4.2" +PreviousRef = "v2.4.4" BaseBranch = "v2.4" -FutureCurrentRefName = "v2.4.3" +FutureCurrentRefName = "v2.4.5" ThresholdPreviousRef = 10 ThresholdCurrentRef = 10