Compare commits

..

15 Commits

Author SHA1 Message Date
Ludovic Fernandez
5afa78e18e Prepare release v1.7.26 2020-07-28 17:32:03 +02:00
Ludovic Fernandez
cfa04c300c fix: clean X-Forwarded-Prefix header for the dashboard. 2020-07-28 10:10:03 +02:00
Cory Claflin
cb6b94ff40 Change apiVersion to apps/v1 in examples/k8s/cheese-deployments.yaml 2020-07-27 16:24:03 +02:00
Ludovic Fernandez
0b2a6cecd1 Prepare release v1.7.25 2020-07-15 12:28:03 +02:00
Fernandez Ludovic
fee89273a3 chore: update doc analytics. 2020-07-03 12:07:46 +02:00
Richard Kojedzinszky
463e2285d6 Backport "Same Configuration Check" from master 2020-07-01 11:36:03 +02:00
Romain
c65277a6f0 Fix ipv6 handling in redirect middleware 2020-06-19 10:08:04 +02:00
Douglas De Toni Machado
bb14c3e812 Doc improvement on entrypoints whitelist for v1.7 2020-05-20 10:44:04 +02:00
kobayashi
85580dde3c Add ingress setup for minikube in docs 2020-05-14 18:06:05 +02:00
Ludovic Fernandez
4bb6d1bf4f Prepare release v1.7.24 2020-03-25 14:48:05 +01:00
Ludovic Fernandez
459cabca8e fix: stickiness annotations support. 2020-03-25 10:58:04 +01:00
Ludovic Fernandez
dcca37fe29 Prepare release v1.7.23 2020-03-23 16:50:04 +01:00
Julien Salleyron
a610f0b2a1 Force http/1.1 for upgrade (Traefik v1) 2020-03-23 15:18:04 +01:00
Ludovic Fernandez
ded285be29 Fix sameSite (Traefik v1) 2020-03-23 13:10:04 +01:00
Ludovic Fernandez
4b31d3306b fix: max TLS version. 2020-03-22 17:54:03 +01:00
54 changed files with 681 additions and 210 deletions

View File

