From 0c2863094801bfb753dabab02c8b0f7cd1ec0302 Mon Sep 17 00:00:00 2001 From: Ludovic Fernandez Date: Mon, 23 Mar 2020 11:24:05 +0100 Subject: [PATCH] Fix sameSite (Traefik v2) --- .../dynamic-configuration/docker-labels.yml | 1 + .../reference/dynamic-configuration/file.toml | 2 ++ .../reference/dynamic-configuration/file.yaml | 2 ++ .../marathon-labels.json | 1 + .../routing/providers/consul-catalog.md | 8 +++++++ docs/content/routing/providers/docker.md | 8 +++++++ .../routing/providers/kubernetes-crd.md | 1 + docs/content/routing/providers/marathon.md | 8 +++++++ docs/content/routing/providers/rancher.md | 8 +++++++ docs/content/routing/services/index.md | 8 +++++-- go.mod | 6 ++--- go.sum | 9 ++++++-- pkg/config/dynamic/http_config.go | 1 + pkg/server/service/service.go | 22 ++++++++++++++++++- 14 files changed, 77 insertions(+), 8 deletions(-) diff --git a/docs/content/reference/dynamic-configuration/docker-labels.yml b/docs/content/reference/dynamic-configuration/docker-labels.yml index 8e2097ce0..3db5df805 100644 --- a/docs/content/reference/dynamic-configuration/docker-labels.yml +++ b/docs/content/reference/dynamic-configuration/docker-labels.yml @@ -146,6 +146,7 @@ - "traefik.http.services.service01.loadbalancer.sticky.cookie.httponly=true" - "traefik.http.services.service01.loadbalancer.sticky.cookie.name=foobar" - "traefik.http.services.service01.loadbalancer.sticky.cookie.secure=true" +- "traefik.http.services.service01.loadbalancer.sticky.cookie.samesite=foobar" - "traefik.http.services.service01.loadbalancer.server.port=foobar" - "traefik.http.services.service01.loadbalancer.server.scheme=foobar" - "traefik.tcp.routers.tcprouter0.entrypoints=foobar, foobar" diff --git a/docs/content/reference/dynamic-configuration/file.toml b/docs/content/reference/dynamic-configuration/file.toml index c61ca3743..c5a55dc25 100644 --- a/docs/content/reference/dynamic-configuration/file.toml +++ b/docs/content/reference/dynamic-configuration/file.toml @@ -43,6 +43,7 @@ name = "foobar" secure = true httpOnly = true + sameSite = "foobar" [[http.services.Service01.loadBalancer.servers]] url = "foobar" @@ -87,6 +88,7 @@ name = "foobar" secure = true httpOnly = true + sameSite = "foobar" [http.middlewares] [http.middlewares.Middleware00] [http.middlewares.Middleware00.addPrefix] diff --git a/docs/content/reference/dynamic-configuration/file.yaml b/docs/content/reference/dynamic-configuration/file.yaml index dbbb95361..f08dff865 100644 --- a/docs/content/reference/dynamic-configuration/file.yaml +++ b/docs/content/reference/dynamic-configuration/file.yaml @@ -52,6 +52,7 @@ http: name: foobar secure: true httpOnly: true + sameSite: foobar servers: - url: foobar - url: foobar @@ -88,6 +89,7 @@ http: name: foobar secure: true httpOnly: true + sameSite: foobar middlewares: Middleware00: addPrefix: diff --git a/docs/content/reference/dynamic-configuration/marathon-labels.json b/docs/content/reference/dynamic-configuration/marathon-labels.json index c466602c8..eea984e3d 100644 --- a/docs/content/reference/dynamic-configuration/marathon-labels.json +++ b/docs/content/reference/dynamic-configuration/marathon-labels.json @@ -143,6 +143,7 @@ "traefik.http.services.service01.loadbalancer.sticky.cookie.httponly": "true", "traefik.http.services.service01.loadbalancer.sticky.cookie.name": "foobar", "traefik.http.services.service01.loadbalancer.sticky.cookie.secure": "true", +"traefik.http.services.service01.loadbalancer.sticky.cookie.samesite": "foobar", "traefik.http.services.service01.loadbalancer.server.port": "foobar", "traefik.http.services.service01.loadbalancer.server.scheme": "foobar", "traefik.tcp.routers.tcprouter0.entrypoints": "foobar, foobar", diff --git a/docs/content/routing/providers/consul-catalog.md b/docs/content/routing/providers/consul-catalog.md index 22b4978d6..1104ec186 100644 --- a/docs/content/routing/providers/consul-catalog.md +++ b/docs/content/routing/providers/consul-catalog.md @@ -225,6 +225,14 @@ you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.pass traefik.http.services.myservice.loadbalancer.sticky.cookie.secure=true ``` +??? info "`traefik.http.services..loadbalancer.sticky.cookie.samesite`" + + See [sticky sessions](../services/index.md#sticky-sessions) for more information. + + ```yaml + traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none + ``` + ??? info "`traefik.http.services..loadbalancer.responseforwarding.flushinterval`" diff --git a/docs/content/routing/providers/docker.md b/docs/content/routing/providers/docker.md index f9b417eea..5a03979a6 100644 --- a/docs/content/routing/providers/docker.md +++ b/docs/content/routing/providers/docker.md @@ -358,6 +358,14 @@ you'd add the label `traefik.http.services..loadbalancer.pa - "traefik.http.services.myservice.loadbalancer.sticky.cookie.secure=true" ``` +??? info "`traefik.http.services..loadbalancer.sticky.cookie.samesite`" + + See [sticky sessions](../services/index.md#sticky-sessions) for more information. + + ```yaml + - "traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none" + ``` + ??? info "`traefik.http.services..loadbalancer.responseforwarding.flushinterval`" See [response forwarding](../services/index.md#response-forwarding) for more information. diff --git a/docs/content/routing/providers/kubernetes-crd.md b/docs/content/routing/providers/kubernetes-crd.md index 523d38a22..4f691654d 100644 --- a/docs/content/routing/providers/kubernetes-crd.md +++ b/docs/content/routing/providers/kubernetes-crd.md @@ -195,6 +195,7 @@ Register the `IngressRoute` kind in the Kubernetes cluster before creating `Ingr httpOnly: true name: cookie secure: true + sameSite: none strategy: RoundRobin weight: 10 tls: # [9] diff --git a/docs/content/routing/providers/marathon.md b/docs/content/routing/providers/marathon.md index 7bc79a6b7..50c92d82f 100644 --- a/docs/content/routing/providers/marathon.md +++ b/docs/content/routing/providers/marathon.md @@ -256,6 +256,14 @@ For example, to change the passHostHeader behavior, you'd add the label `"traefi "traefik.http.services.myservice.loadbalancer.sticky.cookie.secure": "true" ``` +??? info "`traefik.http.services..loadbalancer.sticky.cookie.samesite`" + + See [sticky sessions](../services/index.md#sticky-sessions) for more information. + + ```json + "traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite": "none" + ``` + ??? info "`traefik.http.services..loadbalancer.responseforwarding.flushinterval`" See [response forwarding](../services/index.md#response-forwarding) for more information. diff --git a/docs/content/routing/providers/rancher.md b/docs/content/routing/providers/rancher.md index c0178a910..2d317810e 100644 --- a/docs/content/routing/providers/rancher.md +++ b/docs/content/routing/providers/rancher.md @@ -262,6 +262,14 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa - "traefik.http.services.myservice.loadbalancer.sticky.cookie.secure=true" ``` +??? info "`traefik.http.services..loadbalancer.sticky.cookie.samesite`" + + See [sticky sessions](../services/index.md#sticky-sessions) for more information. + + ```yaml + - "traefik.http.services.myservice.loadbalancer.sticky.cookie.samesite=none" + ``` + ??? info "`traefik.http.services..loadbalancer.responseforwarding.flushinterval`" See [response forwarding](../services/index.md#response-forwarding) for more information. diff --git a/docs/content/routing/services/index.md b/docs/content/routing/services/index.md index eff981637..514f72187 100644 --- a/docs/content/routing/services/index.md +++ b/docs/content/routing/services/index.md @@ -156,9 +156,12 @@ On subsequent requests, the client is forwarded to the same server. The default cookie name is an abbreviation of a sha1 (ex: `_1d52e`). -!!! info "Secure & HTTPOnly flags" +!!! info "Secure & HTTPOnly & SameSite flags" - By default, the affinity cookie is created without those flags. One however can change that through configuration. + By default, the affinity cookie is created without those flags. + One however can change that through configuration. + + `SameSite` can be `none`, `lax`, `strict` or empty. ??? example "Adding Stickiness -- Using the [File Provider](../../providers/file.md)" @@ -189,6 +192,7 @@ On subsequent requests, the client is forwarded to the same server. name = "my_sticky_cookie_name" secure = true httpOnly = true + sameSite = "none" ``` ```yaml tab="YAML" diff --git a/go.mod b/go.mod index ceef0b84e..4fb8c63c6 100644 --- a/go.mod +++ b/go.mod @@ -46,7 +46,7 @@ require ( github.com/google/go-github/v28 v28.0.0 github.com/googleapis/gnostic v0.1.0 // indirect github.com/gorilla/mux v1.7.3 - github.com/gorilla/websocket v1.4.0 + github.com/gorilla/websocket v1.4.2 github.com/hashicorp/consul/api v1.2.0 github.com/hashicorp/go-version v1.2.0 github.com/huandu/xstrings v1.2.0 // indirect @@ -76,7 +76,7 @@ require ( github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 github.com/rancher/go-rancher-metadata v0.0.0-00010101000000-000000000000 github.com/sirupsen/logrus v1.4.2 - github.com/stretchr/testify v1.4.0 + github.com/stretchr/testify v1.5.1 github.com/stvp/go-udp-testing v0.0.0-20171104055251-c4434f09ec13 github.com/tinylib/msgp v1.0.2 // indirect github.com/transip/gotransip v5.8.2+incompatible // indirect @@ -85,7 +85,7 @@ require ( github.com/unrolled/render v1.0.1 github.com/unrolled/secure v1.0.5 github.com/vdemeester/shakers v0.1.0 - github.com/vulcand/oxy v1.0.0 + github.com/vulcand/oxy v1.1.0 github.com/vulcand/predicate v1.1.0 golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a // indirect diff --git a/go.sum b/go.sum index 169dd9242..d42124263 100644 --- a/go.sum +++ b/go.sum @@ -282,6 +282,8 @@ github.com/gorilla/context v1.1.1 h1:AWwleXJkX/nhcU9bZSnZoi3h/qGYqQAGhq6zZe/aQW8 github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gravitational/trace v0.0.0-20190726142706-a535a178675f h1:68WxnfBzJRYktZ30fmIjGQ74RsXYLoeH2/NITPktTMY= github.com/gravitational/trace v0.0.0-20190726142706-a535a178675f/go.mod h1:RvdOUHE4SHqR3oXlFFKnGzms8a5dugHygGw1bqDstYI= github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -558,6 +560,8 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stvp/go-udp-testing v0.0.0-20171104055251-c4434f09ec13 h1:WYRIgR83bWdH2zjqXalfLuQYtgBG1KKxDRxinx2ygMI= github.com/stvp/go-udp-testing v0.0.0-20171104055251-c4434f09ec13/go.mod h1:7jxmlfBCDBXRzr0eAQJ48XC1hBu1np4CS5+cHEYfwpc= github.com/timewasted/linode v0.0.0-20160829202747-37e84520dcf7 h1:CpHxIaZzVy26GqJn8ptRyto8fuoYOd1v0fXm9bG3wQ8= @@ -582,8 +586,8 @@ github.com/unrolled/secure v1.0.5/go.mod h1:R6rugAuzh4TQpbFAq69oqZggyBQxFRFQIewt github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/vdemeester/shakers v0.1.0 h1:K+n9sSyUCg2ywmZkv+3c7vsYZfivcfKhMh8kRxCrONM= github.com/vdemeester/shakers v0.1.0/go.mod h1:IZ1HHynUOQt32iQ3rvAeVddXLd19h/6LWiKsh9RZtAQ= -github.com/vulcand/oxy v1.0.0 h1:7vL5/pjDFzHGbtBEhmlHITUi6KLH4xXTDF33/wrdRKw= -github.com/vulcand/oxy v1.0.0/go.mod h1:6EXgOAl6CRa46/2ZGcDJKf3ywJUp5WtT7vSlGSkvecI= +github.com/vulcand/oxy v1.1.0 h1:DbBijGo1+6cFqR9jarkMxasdj0lgWwrrFtue6ijek4Q= +github.com/vulcand/oxy v1.1.0/go.mod h1:ADiMYHi8gkGl2987yQIzDRoXZilANF4WtKaQ92OppKY= github.com/vulcand/predicate v1.1.0 h1:Gq/uWopa4rx/tnZu2opOSBqHK63Yqlou/SzrbwdJiNg= github.com/vulcand/predicate v1.1.0/go.mod h1:mlccC5IRBoc2cIFmCB8ZM62I3VDb6p2GXESMHa3CnZg= github.com/vultr/govultr v0.1.4 h1:UnNMixYFVO0p80itc8PcweoVENyo1PasfvwKhoasR9U= @@ -853,6 +857,7 @@ k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30 h1:TRb4wNWoBVrH9plmkp2q86 k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc= k8s.io/utils v0.0.0-20190221042446-c2654d5206da h1:ElyM7RPonbKnQqOcw7dG2IK5uvQQn3b/WPHqD5mBvP4= k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0= +launchpad.net/gocheck v0.0.0-20140225173054-000000000087/go.mod h1:hj7XX3B/0A+80Vse0e+BUHsHMTEhd0O4cpUHr/e/BUM= modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= diff --git a/pkg/config/dynamic/http_config.go b/pkg/config/dynamic/http_config.go index c98e10697..6edf3e565 100644 --- a/pkg/config/dynamic/http_config.go +++ b/pkg/config/dynamic/http_config.go @@ -97,6 +97,7 @@ type Cookie struct { Name string `json:"name,omitempty" toml:"name,omitempty" yaml:"name,omitempty"` Secure bool `json:"secure,omitempty" toml:"secure,omitempty" yaml:"secure,omitempty"` HTTPOnly bool `json:"httpOnly,omitempty" toml:"httpOnly,omitempty" yaml:"httpOnly,omitempty"` + SameSite string `json:"sameSite,omitempty" toml:"sameSite,omitempty" yaml:"sameSite,omitempty"` } // +k8s:deepcopy-gen=true diff --git a/pkg/server/service/service.go b/pkg/server/service/service.go index 4ff4d213b..f50a671d4 100644 --- a/pkg/server/service/service.go +++ b/pkg/server/service/service.go @@ -283,8 +283,15 @@ func (m *Manager) getLoadBalancer(ctx context.Context, serviceName string, servi var cookieName string if service.Sticky != nil && service.Sticky.Cookie != nil { cookieName = cookie.GetName(service.Sticky.Cookie.Name, serviceName) - opts := roundrobin.CookieOptions{HTTPOnly: service.Sticky.Cookie.HTTPOnly, Secure: service.Sticky.Cookie.Secure} + + opts := roundrobin.CookieOptions{ + HTTPOnly: service.Sticky.Cookie.HTTPOnly, + Secure: service.Sticky.Cookie.Secure, + SameSite: convertSameSite(service.Sticky.Cookie.SameSite), + } + options = append(options, roundrobin.EnableStickySession(roundrobin.NewStickySessionWithOptions(cookieName, opts))) + logger.Debugf("Sticky session cookie name: %v", cookieName) } @@ -320,3 +327,16 @@ func (m *Manager) upsertServers(ctx context.Context, lb healthcheck.BalancerHand } return nil } + +func convertSameSite(sameSite string) http.SameSite { + switch sameSite { + case "none": + return http.SameSiteNoneMode + case "lax": + return http.SameSiteLaxMode + case "strict": + return http.SameSiteStrictMode + default: + return 0 + } +}