@@ -1,5 +1,39 @@
# Change Log
## [v1.7.26](https://github.com/containous/traefik/tree/v1.7.26) (2020-07-28)
[All Commits](https://github.com/containous/traefik/compare/v1.7.25...v1.7.26)
**Bug fixes:**
- **[webui]** fix: clean X-Forwarded-Prefix header for the dashboard. ([#7108](https://github.com/containous/traefik/pull/7108) by [ldez](https://github.com/ldez))
**Documentation:**
- **[k8s,k8s/ingress]** Change apiVersion to apps/v1 in examples/k8s/cheese-deployments.yaml ([#7090](https://github.com/containous/traefik/pull/7090) by [claflico](https://github.com/claflico))
## [v1.7.25](https://github.com/containous/traefik/tree/v1.7.25) (2020-07-15)
[All Commits](https://github.com/containous/traefik/compare/v1.7.24...v1.7.25)
**Bug fixes:**
- **[middleware]** Fix ipv6 handling in redirect middleware ([#6901](https://github.com/containous/traefik/pull/6901) by [rtribotte](https://github.com/rtribotte))
- **[provider]** Backport "Same Configuration Check" from master ([#6631](https://github.com/containous/traefik/pull/6631) by [rkojedzinszky](https://github.com/rkojedzinszky))
**Documentation:**
- **[k8s]** Add ingress setup for minikube in docs ([#6552](https://github.com/containous/traefik/pull/6552) by [kobayashi](https://github.com/kobayashi))
- Doc improvement on entrypoints whitelist for v1.7 ([#6571](https://github.com/containous/traefik/pull/6571) by [ddtmachado](https://github.com/ddtmachado))
## [v1.7.24](https://github.com/containous/traefik/tree/v1.7.24) (2020-03-25)
[All Commits](https://github.com/containous/traefik/compare/v1.7.23...v1.7.24)
**Bug fixes:**
- **[k8s/ingress]** fix: stickiness annotations support. ([#6576](https://github.com/containous/traefik/pull/6576) by [ldez](https://github.com/ldez))
## [v1.7.23](https://github.com/containous/traefik/tree/v1.7.23) (2020-03-23)
[All Commits](https://github.com/containous/traefik/compare/v1.7.22...v1.7.23)
**Bug fixes:**
- **[consul,consulcatalog,docker,ecs,k8s,marathon,mesos,rancher,sticky-session]** Fix sameSite ([#6537](https://github.com/containous/traefik/pull/6537) by [ldez](https://github.com/ldez))
- **[server]** Force http/1.1 for upgrade ([#6553](https://github.com/containous/traefik/pull/6553) by [juliens](https://github.com/juliens))
- **[tls]** fix: max TLS version. ([#6531](https://github.com/containous/traefik/pull/6531) by [ldez](https://github.com/ldez))
## [v1.7.22](https://github.com/containous/traefik/tree/v1.7.22) (2020-03-09)
[All Commits](https://github.com/containous/traefik/compare/v1.7.21...v1.7.22)

6
Gopkg.lock generated
View File

@@ -1937,8 +1937,7 @@
version = "v0.1.0"
[[projects]]
branch = "master"
digest = "1:86f14aadf288fe3ad8ac060bcb2b5083cec3829dd883803486ec834d031060c9"
digest = "1:a31155114d2977ef48d2cca6810c4e055545d676bf13b604c2debd42de44cad0"
name = "github.com/vulcand/oxy"
packages = [
"buffer",
@@ -1951,7 +1950,8 @@
"utils",
]
pruneopts = "NUT"
revision = "0d102f45103cf49a95b5c6e810e092973cbcb68c"
revision = "9dbd22c030f2187f590fea61ebe84ab78a8146a2"
version = "v1.1.0"
[[projects]]
digest = "1:ca6bac407fedc14fbeeba861dd33a821ba3a1624c10126ec6003b0a28d4139c5"

View File

@@ -175,7 +175,7 @@
version = "0.1.0"
[[constraint]]
branch = "master"
version = "v1.1.0"
name = "github.com/vulcand/oxy"
[[constraint]]

View File

@@ -2,6 +2,7 @@ package api
import (
"net/http"
"net/url"
"github.com/containous/mux"
"github.com/containous/traefik/log"
@@ -23,17 +24,35 @@ func (g DashboardHandler) AddRoutes(router *mux.Router) {
// Expose dashboard
router.Methods(http.MethodGet).
Path("/").
HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
http.Redirect(response, request, request.Header.Get("X-Forwarded-Prefix")+"/dashboard/", 302)
HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
http.Redirect(resp, req, safePrefix(req)+"/dashboard/", 302)
})
router.Methods(http.MethodGet).
Path("/dashboard/status").
HandlerFunc(func(response http.ResponseWriter, request *http.Request) {
http.Redirect(response, request, "/dashboard/", 302)
HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
http.Redirect(resp, req, "/dashboard/", 302)
})
router.Methods(http.MethodGet).
PathPrefix("/dashboard/").
Handler(http.StripPrefix("/dashboard/", http.FileServer(g.Assets)))
}
func safePrefix(req *http.Request) string {
prefix := req.Header.Get("X-Forwarded-Prefix")
if prefix == "" {
return ""
}
parse, err := url.Parse(prefix)
if err != nil {
return ""
}
if parse.Host != "" {
return ""
}
return parse.Path
}

54
api/dashboard_test.go Normal file
View File

@@ -0,0 +1,54 @@
package api
import (
"net/http"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_safePrefix(t *testing.T) {
testCases := []struct {
desc string
value string
expected string
}{
{
desc: "host",
value: "https://example.com",
expected: "",
},
{
desc: "host with path",
value: "https://example.com/foo/bar?test",
expected: "",
},
{
desc: "path",
value: "/foo/bar",
expected: "/foo/bar",
},
{
desc: "path without leading slash",
value: "foo/bar",
expected: "foo/bar",
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
req, err := http.NewRequest(http.MethodGet, "http://localhost", nil)
require.NoError(t, err)
req.Header.Set("X-Forwarded-Prefix", test.value)
prefix := safePrefix(req)
assert.Equal(t, test.expected, prefix)
})
}
}

View File

@@ -159,6 +159,9 @@ var _templatesConsul_catalogTmpl = []byte(`[backends]
{{if $loadBalancer.Stickiness }}
[backends."backend-{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}
@@ -654,6 +657,9 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
{{if $loadBalancer.Stickiness }}
[backends."backend-{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}
@@ -1000,6 +1006,9 @@ var _templatesEcsTmpl = []byte(`[backends]
{{if $loadBalancer.Stickiness }}
[backends."backend-{{ $serviceName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}
@@ -1325,6 +1334,9 @@ var _templatesKubernetesTmpl = []byte(`[backends]
{{if $backend.LoadBalancer.Stickiness }}
[backends."{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $backend.LoadBalancer.Stickiness.CookieName }}"
secure = {{ $backend.LoadBalancer.Stickiness.Secure }}
httpOnly = {{ $backend.LoadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $backend.LoadBalancer.Stickiness.SameSite }}"
{{end}}
{{if $backend.MaxConn }}
@@ -1582,6 +1594,9 @@ var _templatesKvTmpl = []byte(`[backends]
{{if $loadBalancer.Stickiness }}
[backends."{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}
@@ -1970,6 +1985,9 @@ var _templatesMarathonTmpl = []byte(`{{ $apps := .Applications }}
{{if $loadBalancer.Stickiness }}
[backends."{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}
@@ -2302,6 +2320,9 @@ var _templatesMesosTmpl = []byte(`[backends]
{{if $loadBalancer.Stickiness }}
[backends."backend-{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}
@@ -2688,6 +2709,9 @@ var _templatesRancherTmpl = []byte(`{{ $backendServers := .Backends }}
{{if $loadBalancer.Stickiness }}
[backends."backend-{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}

View File

@@ -452,6 +452,27 @@ If not, a new backend will be assigned.
# Default: a sha1 (6 chars)
#
# cookieName = "my_cookie"
# Customize secure option
#
# Optional
# Default: false
#
# secure = true
# Customize http only option
#
# Optional
# Default: false
#
# httpOnly = true
# Customize same site option.
# Can be: "none", "lax", "strict"
#
# Optional
#
# sameSite = "none"
```
The deprecated way:

View File

@@ -124,6 +124,9 @@ Additional settings can be defined using Consul Catalog tags.
| `<prefix>.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm. |
| `<prefix>.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions. |
| `<prefix>.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for sticky sessions. |
| `<prefix>.backend.loadbalancer.stickiness.secure=true` | Sets secure cookie option for sticky sessions. |
| `<prefix>.backend.loadbalancer.stickiness.httpOnly=true` | Sets http only cookie option for sticky sessions. |
| `<prefix>.backend.loadbalancer.stickiness.sameSite=none` | Sets same site cookie option for sticky sessions. (`none`, `lax`, `strict`) |
| `<prefix>.backend.loadbalancer.sticky=true` | Enables backend sticky sessions. (DEPRECATED) |
| `<prefix>.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `<prefix>.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |

View File

@@ -313,6 +313,9 @@ Labels can be used on containers to override default behavior.
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for sticky sessions |
| `traefik.backend.loadbalancer.stickiness.secure=true` | Sets secure cookie option for sticky sessions. |
| `traefik.backend.loadbalancer.stickiness.httpOnly=true` | Sets http only cookie option for sticky sessions. |
| `traefik.backend.loadbalancer.stickiness.sameSite=none` | Sets same site cookie option for sticky sessions. (`none`, `lax`, `strict`) |
| `traefik.backend.loadbalancer.sticky=true` | Enables backend sticky sessions (DEPRECATED) |
| `traefik.backend.loadbalancer.swarm=true` | Uses Swarm's inbuilt load balancer (only relevant under Swarm Mode) [3]. |
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |

View File

@@ -160,6 +160,9 @@ Labels can be used on task containers to override default behaviour:
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie manually name for sticky sessions |
| `traefik.backend.loadbalancer.stickiness.secure=true` | Sets secure cookie option for sticky sessions. |
| `traefik.backend.loadbalancer.stickiness.httpOnly=true` | Sets http only cookie option for sticky sessions. |
| `traefik.backend.loadbalancer.stickiness.sameSite=none` | Sets same site cookie option for sticky sessions. (`none`, `lax`, `strict`) |
| `traefik.backend.loadbalancer.sticky=true` | Enables backend sticky sessions (DEPRECATED) |
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |

View File

@@ -31,6 +31,9 @@ Traefik can be configured with a file.
method = "drr"
[backends.backend1.loadBalancer.stickiness]
cookieName = "foobar"
secure = true
httpOnly = true
sameSite = "foobar"
[backends.backend1.maxConn]
amount = 10

View File

@@ -218,6 +218,9 @@ The following labels can be defined on Marathon applications. They adjust the be
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for sticky sessions |
| `traefik.backend.loadbalancer.stickiness.secure=true` | Sets secure cookie option for sticky sessions. |
| `traefik.backend.loadbalancer.stickiness.httpOnly=true` | Sets http only cookie option for sticky sessions. |
| `traefik.backend.loadbalancer.stickiness.sameSite=none` | Sets same site cookie option for sticky sessions. (`none`, `lax`, `strict`) |
| `traefik.backend.loadbalancer.sticky=true` | Enables backend sticky sessions (DEPRECATED) |
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |

View File

@@ -132,6 +132,9 @@ The following labels can be defined on Mesos tasks. They adjust the behavior for
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie manually name for sticky sessions |
| `traefik.backend.loadbalancer.stickiness.secure=true` | Sets secure cookie option for sticky sessions. |
| `traefik.backend.loadbalancer.stickiness.httpOnly=true` | Sets http only cookie option for sticky sessions. |
| `traefik.backend.loadbalancer.stickiness.sameSite=none` | Sets same site cookie option for sticky sessions. (`none`, `lax`, `strict`) |
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |

View File

@@ -167,6 +167,9 @@ Labels can be used on task containers to override default behavior:
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
| `traefik.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions |
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for sticky sessions |
| `traefik.backend.loadbalancer.stickiness.secure=true` | Sets secure cookie option for sticky sessions. |
| `traefik.backend.loadbalancer.stickiness.httpOnly=true` | Sets http only cookie option for sticky sessions. |
| `traefik.backend.loadbalancer.stickiness.sameSite=none` | Sets same site cookie option for sticky sessions. (`none`, `lax`, `strict`) |
| `traefik.backend.loadbalancer.sticky=true` | Enables backend sticky sessions (DEPRECATED) |
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |

View File

@@ -485,6 +485,13 @@ To enable IP white listing at the entry point level.
# useXForwardedFor = true
```
By setting the `useXForwardedFor` option, the `sourceRange` addresses will be matched against the request header `X-Forwarded-For` address list, from left to right.
!!! danger
When using Traefik behind another load-balancer, its own internal address will be appended in the `X-Forwarded-For` header.
Be sure to carefully configure the `sourceRange` as adding the internal network CIDR,
or the load-balancer address directly, will cause all requests coming from it to pass through.
## ProxyProtocol
To enable [ProxyProtocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) support.

View File

@@ -0,0 +1,7 @@
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-NMWC63S');</script>
<!-- End Google Tag Manager -->

View File

@@ -10,10 +10,14 @@ The config files used in this guide can be found in the [examples directory](htt
1. A working Kubernetes cluster. If you want to follow along with this guide, you should setup [minikube](https://kubernetes.io/docs/getting-started-guides/minikube/) on your machine, as it is the quickest way to get a local Kubernetes cluster setup for experimentation and development.
2. Setup ingress as an add-on. It can be enabled by the following command:
`minikube addons enable ingress`
!!! note
The guide is likely not fully adequate for a production-ready setup.
2. The `kubectl` binary should be [installed on your workstation](https://kubernetes.io/docs/getting-started-guides/minikube/#download-kubectl).
3. The `kubectl` binary should be [installed on your workstation](https://kubernetes.io/docs/getting-started-guides/minikube/#download-kubectl).
### Role Based Access Control configuration (Kubernetes 1.6+ only)

View File

@@ -1,6 +1,6 @@
---
kind: Deployment
apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
name: stilton
labels:
@@ -33,7 +33,7 @@ spec:
- containerPort: 80
---
kind: Deployment
apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
name: cheddar
labels:
@@ -66,7 +66,7 @@ spec:
- containerPort: 80
---
kind: Deployment
apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
name: wensleydale
labels:

View File

@@ -17,7 +17,7 @@ import (
)
const (
defaultRedirectRegex = `^(?:https?:\/\/)?([\w\._-]+)(?::\d+)?(.*)$`
defaultRedirectRegex = `^(?:https?:\/\/)?(\[[\w:.]+\]|[\w\._-]+)(?::\d+)?(.*)$`
)
// NewEntryPointHandler create a new redirection handler base on entry point

View File

@@ -84,6 +84,34 @@ func TestNewEntryPointHandler(t *testing.T) {
url: "http://foo:80",
errorExpected: true,
},
{
desc: "IPV6 HTTP to HTTP",
entryPoint: &configuration.EntryPoint{Address: ":8080"},
url: "http://[::1]",
expectedURL: "http://[::1]:8080",
expectedStatus: http.StatusFound,
},
{
desc: "IPV6 HTTP to HTTPS",
entryPoint: &configuration.EntryPoint{Address: ":443", TLS: &tls.TLS{}},
url: "http://[::1]",
expectedURL: "https://[::1]:443",
expectedStatus: http.StatusFound,
},
{
desc: "IPV6 HTTP with port 80 to HTTP",
entryPoint: &configuration.EntryPoint{Address: ":8080"},
url: "http://[::1]:80",
expectedURL: "http://[::1]:8080",
expectedStatus: http.StatusFound,
},
{
desc: "IPV6 HTTP with port 80 to HTTPS",
entryPoint: &configuration.EntryPoint{Address: ":443", TLS: &tls.TLS{}},
url: "http://[::1]:80",
expectedURL: "https://[::1]:443",
expectedStatus: http.StatusFound,
},
}
for _, test := range testCases {

View File

@@ -28,6 +28,7 @@ theme:
copyright: "Copyright &copy; 2016-2019 Containous"
# only to force the use of the analytics partials
google_analytics:
- 'UA-51880359-3'
- 'docs.traefik.io'

View File

@@ -254,7 +254,8 @@ func TestProviderBuildConfiguration(t *testing.T) {
},
},
},
}, {
},
{
desc: "Should build config with a digest auth",
nodes: []catalogUpdate{
{
@@ -416,6 +417,9 @@ func TestProviderBuildConfiguration(t *testing.T) {
label.TraefikBackendLoadBalancerSticky + "=true",
label.TraefikBackendLoadBalancerStickiness + "=true",
label.TraefikBackendLoadBalancerStickinessCookieName + "=chocolate",
label.TraefikBackendLoadBalancerStickinessSecure + "=true",
label.TraefikBackendLoadBalancerStickinessHTTPOnly + "=true",
label.TraefikBackendLoadBalancerStickinessSameSite + "=none",
label.TraefikBackendMaxConnAmount + "=666",
label.TraefikBackendMaxConnExtractorFunc + "=client.ip",
label.TraefikBackendBufferingMaxResponseBodyBytes + "=10485760",
@@ -700,6 +704,9 @@ func TestProviderBuildConfiguration(t *testing.T) {
Sticky: true,
Stickiness: &types.Stickiness{
CookieName: "chocolate",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
},
MaxConn: &types.MaxConn{

View File

@@ -463,6 +463,9 @@ func TestDockerBuildConfiguration(t *testing.T) {
label.TraefikBackendLoadBalancerSticky: "true",
label.TraefikBackendLoadBalancerStickiness: "true",
label.TraefikBackendLoadBalancerStickinessCookieName: "chocolate",
label.TraefikBackendLoadBalancerStickinessSecure: "true",
label.TraefikBackendLoadBalancerStickinessHTTPOnly: "true",
label.TraefikBackendLoadBalancerStickinessSameSite: "none",
label.TraefikBackendMaxConnAmount: "666",
label.TraefikBackendMaxConnExtractorFunc: "client.ip",
label.TraefikBackendBufferingMaxResponseBodyBytes: "10485760",
@@ -711,6 +714,9 @@ func TestDockerBuildConfiguration(t *testing.T) {
Sticky: true,
Stickiness: &types.Stickiness{
CookieName: "chocolate",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
},
MaxConn: &types.MaxConn{

View File

@@ -412,6 +412,9 @@ func TestSwarmBuildConfiguration(t *testing.T) {
label.TraefikBackendLoadBalancerSticky: "true",
label.TraefikBackendLoadBalancerStickiness: "true",
label.TraefikBackendLoadBalancerStickinessCookieName: "chocolate",
label.TraefikBackendLoadBalancerStickinessSecure: "true",
label.TraefikBackendLoadBalancerStickinessHTTPOnly: "true",
label.TraefikBackendLoadBalancerStickinessSameSite: "none",
label.TraefikBackendMaxConnAmount: "666",
label.TraefikBackendMaxConnExtractorFunc: "client.ip",
label.TraefikBackendBufferingMaxResponseBodyBytes: "10485760",
@@ -611,6 +614,9 @@ func TestSwarmBuildConfiguration(t *testing.T) {
Sticky: true,
Stickiness: &types.Stickiness{
CookieName: "chocolate",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
},
MaxConn: &types.MaxConn{

View File

@@ -353,6 +353,9 @@ func TestBuildConfiguration(t *testing.T) {
label.TraefikBackendLoadBalancerSticky: aws.String("true"),
label.TraefikBackendLoadBalancerStickiness: aws.String("true"),
label.TraefikBackendLoadBalancerStickinessCookieName: aws.String("chocolate"),
label.TraefikBackendLoadBalancerStickinessSecure: aws.String("true"),
label.TraefikBackendLoadBalancerStickinessHTTPOnly: aws.String("true"),
label.TraefikBackendLoadBalancerStickinessSameSite: aws.String("none"),
label.TraefikBackendMaxConnAmount: aws.String("666"),
label.TraefikBackendMaxConnExtractorFunc: aws.String("client.ip"),
label.TraefikBackendBufferingMaxResponseBodyBytes: aws.String("10485760"),
@@ -475,6 +478,9 @@ func TestBuildConfiguration(t *testing.T) {
Sticky: true,
Stickiness: &types.Stickiness{
CookieName: "chocolate",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
},
MaxConn: &types.MaxConn{
@@ -662,6 +668,9 @@ func TestBuildConfiguration(t *testing.T) {
label.TraefikBackendLoadBalancerSticky: aws.String("true"),
label.TraefikBackendLoadBalancerStickiness: aws.String("true"),
label.TraefikBackendLoadBalancerStickinessCookieName: aws.String("chocolate"),
label.TraefikBackendLoadBalancerStickinessSecure: aws.String("true"),
label.TraefikBackendLoadBalancerStickinessHTTPOnly: aws.String("true"),
label.TraefikBackendLoadBalancerStickinessSameSite: aws.String("none"),
label.TraefikBackendMaxConnAmount: aws.String("666"),
label.TraefikBackendMaxConnExtractorFunc: aws.String("client.ip"),
label.TraefikBackendBufferingMaxResponseBodyBytes: aws.String("10485760"),
@@ -750,6 +759,9 @@ func TestBuildConfiguration(t *testing.T) {
label.TraefikBackendLoadBalancerSticky: aws.String("true"),
label.TraefikBackendLoadBalancerStickiness: aws.String("true"),
label.TraefikBackendLoadBalancerStickinessCookieName: aws.String("chocolate"),
label.TraefikBackendLoadBalancerStickinessSecure: aws.String("true"),
label.TraefikBackendLoadBalancerStickinessHTTPOnly: aws.String("true"),
label.TraefikBackendLoadBalancerStickinessSameSite: aws.String("none"),
label.TraefikBackendMaxConnAmount: aws.String("666"),
label.TraefikBackendMaxConnExtractorFunc: aws.String("client.ip"),
label.TraefikBackendBufferingMaxResponseBodyBytes: aws.String("10485760"),
@@ -839,6 +851,9 @@ func TestBuildConfiguration(t *testing.T) {
Sticky: true,
Stickiness: &types.Stickiness{
CookieName: "chocolate",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
},
MaxConn: &types.MaxConn{

View File

@@ -30,6 +30,9 @@ const (
annotationKubernetesLoadBalancerMethod = "ingress.kubernetes.io/load-balancer-method"
annotationKubernetesAffinity = "ingress.kubernetes.io/affinity"
annotationKubernetesSessionCookieName = "ingress.kubernetes.io/session-cookie-name"
annotationKubernetesSessionSecure = "ingress.kubernetes.io/session-secure"
annotationKubernetesSessionHTTPOnly = "ingress.kubernetes.io/session-http-only"
annotationKubernetesSessionSameSite = "ingress.kubernetes.io/session-same-site"
annotationKubernetesRuleType = "ingress.kubernetes.io/rule-type"
annotationKubernetesRedirectEntryPoint = "ingress.kubernetes.io/redirect-entry-point"
annotationKubernetesRedirectPermanent = "ingress.kubernetes.io/redirect-permanent"

View File

@@ -1151,14 +1151,16 @@ func getLoadBalancer(service *corev1.Service) *types.LoadBalancer {
}
func getStickiness(service *corev1.Service) *types.Stickiness {
if getBoolValue(service.Annotations, annotationKubernetesAffinity, false) {
stickiness := &types.Stickiness{}
if cookieName := getStringValue(service.Annotations, annotationKubernetesSessionCookieName, ""); len(cookieName) > 0 {
stickiness.CookieName = cookieName
}
return stickiness
if !getBoolValue(service.Annotations, annotationKubernetesAffinity, false) {
return nil
}
return &types.Stickiness{
CookieName: getStringValue(service.Annotations, annotationKubernetesSessionCookieName, ""),
Secure: getBoolValue(service.Annotations, annotationKubernetesSessionSecure, false),
HTTPOnly: getBoolValue(service.Annotations, annotationKubernetesSessionHTTPOnly, false),
SameSite: getStringValue(service.Annotations, annotationKubernetesSessionSameSite, ""),
}
return nil
}
func getHeader(i *extensionsv1beta1.Ingress) *types.Headers {

View File

@@ -14,6 +14,9 @@ const (
pathBackendLoadBalancerSticky = "/loadbalancer/sticky"
pathBackendLoadBalancerStickiness = "/loadbalancer/stickiness"
pathBackendLoadBalancerStickinessCookieName = "/loadbalancer/stickiness/cookiename"
pathBackendLoadBalancerStickinessSecure = "/loadbalancer/stickiness/secure"
pathBackendLoadBalancerStickinessHTTPOnly = "/loadbalancer/stickiness/httponly"
pathBackendLoadBalancerStickinessSameSite = "/loadbalancer/stickiness/samesite"
pathBackendMaxConnAmount = "/maxconn/amount"
pathBackendMaxConnExtractorFunc = "/maxconn/extractorfunc"
pathBackendServers = "/servers/"

View File

@@ -276,6 +276,9 @@ func (p *Provider) getLoadBalancer(rootPath string) *types.LoadBalancer {
if p.getBool(false, rootPath, pathBackendLoadBalancerStickiness) {
lb.Stickiness = &types.Stickiness{
CookieName: p.get("", rootPath, pathBackendLoadBalancerStickinessCookieName),
Secure: p.getBool(false, rootPath, pathBackendLoadBalancerStickinessSecure),
HTTPOnly: p.getBool(false, rootPath, pathBackendLoadBalancerStickinessHTTPOnly),
SameSite: p.get("", rootPath, pathBackendLoadBalancerStickinessSameSite),
}
}

View File

@@ -260,6 +260,9 @@ func TestProviderBuildConfiguration(t *testing.T) {
withPair(pathBackendLoadBalancerSticky, "true"),
withPair(pathBackendLoadBalancerStickiness, "true"),
withPair(pathBackendLoadBalancerStickinessCookieName, "tomate"),
withPair(pathBackendLoadBalancerStickinessSecure, "true"),
withPair(pathBackendLoadBalancerStickinessHTTPOnly, "true"),
withPair(pathBackendLoadBalancerStickinessSameSite, "none"),
withPair(pathBackendHealthCheckScheme, "http"),
withPair(pathBackendHealthCheckPath, "/health"),
withPair(pathBackendHealthCheckPort, "80"),
@@ -389,6 +392,9 @@ func TestProviderBuildConfiguration(t *testing.T) {
Sticky: true,
Stickiness: &types.Stickiness{
CookieName: "tomate",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
},
MaxConn: &types.MaxConn{
@@ -1949,12 +1955,18 @@ func TestProviderGetLoadBalancer(t *testing.T) {
withPair(pathBackendLoadBalancerMethod, "drr"),
withPair(pathBackendLoadBalancerSticky, "true"),
withPair(pathBackendLoadBalancerStickiness, "true"),
withPair(pathBackendLoadBalancerStickinessCookieName, "aubergine"))),
withPair(pathBackendLoadBalancerStickinessCookieName, "aubergine"),
withPair(pathBackendLoadBalancerStickinessSecure, "true"),
withPair(pathBackendLoadBalancerStickinessHTTPOnly, "true"),
withPair(pathBackendLoadBalancerStickinessSameSite, "none"))),
expected: &types.LoadBalancer{
Method: "drr",
Sticky: true,
Stickiness: &types.Stickiness{
CookieName: "aubergine",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
},
},

View File

@@ -26,6 +26,9 @@ const (
DefaultBackendLoadBalancerMethod = "wrr"
DefaultBackendMaxconnExtractorFunc = "request.host"
DefaultBackendLoadbalancerStickinessCookieName = ""
DefaultBackendLoadbalancerStickinessSecure = false
DefaultBackendLoadbalancerStickinessHTTPOnly = false
DefaultBackendLoadbalancerStickinessSameSite = ""
DefaultBackendHealthCheckPort = 0
)

View File

@@ -2,142 +2,150 @@ package label
// Traefik labels
const (
Prefix = "traefik."
SuffixBackend = "backend"
SuffixDomain = "domain"
SuffixEnable = "enable"
SuffixPort = "port"
SuffixPortName = "portName"
SuffixPortIndex = "portIndex"
SuffixProtocol = "protocol"
SuffixTags = "tags"
SuffixWeight = "weight"
SuffixBackendID = "backend.id"
SuffixBackendCircuitBreaker = "backend.circuitbreaker"
SuffixBackendCircuitBreakerExpression = "backend.circuitbreaker.expression"
SuffixBackendHealthCheckScheme = "backend.healthcheck.scheme"
SuffixBackendHealthCheckPath = "backend.healthcheck.path"
SuffixBackendHealthCheckPort = "backend.healthcheck.port"
SuffixBackendHealthCheckInterval = "backend.healthcheck.interval"
SuffixBackendHealthCheckHostname = "backend.healthcheck.hostname"
SuffixBackendHealthCheckHeaders = "backend.healthcheck.headers"
SuffixBackendLoadBalancer = "backend.loadbalancer"
SuffixBackendLoadBalancerMethod = SuffixBackendLoadBalancer + ".method"
SuffixBackendLoadBalancerSticky = SuffixBackendLoadBalancer + ".sticky"
SuffixBackendLoadBalancerStickiness = SuffixBackendLoadBalancer + ".stickiness"
SuffixBackendLoadBalancerStickinessCookieName = SuffixBackendLoadBalancer + ".stickiness.cookieName"
SuffixBackendMaxConnAmount = "backend.maxconn.amount"
SuffixBackendMaxConnExtractorFunc = "backend.maxconn.extractorfunc"
SuffixBackendBuffering = "backend.buffering"
SuffixBackendResponseForwardingFlushInterval = "backend.responseForwarding.flushInterval"
SuffixBackendBufferingMaxRequestBodyBytes = SuffixBackendBuffering + ".maxRequestBodyBytes"
SuffixBackendBufferingMemRequestBodyBytes = SuffixBackendBuffering + ".memRequestBodyBytes"
SuffixBackendBufferingMaxResponseBodyBytes = SuffixBackendBuffering + ".maxResponseBodyBytes"
SuffixBackendBufferingMemResponseBodyBytes = SuffixBackendBuffering + ".memResponseBodyBytes"
SuffixBackendBufferingRetryExpression = SuffixBackendBuffering + ".retryExpression"
SuffixFrontend = "frontend"
SuffixFrontendAuth = SuffixFrontend + ".auth"
SuffixFrontendAuthBasic = SuffixFrontendAuth + ".basic"
SuffixFrontendAuthBasicRemoveHeader = SuffixFrontendAuthBasic + ".removeHeader"
SuffixFrontendAuthBasicUsers = SuffixFrontendAuthBasic + ".users"
SuffixFrontendAuthBasicUsersFile = SuffixFrontendAuthBasic + ".usersFile"
SuffixFrontendAuthDigest = SuffixFrontendAuth + ".digest"
SuffixFrontendAuthDigestRemoveHeader = SuffixFrontendAuthDigest + ".removeHeader"
SuffixFrontendAuthDigestUsers = SuffixFrontendAuthDigest + ".users"
SuffixFrontendAuthDigestUsersFile = SuffixFrontendAuthDigest + ".usersFile"
SuffixFrontendAuthForward = SuffixFrontendAuth + ".forward"
SuffixFrontendAuthForwardAddress = SuffixFrontendAuthForward + ".address"
SuffixFrontendAuthForwardAuthResponseHeaders = SuffixFrontendAuthForward + ".authResponseHeaders"
SuffixFrontendAuthForwardTLS = SuffixFrontendAuthForward + ".tls"
SuffixFrontendAuthForwardTLSCa = SuffixFrontendAuthForwardTLS + ".ca"
SuffixFrontendAuthForwardTLSCaOptional = SuffixFrontendAuthForwardTLS + ".caOptional"
SuffixFrontendAuthForwardTLSCert = SuffixFrontendAuthForwardTLS + ".cert"
SuffixFrontendAuthForwardTLSInsecureSkipVerify = SuffixFrontendAuthForwardTLS + ".insecureSkipVerify"
SuffixFrontendAuthForwardTLSKey = SuffixFrontendAuthForwardTLS + ".key"
SuffixFrontendAuthForwardTrustForwardHeader = SuffixFrontendAuthForward + ".trustForwardHeader"
SuffixFrontendAuthHeaderField = SuffixFrontendAuth + ".headerField"
SuffixFrontendEntryPoints = "frontend.entryPoints"
SuffixFrontendHeaders = "frontend.headers."
SuffixFrontendRequestHeaders = SuffixFrontendHeaders + "customRequestHeaders"
SuffixFrontendResponseHeaders = SuffixFrontendHeaders + "customResponseHeaders"
SuffixFrontendHeadersAllowedHosts = SuffixFrontendHeaders + "allowedHosts"
SuffixFrontendHeadersHostsProxyHeaders = SuffixFrontendHeaders + "hostsProxyHeaders"
SuffixFrontendHeadersSSLForceHost = SuffixFrontendHeaders + "SSLForceHost"
SuffixFrontendHeadersSSLRedirect = SuffixFrontendHeaders + "SSLRedirect"
SuffixFrontendHeadersSSLTemporaryRedirect = SuffixFrontendHeaders + "SSLTemporaryRedirect"
SuffixFrontendHeadersSSLHost = SuffixFrontendHeaders + "SSLHost"
SuffixFrontendHeadersSSLProxyHeaders = SuffixFrontendHeaders + "SSLProxyHeaders"
SuffixFrontendHeadersSTSSeconds = SuffixFrontendHeaders + "STSSeconds"
SuffixFrontendHeadersSTSIncludeSubdomains = SuffixFrontendHeaders + "STSIncludeSubdomains"
SuffixFrontendHeadersSTSPreload = SuffixFrontendHeaders + "STSPreload"
SuffixFrontendHeadersForceSTSHeader = SuffixFrontendHeaders + "forceSTSHeader"
SuffixFrontendHeadersFrameDeny = SuffixFrontendHeaders + "frameDeny"
SuffixFrontendHeadersCustomFrameOptionsValue = SuffixFrontendHeaders + "customFrameOptionsValue"
SuffixFrontendHeadersContentTypeNosniff = SuffixFrontendHeaders + "contentTypeNosniff"
SuffixFrontendHeadersBrowserXSSFilter = SuffixFrontendHeaders + "browserXSSFilter"
SuffixFrontendHeadersCustomBrowserXSSValue = SuffixFrontendHeaders + "customBrowserXSSValue"
SuffixFrontendHeadersContentSecurityPolicy = SuffixFrontendHeaders + "contentSecurityPolicy"
SuffixFrontendHeadersPublicKey = SuffixFrontendHeaders + "publicKey"
SuffixFrontendHeadersReferrerPolicy = SuffixFrontendHeaders + "referrerPolicy"
SuffixFrontendHeadersIsDevelopment = SuffixFrontendHeaders + "isDevelopment"
SuffixFrontendPassHostHeader = "frontend.passHostHeader"
SuffixFrontendPassTLSClientCert = "frontend.passTLSClientCert"
SuffixFrontendPassTLSClientCertPem = SuffixFrontendPassTLSClientCert + ".pem"
SuffixFrontendPassTLSClientCertInfos = SuffixFrontendPassTLSClientCert + ".infos"
SuffixFrontendPassTLSClientCertInfosIssuer = SuffixFrontendPassTLSClientCertInfos + ".issuer"
SuffixFrontendPassTLSClientCertInfosIssuerCommonName = SuffixFrontendPassTLSClientCertInfosIssuer + ".commonName"
SuffixFrontendPassTLSClientCertInfosIssuerCountry = SuffixFrontendPassTLSClientCertInfosIssuer + ".country"
SuffixFrontendPassTLSClientCertInfosIssuerDomainComponent = SuffixFrontendPassTLSClientCertInfosIssuer + ".domainComponent"
SuffixFrontendPassTLSClientCertInfosIssuerLocality = SuffixFrontendPassTLSClientCertInfosIssuer + ".locality"
SuffixFrontendPassTLSClientCertInfosIssuerOrganization = SuffixFrontendPassTLSClientCertInfosIssuer + ".organization"
SuffixFrontendPassTLSClientCertInfosIssuerProvince = SuffixFrontendPassTLSClientCertInfosIssuer + ".province"
SuffixFrontendPassTLSClientCertInfosIssuerSerialNumber = SuffixFrontendPassTLSClientCertInfosIssuer + ".serialNumber"
SuffixFrontendPassTLSClientCertInfosSubject = SuffixFrontendPassTLSClientCertInfos + ".subject"
SuffixFrontendPassTLSClientCertInfosNotAfter = SuffixFrontendPassTLSClientCertInfos + ".notAfter"
SuffixFrontendPassTLSClientCertInfosNotBefore = SuffixFrontendPassTLSClientCertInfos + ".notBefore"
SuffixFrontendPassTLSClientCertInfosSans = SuffixFrontendPassTLSClientCertInfos + ".sans"
SuffixFrontendPassTLSClientCertInfosSubjectCommonName = SuffixFrontendPassTLSClientCertInfosSubject + ".commonName"
SuffixFrontendPassTLSClientCertInfosSubjectCountry = SuffixFrontendPassTLSClientCertInfosSubject + ".country"
SuffixFrontendPassTLSClientCertInfosSubjectDomainComponent = SuffixFrontendPassTLSClientCertInfosSubject + ".domainComponent"
SuffixFrontendPassTLSClientCertInfosSubjectLocality = SuffixFrontendPassTLSClientCertInfosSubject + ".locality"
SuffixFrontendPassTLSClientCertInfosSubjectOrganization = SuffixFrontendPassTLSClientCertInfosSubject + ".organization"
SuffixFrontendPassTLSClientCertInfosSubjectProvince = SuffixFrontendPassTLSClientCertInfosSubject + ".province"
SuffixFrontendPassTLSClientCertInfosSubjectSerialNumber = SuffixFrontendPassTLSClientCertInfosSubject + ".serialNumber"
SuffixFrontendPassTLSCert = "frontend.passTLSCert" // Deprecated
SuffixFrontendPriority = "frontend.priority"
SuffixFrontendRateLimitExtractorFunc = "frontend.rateLimit.extractorFunc"
SuffixFrontendRedirectEntryPoint = "frontend.redirect.entryPoint"
SuffixFrontendRedirectRegex = "frontend.redirect.regex"
SuffixFrontendRedirectReplacement = "frontend.redirect.replacement"
SuffixFrontendRedirectPermanent = "frontend.redirect.permanent"
SuffixFrontendRule = "frontend.rule"
SuffixFrontendWhitelistSourceRange = "frontend.whitelistSourceRange" // Deprecated
SuffixFrontendWhiteList = "frontend.whiteList."
SuffixFrontendWhiteListSourceRange = SuffixFrontendWhiteList + "sourceRange"
SuffixFrontendWhiteListUseXForwardedFor = SuffixFrontendWhiteList + "useXForwardedFor"
TraefikDomain = Prefix + SuffixDomain
TraefikEnable = Prefix + SuffixEnable
TraefikPort = Prefix + SuffixPort
TraefikPortName = Prefix + SuffixPortName
TraefikPortIndex = Prefix + SuffixPortIndex
TraefikProtocol = Prefix + SuffixProtocol
TraefikTags = Prefix + SuffixTags
TraefikWeight = Prefix + SuffixWeight
TraefikBackend = Prefix + SuffixBackend
TraefikBackendID = Prefix + SuffixBackendID
TraefikBackendCircuitBreaker = Prefix + SuffixBackendCircuitBreaker
TraefikBackendCircuitBreakerExpression = Prefix + SuffixBackendCircuitBreakerExpression
TraefikBackendHealthCheckScheme = Prefix + SuffixBackendHealthCheckScheme
TraefikBackendHealthCheckPath = Prefix + SuffixBackendHealthCheckPath
TraefikBackendHealthCheckPort = Prefix + SuffixBackendHealthCheckPort
TraefikBackendHealthCheckInterval = Prefix + SuffixBackendHealthCheckInterval
TraefikBackendHealthCheckHostname = Prefix + SuffixBackendHealthCheckHostname
TraefikBackendHealthCheckHeaders = Prefix + SuffixBackendHealthCheckHeaders
TraefikBackendLoadBalancer = Prefix + SuffixBackendLoadBalancer
TraefikBackendLoadBalancerMethod = Prefix + SuffixBackendLoadBalancerMethod
TraefikBackendLoadBalancerSticky = Prefix + SuffixBackendLoadBalancerSticky
TraefikBackendLoadBalancerStickiness = Prefix + SuffixBackendLoadBalancerStickiness
TraefikBackendLoadBalancerStickinessCookieName = Prefix + SuffixBackendLoadBalancerStickinessCookieName
Prefix = "traefik."
SuffixBackend = "backend"
SuffixDomain = "domain"
SuffixEnable = "enable"
SuffixPort = "port"
SuffixPortName = "portName"
SuffixPortIndex = "portIndex"
SuffixProtocol = "protocol"
SuffixTags = "tags"
SuffixWeight = "weight"
SuffixBackendID = "backend.id"
SuffixBackendCircuitBreaker = "backend.circuitbreaker"
SuffixBackendCircuitBreakerExpression = "backend.circuitbreaker.expression"
SuffixBackendHealthCheckScheme = "backend.healthcheck.scheme"
SuffixBackendHealthCheckPath = "backend.healthcheck.path"
SuffixBackendHealthCheckPort = "backend.healthcheck.port"
SuffixBackendHealthCheckInterval = "backend.healthcheck.interval"
SuffixBackendHealthCheckHostname = "backend.healthcheck.hostname"
SuffixBackendHealthCheckHeaders = "backend.healthcheck.headers"
SuffixBackendLoadBalancer = "backend.loadbalancer"
SuffixBackendLoadBalancerMethod = SuffixBackendLoadBalancer + ".method"
SuffixBackendLoadBalancerSticky = SuffixBackendLoadBalancer + ".sticky"
SuffixBackendLoadBalancerStickiness = SuffixBackendLoadBalancer + ".stickiness"
SuffixBackendLoadBalancerStickinessCookieName = SuffixBackendLoadBalancer + ".stickiness.cookieName"
SuffixBackendLoadBalancerStickinessSecure = SuffixBackendLoadBalancer + ".stickiness.secure"
SuffixBackendLoadBalancerStickinessCHTTPOnly = SuffixBackendLoadBalancer + ".stickiness.httpOnly"
SuffixBackendLoadBalancerStickinessSameSite = SuffixBackendLoadBalancer + ".stickiness.sameSite"
SuffixBackendMaxConnAmount = "backend.maxconn.amount"
SuffixBackendMaxConnExtractorFunc = "backend.maxconn.extractorfunc"
SuffixBackendBuffering = "backend.buffering"
SuffixBackendResponseForwardingFlushInterval = "backend.responseForwarding.flushInterval"
SuffixBackendBufferingMaxRequestBodyBytes = SuffixBackendBuffering + ".maxRequestBodyBytes"
SuffixBackendBufferingMemRequestBodyBytes = SuffixBackendBuffering + ".memRequestBodyBytes"
SuffixBackendBufferingMaxResponseBodyBytes = SuffixBackendBuffering + ".maxResponseBodyBytes"
SuffixBackendBufferingMemResponseBodyBytes = SuffixBackendBuffering + ".memResponseBodyBytes"
SuffixBackendBufferingRetryExpression = SuffixBackendBuffering + ".retryExpression"
SuffixFrontend = "frontend"
SuffixFrontendAuth = SuffixFrontend + ".auth"
SuffixFrontendAuthBasic = SuffixFrontendAuth + ".basic"
SuffixFrontendAuthBasicRemoveHeader = SuffixFrontendAuthBasic + ".removeHeader"
SuffixFrontendAuthBasicUsers = SuffixFrontendAuthBasic + ".users"
SuffixFrontendAuthBasicUsersFile = SuffixFrontendAuthBasic + ".usersFile"
SuffixFrontendAuthDigest = SuffixFrontendAuth + ".digest"
SuffixFrontendAuthDigestRemoveHeader = SuffixFrontendAuthDigest + ".removeHeader"
SuffixFrontendAuthDigestUsers = SuffixFrontendAuthDigest + ".users"
SuffixFrontendAuthDigestUsersFile = SuffixFrontendAuthDigest + ".usersFile"
SuffixFrontendAuthForward = SuffixFrontendAuth + ".forward"
SuffixFrontendAuthForwardAddress = SuffixFrontendAuthForward + ".address"
SuffixFrontendAuthForwardAuthResponseHeaders = SuffixFrontendAuthForward + ".authResponseHeaders"
SuffixFrontendAuthForwardTLS = SuffixFrontendAuthForward + ".tls"
SuffixFrontendAuthForwardTLSCa = SuffixFrontendAuthForwardTLS + ".ca"
SuffixFrontendAuthForwardTLSCaOptional = SuffixFrontendAuthForwardTLS + ".caOptional"
SuffixFrontendAuthForwardTLSCert = SuffixFrontendAuthForwardTLS + ".cert"
SuffixFrontendAuthForwardTLSInsecureSkipVerify = SuffixFrontendAuthForwardTLS + ".insecureSkipVerify"
SuffixFrontendAuthForwardTLSKey = SuffixFrontendAuthForwardTLS + ".key"
SuffixFrontendAuthForwardTrustForwardHeader = SuffixFrontendAuthForward + ".trustForwardHeader"
SuffixFrontendAuthHeaderField = SuffixFrontendAuth + ".headerField"
SuffixFrontendEntryPoints = "frontend.entryPoints"
SuffixFrontendHeaders = "frontend.headers."
SuffixFrontendRequestHeaders = SuffixFrontendHeaders + "customRequestHeaders"
SuffixFrontendResponseHeaders = SuffixFrontendHeaders + "customResponseHeaders"
SuffixFrontendHeadersAllowedHosts = SuffixFrontendHeaders + "allowedHosts"
SuffixFrontendHeadersHostsProxyHeaders = SuffixFrontendHeaders + "hostsProxyHeaders"
SuffixFrontendHeadersSSLForceHost = SuffixFrontendHeaders + "SSLForceHost"
SuffixFrontendHeadersSSLRedirect = SuffixFrontendHeaders + "SSLRedirect"
SuffixFrontendHeadersSSLTemporaryRedirect = SuffixFrontendHeaders + "SSLTemporaryRedirect"
SuffixFrontendHeadersSSLHost = SuffixFrontendHeaders + "SSLHost"
SuffixFrontendHeadersSSLProxyHeaders = SuffixFrontendHeaders + "SSLProxyHeaders"
SuffixFrontendHeadersSTSSeconds = SuffixFrontendHeaders + "STSSeconds"
SuffixFrontendHeadersSTSIncludeSubdomains = SuffixFrontendHeaders + "STSIncludeSubdomains"
SuffixFrontendHeadersSTSPreload = SuffixFrontendHeaders + "STSPreload"
SuffixFrontendHeadersForceSTSHeader = SuffixFrontendHeaders + "forceSTSHeader"
SuffixFrontendHeadersFrameDeny = SuffixFrontendHeaders + "frameDeny"
SuffixFrontendHeadersCustomFrameOptionsValue = SuffixFrontendHeaders + "customFrameOptionsValue"
SuffixFrontendHeadersContentTypeNosniff = SuffixFrontendHeaders + "contentTypeNosniff"
SuffixFrontendHeadersBrowserXSSFilter = SuffixFrontendHeaders + "browserXSSFilter"
SuffixFrontendHeadersCustomBrowserXSSValue = SuffixFrontendHeaders + "customBrowserXSSValue"
SuffixFrontendHeadersContentSecurityPolicy = SuffixFrontendHeaders + "contentSecurityPolicy"
SuffixFrontendHeadersPublicKey = SuffixFrontendHeaders + "publicKey"
SuffixFrontendHeadersReferrerPolicy = SuffixFrontendHeaders + "referrerPolicy"
SuffixFrontendHeadersIsDevelopment = SuffixFrontendHeaders + "isDevelopment"
SuffixFrontendPassHostHeader = "frontend.passHostHeader"
SuffixFrontendPassTLSClientCert = "frontend.passTLSClientCert"
SuffixFrontendPassTLSClientCertPem = SuffixFrontendPassTLSClientCert + ".pem"
SuffixFrontendPassTLSClientCertInfos = SuffixFrontendPassTLSClientCert + ".infos"
SuffixFrontendPassTLSClientCertInfosIssuer = SuffixFrontendPassTLSClientCertInfos + ".issuer"
SuffixFrontendPassTLSClientCertInfosIssuerCommonName = SuffixFrontendPassTLSClientCertInfosIssuer + ".commonName"
SuffixFrontendPassTLSClientCertInfosIssuerCountry = SuffixFrontendPassTLSClientCertInfosIssuer + ".country"
SuffixFrontendPassTLSClientCertInfosIssuerDomainComponent = SuffixFrontendPassTLSClientCertInfosIssuer + ".domainComponent"
SuffixFrontendPassTLSClientCertInfosIssuerLocality = SuffixFrontendPassTLSClientCertInfosIssuer + ".locality"
SuffixFrontendPassTLSClientCertInfosIssuerOrganization = SuffixFrontendPassTLSClientCertInfosIssuer + ".organization"
SuffixFrontendPassTLSClientCertInfosIssuerProvince = SuffixFrontendPassTLSClientCertInfosIssuer + ".province"
SuffixFrontendPassTLSClientCertInfosIssuerSerialNumber = SuffixFrontendPassTLSClientCertInfosIssuer + ".serialNumber"
SuffixFrontendPassTLSClientCertInfosSubject = SuffixFrontendPassTLSClientCertInfos + ".subject"
SuffixFrontendPassTLSClientCertInfosNotAfter = SuffixFrontendPassTLSClientCertInfos + ".notAfter"
SuffixFrontendPassTLSClientCertInfosNotBefore = SuffixFrontendPassTLSClientCertInfos + ".notBefore"
SuffixFrontendPassTLSClientCertInfosSans = SuffixFrontendPassTLSClientCertInfos + ".sans"
SuffixFrontendPassTLSClientCertInfosSubjectCommonName = SuffixFrontendPassTLSClientCertInfosSubject + ".commonName"
SuffixFrontendPassTLSClientCertInfosSubjectCountry = SuffixFrontendPassTLSClientCertInfosSubject + ".country"
SuffixFrontendPassTLSClientCertInfosSubjectDomainComponent = SuffixFrontendPassTLSClientCertInfosSubject + ".domainComponent"
SuffixFrontendPassTLSClientCertInfosSubjectLocality = SuffixFrontendPassTLSClientCertInfosSubject + ".locality"
SuffixFrontendPassTLSClientCertInfosSubjectOrganization = SuffixFrontendPassTLSClientCertInfosSubject + ".organization"
SuffixFrontendPassTLSClientCertInfosSubjectProvince = SuffixFrontendPassTLSClientCertInfosSubject + ".province"
SuffixFrontendPassTLSClientCertInfosSubjectSerialNumber = SuffixFrontendPassTLSClientCertInfosSubject + ".serialNumber"
SuffixFrontendPassTLSCert = "frontend.passTLSCert" // Deprecated
SuffixFrontendPriority = "frontend.priority"
SuffixFrontendRateLimitExtractorFunc = "frontend.rateLimit.extractorFunc"
SuffixFrontendRedirectEntryPoint = "frontend.redirect.entryPoint"
SuffixFrontendRedirectRegex = "frontend.redirect.regex"
SuffixFrontendRedirectReplacement = "frontend.redirect.replacement"
SuffixFrontendRedirectPermanent = "frontend.redirect.permanent"
SuffixFrontendRule = "frontend.rule"
SuffixFrontendWhitelistSourceRange = "frontend.whitelistSourceRange" // Deprecated
SuffixFrontendWhiteList = "frontend.whiteList."
SuffixFrontendWhiteListSourceRange = SuffixFrontendWhiteList + "sourceRange"
SuffixFrontendWhiteListUseXForwardedFor = SuffixFrontendWhiteList + "useXForwardedFor"
TraefikDomain = Prefix + SuffixDomain
TraefikEnable = Prefix + SuffixEnable
TraefikPort = Prefix + SuffixPort
TraefikPortName = Prefix + SuffixPortName
TraefikPortIndex = Prefix + SuffixPortIndex
TraefikProtocol = Prefix + SuffixProtocol
TraefikTags = Prefix + SuffixTags
TraefikWeight = Prefix + SuffixWeight
TraefikBackend = Prefix + SuffixBackend
TraefikBackendID = Prefix + SuffixBackendID
TraefikBackendCircuitBreaker = Prefix + SuffixBackendCircuitBreaker
TraefikBackendCircuitBreakerExpression = Prefix + SuffixBackendCircuitBreakerExpression
TraefikBackendHealthCheckScheme = Prefix + SuffixBackendHealthCheckScheme
TraefikBackendHealthCheckPath = Prefix + SuffixBackendHealthCheckPath
TraefikBackendHealthCheckPort = Prefix + SuffixBackendHealthCheckPort
TraefikBackendHealthCheckInterval = Prefix + SuffixBackendHealthCheckInterval
TraefikBackendHealthCheckHostname = Prefix + SuffixBackendHealthCheckHostname
TraefikBackendHealthCheckHeaders = Prefix + SuffixBackendHealthCheckHeaders
TraefikBackendLoadBalancer = Prefix + SuffixBackendLoadBalancer
TraefikBackendLoadBalancerMethod = Prefix + SuffixBackendLoadBalancerMethod
TraefikBackendLoadBalancerSticky = Prefix + SuffixBackendLoadBalancerSticky
TraefikBackendLoadBalancerStickiness = Prefix + SuffixBackendLoadBalancerStickiness
TraefikBackendLoadBalancerStickinessCookieName = Prefix + SuffixBackendLoadBalancerStickinessCookieName
// FIXME
TraefikBackendLoadBalancerStickinessSecure = Prefix + SuffixBackendLoadBalancerStickinessSecure
TraefikBackendLoadBalancerStickinessHTTPOnly = Prefix + SuffixBackendLoadBalancerStickinessCHTTPOnly
TraefikBackendLoadBalancerStickinessSameSite = Prefix + SuffixBackendLoadBalancerStickinessSameSite
TraefikBackendMaxConnAmount = Prefix + SuffixBackendMaxConnAmount
TraefikBackendMaxConnExtractorFunc = Prefix + SuffixBackendMaxConnExtractorFunc
TraefikBackendBuffering = Prefix + SuffixBackendBuffering

View File

@@ -426,8 +426,12 @@ func GetLoadBalancer(labels map[string]string) *types.LoadBalancer {
}
if GetBoolValue(labels, TraefikBackendLoadBalancerStickiness, false) {
cookieName := GetStringValue(labels, TraefikBackendLoadBalancerStickinessCookieName, DefaultBackendLoadbalancerStickinessCookieName)
lb.Stickiness = &types.Stickiness{CookieName: cookieName}
lb.Stickiness = &types.Stickiness{
CookieName: GetStringValue(labels, TraefikBackendLoadBalancerStickinessCookieName, DefaultBackendLoadbalancerStickinessCookieName),
Secure: GetBoolValue(labels, TraefikBackendLoadBalancerStickinessSecure, DefaultBackendLoadbalancerStickinessSecure),
HTTPOnly: GetBoolValue(labels, TraefikBackendLoadBalancerStickinessHTTPOnly, DefaultBackendLoadbalancerStickinessHTTPOnly),
SameSite: GetStringValue(labels, TraefikBackendLoadBalancerStickinessSameSite, DefaultBackendLoadbalancerStickinessSameSite),
}
}
return lb

View File

@@ -257,12 +257,18 @@ func TestGetLoadBalancer(t *testing.T) {
TraefikBackendLoadBalancerSticky: "true",
TraefikBackendLoadBalancerStickiness: "true",
TraefikBackendLoadBalancerStickinessCookieName: "foo",
TraefikBackendLoadBalancerStickinessSecure: "true",
TraefikBackendLoadBalancerStickinessHTTPOnly: "true",
TraefikBackendLoadBalancerStickinessSameSite: "none",
},
expected: &types.LoadBalancer{
Method: "drr",
Sticky: true,
Stickiness: &types.Stickiness{
CookieName: "foo",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
},
},

View File

@@ -101,6 +101,9 @@ func TestBuildConfigurationSegments(t *testing.T) {
withLabel(label.TraefikBackendLoadBalancerSticky, "true"),
withLabel(label.TraefikBackendLoadBalancerStickiness, "true"),
withLabel(label.TraefikBackendLoadBalancerStickinessCookieName, "chocolate"),
withLabel(label.TraefikBackendLoadBalancerStickinessSecure, "true"),
withLabel(label.TraefikBackendLoadBalancerStickinessHTTPOnly, "true"),
withLabel(label.TraefikBackendLoadBalancerStickinessSameSite, "none"),
withLabel(label.TraefikBackendMaxConnAmount, "666"),
withLabel(label.TraefikBackendMaxConnExtractorFunc, "client.ip"),
withLabel(label.TraefikBackendBufferingMaxResponseBodyBytes, "10485760"),
@@ -347,6 +350,9 @@ func TestBuildConfigurationSegments(t *testing.T) {
Sticky: true,
Stickiness: &types.Stickiness{
CookieName: "chocolate",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
},
MaxConn: &types.MaxConn{

View File

@@ -369,6 +369,9 @@ func TestBuildConfiguration(t *testing.T) {
withLabel(label.TraefikBackendLoadBalancerSticky, "true"),
withLabel(label.TraefikBackendLoadBalancerStickiness, "true"),
withLabel(label.TraefikBackendLoadBalancerStickinessCookieName, "chocolate"),
withLabel(label.TraefikBackendLoadBalancerStickinessSecure, "true"),
withLabel(label.TraefikBackendLoadBalancerStickinessHTTPOnly, "true"),
withLabel(label.TraefikBackendLoadBalancerStickinessSameSite, "none"),
withLabel(label.TraefikBackendMaxConnAmount, "666"),
withLabel(label.TraefikBackendMaxConnExtractorFunc, "client.ip"),
withLabel(label.TraefikBackendBufferingMaxResponseBodyBytes, "10485760"),
@@ -613,6 +616,9 @@ func TestBuildConfiguration(t *testing.T) {
Sticky: true,
Stickiness: &types.Stickiness{
CookieName: "chocolate",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
},
MaxConn: &types.MaxConn{

View File

@@ -119,6 +119,9 @@ func TestBuildConfigurationSegments(t *testing.T) {
withLabel(label.TraefikBackendLoadBalancerSticky, "true"),
withLabel(label.TraefikBackendLoadBalancerStickiness, "true"),
withLabel(label.TraefikBackendLoadBalancerStickinessCookieName, "chocolate"),
withLabel(label.TraefikBackendLoadBalancerStickinessSecure, "true"),
withLabel(label.TraefikBackendLoadBalancerStickinessHTTPOnly, "true"),
withLabel(label.TraefikBackendLoadBalancerStickinessSameSite, "none"),
withLabel(label.TraefikBackendMaxConnAmount, "666"),
withLabel(label.TraefikBackendMaxConnExtractorFunc, "client.ip"),
withLabel(label.TraefikBackendBufferingMaxResponseBodyBytes, "10485760"),
@@ -368,6 +371,9 @@ func TestBuildConfigurationSegments(t *testing.T) {
Sticky: true,
Stickiness: &types.Stickiness{
CookieName: "chocolate",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
},
MaxConn: &types.MaxConn{

View File

@@ -325,6 +325,9 @@ func TestBuildConfiguration(t *testing.T) {
withLabel(label.TraefikBackendLoadBalancerMethod, "drr"),
withLabel(label.TraefikBackendLoadBalancerStickiness, "true"),
withLabel(label.TraefikBackendLoadBalancerStickinessCookieName, "chocolate"),
withLabel(label.TraefikBackendLoadBalancerStickinessSecure, "true"),
withLabel(label.TraefikBackendLoadBalancerStickinessHTTPOnly, "true"),
withLabel(label.TraefikBackendLoadBalancerStickinessSameSite, "none"),
withLabel(label.TraefikBackendMaxConnAmount, "666"),
withLabel(label.TraefikBackendMaxConnExtractorFunc, "client.ip"),
withLabel(label.TraefikBackendBufferingMaxResponseBodyBytes, "10485760"),
@@ -572,6 +575,9 @@ func TestBuildConfiguration(t *testing.T) {
Method: "drr",
Stickiness: &types.Stickiness{
CookieName: "chocolate",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
},
MaxConn: &types.MaxConn{

View File

@@ -52,6 +52,9 @@ func TestProviderBuildConfiguration(t *testing.T) {
label.TraefikBackendLoadBalancerSticky: "true",
label.TraefikBackendLoadBalancerStickiness: "true",
label.TraefikBackendLoadBalancerStickinessCookieName: "chocolate",
label.TraefikBackendLoadBalancerStickinessSecure: "true",
label.TraefikBackendLoadBalancerStickinessHTTPOnly: "true",
label.TraefikBackendLoadBalancerStickinessSameSite: "none",
label.TraefikBackendMaxConnAmount: "666",
label.TraefikBackendMaxConnExtractorFunc: "client.ip",
label.TraefikBackendBufferingMaxResponseBodyBytes: "10485760",
@@ -304,6 +307,9 @@ func TestProviderBuildConfiguration(t *testing.T) {
Sticky: true,
Stickiness: &types.Stickiness{
CookieName: "chocolate",
Secure: true,
HTTPOnly: true,
SameSite: "none",
},
},
MaxConn: &types.MaxConn{

View File

@@ -218,7 +218,10 @@ func NewServer(globalConfiguration configuration.GlobalConfiguration, provider p
log.Errorf("failed to create HTTP transport: %v", err)
}
server.defaultForwardingRoundTripper = transport
server.defaultForwardingRoundTripper, err = newSmartRoundTripper(transport)
if err != nil {
log.Errorf("Failed to create HTTP transport: %v", err)
}
server.tracingMiddleware = globalConfiguration.Tracing
if server.tracingMiddleware != nil && server.tracingMiddleware.Backend != "" {
@@ -498,10 +501,10 @@ func (s *Server) createTLSConfig(entryPointName string, tlsOption *traefiktls.TL
}
// workaround for users who used GODEBUG to activate TLS1.3
config.MaxVersion = tls.VersionTLS12
if strings.Contains(os.Getenv("GODEBUG"), "tls13=1") {
config.MaxVersion = tls.VersionTLS13
}
config.MaxVersion = tls.VersionTLS12
// Set the minimum TLS version if set in the config TOML
if minConst, exists := traefiktls.MinVersion[s.entryPoints[entryPointName].Configuration.TLS.MinVersion]; exists {

View File

@@ -237,11 +237,17 @@ func (s *Server) buildForwarder(entryPointName string, entryPoint *configuration
}
}
var tlsConfig *tls.Config
if smartRt, ok := roundTripper.(*smartRoundTripper); ok {
tlsConfig = smartRt.GetTLSClientConfig()
}
var fwd http.Handler
fwd, err = forward.New(
forward.Stream(true),
forward.PassHostHeader(frontend.PassHostHeader),
forward.RoundTripper(roundTripper),
forward.WebsocketTLSClientConfig(tlsConfig),
forward.Rewriter(rewriter),
forward.ResponseModifier(responseModifier),
forward.BufferPool(s.bufferPool),
@@ -303,7 +309,6 @@ func buildServerRoute(serverEntryPoint *serverEntryPoint, frontendName string, f
func (s *Server) preLoadConfiguration(configMsg types.ConfigMessage) {
providersThrottleDuration := time.Duration(s.globalConfiguration.ProvidersThrottleDuration)
s.defaultConfigurationValues(configMsg.Configuration)
currentConfigurations := s.currentConfigurations.Get().(types.Configurations)
if log.GetLevel() == logrus.DebugLevel {
jsonConf, _ := json.Marshal(configMsg.Configuration)
@@ -315,11 +320,6 @@ func (s *Server) preLoadConfiguration(configMsg types.ConfigMessage) {
return
}
if reflect.DeepEqual(currentConfigurations[configMsg.ProviderName], configMsg.Configuration) {
log.Infof("Skipping same configuration for provider %s", configMsg.ProviderName)
return
}
providerConfigUpdateCh, ok := s.providerConfigUpdateMap[configMsg.ProviderName]
if !ok {
providerConfigUpdateCh = make(chan types.ConfigMessage)
@@ -455,11 +455,17 @@ func (s *Server) throttleProviderConfigReload(throttle time.Duration, publish ch
}
})
var previousConfig types.ConfigMessage
for {
select {
case <-stop:
return
case nextConfig := <-in:
if reflect.DeepEqual(previousConfig, nextConfig) {
log.Infof("Skipping same configuration for provider %s", nextConfig.ProviderName)
continue
}
previousConfig = nextConfig
ring.In() <- nextConfig
}
}

View File

@@ -304,9 +304,11 @@ func TestThrottleProviderConfigReload(t *testing.T) {
}
}()
// publish 5 new configs, one new config each 10 milliseconds
// publish 5 new and different configs, one new config each 10 milliseconds
for i := 0; i < 5; i++ {
providerConfig <- types.ConfigMessage{}
providerConfig <- types.ConfigMessage{
ProviderName: fmt.Sprintf("test-%d", i),
}
time.Sleep(10 * time.Millisecond)
}

View File

@@ -123,13 +123,6 @@ func (s *Server) buildLoadBalancer(frontendName string, backendName string, back
rr, _ = roundrobin.New(fwd)
}
var stickySession *roundrobin.StickySession
var cookieName string
if stickiness := backend.LoadBalancer.Stickiness; stickiness != nil {
cookieName = cookie.GetName(stickiness.CookieName, backendName)
stickySession = roundrobin.NewStickySession(cookieName)
}
lbMethod, err := types.NewLoadBalancerMethod(backend.LoadBalancer)
if err != nil {
return nil, fmt.Errorf("error loading load balancer method '%+v' for frontend %s: %v", backend.LoadBalancer, frontendName, err)
@@ -141,8 +134,10 @@ func (s *Server) buildLoadBalancer(frontendName string, backendName string, back
case types.Drr:
log.Debug("Creating load-balancer drr")
if stickySession != nil {
log.Debugf("Sticky session with cookie %v", cookieName)
if backend.LoadBalancer.Stickiness != nil {
cookieName := cookie.GetName(backend.LoadBalancer.Stickiness.CookieName, backendName)
stickySession := newStickySession(cookieName, backend.LoadBalancer.Stickiness)
lb, err = roundrobin.NewRebalancer(rr, roundrobin.RebalancerStickySession(stickySession))
if err != nil {
@@ -157,16 +152,19 @@ func (s *Server) buildLoadBalancer(frontendName string, backendName string, back
case types.Wrr:
log.Debug("Creating load-balancer wrr")
if stickySession != nil {
log.Debugf("Sticky session with cookie %v", cookieName)
if backend.LoadBalancer.Stickiness != nil {
cookieName := cookie.GetName(backend.LoadBalancer.Stickiness.CookieName, backendName)
stickySession := newStickySession(cookieName, backend.LoadBalancer.Stickiness)
option := roundrobin.EnableStickySession(stickySession)
if s.accessLoggerMiddleware != nil {
lb, err = roundrobin.New(saveFrontend, roundrobin.EnableStickySession(stickySession))
lb, err = roundrobin.New(saveFrontend, option)
if err != nil {
return nil, err
}
} else {
lb, err = roundrobin.New(fwd, roundrobin.EnableStickySession(stickySession))
lb, err = roundrobin.New(fwd, option)
if err != nil {
return nil, err
}
@@ -185,6 +183,30 @@ func (s *Server) buildLoadBalancer(frontendName string, backendName string, back
return lb, nil
}
func newStickySession(cookieName string, stickiness *types.Stickiness) *roundrobin.StickySession {
log.Debugf("Sticky session with cookie %v", cookieName)
opts := roundrobin.CookieOptions{
HTTPOnly: stickiness.HTTPOnly,
Secure: stickiness.Secure,
SameSite: convertSameSite(stickiness.SameSite),
}
return roundrobin.NewStickySessionWithOptions(cookieName, opts)
}
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
}
}
func (s *Server) configureLBServers(lb healthcheck.BalancerHandler, backend *types.Backend, backendName string) error {
for name, srv := range backend.Servers {
u, err := url.Parse(srv.URL)
@@ -206,23 +228,29 @@ func (s *Server) configureLBServers(lb healthcheck.BalancerHandler, backend *typ
// getRoundTripper will either use server.defaultForwardingRoundTripper or create a new one
// given a custom TLS configuration is passed and the passTLSCert option is set to true.
func (s *Server) getRoundTripper(entryPointName string, passTLSCert bool, tls *traefiktls.TLS) (http.RoundTripper, error) {
if passTLSCert {
tlsConfig, err := createClientTLSConfig(entryPointName, tls)
if err != nil {
return nil, fmt.Errorf("failed to create TLSClientConfig: %v", err)
}
tlsConfig.InsecureSkipVerify = s.globalConfiguration.InsecureSkipVerify
transport, err := createHTTPTransport(s.globalConfiguration)
if err != nil {
return nil, fmt.Errorf("failed to create HTTP transport: %v", err)
}
transport.TLSClientConfig = tlsConfig
return transport, nil
if !passTLSCert {
return s.defaultForwardingRoundTripper, nil
}
return s.defaultForwardingRoundTripper, nil
tlsConfig, err := createClientTLSConfig(entryPointName, tls)
if err != nil {
return nil, fmt.Errorf("failed to create TLSClientConfig: %v", err)
}
tlsConfig.InsecureSkipVerify = s.globalConfiguration.InsecureSkipVerify
transport, err := createHTTPTransport(s.globalConfiguration)
if err != nil {
return nil, fmt.Errorf("failed to create HTTP transport: %v", err)
}
transport.TLSClientConfig = tlsConfig
smartTransport, err := newSmartRoundTripper(transport)
if err != nil {
return nil, err
}
return smartTransport, nil
}
// createHTTPTransport creates an http.Transport configured with the GlobalConfiguration settings.
@@ -263,25 +291,21 @@ func createHTTPTransport(globalConfiguration configuration.GlobalConfiguration)
transport.ResponseHeaderTimeout = time.Duration(globalConfiguration.ForwardingTimeouts.ResponseHeaderTimeout)
}
if globalConfiguration.InsecureSkipVerify {
transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
}
if len(globalConfiguration.RootCAs) > 0 {
if globalConfiguration.InsecureSkipVerify || len(globalConfiguration.RootCAs) > 0 {
transport.TLSClientConfig = &tls.Config{
RootCAs: createRootCACertPool(globalConfiguration.RootCAs),
InsecureSkipVerify: globalConfiguration.InsecureSkipVerify,
RootCAs: createRootCACertPool(globalConfiguration.RootCAs),
}
}
err := http2.ConfigureTransport(transport)
if err != nil {
return nil, err
}
return transport, nil
}
func createRootCACertPool(rootCAs traefiktls.FilesOrContents) *x509.CertPool {
if len(rootCAs) == 0 {
return nil
}
roots := x509.NewCertPool()
for _, cert := range rootCAs {

View File

@@ -0,0 +1,43 @@
package server
import (
"crypto/tls"
"net/http"
"golang.org/x/net/http/httpguts"
"golang.org/x/net/http2"
)
func newSmartRoundTripper(transport *http.Transport) (http.RoundTripper, error) {
transportHTTP1 := transport.Clone()
err := http2.ConfigureTransport(transport)
if err != nil {
return nil, err
}
return &smartRoundTripper{
http2: transport,
http: transportHTTP1,
}, nil
}
// smartRoundTripper implements RoundTrip while making sure that HTTP/2 is not used
// with protocols that start with a Connection Upgrade, such as SPDY or Websocket.
type smartRoundTripper struct {
http2 *http.Transport
http *http.Transport
}
func (m *smartRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
// If we have a connection upgrade, we don't use HTTP2
if httpguts.HeaderValuesContainsToken(req.Header["Connection"], "Upgrade") {
return m.http.RoundTrip(req)
}
return m.http2.RoundTrip(req)
}
func (m *smartRoundTripper) GetTLSClientConfig() *tls.Config {
return m.http2.TLSClientConfig
}

View File

@@ -24,6 +24,9 @@
{{if $loadBalancer.Stickiness }}
[backends."backend-{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}

View File

@@ -23,6 +23,9 @@
{{if $loadBalancer.Stickiness }}
[backends."backend-{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}

View File

@@ -22,6 +22,9 @@
{{if $loadBalancer.Stickiness }}
[backends."backend-{{ $serviceName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}

View File

@@ -19,6 +19,9 @@
{{if $backend.LoadBalancer.Stickiness }}
[backends."{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $backend.LoadBalancer.Stickiness.CookieName }}"
secure = {{ $backend.LoadBalancer.Stickiness.Secure }}
httpOnly = {{ $backend.LoadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $backend.LoadBalancer.Stickiness.SameSite }}"
{{end}}
{{if $backend.MaxConn }}

View File

@@ -22,6 +22,9 @@
{{if $loadBalancer.Stickiness }}
[backends."{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}

View File

@@ -25,6 +25,9 @@
{{if $loadBalancer.Stickiness }}
[backends."{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}

View File

@@ -25,6 +25,9 @@
{{if $loadBalancer.Stickiness }}
[backends."backend-{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}

View File

@@ -24,6 +24,9 @@
{{if $loadBalancer.Stickiness }}
[backends."backend-{{ $backendName }}".loadBalancer.stickiness]
cookieName = "{{ $loadBalancer.Stickiness.CookieName }}"
secure = {{ $loadBalancer.Stickiness.Secure }}
httpOnly = {{ $loadBalancer.Stickiness.HTTPOnly }}
sameSite = "{{ $loadBalancer.Stickiness.SameSite }}"
{{end}}
{{end}}

View File

@@ -52,6 +52,9 @@ type LoadBalancer struct {
// Stickiness holds sticky session configuration.
type Stickiness struct {
CookieName string `json:"cookieName,omitempty"`
Secure bool `json:"secure,omitempty"`
HTTPOnly bool `json:"httpOnly,omitempty"`
SameSite string `json:"sameSite,omitempty"`
}
// CircuitBreaker holds circuit breaker configuration.

View File

@@ -3,11 +3,26 @@ package roundrobin
import (
"net/http"
"net/url"
"time"
)
// CookieOptions has all the options one would like to set on the affinity cookie
type CookieOptions struct {
HTTPOnly bool
Secure bool
Path string
Domain string
Expires time.Time
MaxAge int
SameSite http.SameSite
}
// StickySession is a mixin for load balancers that implements layer 7 (http cookie) session affinity
type StickySession struct {
cookieName string
options CookieOptions
}
// NewStickySession creates a new StickySession
@@ -15,6 +30,12 @@ func NewStickySession(cookieName string) *StickySession {
return &StickySession{cookieName: cookieName}
}
// NewStickySessionWithOptions creates a new StickySession whilst allowing for options to
// shape its affinity cookie such as "httpOnly" or "secure"
func NewStickySessionWithOptions(cookieName string, options CookieOptions) *StickySession {
return &StickySession{cookieName: cookieName, options: options}
}
// GetBackend returns the backend URL stored in the sticky cookie, iff the backend is still in the valid list of servers.
func (s *StickySession) GetBackend(req *http.Request, servers []*url.URL) (*url.URL, bool, error) {
cookie, err := req.Cookie(s.cookieName)
@@ -39,7 +60,24 @@ func (s *StickySession) GetBackend(req *http.Request, servers []*url.URL) (*url.
// StickBackend creates and sets the cookie
func (s *StickySession) StickBackend(backend *url.URL, w *http.ResponseWriter) {
cookie := &http.Cookie{Name: s.cookieName, Value: backend.String(), Path: "/"}
opt := s.options
cp := "/"
if opt.Path != "" {
cp = opt.Path
}
cookie := &http.Cookie{
Name: s.cookieName,
Value: backend.String(),
Path: cp,
Domain: opt.Domain,
Expires: opt.Expires,
MaxAge: opt.MaxAge,
Secure: opt.Secure,
HttpOnly: opt.HTTPOnly,
SameSite: opt.SameSite,
}
http.SetCookie(*w, cookie)
}