From efc6560d8370a921ee0bc423668b63d2a984d608 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Doumenjou Date: Wed, 29 Aug 2018 11:36:03 +0200 Subject: [PATCH] Pass the TLS Cert infos in headers --- anonymize/anonymize_config_test.go | 6 +- autogen/gentemplates/gen.go | 164 +++- cmd/bug/bug_test.go | 2 +- cmd/traefik/traefik.go | 2 +- configuration/configuration.go | 2 +- configuration/entrypoints.go | 3 +- configuration/entrypoints_test.go | 4 +- docs/basics.md | 5 +- docs/configuration/backends/consulcatalog.md | 122 +-- docs/configuration/backends/docker.md | 222 ++--- docs/configuration/backends/ecs.md | 222 ++--- docs/configuration/backends/file.md | 18 +- docs/configuration/backends/marathon.md | 226 ++--- docs/configuration/backends/mesos.md | 228 ++--- docs/configuration/backends/rancher.md | 218 ++--- docs/user-guide/examples.md | 1 - .../fixtures/tlsclientheaders/root.pem | 21 + .../fixtures/tlsclientheaders/server.key | 27 + .../fixtures/tlsclientheaders/server.pem | 19 + .../fixtures/tlsclientheaders/simple.toml | 24 + integration/integration_test.go | 1 + .../resources/compose/tlsclientheaders.yml | 6 + integration/tls_client_headers_test.go | 71 ++ middlewares/tlsClientHeaders.go | 251 ++++++ middlewares/tlsClientHeaders_test.go | 799 ++++++++++++++++++ provider/consulcatalog/config.go | 1 + provider/consulcatalog/config_test.go | 103 +-- provider/docker/config.go | 27 +- .../docker/config_container_docker_test.go | 90 ++ .../docker/config_container_swarm_test.go | 66 ++ provider/docker/config_segment_test.go | 92 ++ provider/ecs/config.go | 29 +- provider/ecs/config_segment_test.go | 27 + provider/ecs/config_test.go | 27 + provider/kv/keynames.go | 29 +- provider/kv/kv_config.go | 60 +- provider/kv/kv_config_test.go | 28 + provider/label/names.go | 392 +++++---- provider/label/partial.go | 33 + provider/label/partial_test.go | 175 ++++ provider/marathon/config.go | 1 + provider/marathon/config_test.go | 55 +- provider/mesos/config.go | 1 + provider/mesos/config_test.go | 54 ++ provider/rancher/config.go | 27 +- provider/rancher/config_test.go | 54 ++ server/server.go | 3 +- server/server_loadbalancer.go | 5 +- server/server_middlewares.go | 9 + templates/consul_catalog.tmpl | 24 +- templates/docker.tmpl | 23 + templates/ecs.tmpl | 23 + templates/kv.tmpl | 23 + templates/marathon.tmpl | 25 +- templates/mesos.tmpl | 23 + templates/rancher.tmpl | 23 + tls/tls.go | 36 +- types/types.go | 27 +- 58 files changed, 3352 insertions(+), 927 deletions(-) create mode 100644 integration/fixtures/tlsclientheaders/root.pem create mode 100644 integration/fixtures/tlsclientheaders/server.key create mode 100644 integration/fixtures/tlsclientheaders/server.pem create mode 100644 integration/fixtures/tlsclientheaders/simple.toml create mode 100644 integration/resources/compose/tlsclientheaders.yml create mode 100644 integration/tls_client_headers_test.go create mode 100644 middlewares/tlsClientHeaders.go create mode 100644 middlewares/tlsClientHeaders_test.go diff --git a/anonymize/anonymize_config_test.go b/anonymize/anonymize_config_test.go index adba7cead..bb5975e4e 100644 --- a/anonymize/anonymize_config_test.go +++ b/anonymize/anonymize_config_test.go @@ -54,7 +54,7 @@ func TestDo_globalConfiguration(t *testing.T) { {CertFile: "CertFile 2", KeyFile: "KeyFile 2"}, }, ClientCA: traefiktls.ClientCA{ - Files: []string{"foo ClientCAFiles 1", "foo ClientCAFiles 2", "foo ClientCAFiles 3"}, + Files: traefiktls.FilesOrContents{"foo ClientCAFiles 1", "foo ClientCAFiles 2", "foo ClientCAFiles 3"}, Optional: false, }, }, @@ -99,7 +99,7 @@ func TestDo_globalConfiguration(t *testing.T) { {CertFile: "CertFile 2", KeyFile: "KeyFile 2"}, }, ClientCA: traefiktls.ClientCA{ - Files: []string{"fii ClientCAFiles 1", "fii ClientCAFiles 2", "fii ClientCAFiles 3"}, + Files: traefiktls.FilesOrContents{"fii ClientCAFiles 1", "fii ClientCAFiles 2", "fii ClientCAFiles 3"}, Optional: false, }, }, @@ -181,7 +181,7 @@ func TestDo_globalConfiguration(t *testing.T) { config.MaxIdleConnsPerHost = 666 config.IdleTimeout = flaeg.Duration(666 * time.Second) config.InsecureSkipVerify = true - config.RootCAs = traefiktls.RootCAs{"RootCAs 1", "RootCAs 2", "RootCAs 3"} + config.RootCAs = traefiktls.FilesOrContents{"RootCAs 1", "RootCAs 2", "RootCAs 3"} config.Retry = &configuration.Retry{ Attempts: 666, } diff --git a/autogen/gentemplates/gen.go b/autogen/gentemplates/gen.go index b6abce863..5fd14d24d 100644 --- a/autogen/gentemplates/gen.go +++ b/autogen/gentemplates/gen.go @@ -209,8 +209,30 @@ var _templatesConsul_catalogTmpl = []byte(`[backends] "{{.}}", {{end}}] - {{ $auth := getAuth $service.TraefikLabels }} + {{ $tlsClientCert := getPassTLSClientCert $service.TraefikLabels }} + {{if $tlsClientCert }} + [frontends."frontend-{{ $service.ServiceName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."frontend-{{ $service.ServiceName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."frontend-{{ $service.ServiceName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + {{ $auth := getAuth $service.TraefikLabels }} {{if $auth }} [frontends."frontend-{{ $service.ServiceName }}".auth] headerField = "{{ $auth.HeaderField }}" @@ -659,6 +681,29 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}} "{{.}}", {{end}}] + {{ $tlsClientCert := getPassTLSClientCert $container.SegmentLabels }} + {{if $tlsClientCert }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + {{ $auth := getAuth $container.SegmentLabels }} {{if $auth }} [frontends."frontend-{{ $frontendName }}".auth] @@ -961,6 +1006,29 @@ var _templatesEcsTmpl = []byte(`[backends] "{{.}}", {{end}}] + {{ $tlsClientCert := getPassTLSClientCert $instance.SegmentLabels }} + {{if $tlsClientCert }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + {{ $auth := getAuth $instance.SegmentLabels }} {{if $auth }} [frontends."frontend-{{ $frontendName }}".auth] @@ -1454,6 +1522,29 @@ var _templatesKvTmpl = []byte(`[backends] "{{.}}", {{end}}] + {{ $tlsClientCert := getPassTLSClientCert $frontend }} + {{if $tlsClientCert }} + [frontends."{{ $frontendName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."{{ $frontendName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."{{ $frontendName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + {{ $auth := getAuth $frontend }} {{if $auth }} [frontends."{{ $frontendName }}".auth] @@ -1796,7 +1887,30 @@ var _templatesMarathonTmpl = []byte(`{{ $apps := .Applications }} "{{.}}", {{end}}] - {{ $auth := getAuth $app.SegmentLabels }} + {{ $tlsClientCert := getPassTLSClientCert $app.SegmentLabels }} + {{if $tlsClientCert }} + [frontends."{{ $frontendName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."{{ $frontendName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."{{ $frontendName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + + {{ $auth := getAuth $app.SegmentLabels }} {{if $auth }} [frontends."{{ $frontendName }}".auth] headerField = "{{ $auth.HeaderField }}" @@ -2082,6 +2196,29 @@ var _templatesMesosTmpl = []byte(`[backends] "{{.}}", {{end}}] + {{ $tlsClientCert := getPassTLSClientCert $app.TraefikLabels }} + {{if $tlsClientCert }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + {{ $auth := getAuth $app.TraefikLabels }} {{if $auth }} [frontends."frontend-{{ $frontendName }}".auth] @@ -2421,6 +2558,29 @@ var _templatesRancherTmpl = []byte(`{{ $backendServers := .Backends }} "{{.}}", {{end}}] + {{ $tlsClientCert := getPassTLSClientCert $service.SegmentLabels }} + {{if $tlsClientCert }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + {{ $auth := getAuth $service.SegmentLabels }} {{if $auth }} [frontends."frontend-{{ $frontendName }}".auth] diff --git a/cmd/bug/bug_test.go b/cmd/bug/bug_test.go index 9c66ac110..2d78a93b6 100644 --- a/cmd/bug/bug_test.go +++ b/cmd/bug/bug_test.go @@ -34,7 +34,7 @@ func Test_createReport(t *testing.T) { File: &file.Provider{ Directory: "BAR", }, - RootCAs: tls.RootCAs{"fllf"}, + RootCAs: tls.FilesOrContents{"fllf"}, }, } diff --git a/cmd/traefik/traefik.go b/cmd/traefik/traefik.go index 2647523f0..8cf540dac 100644 --- a/cmd/traefik/traefik.go +++ b/cmd/traefik/traefik.go @@ -66,7 +66,7 @@ Complete documentation is available at https://traefik.io`, // add custom parsers f.AddParser(reflect.TypeOf(configuration.EntryPoints{}), &configuration.EntryPoints{}) f.AddParser(reflect.TypeOf(configuration.DefaultEntryPoints{}), &configuration.DefaultEntryPoints{}) - f.AddParser(reflect.TypeOf(traefiktls.RootCAs{}), &traefiktls.RootCAs{}) + f.AddParser(reflect.TypeOf(traefiktls.FilesOrContents{}), &traefiktls.FilesOrContents{}) f.AddParser(reflect.TypeOf(types.Constraints{}), &types.Constraints{}) f.AddParser(reflect.TypeOf(kubernetes.Namespaces{}), &kubernetes.Namespaces{}) f.AddParser(reflect.TypeOf(ecs.Clusters{}), &ecs.Clusters{}) diff --git a/configuration/configuration.go b/configuration/configuration.go index f21850c25..47899bd9e 100644 --- a/configuration/configuration.go +++ b/configuration/configuration.go @@ -79,7 +79,7 @@ type GlobalConfiguration struct { MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used" export:"true"` IdleTimeout flaeg.Duration `description:"(Deprecated) maximum amount of time an idle (keep-alive) connection will remain idle before closing itself." export:"true"` // Deprecated InsecureSkipVerify bool `description:"Disable SSL certificate verification" export:"true"` - RootCAs tls.RootCAs `description:"Add cert file for self-signed certificate"` + RootCAs tls.FilesOrContents `description:"Add cert file for self-signed certificate"` Retry *Retry `description:"Enable retry sending request if network error" export:"true"` HealthCheck *HealthCheckConfig `description:"Health check parameters" export:"true"` RespondingTimeouts *RespondingTimeouts `description:"Timeouts for incoming requests to the Traefik instance" export:"true"` diff --git a/configuration/entrypoints.go b/configuration/entrypoints.go index abb0eebc9..0d3e32580 100644 --- a/configuration/entrypoints.go +++ b/configuration/entrypoints.go @@ -234,7 +234,8 @@ func makeEntryPointTLS(result map[string]string) (*tls.TLS, error) { if configTLS != nil { if len(result["ca"]) > 0 { - files := strings.Split(result["ca"], ",") + files := tls.FilesOrContents{} + files.Set(result["ca"]) optional := toBool(result, "ca_optional") configTLS.ClientCA = tls.ClientCA{ Files: files, diff --git a/configuration/entrypoints_test.go b/configuration/entrypoints_test.go index 214ace662..ae4d88a6c 100644 --- a/configuration/entrypoints_test.go +++ b/configuration/entrypoints_test.go @@ -226,7 +226,7 @@ func TestEntryPoints_Set(t *testing.T) { }, }, ClientCA: tls.ClientCA{ - Files: []string{"car"}, + Files: tls.FilesOrContents{"car"}, Optional: true, }, }, @@ -338,7 +338,7 @@ func TestEntryPoints_Set(t *testing.T) { }, }, ClientCA: tls.ClientCA{ - Files: []string{"car"}, + Files: tls.FilesOrContents{"car"}, Optional: true, }, }, diff --git a/docs/basics.md b/docs/basics.md index 35d2bbe5d..754a3bf30 100644 --- a/docs/basics.md +++ b/docs/basics.md @@ -122,7 +122,7 @@ In order to use regular expressions with Host and Path matchers, you must declar The variable has no special meaning; however, it is required by the [gorilla/mux](https://github.com/gorilla/mux) dependency which embeds the regular expression and defines the syntax. You can optionally enable `passHostHeader` to forward client `Host` header to the backend. -You can also optionally enable `passTLSCert` to forward TLS Client certificates to the backend. +You can also optionally configure the `passTLSClientCert` option to pass the Client certificates to the backend in a specific header. ##### Path Matcher Usage Guidelines @@ -157,7 +157,8 @@ Here is an example of frontends definition: [frontends.frontend2] backend = "backend1" passHostHeader = true - passTLSCert = true + [frontends.frontend2.passTLSClientCert] + pem = true priority = 10 entrypoints = ["https"] # overrides defaultEntryPoints [frontends.frontend2.routes.test_1] diff --git a/docs/configuration/backends/consulcatalog.md b/docs/configuration/backends/consulcatalog.md index 4eb124a54..9a8da9e69 100644 --- a/docs/configuration/backends/consulcatalog.md +++ b/docs/configuration/backends/consulcatalog.md @@ -94,62 +94,72 @@ Additional settings can be defined using Consul Catalog tags. !!! note The default prefix is `traefik`. -| Label | Description | -|-------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `.enable=false` | Disables this container in Træfik. | -| `.protocol=https` | Overrides the default `http` protocol. | -| `.weight=10` | Assigns this weight to the container. | -| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. | -| `.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend. ex: `NetworkErrorRatio() > 0.` | -| `.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. | -| `.backend.healthcheck.interval=1s` | Defines the health check interval. | -| `.backend.healthcheck.port=8080` | Sets a different port for the health check. | -| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. | -| `.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. | -| `.backend.healthcheck.headers=EXPR` | Defines the health check request headers
Format: HEADER:value||HEADER2:value2 | -| `.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm. | -| `.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions. | -| `.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for sticky sessions. | -| `.backend.loadbalancer.sticky=true` | Enables backend sticky sessions. (DEPRECATED) | -| `.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.
Must be used in conjunction with the below label to take effect. | -| `.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.
Must be used in conjunction with the above label to take effect. | -| `.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). | -| `.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. | -| `.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. | -| `.frontend.auth.basic.usersfile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | -| `.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. | -| `.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. | -| `.frontend.auth.digest.usersfile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | -| `.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. | -| `.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. | -| `.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). | -| `.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. | -| `.frontend.auth.forward.tls.insecureSkipVerify=true`| If set to true invalid SSL certificates are accepted. | -| `.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. | -| `.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. | -| `.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. | -| `.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.
Overrides `defaultEntryPoints` | -| `.frontend.errors..backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `.frontend.errors..query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `.frontend.errors..status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. | -| `.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. | -| `.frontend.priority=10` | Overrides default frontend priority. | -| `.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `.frontend.rateLimit.rateSet..period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `.frontend.rateLimit.rateSet..average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `.frontend.rateLimit.rateSet..burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS). | -| `.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.replacement`. | -| `.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.regex`. | -| `.frontend.redirect.permanent=true` | Returns 301 instead of 302. | -| `.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{{.ServiceName}}.{{.Domain}}`. | -| `.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.
An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. | -| `.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. | +| Label | Description | +|----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `.enable=false` | Disables this container in Træfik. | +| `.protocol=https` | Overrides the default `http` protocol. | +| `.weight=10` | Assigns this weight to the container. | +| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. | +| `.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend. ex: `NetworkErrorRatio() > 0.` | +| `.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. | +| `.backend.healthcheck.interval=1s` | Defines the health check interval. | +| `.backend.healthcheck.port=8080` | Sets a different port for the health check. | +| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. | +| `.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. | +| `.backend.healthcheck.headers=EXPR` | Defines the health check request headers
Format: HEADER:value||HEADER2:value2 | +| `.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm. | +| `.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions. | +| `.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for sticky sessions. | +| `.backend.loadbalancer.sticky=true` | Enables backend sticky sessions. (DEPRECATED) | +| `.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.
Must be used in conjunction with the below label to take effect. | +| `.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.
Must be used in conjunction with the above label to take effect. | +| `.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). | +| `.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. | +| `.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. | +| `.frontend.auth.basic.usersfile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | +| `.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. | +| `.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. | +| `.frontend.auth.digest.usersfile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | +| `.frontend.auth.forward.address=https://example.com` | Sets the URL of the authentication server. | +| `.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. | +| `.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). | +| `.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. | +| `.frontend.auth.forward.tls.insecureSkipVerify=true` | If set to true invalid SSL certificates are accepted. | +| `.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. | +| `.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. | +| `.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. | +| `.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.
Overrides `defaultEntryPoints` | +| `.frontend.errors..backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `.frontend.errors..query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `.frontend.errors..status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. | +| `.frontend.passTLSClientCert.infos.notAfter=true` | Add the noAfter field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `.frontend.passTLSClientCert.infos.notBefore=true` | Add the noBefore field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `.frontend.passTLSClientCert.infos.sans=true` | Add the sans field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `.frontend.passTLSClientCert.infos.subject.commonName=true` | Add the subject.commonName field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `.frontend.passTLSClientCert.infos.subject.country=true` | Add the subject.country field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `.frontend.passTLSClientCert.infos.subject.locality=true` | Add the subject.locality field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `.frontend.passTLSClientCert.infos.subject.organization=true`| Add the subject.organization field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `.frontend.passTLSClientCert.infos.subject.province=true` | Add the subject.province field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `.frontend.passTLSClientCert.infos.subject.serialNumber=true`| Add the subject.serialNumber field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `.frontend.passTLSClientCert.pem=true` | Pass the escaped pem in the `X-Forwarded-Ssl-Client-Cert` header. | +| `.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. | +| `.frontend.priority=10` | Overrides default frontend priority. | +| `.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `.frontend.rateLimit.rateSet..period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `.frontend.rateLimit.rateSet..average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `.frontend.rateLimit.rateSet..burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS). | +| `.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.replacement`. | +| `.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.regex`. | +| `.frontend.redirect.permanent=true` | Returns 301 instead of 302. | +| `.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{{.ServiceName}}.{{.Domain}}`. | +| `.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.
An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. | +| `.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. | ### Multiple frontends for a single service diff --git a/docs/configuration/backends/docker.md b/docs/configuration/backends/docker.md index 3f356729c..a9c342305 100644 --- a/docs/configuration/backends/docker.md +++ b/docs/configuration/backends/docker.md @@ -207,67 +207,77 @@ services: Labels can be used on containers to override default behavior. -| Label | Description | -|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `traefik.docker.network` | Overrides the default docker network to use for connections to the container. [1] | -| `traefik.domain` | Sets the default base domain for the frontend rules. For more information, check the [Container Labels section's of the user guide "Let's Encrypt & Docker"](/user-guide/docker-and-lets-encrypt/#container-labels) | -| `traefik.enable=false` | Disables this container in Træfik. | -| `traefik.port=80` | Registers this port. Useful when the container exposes multiples ports. | -| `traefik.protocol=https` | Overrides the default `http` protocol | -| `traefik.weight=10` | Assigns this weight to the container | -| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. | -| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend | -| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. | -| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. | -| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. | -| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. | -| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. | -| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers
Format: HEADER:value||HEADER2:value2 | -| `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.sticky=true` | Enables backend sticky sessions (DEPRECATED) | -| `traefik.backend.loadbalancer.swarm=true` | Uses Swarm's inbuilt load balancer (only relevant under Swarm Mode). | -| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.
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.
Must be used in conjunction with the above label to take effect. | -| `traefik.frontend.auth.basic=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` [2] (DEPRECATED). | -| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. | -| `traefik.frontend.auth.basic.users=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` [2]. | -| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets the basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | -| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. | -| `traefik.frontend.auth.digest.users=EXPR` | Sets the digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. | -| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets the digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | -| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. | -| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). | -| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true`| If set to true invalid SSL certificates are accepted. | -| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. | -| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header user to pass the authenticated user to the application. | -| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.
Overrides `defaultEntryPoints` | -| `traefik.frontend.errors..backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.errors..query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.errors..status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. | -| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. | -| `traefik.frontend.priority=10` | Overrides default frontend priority | -| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) | -| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.replacement`. | -| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.regex`. | -| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. | -| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{containerName}.{domain}` or `Host:{service}.{project_name}.{domain}` if you are using `docker-compose`. | -| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.
An unset or empty list allows all Source-IPs to access.
If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. | -| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. | +| Label | Description | +|---------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `traefik.docker.network` | Overrides the default docker network to use for connections to the container. [1] | +| `traefik.domain` | Sets the default base domain for the frontend rules. For more information, check the [Container Labels section's of the user guide "Let's Encrypt & Docker"](/user-guide/docker-and-lets-encrypt/#container-labels) | +| `traefik.enable=false` | Disables this container in Træfik. | +| `traefik.port=80` | Registers this port. Useful when the container exposes multiples ports. | +| `traefik.protocol=https` | Overrides the default `http` protocol | +| `traefik.weight=10` | Assigns this weight to the container | +| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. | +| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend | +| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. | +| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. | +| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. | +| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. | +| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. | +| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers
Format: HEADER:value||HEADER2:value2 | +| `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.sticky=true` | Enables backend sticky sessions (DEPRECATED) | +| `traefik.backend.loadbalancer.swarm=true` | Uses Swarm's inbuilt load balancer (only relevant under Swarm Mode). | +| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.
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.
Must be used in conjunction with the above label to take effect. | +| `traefik.frontend.auth.basic=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` [2] (DEPRECATED). | +| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. | +| `traefik.frontend.auth.basic.users=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` [2]. | +| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets the basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | +| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. | +| `traefik.frontend.auth.digest.users=EXPR` | Sets the digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. | +| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets the digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | +| `traefik.frontend.auth.forward.address=https://example.com` | Sets the URL of the authentication server. | +| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). | +| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true` | If set to true invalid SSL certificates are accepted. | +| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. | +| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header user to pass the authenticated user to the application. | +| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.
Overrides `defaultEntryPoints` | +| `traefik.frontend.errors..backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.errors..query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.errors..status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. | +| `traefik.frontend.passTLSClientCert.infos.notAfter=true` | Add the noAfter field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.notBefore=true` | Add the noBefore field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.sans=true` | Add the sans field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.commonName=true` | Add the subject.commonName field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.country=true` | Add the subject.country field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.locality=true` | Add the subject.locality field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.organization=true`| Add the subject.organization field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.province=true` | Add the subject.province field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.serialNumber=true`| Add the subject.serialNumber field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.pem=true` | Pass the escaped pem in the `X-Forwarded-Ssl-Client-Cert` header. | +| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend (DEPRECATED). | +| `traefik.frontend.priority=10` | Overrides default frontend priority | +| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) | +| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.replacement`. | +| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.regex`. | +| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. | +| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{containerName}.{domain}` or `Host:{service}.{project_name}.{domain}` if you are using `docker-compose`. | +| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.
An unset or empty list allows all Source-IPs to access.
If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. | +| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. | [1] `traefik.docker.network`: If a container is linked to several networks, be sure to set the proper network name (you can check with `docker inspect `) otherwise it will randomly pick one (depending on how docker is returning them). @@ -320,46 +330,56 @@ You can define as many segments as ports exposed in a container. Segment labels override the default behavior. -| Label | Description | -|---------------------------------------------------------------------------|---------------------------------------------------------------| -| `traefik..backend=BACKEND` | Same as `traefik.backend` | -| `traefik..domain=DOMAIN` | Same as `traefik.domain` | -| `traefik..port=PORT` | Same as `traefik.port` | -| `traefik..protocol=http` | Same as `traefik.protocol` | -| `traefik..weight=10` | Same as `traefik.weight` | -| `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` | -| `traefik..frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` | -| `traefik..frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` | -| `traefik..frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` | -| `traefik..frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` | -| `traefik..frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` | -| `traefik..frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` | -| `traefik..frontend.auth.forward.address=https://example.com`| Same as `traefik.frontend.auth.forward.address` | -| `traefik..frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` | -| `traefik..frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` | -| `traefik..frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` | -| `traefik..frontend.auth.forward.tls.insecureSkipVerify=true`| Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify`| -| `traefik..frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` | -| `traefik..frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` | -| `traefik..frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` | -| `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` | -| `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` | -| `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` | -| `traefik..frontend.errors..status=RANGE` | Same as `traefik.frontend.errors..status` | -| `traefik..frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` | -| `traefik..frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` | -| `traefik..frontend.priority=10` | Same as `traefik.frontend.priority` | -| `traefik..frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` | -| `traefik..frontend.rateLimit.rateSet..period=6` | Same as `traefik.frontend.rateLimit.rateSet..period` | -| `traefik..frontend.rateLimit.rateSet..average=6` | Same as `traefik.frontend.rateLimit.rateSet..average` | -| `traefik..frontend.rateLimit.rateSet..burst=6` | Same as `traefik.frontend.rateLimit.rateSet..burst` | -| `traefik..frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` | -| `traefik..frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` | -| `traefik..frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` | -| `traefik..frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` | -| `traefik..frontend.rule=EXP` | Same as `traefik.frontend.rule` | -| `traefik..frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` | -| `traefik..frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` | +| Label | Description | +|------------------------------------------------------------------------------------|------------------------------------------------------------------------| +| `traefik..backend=BACKEND` | Same as `traefik.backend` | +| `traefik..domain=DOMAIN` | Same as `traefik.domain` | +| `traefik..port=PORT` | Same as `traefik.port` | +| `traefik..protocol=http` | Same as `traefik.protocol` | +| `traefik..weight=10` | Same as `traefik.weight` | +| `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` | +| `traefik..frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` | +| `traefik..frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` | +| `traefik..frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` | +| `traefik..frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` | +| `traefik..frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` | +| `traefik..frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` | +| `traefik..frontend.auth.forward.address=https://example.com` | Same as `traefik.frontend.auth.forward.address` | +| `traefik..frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` | +| `traefik..frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` | +| `traefik..frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` | +| `traefik..frontend.auth.forward.tls.insecureSkipVerify=true` | Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` | +| `traefik..frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` | +| `traefik..frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` | +| `traefik..frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` | +| `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` | +| `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` | +| `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` | +| `traefik..frontend.errors..status=RANGE` | Same as `traefik.frontend.errors..status` | +| `traefik..frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` | +| `traefik..frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` | +| `traefik..frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` | +| `traefik..frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` | +| `traefik..frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` | +| `traefik..frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` | +| `traefik..frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` | +| `traefik..frontend.passTLSClientCert.infos.subject.organization=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.organization`| +| `traefik..frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` | +| `traefik..frontend.passTLSClientCert.infos.subject.serialNumber=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber`| +| `traefik..frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` | +| `traefik..frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` | +| `traefik..frontend.priority=10` | Same as `traefik.frontend.priority` | +| `traefik..frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` | +| `traefik..frontend.rateLimit.rateSet..period=6` | Same as `traefik.frontend.rateLimit.rateSet..period` | +| `traefik..frontend.rateLimit.rateSet..average=6` | Same as `traefik.frontend.rateLimit.rateSet..average` | +| `traefik..frontend.rateLimit.rateSet..burst=6` | Same as `traefik.frontend.rateLimit.rateSet..burst` | +| `traefik..frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` | +| `traefik..frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` | +| `traefik..frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` | +| `traefik..frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` | +| `traefik..frontend.rule=EXP` | Same as `traefik.frontend.rule` | +| `traefik..frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` | +| `traefik..frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` | #### Custom Headers diff --git a/docs/configuration/backends/ecs.md b/docs/configuration/backends/ecs.md index b1dbbbe49..0089dee15 100644 --- a/docs/configuration/backends/ecs.md +++ b/docs/configuration/backends/ecs.md @@ -136,66 +136,76 @@ Træfik needs the following policy to read ECS information: Labels can be used on task containers to override default behaviour: -| Label | Description | -|------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `traefik.domain` | Sets the default domain for frontend rules. | -| `traefik.enable=false` | Disables this container in Træfik. | -| `traefik.port=80` | Overrides the default `port` value. Overrides `NetworkBindings` from Docker Container | -| `traefik.protocol=https` | Overrides the default `http` protocol | -| `traefik.weight=10` | Assigns this weight to the container | -| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. | -| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend | -| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. | -| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. (Default: 30s) | -| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. | -| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. | -| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. | -| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers
Format: HEADER:value||HEADER2:value2 | -| `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.sticky=true` | Enables backend sticky sessions (DEPRECATED) | -| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.
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.
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). | -| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. | -| `traefik.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. | -| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | -| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. | -| `traefik.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. | -| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | -| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. | -| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). | -| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true`| If set to true invalid SSL certificates are accepted. | -| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. | -| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. | -| `traefik.frontend.auth.removeHeader=true` | If set to true, removes the Authorization header. | -| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.
Overrides `defaultEntryPoints` | -| `traefik.frontend.errors..backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.errors..query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.errors..status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. | -| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. | -| `traefik.frontend.priority=10` | Overrides default frontend priority | -| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) | -| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.replacement`. | -| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.regex`. | -| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. | -| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{instance_name}.{domain}`. | -| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.
An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. | -| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. | +| Label | Description | +|---------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `traefik.domain` | Sets the default domain for frontend rules. | +| `traefik.enable=false` | Disables this container in Træfik. | +| `traefik.port=80` | Overrides the default `port` value. Overrides `NetworkBindings` from Docker Container | +| `traefik.protocol=https` | Overrides the default `http` protocol | +| `traefik.weight=10` | Assigns this weight to the container | +| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. | +| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend | +| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. | +| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. (Default: 30s) | +| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. | +| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. | +| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. | +| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers
Format: HEADER:value||HEADER2:value2 | +| `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.sticky=true` | Enables backend sticky sessions (DEPRECATED) | +| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.
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.
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). | +| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. | +| `traefik.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. | +| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | +| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. | +| `traefik.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. | +| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | +| `traefik.frontend.auth.forward.address=https://example.com` | Sets the URL of the authentication server. | +| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). | +| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true` | If set to true invalid SSL certificates are accepted. | +| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. | +| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. | +| `traefik.frontend.auth.removeHeader=true` | If set to true, removes the Authorization header. | +| `traefik.frontend.passTLSClientCert.infos.notAfter=true` | Add the noAfter field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.notBefore=true` | Add the noBefore field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.sans=true` | Add the sans field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.commonName=true` | Add the subject.commonName field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.country=true` | Add the subject.country field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.locality=true` | Add the subject.locality field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.organization=true`| Add the subject.organization field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.province=true` | Add the subject.province field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.serialNumber=true`| Add the subject.serialNumber field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.pem=true` | Pass the escaped pem in the `X-Forwarded-Ssl-Client-Cert` header. | +| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.
Overrides `defaultEntryPoints` | +| `traefik.frontend.errors..backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.errors..query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.errors..status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. | +| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. | +| `traefik.frontend.priority=10` | Overrides default frontend priority | +| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) | +| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.replacement`. | +| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.regex`. | +| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. | +| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{instance_name}.{domain}`. | +| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.
An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. | +| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. | ### Custom Headers @@ -237,47 +247,57 @@ You can define as many segments as ports exposed in an application. Segment labels override the default behavior. -| Label | Description | -|---------------------------------------------------------------------------|----------------------------------------------------------------| -| `traefik..backend=BACKEND` | Same as `traefik.backend` | -| `traefik..domain=DOMAIN` | Same as `traefik.domain` | -| `traefik..port=PORT` | Same as `traefik.port` | -| `traefik..protocol=http` | Same as `traefik.protocol` | -| `traefik..weight=10` | Same as `traefik.weight` | -| `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` | -| `traefik..frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` | -| `traefik..frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` | -| `traefik..frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` | -| `traefik..frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` | -| `traefik..frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` | -| `traefik..frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` | -| `traefik..frontend.auth.forward.address=https://example.com`| Same as `traefik.frontend.auth.forward.address` | -| `traefik..frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` | -| `traefik..frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` | -| `traefik..frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` | -| `traefik..frontend.auth.forward.tls.insecureSkipVerify=true`| Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` | -| `traefik..frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` | -| `traefik..frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` | -| `traefik..frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` | -| `traefik..frontend.auth.removeHeader=true` | Same as `traefik.frontend.auth.removeHeader` | -| `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` | -| `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` | -| `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` | -| `traefik..frontend.errors..status=RANGE` | Same as `traefik.frontend.errors..status` | -| `traefik..frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` | -| `traefik..frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` | -| `traefik..frontend.priority=10` | Same as `traefik.frontend.priority` | -| `traefik..frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` | -| `traefik..frontend.rateLimit.rateSet..period=6` | Same as `traefik.frontend.rateLimit.rateSet..period` | -| `traefik..frontend.rateLimit.rateSet..average=6` | Same as `traefik.frontend.rateLimit.rateSet..average` | -| `traefik..frontend.rateLimit.rateSet..burst=6` | Same as `traefik.frontend.rateLimit.rateSet..burst` | -| `traefik..frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` | -| `traefik..frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` | -| `traefik..frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` | -| `traefik..frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` | -| `traefik..frontend.rule=EXP` | Same as `traefik.frontend.rule` | -| `traefik..frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` | -| `traefik..frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` | +| Label | Description | +|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------| +| `traefik..backend=BACKEND` | Same as `traefik.backend` | +| `traefik..domain=DOMAIN` | Same as `traefik.domain` | +| `traefik..port=PORT` | Same as `traefik.port` | +| `traefik..protocol=http` | Same as `traefik.protocol` | +| `traefik..weight=10` | Same as `traefik.weight` | +| `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` | +| `traefik..frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` | +| `traefik..frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` | +| `traefik..frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` | +| `traefik..frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` | +| `traefik..frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` | +| `traefik..frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` | +| `traefik..frontend.auth.forward.address=https://example.com` | Same as `traefik.frontend.auth.forward.address` | +| `traefik..frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` | +| `traefik..frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` | +| `traefik..frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` | +| `traefik..frontend.auth.forward.tls.insecureSkipVerify=true` | Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` | +| `traefik..frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` | +| `traefik..frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` | +| `traefik..frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` | +| `traefik..frontend.auth.removeHeader=true` | Same as `traefik.frontend.auth.removeHeader` | +| `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` | +| `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` | +| `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` | +| `traefik..frontend.errors..status=RANGE` | Same as `traefik.frontend.errors..status` | +| `traefik..frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` | +| `traefik..frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` | +| `traefik..frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` | +| `traefik..frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` | +| `traefik..frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` | +| `traefik..frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` | +| `traefik..frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` | +| `traefik..frontend.passTLSClientCert.infos.subject.organization=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.organization` | +| `traefik..frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` | +| `traefik..frontend.passTLSClientCert.infos.subject.serialNumber=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber` | +| `traefik..frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` | +| `traefik..frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` | +| `traefik..frontend.priority=10` | Same as `traefik.frontend.priority` | +| `traefik..frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` | +| `traefik..frontend.rateLimit.rateSet..period=6` | Same as `traefik.frontend.rateLimit.rateSet..period` | +| `traefik..frontend.rateLimit.rateSet..average=6` | Same as `traefik.frontend.rateLimit.rateSet..average` | +| `traefik..frontend.rateLimit.rateSet..burst=6` | Same as `traefik.frontend.rateLimit.rateSet..burst` | +| `traefik..frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` | +| `traefik..frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` | +| `traefik..frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` | +| `traefik..frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` | +| `traefik..frontend.rule=EXP` | Same as `traefik.frontend.rule` | +| `traefik..frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` | +| `traefik..frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` | #### Custom Headers diff --git a/docs/configuration/backends/file.md b/docs/configuration/backends/file.md index beb4e0b5e..f77aafb2d 100644 --- a/docs/configuration/backends/file.md +++ b/docs/configuration/backends/file.md @@ -53,7 +53,6 @@ Træfik can be configured with a file. entryPoints = ["http", "https"] backend = "backend1" passHostHeader = true - passTLSCert = true priority = 42 # Use frontends.frontend1.auth.basic below instead @@ -61,7 +60,22 @@ Træfik can be configured with a file. "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", ] - + [frontends.frontend1.passTLSClientCert] + # Pass the escaped pem in a `X-Forwarded-Ssl-Client-Cert` header + pem = true + # Pass the escaped client cert infos selected below in a `X-Forwarded-Ssl-Client-Cert-Infos` header + # The unescaped header is like `Subject="C=%s,ST=%s,L=%s,O=%s,CN=%s",NB=%d,NA=%d,SAN=%s` + # It there is more than one certificates, their are separated by a `;` + [frontends.frontend-server.passTLSClientCert.infos] + notBefore = true + notAfter = true + [frontends.frontend-server.passTLSClientCert.infos.subject] + country = true + province = true + locality = true + organization = true + commonName = true + serialNumber = true [frontends.frontend1.auth] headerField = "X-WebAuth-User" [frontends.frontend1.auth.basic] diff --git a/docs/configuration/backends/marathon.md b/docs/configuration/backends/marathon.md index e6ad58d19..baf65a943 100644 --- a/docs/configuration/backends/marathon.md +++ b/docs/configuration/backends/marathon.md @@ -193,67 +193,77 @@ They may be specified on one of two levels: Application or service. The following labels can be defined on Marathon applications. They adjust the behavior for the entire application. -| Label | Description | -|------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `traefik.domain` | Sets the default domain used for the frontend rules. | -| `traefik.enable=false` | Disables this container in Træfik. | -| `traefik.port=80` | Registers this port. Useful when the container exposes multiples ports. | -| `traefik.portIndex=1` | Registers port by index in the application's ports array. Useful when the application exposes multiple ports. | -| `traefik.protocol=https` | Overrides the default `http` protocol. | -| `traefik.weight=10` | Assigns this weight to the container. | -| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. | -| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend | -| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. | -| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. (Default: 30s) | -| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. | -| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. | -| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. | -| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers
Format: HEADER:value||HEADER2:value2 | -| `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.sticky=true` | Enables backend sticky sessions (DEPRECATED) | -| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.
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.
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). | -| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. | -| `traefik.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. | -| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | -| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. | -| `traefik.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. | -| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | -| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. | -| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). | -| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true`| If set to true invalid SSL certificates are accepted. | -| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. | -| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. | -| `traefik.frontend.auth.removeHeader=true` | If set to true, removes the Authorization header. | -| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.
Overrides `defaultEntryPoints` | -| `traefik.frontend.errors..backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.errors..query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.errors..status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. | -| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. | -| `traefik.frontend.priority=10` | Overrides default frontend priority | -| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) | -| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.replacement`. | -| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.regex`. | -| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. | -| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{sub_domain}.{domain}`. | -| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.
An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. | -| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. | +| Label | Description | +|---------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `traefik.domain` | Sets the default domain used for the frontend rules. | +| `traefik.enable=false` | Disables this container in Træfik. | +| `traefik.port=80` | Registers this port. Useful when the container exposes multiples ports. | +| `traefik.portIndex=1` | Registers port by index in the application's ports array. Useful when the application exposes multiple ports. | +| `traefik.protocol=https` | Overrides the default `http` protocol. | +| `traefik.weight=10` | Assigns this weight to the container. | +| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. | +| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend | +| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. | +| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. (Default: 30s) | +| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. | +| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. | +| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. | +| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers
Format: HEADER:value||HEADER2:value2 | +| `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.sticky=true` | Enables backend sticky sessions (DEPRECATED) | +| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.
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.
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). | +| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. | +| `traefik.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. | +| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | +| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. | +| `traefik.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. | +| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | +| `traefik.frontend.auth.forward.address=https://example.com` | Sets the URL of the authentication server. | +| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). | +| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true` | If set to true invalid SSL certificates are accepted. | +| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. | +| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. | +| `traefik.frontend.auth.removeHeader=true` | If set to true, removes the Authorization header. | +| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.
Overrides `defaultEntryPoints` | +| `traefik.frontend.errors..backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.errors..query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.errors..status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. | +| `traefik.frontend.passTLSClientCert.infos.notAfter=true` | Add the noAfter field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.notBefore=true` | Add the noBefore field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.sans=true` | Add the sans field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.commonName=true` | Add the subject.commonName field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.country=true` | Add the subject.country field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.locality=true` | Add the subject.locality field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.organization=true`| Add the subject.organization field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.province=true` | Add the subject.province field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.serialNumber=true`| Add the subject.serialNumber field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.pem=true` | Pass the escaped pem in the `X-Forwarded-Ssl-Client-Cert` header. | +| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. | +| `traefik.frontend.priority=10` | Overrides default frontend priority | +| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) | +| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.replacement`. | +| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.regex`. | +| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. | +| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{sub_domain}.{domain}`. | +| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.
An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. | +| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. | #### Custom Headers @@ -296,48 +306,58 @@ You can define as many segments as ports exposed in an application. Segment labels override the default behavior. -| Label | Description | -|---------------------------------------------------------------------------|----------------------------------------------------------------| -| `traefik..backend=BACKEND` | Same as `traefik.backend` | -| `traefik..domain=DOMAIN` | Same as `traefik.domain` | -| `traefik..portIndex=1` | Same as `traefik.portIndex` | -| `traefik..port=PORT` | Same as `traefik.port` | -| `traefik..protocol=http` | Same as `traefik.protocol` | -| `traefik..weight=10` | Same as `traefik.weight` | -| `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` | -| `traefik..frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` | -| `traefik..frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` | -| `traefik..frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` | -| `traefik..frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` | -| `traefik..frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` | -| `traefik..frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` | -| `traefik..frontend.auth.forward.address=https://example.com`| Same as `traefik.frontend.auth.forward.address` | -| `traefik..frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` | -| `traefik..frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` | -| `traefik..frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` | -| `traefik..frontend.auth.forward.tls.insecureSkipVerify=true`| Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` | -| `traefik..frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` | -| `traefik..frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` | -| `traefik..frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` | -| `traefik..frontend.auth.removeHeader=true` | Same as `traefik.frontend.auth.removeHeader` | -| `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` | -| `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` | -| `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` | -| `traefik..frontend.errors..status=RANGE` | Same as `traefik.frontend.errors..status` | -| `traefik..frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` | -| `traefik..frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` | -| `traefik..frontend.priority=10` | Same as `traefik.frontend.priority` | -| `traefik..frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` | -| `traefik..frontend.rateLimit.rateSet..period=6` | Same as `traefik.frontend.rateLimit.rateSet..period` | -| `traefik..frontend.rateLimit.rateSet..average=6` | Same as `traefik.frontend.rateLimit.rateSet..average` | -| `traefik..frontend.rateLimit.rateSet..burst=6` | Same as `traefik.frontend.rateLimit.rateSet..burst` | -| `traefik..frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` | -| `traefik..frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` | -| `traefik..frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` | -| `traefik..frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` | -| `traefik..frontend.rule=EXP` | Same as `traefik.frontend.rule` | -| `traefik..frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` | -| `traefik..frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` | +| Label | Description | +|------------------------------------------------------------------------------------|------------------------------------------------------------------------| +| `traefik..backend=BACKEND` | Same as `traefik.backend` | +| `traefik..domain=DOMAIN` | Same as `traefik.domain` | +| `traefik..portIndex=1` | Same as `traefik.portIndex` | +| `traefik..port=PORT` | Same as `traefik.port` | +| `traefik..protocol=http` | Same as `traefik.protocol` | +| `traefik..weight=10` | Same as `traefik.weight` | +| `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` | +| `traefik..frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` | +| `traefik..frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` | +| `traefik..frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` | +| `traefik..frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` | +| `traefik..frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` | +| `traefik..frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` | +| `traefik..frontend.auth.forward.address=https://example.com` | Same as `traefik.frontend.auth.forward.address` | +| `traefik..frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` | +| `traefik..frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` | +| `traefik..frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` | +| `traefik..frontend.auth.forward.tls.insecureSkipVerify=true` | Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` | +| `traefik..frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` | +| `traefik..frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` | +| `traefik..frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` | +| `traefik..frontend.auth.removeHeader=true` | Same as `traefik.frontend.auth.removeHeader` | +| `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` | +| `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` | +| `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` | +| `traefik..frontend.errors..status=RANGE` | Same as `traefik.frontend.errors..status` | +| `traefik..frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` | +| `traefik..frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` | +| `traefik..frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` | +| `traefik..frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` | +| `traefik..frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` | +| `traefik..frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` | +| `traefik..frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` | +| `traefik..frontend.passTLSClientCert.infos.subject.organization=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.organization`| +| `traefik..frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` | +| `traefik..frontend.passTLSClientCert.infos.subject.serialNumber=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber`| +| `traefik..frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` | +| `traefik..frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` | +| `traefik..frontend.priority=10` | Same as `traefik.frontend.priority` | +| `traefik..frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` | +| `traefik..frontend.rateLimit.rateSet..period=6` | Same as `traefik.frontend.rateLimit.rateSet..period` | +| `traefik..frontend.rateLimit.rateSet..average=6` | Same as `traefik.frontend.rateLimit.rateSet..average` | +| `traefik..frontend.rateLimit.rateSet..burst=6` | Same as `traefik.frontend.rateLimit.rateSet..burst` | +| `traefik..frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` | +| `traefik..frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` | +| `traefik..frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` | +| `traefik..frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` | +| `traefik..frontend.rule=EXP` | Same as `traefik.frontend.rule` | +| `traefik..frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` | +| `traefik..frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` | #### Custom Headers diff --git a/docs/configuration/backends/mesos.md b/docs/configuration/backends/mesos.md index e1b83e85a..60b31e7c1 100644 --- a/docs/configuration/backends/mesos.md +++ b/docs/configuration/backends/mesos.md @@ -106,67 +106,77 @@ domain = "mesos.localhost" The following labels can be defined on Mesos tasks. They adjust the behavior for the entire application. -| Label | Description | -|------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `traefik.domain` | Sets the default domain for the frontend rules. | -| `traefik.enable=false` | Disables this container in Træfik. | -| `traefik.port=80` | Registers this port. Useful when the application exposes multiple ports. | -| `traefik.portName=web` | Registers port by name in the application's ports array. Useful when the application exposes multiple ports. | -| `traefik.portIndex=1` | Registers port by index in the application's ports array. Useful when the application exposes multiple ports. | -| `traefik.protocol=https` | Overrides the default `http` protocol | -| `traefik.weight=10` | Assigns this weight to the container | -| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. | -| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend | -| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. | -| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. (Default: 30s) | -| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. | -| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. | -| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. | -| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers
Format: HEADER:value||HEADER2:value2 | -| `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.maxconn.amount=10` | Sets a maximum number of connections to the backend.
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.
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). | -| `traefik.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. | -| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. | -| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | -| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. | -| `traefik.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. | -| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | -| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. | -| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). | -| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true`| If set to true invalid SSL certificates are accepted. | -| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. | -| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. | -| `traefik.frontend.auth.removeHeader=true` | If set to true, removes the Authorization header. | -| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.
Overrides `defaultEntryPoints` | -| `traefik.frontend.errors..backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.errors..query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.errors..status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. | -| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. | -| `traefik.frontend.priority=10` | Overrides default frontend priority | -| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) | -| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.replacement`. | -| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.regex`. | -| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. | -| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{discovery_name}.{domain}`. | -| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.
An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. | -| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. | +| Label | Description | +|---------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `traefik.domain` | Sets the default domain for the frontend rules. | +| `traefik.enable=false` | Disables this container in Træfik. | +| `traefik.port=80` | Registers this port. Useful when the application exposes multiple ports. | +| `traefik.portName=web` | Registers port by name in the application's ports array. Useful when the application exposes multiple ports. | +| `traefik.portIndex=1` | Registers port by index in the application's ports array. Useful when the application exposes multiple ports. | +| `traefik.protocol=https` | Overrides the default `http` protocol | +| `traefik.weight=10` | Assigns this weight to the container | +| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. | +| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend | +| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. | +| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. (Default: 30s) | +| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. | +| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. | +| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. | +| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers
Format: HEADER:value||HEADER2:value2 | +| `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.maxconn.amount=10` | Sets a maximum number of connections to the backend.
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.
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). | +| `traefik.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. | +| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. | +| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | +| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. | +| `traefik.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. | +| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | +| `traefik.frontend.auth.forward.address=https://example.com` | Sets the URL of the authentication server. | +| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). | +| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true` | If set to true invalid SSL certificates are accepted. | +| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. | +| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. | +| `traefik.frontend.auth.removeHeader=true` | If set to true, removes the Authorization header. | +| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.
Overrides `defaultEntryPoints` | +| `traefik.frontend.errors..backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.errors..query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.errors..status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. | +| `traefik.frontend.passTLSClientCert.infos.notAfter=true` | Add the noAfter field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.notBefore=true` | Add the noBefore field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.sans=true` | Add the sans field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.commonName=true` | Add the subject.commonName field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.country=true` | Add the subject.country field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.locality=true` | Add the subject.locality field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.organization=true`| Add the subject.organization field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.province=true` | Add the subject.province field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.serialNumber=true`| Add the subject.serialNumber field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.pem=true` | Pass the escaped pem in the `X-Forwarded-Ssl-Client-Cert` header. | +| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. | +| `traefik.frontend.priority=10` | Overrides default frontend priority | +| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) | +| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.replacement`. | +| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.regex`. | +| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. | +| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{discovery_name}.{domain}`. | +| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.
An unset or empty list allows all Source-IPs to access. If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. | +| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. | ### Custom Headers @@ -210,49 +220,59 @@ Additionally, if a segment name matches a named port, that port will be used unl Segment labels override the default behavior. -| Label | Description | -|---------------------------------------------------------------------------|----------------------------------------------------------------| -| `traefik..backend=BACKEND` | Same as `traefik.backend` | -| `traefik..domain=DOMAIN` | Same as `traefik.domain` | -| `traefik..portIndex=1` | Same as `traefik.portIndex` | -| `traefik..portName=web` | Same as `traefik.portName` | -| `traefik..port=PORT` | Same as `traefik.port` | -| `traefik..protocol=http` | Same as `traefik.protocol` | -| `traefik..weight=10` | Same as `traefik.weight` | -| `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` | -| `traefik..frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` | -| `traefik..frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` | -| `traefik..frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` | -| `traefik..frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` | -| `traefik..frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` | -| `traefik..frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` | -| `traefik..frontend.auth.forward.address=https://example.com`| Same as `traefik.frontend.auth.forward.address` | -| `traefik..frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` | -| `traefik..frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` | -| `traefik..frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` | -| `traefik..frontend.auth.forward.tls.insecureSkipVerify=true`| Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` | -| `traefik..frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` | -| `traefik..frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` | -| `traefik..frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` | -| `traefik..frontend.auth.removeHeader=true` | Same as `traefik.frontend.auth.removeHeader` | -| `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` | -| `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` | -| `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` | -| `traefik..frontend.errors..status=RANGE` | Same as `traefik.frontend.errors..status` | -| `traefik..frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` | -| `traefik..frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` | -| `traefik..frontend.priority=10` | Same as `traefik.frontend.priority` | -| `traefik..frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` | -| `traefik..frontend.rateLimit.rateSet..period=6` | Same as `traefik.frontend.rateLimit.rateSet..period` | -| `traefik..frontend.rateLimit.rateSet..average=6` | Same as `traefik.frontend.rateLimit.rateSet..average` | -| `traefik..frontend.rateLimit.rateSet..burst=6` | Same as `traefik.frontend.rateLimit.rateSet..burst` | -| `traefik..frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` | -| `traefik..frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` | -| `traefik..frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` | -| `traefik..frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` | -| `traefik..frontend.rule=EXP` | Same as `traefik.frontend.rule` | -| `traefik..frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` | -| `traefik..frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` | +| Label | Description | +|------------------------------------------------------------------------------------|------------------------------------------------------------------------| +| `traefik..backend=BACKEND` | Same as `traefik.backend` | +| `traefik..domain=DOMAIN` | Same as `traefik.domain` | +| `traefik..portIndex=1` | Same as `traefik.portIndex` | +| `traefik..portName=web` | Same as `traefik.portName` | +| `traefik..port=PORT` | Same as `traefik.port` | +| `traefik..protocol=http` | Same as `traefik.protocol` | +| `traefik..weight=10` | Same as `traefik.weight` | +| `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` | +| `traefik..frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` | +| `traefik..frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` | +| `traefik..frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` | +| `traefik..frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` | +| `traefik..frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` | +| `traefik..frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` | +| `traefik..frontend.auth.forward.address=https://example.com` | Same as `traefik.frontend.auth.forward.address` | +| `traefik..frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` | +| `traefik..frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` | +| `traefik..frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` | +| `traefik..frontend.auth.forward.tls.insecureSkipVerify=true` | Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` | +| `traefik..frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` | +| `traefik..frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` | +| `traefik..frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` | +| `traefik..frontend.auth.removeHeader=true` | Same as `traefik.frontend.auth.removeHeader` | +| `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` | +| `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` | +| `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` | +| `traefik..frontend.errors..status=RANGE` | Same as `traefik.frontend.errors..status` | +| `traefik..frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` | +| `traefik..frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` | +| `traefik..frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` | +| `traefik..frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` | +| `traefik..frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` | +| `traefik..frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` | +| `traefik..frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` | +| `traefik..frontend.passTLSClientCert.infos.subject.organization=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.organization`| +| `traefik..frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` | +| `traefik..frontend.passTLSClientCert.infos.subject.serialNumber=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber`| +| `traefik..frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` | +| `traefik..frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` | +| `traefik..frontend.priority=10` | Same as `traefik.frontend.priority` | +| `traefik..frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` | +| `traefik..frontend.rateLimit.rateSet..period=6` | Same as `traefik.frontend.rateLimit.rateSet..period` | +| `traefik..frontend.rateLimit.rateSet..average=6` | Same as `traefik.frontend.rateLimit.rateSet..average` | +| `traefik..frontend.rateLimit.rateSet..burst=6` | Same as `traefik.frontend.rateLimit.rateSet..burst` | +| `traefik..frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` | +| `traefik..frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` | +| `traefik..frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` | +| `traefik..frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` | +| `traefik..frontend.rule=EXP` | Same as `traefik.frontend.rule` | +| `traefik..frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` | +| `traefik..frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` | #### Custom Headers diff --git a/docs/configuration/backends/rancher.md b/docs/configuration/backends/rancher.md index f34272bf4..8bbcebaef 100644 --- a/docs/configuration/backends/rancher.md +++ b/docs/configuration/backends/rancher.md @@ -138,65 +138,75 @@ secretKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" Labels can be used on task containers to override default behavior: -| Label | Description | -|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `traefik.domain` | Sets the default domain for the frontend rules. | -| `traefik.enable=false` | Disables this container in Træfik. | -| `traefik.port=80` | Registers this port. Useful when the container exposes multiple ports. | -| `traefik.protocol=https` | Overrides the default `http` protocol. | -| `traefik.weight=10` | Assigns this weight to the container. | -| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. | -| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. | -| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend | -| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. | -| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. | -| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. | -| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. | -| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. | -| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers
Format: HEADER:value||HEADER2:value2 | -| `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.sticky=true` | Enables backend sticky sessions (DEPRECATED) | -| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.
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.
Must be used in conjunction with the above label to take effect. | -| `traefik.frontend.auth.basic=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). | -| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. | -| `traefik.frontend.auth.basic.users=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` . | -| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets the basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | -| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. | -| `traefik.frontend.auth.digest.users=EXPR` | Sets the digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. | -| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets the digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | -| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. | -| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). | -| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true`| If set to true invalid SSL certificates are accepted. | -| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. | -| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. | -| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. | -| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.
Overrides `defaultEntryPoints` | -| `traefik.frontend.errors..backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.errors..query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.errors..status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | -| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. | -| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. | -| `traefik.frontend.priority=10` | Overrides default frontend priority | -| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.rateLimit.rateSet..burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | -| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) | -| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.replacement`. | -| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.regex`. | -| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. | -| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{containerName}.{domain}` or `Host:{service}.{project_name}.{domain}` if you are using `docker-compose`. | -| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.
An unset or empty list allows all Source-IPs to access.
If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. | -| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. | +| Label | Description | +|---------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `traefik.domain` | Sets the default domain for the frontend rules. | +| `traefik.enable=false` | Disables this container in Træfik. | +| `traefik.port=80` | Registers this port. Useful when the container exposes multiple ports. | +| `traefik.protocol=https` | Overrides the default `http` protocol. | +| `traefik.weight=10` | Assigns this weight to the container. | +| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. | +| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.buffering.retryExpression=EXPR` | See [buffering](/configuration/commons/#buffering) section. | +| `traefik.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend | +| `traefik.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. | +| `traefik.backend.healthcheck.interval=1s` | Defines the health check interval. | +| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. | +| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. | +| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. | +| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers
Format: HEADER:value||HEADER2:value2 | +| `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.sticky=true` | Enables backend sticky sessions (DEPRECATED) | +| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.
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.
Must be used in conjunction with the above label to take effect. | +| `traefik.frontend.auth.basic=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). | +| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. | +| `traefik.frontend.auth.basic.users=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` . | +| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets the basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | +| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. | +| `traefik.frontend.auth.digest.users=EXPR` | Sets the digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. | +| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets the digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. | +| `traefik.frontend.auth.forward.address=https://example.com` | Sets the URL of the authentication server. | +| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). | +| `traefik.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.tls.insecureSkipVerify=true` | If set to true invalid SSL certificates are accepted. | +| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. | +| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. | +| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. | +| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.
Overrides `defaultEntryPoints` | +| `traefik.frontend.errors..backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.errors..query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.errors..status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. | +| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. | +| `traefik.frontend.passTLSClientCert.infos.notAfter=true` | Add the noAfter field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.notBefore=true` | Add the noBefore field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.sans=true` | Add the sans field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.commonName=true` | Add the subject.commonName field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.country=true` | Add the subject.country field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.locality=true` | Add the subject.locality field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.organization=true`| Add the subject.organization field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.province=true` | Add the subject.province field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.infos.subject.serialNumber=true`| Add the subject.serialNumber field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. | +| `traefik.frontend.passTLSClientCert.pem=true` | Pass the escaped pem in the `X-Forwarded-Ssl-Client-Cert` header. | +| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. | +| `traefik.frontend.priority=10` | Overrides default frontend priority | +| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.rateLimit.rateSet..burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. | +| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) | +| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.replacement`. | +| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.
Must be set with `traefik.frontend.redirect.regex`. | +| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. | +| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{containerName}.{domain}` or `Host:{service}.{project_name}.{domain}` if you are using `docker-compose`. | +| `traefik.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.
An unset or empty list allows all Source-IPs to access.
If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. | +| `traefik.frontend.whiteList.useXForwardedFor=true` | Uses `X-Forwarded-For` header as valid source of IP for the white list. | #### Custom Headers @@ -238,46 +248,56 @@ You can define as many segments as ports exposed in a container. Segment labels override the default behavior. -| Label | Description | -|---------------------------------------------------------------------------|---------------------------------------------------------------| -| `traefik..backend=BACKEND` | Same as `traefik.backend` | -| `traefik..domain=DOMAIN` | Same as `traefik.domain` | -| `traefik..port=PORT` | Same as `traefik.port` | -| `traefik..protocol=http` | Same as `traefik.protocol` | -| `traefik..weight=10` | Same as `traefik.weight` | -| `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` | -| `traefik..frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` | -| `traefik..frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` | -| `traefik..frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` | -| `traefik..frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` | -| `traefik..frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` | -| `traefik..frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` | -| `traefik..frontend.auth.forward.address=https://example.com`| Same as `traefik.frontend.auth.forward.address` | -| `traefik..frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` | -| `traefik..frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` | -| `traefik..frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` | -| `traefik..frontend.auth.forward.tls.insecureSkipVerify=true`| Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify`| -| `traefik..frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` | -| `traefik..frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` | -| `traefik..frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` | -| `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` | -| `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` | -| `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` | -| `traefik..frontend.errors..status=RANGE` | Same as `traefik.frontend.errors..status` | -| `traefik..frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` | -| `traefik..frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` | -| `traefik..frontend.priority=10` | Same as `traefik.frontend.priority` | -| `traefik..frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` | -| `traefik..frontend.rateLimit.rateSet..period=6` | Same as `traefik.frontend.rateLimit.rateSet..period` | -| `traefik..frontend.rateLimit.rateSet..average=6` | Same as `traefik.frontend.rateLimit.rateSet..average` | -| `traefik..frontend.rateLimit.rateSet..burst=6` | Same as `traefik.frontend.rateLimit.rateSet..burst` | -| `traefik..frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` | -| `traefik..frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` | -| `traefik..frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` | -| `traefik..frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` | -| `traefik..frontend.rule=EXP` | Same as `traefik.frontend.rule` | -| `traefik..frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` | -| `traefik..frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` | +| Label | Description | +|------------------------------------------------------------------------------------|------------------------------------------------------------------------| +| `traefik..backend=BACKEND` | Same as `traefik.backend` | +| `traefik..domain=DOMAIN` | Same as `traefik.domain` | +| `traefik..port=PORT` | Same as `traefik.port` | +| `traefik..protocol=http` | Same as `traefik.protocol` | +| `traefik..weight=10` | Same as `traefik.weight` | +| `traefik..frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` | +| `traefik..frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` | +| `traefik..frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` | +| `traefik..frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` | +| `traefik..frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` | +| `traefik..frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` | +| `traefik..frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` | +| `traefik..frontend.auth.forward.address=https://example.com` | Same as `traefik.frontend.auth.forward.address` | +| `traefik..frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` | +| `traefik..frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` | +| `traefik..frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` | +| `traefik..frontend.auth.forward.tls.insecureSkipVerify=true` | Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` | +| `traefik..frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` | +| `traefik..frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` | +| `traefik..frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` | +| `traefik..frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` | +| `traefik..frontend.errors..backend=NAME` | Same as `traefik.frontend.errors..backend` | +| `traefik..frontend.errors..query=PATH` | Same as `traefik.frontend.errors..query` | +| `traefik..frontend.errors..status=RANGE` | Same as `traefik.frontend.errors..status` | +| `traefik..frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` | +| `traefik..frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` | +| `traefik..frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` | +| `traefik..frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` | +| `traefik..frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` | +| `traefik..frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` | +| `traefik..frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` | +| `traefik..frontend.passTLSClientCert.infos.subject.organization=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.organization`| +| `traefik..frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` | +| `traefik..frontend.passTLSClientCert.infos.subject.serialNumber=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber`| +| `traefik..frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` | +| `traefik..frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` | +| `traefik..frontend.priority=10` | Same as `traefik.frontend.priority` | +| `traefik..frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` | +| `traefik..frontend.rateLimit.rateSet..period=6` | Same as `traefik.frontend.rateLimit.rateSet..period` | +| `traefik..frontend.rateLimit.rateSet..average=6` | Same as `traefik.frontend.rateLimit.rateSet..average` | +| `traefik..frontend.rateLimit.rateSet..burst=6` | Same as `traefik.frontend.rateLimit.rateSet..burst` | +| `traefik..frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` | +| `traefik..frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` | +| `traefik..frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` | +| `traefik..frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` | +| `traefik..frontend.rule=EXP` | Same as `traefik.frontend.rule` | +| `traefik..frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` | +| `traefik..frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` | #### Custom Headers diff --git a/docs/user-guide/examples.md b/docs/user-guide/examples.md index 51bc7c1be..2b24194a0 100644 --- a/docs/user-guide/examples.md +++ b/docs/user-guide/examples.md @@ -311,7 +311,6 @@ The `consul` provider contains the configuration. [frontends.frontend2] backend = "backend1" passHostHeader = true - passTLSCert = true entrypoints = ["https"] # overrides defaultEntryPoints [frontends.frontend2.routes.test_1] rule = "Host:{subdomain:[a-z]+}.localhost" diff --git a/integration/fixtures/tlsclientheaders/root.pem b/integration/fixtures/tlsclientheaders/root.pem new file mode 100644 index 000000000..633325fc9 --- /dev/null +++ b/integration/fixtures/tlsclientheaders/root.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDhDCCAmygAwIBAgIJAK4Ed0WF/YNQMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNV +BAYTAkZSMQ8wDQYDVQQIDAZGUkFOQ0UxETAPBgNVBAcMCFRPVUxPVVNFMRMwEQYD +VQQKDApjb250YWlub3VzMQ8wDQYDVQQDDAZzZXJ2ZXIwHhcNMTgwMzIxMTMzOTM4 +WhcNMjEwMTA4MTMzOTM4WjBXMQswCQYDVQQGEwJGUjEPMA0GA1UECAwGRlJBTkNF +MREwDwYDVQQHDAhUT1VMT1VTRTETMBEGA1UECgwKY29udGFpbm91czEPMA0GA1UE +AwwGc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2DfZMdW1 +QKmdOTPULt6WUMVFU3PUcovq4cVtvNAzAshduC/7nHZx60uFzVKLYnOfZ+5VYfOS +zfVXPvltmBSWga1Yj6CuzfDZwY1nkcoL+22yBD6x4w2nB7aFaPNgj6M4ALVEZRKX +lMow+a0c0mOr1kLHm99MT/oabcdI+wbAp8VnLz9DF6SD7iDjIOb4RjvmcyetBzwu +1rQYti0bFHOnLCxiz0asXly0zspFajWkbGkvBdvEoP2qOHMeTV604PaBwpIMX/ly +ymGgYUctHeC16ptDRDDj7Spmu7ec2NzjgNW+MOth6EkFlhYgg1OEIXP+IFJ5LbS8 +1t/Y+fDUoc6+IQIDAQABo1MwUTAdBgNVHQ4EFgQUYeZvrzWyLI3TjmTIJYpSTjTb +/XUwHwYDVR0jBBgwFoAUYeZvrzWyLI3TjmTIJYpSTjTb/XUwDwYDVR0TAQH/BAUw +AwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAYQL8d/WQxu7rE58GC7le53FNzujMNZ+h +1kdS35LrTXPv5b6QTi5oUGi5LCesP4HnCpGdMFodyydhY8rhIDZWEFgkJZOLZhdt +sAyRONdI/Ms/NGQO2oJD+TlV92e4k3ey4WJyXIFHXE2Apb77VlsiHp8pI/iF/R5t +h4o4OADG7k6Fjf/wx7A18ru2eoH+PcwA8i6sQaQ1qEwxC0b3rh2TwaCpFQVcmMv5 +5jKPRBN0UC0PyHwqFZsSg1folhMAIBAjUsHgA6WleN9zMCyLAIn0LSai1CpFby6o +d6xu6pp8pwot8YTL0yS5T0X9aNhK2/uDoP50ei6eWI3uuPa8NJxbyA== +-----END CERTIFICATE----- diff --git a/integration/fixtures/tlsclientheaders/server.key b/integration/fixtures/tlsclientheaders/server.key new file mode 100644 index 000000000..f5d218904 --- /dev/null +++ b/integration/fixtures/tlsclientheaders/server.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAo0eupztBxEchz/9BbegBzKX35YUt0S2Xzp/mFM+hXQylWDHB +z3wED7R89v3sY6ePTk/tAT5l6uKjmQ/zRlQFf7QtVWKUtYq8rjuFn9/EeC+233mx +kVP7QAcuT6T8PzoUgysW6Tx3zz18VDRMnPhx1fjA1jAq3+IU03BpbFz7CkYCxkG/ +1wWHmsB16LH2bMxJrzapph2nSDnUkoATugSJec+DxTtX1hdjAaJK/JsIwioA/Lyy +6YgE2oX7uRZBou0bA3y0TDnFoIVAVqISYWfszTGDlwL+SD/P9GYa19GZk4imdp8j +LD/+J9eLuHG75rkROvE4xbSPbGIGkZOEYTmjHwIDAQABAoIBAGok81kroHlkdIqu +uW4lYOYVDq5agYp2RTXBpOTqhU/kJKjMz91+FXXQM1ytfbra9sJGGyCv27lyVD/w +qomRnXGDQ+U6DMpnwnjRoPBpm2M2QX/NsK11FuRsxqJn8sN3klYi8OX2tTw4EFb9 +GMECkZ4z88hJz9VzN26sqRwU5e2qw45Fhk+Jl6RBsiBfMGNGsmI5n1yIgvQd2PoM +wVxHI+bb3rWL7zE7wy2rb2c+J0P2gy7fZlFN2ZLkC5RjTqdzD2P4erp4gcpgffuO +0Epu7ZzuJ0UKCBXJOkhjlM79opLK6IBpF1YgxVCoMPbQVYAHP9hSwuz6hgc0ocwa ++6PqzSECgYEA1kTSFN8tHq2VMFgwPyguppSmeJJdIcnMYdicJNkv9YXeIt4mAk9c +Qm5eMLoqRJL94fdRDGb7QIqcfSrQODHy5dmqrTZd+TeSc4VRC1gZ7RPg5ja8b0dR +DoktPizIYzWrNEaEjhWojqYXT5DOOmNgDbOYrlR6Qdrd6VOmQkIgHz0CgYEAwxSf +NMe6LasWg9PYgLeVBcNc9oOjGvczOmNULngte8LpiJm4yzI0gMer20VdCtXYsyR1 +Zs/rItzSQuvr+3v5qW2NfJ/TaJkZ+bcc/fGJ2LcnM2Kfjfih8DSy5/MBzNM4cqw2 +arHVvQlAvfOSB8WoFzdXOS41Z+BumLsZE3/mMYsCgYBGNTKpCB+ep730o1DbwOzY +RGjvpPXDNn4zqWgwYsHmL0EEJ8pIg3x1f/h4+ucSpR9vRTxXVf8JvOFd2gN0BlnS +mqnkK6ZLHLxuAcb2cp28IwFULac8xx92JdifQMlASLuaW2jfrZUXeLC2r3oDg8Bb +fPeQV7nfjjmcVH5rw4MG+QKBgQCi4RH4oJZLUSEQWo3XEvDjCfYRgWFqv2FPa+W6 +ku7u+ZPBURAg4D9EEvLjtmt0A47WLCe1+v3JcvQ/mfnDVQTkOKs8lbmPCN3OSNx1 +DvnYLzwUxFCR2jljdKy3y4cCPI1R+YXJ2ceq+RHMR5Ty1k59a+BwxqsimxncfcL3 +K//H9wKBgQChT3kvF9Igcdna8g+JneGD6RHXJX1o80QrO+eWma4NozEOmXqA7R7r ++GwAyqy9GFM7pwUhHmhJAxILMBxR84EY7kCBvi1VlZ3JbT7w0gjjOqPHklvbsPj9 +BruA5xPMq1gzCOgejQIRoODtpH1S6Fi/YMTO6eq75qw6minHWi4dPw== +-----END RSA PRIVATE KEY----- diff --git a/integration/fixtures/tlsclientheaders/server.pem b/integration/fixtures/tlsclientheaders/server.pem new file mode 100644 index 000000000..97c39f730 --- /dev/null +++ b/integration/fixtures/tlsclientheaders/server.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDKjCCAhICCQDKAJTeuq3LHjANBgkqhkiG9w0BAQsFADBXMQswCQYDVQQGEwJG +UjEPMA0GA1UECAwGRlJBTkNFMREwDwYDVQQHDAhUT1VMT1VTRTETMBEGA1UECgwK +Y29udGFpbm91czEPMA0GA1UEAwwGc2VydmVyMB4XDTE4MDMyMTEzNDM0MVoXDTIx +MDEwODEzNDM0MVowVzELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZSQU5DRTERMA8G +A1UEBwwIVE9VTE9VU0UxEzARBgNVBAoMCmNvbnRhaW5vdXMxDzANBgNVBAMMBnNl +cnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNHrqc7QcRHIc// +QW3oAcyl9+WFLdEtl86f5hTPoV0MpVgxwc98BA+0fPb97GOnj05P7QE+Zerio5kP +80ZUBX+0LVVilLWKvK47hZ/fxHgvtt95sZFT+0AHLk+k/D86FIMrFuk8d889fFQ0 +TJz4cdX4wNYwKt/iFNNwaWxc+wpGAsZBv9cFh5rAdeix9mzMSa82qaYdp0g51JKA +E7oEiXnPg8U7V9YXYwGiSvybCMIqAPy8sumIBNqF+7kWQaLtGwN8tEw5xaCFQFai +EmFn7M0xg5cC/kg/z/RmGtfRmZOIpnafIyw//ifXi7hxu+a5ETrxOMW0j2xiBpGT +hGE5ox8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAPYDdGyNWp7R9j2oxZEbQS4lb ++2Ol1r6PFo/zmpB6GK3CSNo65a0DtW/ITeQi97MMgGS1D3wnaFPrwxtp0mEn7HjU +uDcufHBqqBsjYC3NEtt+yyxNeYddLD/GdFXw4d6wNRdRaFCq5N1CPQzF4VTdoSLD +xsOq/WAHHc2cyZyOprAqm2UXyWXxn4yWZqzDsZ41/v2f3uMNxeqyIEtNZVzTKQBu +wWw+jlQKGu0T8Ex1f0jaKI1OPtN5dzaIfO8acHcuNdmnE+hVsoqe17Dckxsj1ORf +8ZcZ4qvULVouGINQBP4fcl5jv6TOm1U+ZSk01FcHPmiDEMB6Utyy4ZLHPbmKYg== +-----END CERTIFICATE----- diff --git a/integration/fixtures/tlsclientheaders/simple.toml b/integration/fixtures/tlsclientheaders/simple.toml new file mode 100644 index 000000000..40809f315 --- /dev/null +++ b/integration/fixtures/tlsclientheaders/simple.toml @@ -0,0 +1,24 @@ +logLevel = "DEBUG" +defaultEntryPoints = ["https"] +debug = true +rootCAs = [ """{{ .RootCertContent }}""" ] + +[entryPoints] + [entryPoints.https] + address = ":8443" + + [entryPoints.https.tls] + + [entryPoints.https.tls.ClientCA] + files = [ """{{ .RootCertContent }}""" ] + optional = false + + [[entryPoints.https.tls.certificates]] + certFile = """{{ .ServerCertContent }}""" + keyFile = """{{ .ServerKeyContent }}""" + +[api] + +[docker] +endpoint = "unix:///var/run/docker.sock" +watch = true diff --git a/integration/integration_test.go b/integration/integration_test.go index c817b2276..f68e62b6b 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -60,6 +60,7 @@ func init() { check.Suite(&RateLimitSuite{}) check.Suite(&RetrySuite{}) check.Suite(&SimpleSuite{}) + check.Suite(&TLSClientHeadersSuite{}) check.Suite(&TimeoutSuite{}) check.Suite(&TracingSuite{}) check.Suite(&WebsocketSuite{}) diff --git a/integration/resources/compose/tlsclientheaders.yml b/integration/resources/compose/tlsclientheaders.yml new file mode 100644 index 000000000..42ba2007b --- /dev/null +++ b/integration/resources/compose/tlsclientheaders.yml @@ -0,0 +1,6 @@ +whoami: + image: containous/whoami + labels: + - traefik.frontend.passTLSClientCert.pem=true + - traefik.frontend.rule=PathPrefix:/ + diff --git a/integration/tls_client_headers_test.go b/integration/tls_client_headers_test.go new file mode 100644 index 000000000..373e855ed --- /dev/null +++ b/integration/tls_client_headers_test.go @@ -0,0 +1,71 @@ +package integration + +import ( + "crypto/tls" + "io/ioutil" + "net/http" + "os" + "time" + + "github.com/containous/traefik/integration/try" + "github.com/go-check/check" + checker "github.com/vdemeester/shakers" +) + +const ( + rootCertPath = "./fixtures/tlsclientheaders/root.pem" + certPemPath = "./fixtures/tlsclientheaders/server.pem" + certKeyPath = "./fixtures/tlsclientheaders/server.key" +) + +type TLSClientHeadersSuite struct{ BaseSuite } + +func (s *TLSClientHeadersSuite) SetUpSuite(c *check.C) { + s.createComposeProject(c, "tlsclientheaders") + s.composeProject.Start(c) +} + +func (s *TLSClientHeadersSuite) TestTLSClientHeaders(c *check.C) { + rootCertContent, err := ioutil.ReadFile(rootCertPath) + c.Assert(err, check.IsNil) + serverCertContent, err := ioutil.ReadFile(certPemPath) + c.Assert(err, check.IsNil) + ServerKeyContent, err := ioutil.ReadFile(certKeyPath) + c.Assert(err, check.IsNil) + + file := s.adaptFile(c, "fixtures/tlsclientheaders/simple.toml", struct { + RootCertContent string + ServerCertContent string + ServerKeyContent string + }{ + RootCertContent: string(rootCertContent), + ServerCertContent: string(serverCertContent), + ServerKeyContent: string(ServerKeyContent), + }) + defer os.Remove(file) + + cmd, display := s.traefikCmd(withConfigFile(file)) + defer display(c) + err = cmd.Start() + c.Assert(err, checker.IsNil) + defer cmd.Process.Kill() + + err = try.GetRequest("http://127.0.0.1:8080/api/providers", 2*time.Second, try.BodyContains("PathPrefix:/")) + c.Assert(err, checker.IsNil) + + request, err := http.NewRequest(http.MethodGet, "https://127.0.0.1:8443", nil) + c.Assert(err, checker.IsNil) + + certificate, err := tls.LoadX509KeyPair(certPemPath, certKeyPath) + c.Assert(err, checker.IsNil) + + tr := &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + Certificates: []tls.Certificate{certificate}, + }, + } + + err = try.RequestWithTransport(request, 2*time.Second, tr, try.BodyContains("Forwarded-Tls-Client-Cert: MIIDKjCCAhICCQDKAJTeuq3LHjANBgkqhkiG9w0BAQsFADBXMQswCQYDVQQGEwJGUjEPMA0GA1UECAwGRlJBTkNFMREwDwYDVQQHDAhUT1VMT1VTRTETMBEGA1UECgwKY29udGFpbm91czEPMA0GA1UEAwwGc2VydmVyMB4XDTE4MDMyMTEzNDM0MVoXDTIxMDEwODEzNDM0MVowVzELMAkGA1UEBhMCRlIxDzANBgNVBAgMBkZSQU5DRTERMA8GA1UEBwwIVE9VTE9VU0UxEzARBgNVBAoMCmNvbnRhaW5vdXMxDzANBgNVBAMMBnNlcnZlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNHrqc7QcRHIc%2F%2FQW3oAcyl9%2BWFLdEtl86f5hTPoV0MpVgxwc98BA%2B0fPb97GOnj05P7QE%2BZerio5kP80ZUBX%2B0LVVilLWKvK47hZ%2FfxHgvtt95sZFT%2B0AHLk%2Bk%2FD86FIMrFuk8d889fFQ0TJz4cdX4wNYwKt%2FiFNNwaWxc%2BwpGAsZBv9cFh5rAdeix9mzMSa82qaYdp0g51JKAE7oEiXnPg8U7V9YXYwGiSvybCMIqAPy8sumIBNqF%2B7kWQaLtGwN8tEw5xaCFQFaiEmFn7M0xg5cC%2Fkg%2Fz%2FRmGtfRmZOIpnafIyw%2F%2FifXi7hxu%2Ba5ETrxOMW0j2xiBpGThGE5ox8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAPYDdGyNWp7R9j2oxZEbQS4lb%2B2Ol1r6PFo%2FzmpB6GK3CSNo65a0DtW%2FITeQi97MMgGS1D3wnaFPrwxtp0mEn7HjUuDcufHBqqBsjYC3NEtt%2ByyxNeYddLD%2FGdFXw4d6wNRdRaFCq5N1CPQzF4VTdoSLDxsOq%2FWAHHc2cyZyOprAqm2UXyWXxn4yWZqzDsZ41%2Fv2f3uMNxeqyIEtNZVzTKQBuwWw%2BjlQKGu0T8Ex1f0jaKI1OPtN5dzaIfO8acHcuNdmnE%2BhVsoqe17Dckxsj1ORf8ZcZ4qvULVouGINQBP4fcl5jv6TOm1U%2BZSk01FcHPmiDEMB6Utyy4ZLHPbmKYg%3D%3D")) + c.Assert(err, checker.IsNil) +} diff --git a/middlewares/tlsClientHeaders.go b/middlewares/tlsClientHeaders.go new file mode 100644 index 000000000..ac4a5cb41 --- /dev/null +++ b/middlewares/tlsClientHeaders.go @@ -0,0 +1,251 @@ +package middlewares + +import ( + "crypto/x509" + "crypto/x509/pkix" + "encoding/pem" + "fmt" + "net/http" + "net/url" + "strings" + + "github.com/containous/traefik/log" + "github.com/containous/traefik/types" +) + +const xForwardedTLSClientCert = "X-Forwarded-Tls-Client-Cert" +const xForwardedTLSClientCertInfos = "X-Forwarded-Tls-Client-Cert-Infos" + +// TLSClientCertificateInfos is a struct for specifying the configuration for the tlsClientHeaders middleware. +type TLSClientCertificateInfos struct { + NotAfter bool + NotBefore bool + Subject *TLSCLientCertificateSubjectInfos + Sans bool +} + +// TLSCLientCertificateSubjectInfos contains the configuration for the certificate subject infos. +type TLSCLientCertificateSubjectInfos struct { + Country bool + Province bool + Locality bool + Organization bool + CommonName bool + SerialNumber bool +} + +// TLSClientHeaders is a middleware that helps setup a few tls infos features. +type TLSClientHeaders struct { + PEM bool // pass the sanitized pem to the backend in a specific header + Infos *TLSClientCertificateInfos // pass selected informations from the client certificate +} + +func newTLSCLientCertificateSubjectInfos(infos *types.TLSCLientCertificateSubjectInfos) *TLSCLientCertificateSubjectInfos { + if infos == nil { + return nil + } + + return &TLSCLientCertificateSubjectInfos{ + SerialNumber: infos.SerialNumber, + CommonName: infos.CommonName, + Country: infos.Country, + Locality: infos.Locality, + Organization: infos.Organization, + Province: infos.Province, + } +} + +func newTLSClientInfos(infos *types.TLSClientCertificateInfos) *TLSClientCertificateInfos { + if infos == nil { + return nil + } + + return &TLSClientCertificateInfos{ + NotBefore: infos.NotBefore, + NotAfter: infos.NotAfter, + Sans: infos.Sans, + Subject: newTLSCLientCertificateSubjectInfos(infos.Subject), + } +} + +// NewTLSClientHeaders constructs a new TLSClientHeaders instance from supplied frontend header struct. +func NewTLSClientHeaders(frontend *types.Frontend) *TLSClientHeaders { + if frontend == nil { + return nil + } + + var pem bool + var infos *TLSClientCertificateInfos + + if frontend.PassTLSClientCert != nil { + conf := frontend.PassTLSClientCert + pem = conf.PEM + infos = newTLSClientInfos(conf.Infos) + } + + return &TLSClientHeaders{ + PEM: pem, + Infos: infos, + } +} + +func (s *TLSClientHeaders) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + s.ModifyRequestHeaders(r) + // If there is a next, call it. + if next != nil { + next(w, r) + } +} + +// sanitize As we pass the raw certificates, remove the useless data and make it http request compliant +func sanitize(cert []byte) string { + s := string(cert) + r := strings.NewReplacer("-----BEGIN CERTIFICATE-----", "", + "-----END CERTIFICATE-----", "", + "\n", "") + cleaned := r.Replace(s) + + return url.QueryEscape(cleaned) +} + +// extractCertificate extract the certificate from the request +func extractCertificate(cert *x509.Certificate) string { + b := pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw} + certPEM := pem.EncodeToMemory(&b) + if certPEM == nil { + log.Error("Cannot extract the certificate content") + return "" + } + return sanitize(certPEM) +} + +// getXForwardedTLSClientCert Build a string with the client certificates +func getXForwardedTLSClientCert(certs []*x509.Certificate) string { + var headerValues []string + + for _, peerCert := range certs { + headerValues = append(headerValues, extractCertificate(peerCert)) + } + + return strings.Join(headerValues, ",") +} + +// getSANs get the Subject Alternate Name values +func getSANs(cert *x509.Certificate) []string { + var sans []string + if cert == nil { + return sans + } + + sans = append(cert.DNSNames, cert.EmailAddresses...) + + var ips []string + for _, ip := range cert.IPAddresses { + ips = append(ips, ip.String()) + } + sans = append(sans, ips...) + + var uris []string + for _, uri := range cert.URIs { + uris = append(uris, uri.String()) + } + + return append(sans, uris...) +} + +// getSubjectInfos extract the requested informations from the certificate subject +func (s *TLSClientHeaders) getSubjectInfos(cs *pkix.Name) string { + var subject string + + if s.Infos != nil && s.Infos.Subject != nil { + options := s.Infos.Subject + + var content []string + + if options.Country && len(cs.Country) > 0 { + content = append(content, fmt.Sprintf("C=%s", cs.Country[0])) + } + + if options.Province && len(cs.Province) > 0 { + content = append(content, fmt.Sprintf("ST=%s", cs.Province[0])) + } + + if options.Locality && len(cs.Locality) > 0 { + content = append(content, fmt.Sprintf("L=%s", cs.Locality[0])) + } + + if options.Organization && len(cs.Organization) > 0 { + content = append(content, fmt.Sprintf("O=%s", cs.Organization[0])) + } + + if options.CommonName && len(cs.CommonName) > 0 { + content = append(content, fmt.Sprintf("CN=%s", cs.CommonName)) + } + + if len(content) > 0 { + subject = `Subject="` + strings.Join(content, ",") + `"` + } + } + + return subject +} + +// getXForwardedTLSClientCertInfos Build a string with the wanted client certificates informations +// like Subject="C=%s,ST=%s,L=%s,O=%s,CN=%s",NB=%d,NA=%d,SAN=%s; +func (s *TLSClientHeaders) getXForwardedTLSClientCertInfos(certs []*x509.Certificate) string { + var headerValues []string + + for _, peerCert := range certs { + var values []string + var sans string + var nb string + var na string + + subject := s.getSubjectInfos(&peerCert.Subject) + if len(subject) > 0 { + values = append(values, subject) + } + + ci := s.Infos + if ci != nil { + if ci.NotBefore { + nb = fmt.Sprintf("NB=%d", uint64(peerCert.NotBefore.Unix())) + values = append(values, nb) + } + if ci.NotAfter { + na = fmt.Sprintf("NA=%d", uint64(peerCert.NotAfter.Unix())) + values = append(values, na) + } + + if ci.Sans { + sans = fmt.Sprintf("SAN=%s", strings.Join(getSANs(peerCert), ",")) + values = append(values, sans) + } + } + + value := strings.Join(values, ",") + headerValues = append(headerValues, value) + } + + return strings.Join(headerValues, ";") +} + +// ModifyRequestHeaders set the wanted headers with the certificates informations +func (s *TLSClientHeaders) ModifyRequestHeaders(r *http.Request) { + if s.PEM { + if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 { + r.Header.Set(xForwardedTLSClientCert, getXForwardedTLSClientCert(r.TLS.PeerCertificates)) + } else { + log.Warn("Try to extract certificate on a request without TLS") + } + } + + if s.Infos != nil { + if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 { + headerContent := s.getXForwardedTLSClientCertInfos(r.TLS.PeerCertificates) + r.Header.Set(xForwardedTLSClientCertInfos, url.QueryEscape(headerContent)) + } else { + log.Warn("Try to extract certificate on a request without TLS") + } + } +} diff --git a/middlewares/tlsClientHeaders_test.go b/middlewares/tlsClientHeaders_test.go new file mode 100644 index 000000000..583da2bb6 --- /dev/null +++ b/middlewares/tlsClientHeaders_test.go @@ -0,0 +1,799 @@ +package middlewares + +import ( + "crypto/tls" + "crypto/x509" + "encoding/pem" + "net" + "net/http" + "net/http/httptest" + "net/url" + "regexp" + "strings" + "testing" + + "github.com/containous/traefik/testhelpers" + "github.com/containous/traefik/types" + "github.com/stretchr/testify/require" +) + +const ( + rootCrt = `-----BEGIN CERTIFICATE----- +MIIDhjCCAm6gAwIBAgIJAIKZlW9a3VrYMA0GCSqGSIb3DQEBCwUAMFgxCzAJBgNV +BAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRlMREwDwYDVQQHDAhUb3Vsb3VzZTEh +MB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMB4XDTE4MDcxNzIwMzQz +OFoXDTE4MDgxNjIwMzQzOFowWDELMAkGA1UEBhMCRlIxEzARBgNVBAgMClNvbWUt +U3RhdGUxETAPBgNVBAcMCFRvdWxvdXNlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRn +aXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1P8GJ +H9LkIxIIqK9MyUpushnjmjwccpSMB3OecISKYLy62QDIcAw6NzGcSe8hMwciMJr+ +CdCjJlohybnaRI9hrJ3GPnI++UT/MMthf2IIcjmJxmD4k9L1fgs1V6zSTlo0+o0x +0gkAGlWvRkgA+3nt555ee84XQZuneKKeRRIlSA1ygycewFobZ/pGYijIEko+gYkV +sF3LnRGxNl673w+EQsvI7+z29T1nzjmM/xE7WlvnsrVd1/N61jAohLota0YTufwd +ioJZNryzuPejHBCiQRGMbJ7uEEZLiSCN6QiZEfqhS3AulykjgFXQQHn4zoVljSBR +UyLV0prIn5Scbks/AgMBAAGjUzBRMB0GA1UdDgQWBBTroRRnSgtkV+8dumtcftb/ +lwIkATAfBgNVHSMEGDAWgBTroRRnSgtkV+8dumtcftb/lwIkATAPBgNVHRMBAf8E +BTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAJ67U5cLa0ZFa/7zQQT4ldkY6YOEgR +0LNoTu51hc+ozaXSvF8YIBzkEpEnbGS3x4xodrwEBZjK2LFhNu/33gkCAuhmedgk +KwZrQM6lqRFGHGVOlkVz+QrJ2EsKYaO4SCUIwVjijXRLA7A30G5C/CIh66PsMgBY +6QHXVPEWm/v1d1Q/DfFfFzSOa1n1rIUw03qVJsxqSwfwYcegOF8YvS/eH4HUr2gF +cEujh6CCnylf35ExHa45atr3+xxbOVdNjobISkYADtbhAAn4KjLS4v8W6445vxxj +G5EIZLjOHyWg1sGaHaaAPkVpZQg8EKm21c4hrEEMfel60AMSSzad/a/V +-----END CERTIFICATE-----` + + minimalCert = `-----BEGIN CERTIFICATE----- +MIIDGTCCAgECCQCqLd75YLi2kDANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJG +UjETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UEBwwIVG91bG91c2UxITAfBgNV +BAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xODA3MTgwODI4MTZaFw0x +ODA4MTcwODI4MTZaMEUxCzAJBgNVBAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRl +MSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC/+frDMMTLQyXG34F68BPhQq0kzK4LIq9Y0/gl +FjySZNn1C0QDWA1ubVCAcA6yY204I9cxcQDPNrhC7JlS5QA8Y5rhIBrqQlzZizAi +Rj3NTrRjtGUtOScnHuJaWjLy03DWD+aMwb7q718xt5SEABmmUvLwQK+EjW2MeDwj +y8/UEIpvrRDmdhGaqv7IFpIDkcIF7FowJ/hwDvx3PMc+z/JWK0ovzpvgbx69AVbw +ZxCimeha65rOqVi+lEetD26le+WnOdYsdJ2IkmpPNTXGdfb15xuAc+gFXfMCh7Iw +3Ynl6dZtZM/Ok2kiA7/OsmVnRKkWrtBfGYkI9HcNGb3zrk6nAgMBAAEwDQYJKoZI +hvcNAQELBQADggEBAC/R+Yvhh1VUhcbK49olWsk/JKqfS3VIDQYZg1Eo+JCPbwgS +I1BSYVfMcGzuJTX6ua3m/AHzGF3Tap4GhF4tX12jeIx4R4utnjj7/YKkTvuEM2f4 +xT56YqI7zalGScIB0iMeyNz1QcimRl+M/49au8ow9hNX8C2tcA2cwd/9OIj/6T8q +SBRHc6ojvbqZSJCO0jziGDT1L3D+EDgTjED4nd77v/NRdP+egb0q3P0s4dnQ/5AV +aQlQADUn61j3ScbGJ4NSeZFFvsl38jeRi/MEzp0bGgNBcPj6JHi7qbbauZcZfQ05 +jECvgAY7Nfd9mZ1KtyNaW31is+kag7NsvjxU/kM= +-----END CERTIFICATE-----` + + completeCert = `Certificate: + Data: + Version: 3 (0x2) + Serial Number: 3 (0x3) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, ST=Some-State, L=Toulouse, O=Internet Widgits Pty Ltd + Validity + Not Before: Jul 18 08:00:16 2018 GMT + Not After : Jul 18 08:00:16 2019 GMT + Subject: C=FR, ST=SomeState, L=Toulouse, O=Cheese, CN=*.cheese.org + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:a6:1f:96:7c:c1:cc:b8:1c:b5:91:5d:b8:bf:70: + bc:f7:b8:04:4f:2a:42:de:ea:c5:c3:19:0b:03:04: + ec:ef:a1:24:25:de:ad:05:e7:26:ea:89:6c:59:60: + 10:18:0c:73:f1:bf:d3:cc:7b:ed:6b:9c:ea:1d:88: + e2:ee:14:81:d7:07:ee:87:95:3d:36:df:9c:38:b7: + 7b:1e:2b:51:9c:4a:1f:d0:cc:5b:af:5d:6c:5c:35: + 49:32:e4:01:5b:f9:8c:71:cf:62:48:5a:ea:b7:31: + 58:e2:c6:d0:5b:1c:50:b5:5c:6d:5a:6f:da:41:5e: + d5:4c:6e:1a:21:f3:40:f9:9e:52:76:50:25:3e:03: + 9b:87:19:48:5b:47:87:d3:67:c6:25:69:77:29:8e: + 56:97:45:d9:6f:64:a8:4e:ad:35:75:2e:fc:6a:2e: + 47:87:76:fc:4e:3e:44:e9:16:b2:c7:f0:23:98:13: + a2:df:15:23:cb:0c:3d:fd:48:5e:c7:2c:86:70:63: + 8b:c6:c8:89:17:52:d5:a7:8e:cb:4e:11:9d:69:8e: + 8e:59:cc:7e:a3:bd:a1:11:88:d7:cf:7b:8c:19:46: + 9c:1b:7a:c9:39:81:4c:58:08:1f:c7:ce:b0:0e:79: + 64:d3:11:72:65:e6:dd:bd:00:7f:22:30:46:9b:66: + 9c:b9 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + X509v3 Subject Alternative Name: + DNS:*.cheese.org, DNS:*.cheese.net, DNS:cheese.in, IP Address:10.0.1.0, IP Address:10.0.1.2, email:test@cheese.org, email:test@cheese.net + X509v3 Subject Key Identifier: + AB:6B:89:25:11:FC:5E:7B:D4:B0:F7:D4:B6:D9:EB:D0:30:93:E5:58 + Signature Algorithm: sha1WithRSAEncryption + ad:87:84:a0:88:a3:4c:d9:0a:c0:14:e4:2d:9a:1d:bb:57:b7: + 12:ef:3a:fb:8b:b2:ce:32:b8:04:e6:59:c8:4f:14:6a:b5:12: + 46:e9:c9:0a:11:64:ea:a1:86:20:96:0e:a7:40:e3:aa:e5:98: + 91:36:89:77:b6:b9:73:7e:1a:58:19:ae:d1:14:83:1e:c1:5f: + a5:a0:32:bb:52:68:b4:8d:a3:1d:b3:08:d7:45:6e:3b:87:64: + 7e:ef:46:e6:6f:d5:79:d7:1d:57:68:67:d8:18:39:61:5b:8b: + 1a:7f:88:da:0a:51:9b:3d:6c:5d:b1:cf:b7:e9:1e:06:65:8e: + 96:d3:61:96:f8:a2:61:f9:40:5e:fa:bc:76:b9:64:0e:6f:90: + 37:de:ac:6d:7f:36:84:35:19:88:8c:26:af:3e:c3:6a:1a:03: + ed:d7:90:89:ed:18:4c:9e:94:1f:d8:ae:6c:61:36:17:72:f9: + bb:de:0a:56:9a:79:b4:7d:4a:9d:cb:4a:7d:71:9f:38:e7:8d: + f0:87:24:21:0a:24:1f:82:9a:6b:67:ce:7d:af:cb:91:6b:8a: + de:e6:d8:6f:a1:37:b9:2d:d0:cb:e8:4e:f4:43:af:ad:90:13: + 7d:61:7a:ce:86:48:fc:00:8c:37:fb:e0:31:6b:e2:18:ad:fd: + 1e:df:08:db +-----BEGIN CERTIFICATE----- +MIIDvTCCAqWgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJGUjET +MBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UEBwwIVG91bG91c2UxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xODA3MTgwODAwMTZaFw0xOTA3 +MTgwODAwMTZaMFwxCzAJBgNVBAYTAkZSMRIwEAYDVQQIDAlTb21lU3RhdGUxETAP +BgNVBAcMCFRvdWxvdXNlMQ8wDQYDVQQKDAZDaGVlc2UxFTATBgNVBAMMDCouY2hl +ZXNlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKYflnzBzLgc +tZFduL9wvPe4BE8qQt7qxcMZCwME7O+hJCXerQXnJuqJbFlgEBgMc/G/08x77Wuc +6h2I4u4UgdcH7oeVPTbfnDi3ex4rUZxKH9DMW69dbFw1STLkAVv5jHHPYkha6rcx +WOLG0FscULVcbVpv2kFe1UxuGiHzQPmeUnZQJT4Dm4cZSFtHh9NnxiVpdymOVpdF +2W9kqE6tNXUu/GouR4d2/E4+ROkWssfwI5gTot8VI8sMPf1IXscshnBji8bIiRdS +1aeOy04RnWmOjlnMfqO9oRGI1897jBlGnBt6yTmBTFgIH8fOsA55ZNMRcmXm3b0A +fyIwRptmnLkCAwEAAaOBjTCBijAJBgNVHRMEAjAAMF4GA1UdEQRXMFWCDCouY2hl +ZXNlLm9yZ4IMKi5jaGVlc2UubmV0ggljaGVlc2UuaW6HBAoAAQCHBAoAAQKBD3Rl +c3RAY2hlZXNlLm9yZ4EPdGVzdEBjaGVlc2UubmV0MB0GA1UdDgQWBBSra4klEfxe +e9Sw99S22evQMJPlWDANBgkqhkiG9w0BAQUFAAOCAQEArYeEoIijTNkKwBTkLZod +u1e3Eu86+4uyzjK4BOZZyE8UarUSRunJChFk6qGGIJYOp0DjquWYkTaJd7a5c34a +WBmu0RSDHsFfpaAyu1JotI2jHbMI10VuO4dkfu9G5m/VedcdV2hn2Bg5YVuLGn+I +2gpRmz1sXbHPt+keBmWOltNhlviiYflAXvq8drlkDm+QN96sbX82hDUZiIwmrz7D +ahoD7deQie0YTJ6UH9iubGE2F3L5u94KVpp5tH1KnctKfXGfOOeN8IckIQokH4Ka +a2fOfa/LkWuK3ubYb6E3uS3Qy+hO9EOvrZATfWF6zoZI/ACMN/vgMWviGK39Ht8I +2w== +-----END CERTIFICATE----- +` +) + +func getCleanCertContents(certContents []string) string { + var re = regexp.MustCompile("-----BEGIN CERTIFICATE-----(?s)(.*)") + + var cleanedCertContent []string + for _, certContent := range certContents { + cert := re.FindString(string(certContent)) + cleanedCertContent = append(cleanedCertContent, sanitize([]byte(cert))) + } + + return strings.Join(cleanedCertContent, ",") +} + +func getCertificate(certContent string) *x509.Certificate { + roots := x509.NewCertPool() + ok := roots.AppendCertsFromPEM([]byte(rootCrt)) + if !ok { + panic("failed to parse root certificate") + } + + block, _ := pem.Decode([]byte(certContent)) + if block == nil { + panic("failed to parse certificate PEM") + } + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + panic("failed to parse certificate: " + err.Error()) + } + + return cert +} + +func buildTLSWith(certContents []string) *tls.ConnectionState { + var peerCertificates []*x509.Certificate + + for _, certContent := range certContents { + peerCertificates = append(peerCertificates, getCertificate(certContent)) + } + + return &tls.ConnectionState{PeerCertificates: peerCertificates} +} + +var myPassTLSClientCustomHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("bar")) +}) + +func getExpectedSanitized(s string) string { + return url.QueryEscape(strings.Replace(s, "\n", "", -1)) +} + +func TestSanitize(t *testing.T) { + testCases := []struct { + desc string + toSanitize []byte + expected string + }{ + { + desc: "Empty", + }, + { + desc: "With a minimal cert", + toSanitize: []byte(minimalCert), + expected: getExpectedSanitized(`MIIDGTCCAgECCQCqLd75YLi2kDANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJG +UjETMBEGA1UECAwKU29tZS1TdGF0ZTERMA8GA1UEBwwIVG91bG91c2UxITAfBgNV +BAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0xODA3MTgwODI4MTZaFw0x +ODA4MTcwODI4MTZaMEUxCzAJBgNVBAYTAkZSMRMwEQYDVQQIDApTb21lLVN0YXRl +MSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQC/+frDMMTLQyXG34F68BPhQq0kzK4LIq9Y0/gl +FjySZNn1C0QDWA1ubVCAcA6yY204I9cxcQDPNrhC7JlS5QA8Y5rhIBrqQlzZizAi +Rj3NTrRjtGUtOScnHuJaWjLy03DWD+aMwb7q718xt5SEABmmUvLwQK+EjW2MeDwj +y8/UEIpvrRDmdhGaqv7IFpIDkcIF7FowJ/hwDvx3PMc+z/JWK0ovzpvgbx69AVbw +ZxCimeha65rOqVi+lEetD26le+WnOdYsdJ2IkmpPNTXGdfb15xuAc+gFXfMCh7Iw +3Ynl6dZtZM/Ok2kiA7/OsmVnRKkWrtBfGYkI9HcNGb3zrk6nAgMBAAEwDQYJKoZI +hvcNAQELBQADggEBAC/R+Yvhh1VUhcbK49olWsk/JKqfS3VIDQYZg1Eo+JCPbwgS +I1BSYVfMcGzuJTX6ua3m/AHzGF3Tap4GhF4tX12jeIx4R4utnjj7/YKkTvuEM2f4 +xT56YqI7zalGScIB0iMeyNz1QcimRl+M/49au8ow9hNX8C2tcA2cwd/9OIj/6T8q +SBRHc6ojvbqZSJCO0jziGDT1L3D+EDgTjED4nd77v/NRdP+egb0q3P0s4dnQ/5AV +aQlQADUn61j3ScbGJ4NSeZFFvsl38jeRi/MEzp0bGgNBcPj6JHi7qbbauZcZfQ05 +jECvgAY7Nfd9mZ1KtyNaW31is+kag7NsvjxU/kM=`), + }, + } + + for _, test := range testCases { + test := test + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + require.Equal(t, test.expected, sanitize(test.toSanitize), "The sanitized certificates should be equal") + }) + } + +} + +func TestTlsClientheadersWithPEM(t *testing.T) { + testCases := []struct { + desc string + certContents []string // set the request TLS attribute if defined + tlsClientCertHeaders *types.TLSClientHeaders + expectedHeader string + }{ + { + desc: "No TLS, no option", + }, + { + desc: "TLS, no option", + certContents: []string{minimalCert}, + }, + { + desc: "No TLS, with pem option true", + tlsClientCertHeaders: &types.TLSClientHeaders{PEM: true}, + }, + { + desc: "TLS with simple certificate, with pem option true", + certContents: []string{minimalCert}, + tlsClientCertHeaders: &types.TLSClientHeaders{PEM: true}, + expectedHeader: getCleanCertContents([]string{minimalCert}), + }, + { + desc: "TLS with complete certificate, with pem option true", + certContents: []string{completeCert}, + tlsClientCertHeaders: &types.TLSClientHeaders{PEM: true}, + expectedHeader: getCleanCertContents([]string{completeCert}), + }, + { + desc: "TLS with two certificate, with pem option true", + certContents: []string{minimalCert, completeCert}, + tlsClientCertHeaders: &types.TLSClientHeaders{PEM: true}, + expectedHeader: getCleanCertContents([]string{minimalCert, completeCert}), + }, + } + + for _, test := range testCases { + tlsClientHeaders := NewTLSClientHeaders(&types.Frontend{PassTLSClientCert: test.tlsClientCertHeaders}) + + res := httptest.NewRecorder() + req := testhelpers.MustNewRequest(http.MethodGet, "http://example.com/foo", nil) + + if test.certContents != nil && len(test.certContents) > 0 { + req.TLS = buildTLSWith(test.certContents) + } + + tlsClientHeaders.ServeHTTP(res, req, myPassTLSClientCustomHandler) + + test := test + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + require.Equal(t, http.StatusOK, res.Code, "Http Status should be OK") + require.Equal(t, "bar", res.Body.String(), "Should be the expected body") + + if test.expectedHeader != "" { + require.Equal(t, getCleanCertContents(test.certContents), req.Header.Get(xForwardedTLSClientCert), "The request header should contain the cleaned certificate") + } else { + require.Empty(t, req.Header.Get(xForwardedTLSClientCert)) + } + require.Empty(t, res.Header().Get(xForwardedTLSClientCert), "The response header should be always empty") + }) + } + +} + +func TestGetSans(t *testing.T) { + urlFoo, err := url.Parse("my.foo.com") + require.NoError(t, err) + urlBar, err := url.Parse("my.bar.com") + require.NoError(t, err) + + testCases := []struct { + desc string + cert *x509.Certificate // set the request TLS attribute if defined + expected []string + }{ + { + desc: "With nil", + }, + { + desc: "Certificate without Sans", + cert: &x509.Certificate{}, + }, + { + desc: "Certificate with all Sans", + cert: &x509.Certificate{ + DNSNames: []string{"foo", "bar"}, + EmailAddresses: []string{"test@test.com", "test2@test.com"}, + IPAddresses: []net.IP{net.IPv4(10, 0, 0, 1), net.IPv4(10, 0, 0, 2)}, + URIs: []*url.URL{urlFoo, urlBar}, + }, + expected: []string{"foo", "bar", "test@test.com", "test2@test.com", "10.0.0.1", "10.0.0.2", urlFoo.String(), urlBar.String()}, + }, + } + + for _, test := range testCases { + sans := getSANs(test.cert) + test := test + + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + if len(test.expected) > 0 { + for i, expected := range test.expected { + require.Equal(t, expected, sans[i]) + } + } else { + require.Empty(t, sans) + } + }) + } + +} + +func TestTlsClientheadersWithCertInfos(t *testing.T) { + minimalCertAllInfos := `Subject="C=FR,ST=Some-State,O=Internet Widgits Pty Ltd",NB=1531902496,NA=1534494496,SAN=` + completeCertAllInfos := `Subject="C=FR,ST=SomeState,L=Toulouse,O=Cheese,CN=*.cheese.org",NB=1531900816,NA=1563436816,SAN=*.cheese.org,*.cheese.net,cheese.in,test@cheese.org,test@cheese.net,10.0.1.0,10.0.1.2` + + testCases := []struct { + desc string + certContents []string // set the request TLS attribute if defined + tlsClientCertHeaders *types.TLSClientHeaders + expectedHeader string + }{ + { + desc: "No TLS, no option", + }, + { + desc: "TLS, no option", + certContents: []string{minimalCert}, + }, + { + desc: "No TLS, with pem option true", + tlsClientCertHeaders: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Organization: true, + Locality: true, + Province: true, + Country: true, + SerialNumber: true, + }, + }, + }, + }, + { + desc: "No TLS, with pem option true with no flag", + tlsClientCertHeaders: &types.TLSClientHeaders{ + PEM: false, + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{}, + }, + }, + }, + { + desc: "TLS with simple certificate, with all infos", + certContents: []string{minimalCert}, + tlsClientCertHeaders: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + NotAfter: true, + NotBefore: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Organization: true, + Locality: true, + Province: true, + Country: true, + SerialNumber: true, + }, + Sans: true, + }, + }, + expectedHeader: url.QueryEscape(minimalCertAllInfos), + }, + { + desc: "TLS with simple certificate, with some infos", + certContents: []string{minimalCert}, + tlsClientCertHeaders: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + Organization: true, + }, + Sans: true, + }, + }, + expectedHeader: url.QueryEscape(`Subject="O=Internet Widgits Pty Ltd",NA=1534494496,SAN=`), + }, + { + desc: "TLS with complete certificate, with all infos", + certContents: []string{completeCert}, + tlsClientCertHeaders: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + NotAfter: true, + NotBefore: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Organization: true, + Locality: true, + Province: true, + Country: true, + SerialNumber: true, + }, + Sans: true, + }, + }, + expectedHeader: url.QueryEscape(completeCertAllInfos), + }, + { + desc: "TLS with 2 certificates, with all infos", + certContents: []string{minimalCert, completeCert}, + tlsClientCertHeaders: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + NotAfter: true, + NotBefore: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Organization: true, + Locality: true, + Province: true, + Country: true, + SerialNumber: true, + }, + Sans: true, + }, + }, + expectedHeader: url.QueryEscape(strings.Join([]string{minimalCertAllInfos, completeCertAllInfos}, ";")), + }, + } + + for _, test := range testCases { + tlsClientHeaders := NewTLSClientHeaders(&types.Frontend{PassTLSClientCert: test.tlsClientCertHeaders}) + + res := httptest.NewRecorder() + req := testhelpers.MustNewRequest(http.MethodGet, "http://example.com/foo", nil) + + if test.certContents != nil && len(test.certContents) > 0 { + req.TLS = buildTLSWith(test.certContents) + } + + tlsClientHeaders.ServeHTTP(res, req, myPassTLSClientCustomHandler) + + test := test + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + require.Equal(t, http.StatusOK, res.Code, "Http Status should be OK") + require.Equal(t, "bar", res.Body.String(), "Should be the expected body") + + if test.expectedHeader != "" { + require.Equal(t, test.expectedHeader, req.Header.Get(xForwardedTLSClientCertInfos), "The request header should contain the cleaned certificate") + } else { + require.Empty(t, req.Header.Get(xForwardedTLSClientCertInfos)) + } + require.Empty(t, res.Header().Get(xForwardedTLSClientCertInfos), "The response header should be always empty") + }) + } + +} + +func TestNewTLSClientHeadersFromStruct(t *testing.T) { + testCases := []struct { + desc string + frontend *types.Frontend + expected *TLSClientHeaders + }{ + { + desc: "Without frontend", + }, + { + desc: "frontend without the option", + frontend: &types.Frontend{}, + expected: &TLSClientHeaders{}, + }, + { + desc: "frontend with the pem set false", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: false, + }, + }, + expected: &TLSClientHeaders{PEM: false}, + }, + { + desc: "frontend with the pem set true", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + }, + }, + expected: &TLSClientHeaders{PEM: true}, + }, + { + desc: "frontend with the Infos with no flag", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + NotAfter: false, + NotBefore: false, + Sans: false, + }, + }, + }, + expected: &TLSClientHeaders{ + PEM: false, + Infos: &TLSClientCertificateInfos{}, + }, + }, + { + desc: "frontend with the Infos basic", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + NotAfter: true, + NotBefore: true, + Sans: true, + }, + }, + }, + expected: &TLSClientHeaders{ + PEM: false, + Infos: &TLSClientCertificateInfos{ + NotBefore: true, + NotAfter: true, + Sans: true, + }, + }, + }, + { + desc: "frontend with the Infos NotAfter", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + NotAfter: true, + }, + }, + }, + expected: &TLSClientHeaders{ + PEM: false, + Infos: &TLSClientCertificateInfos{ + NotAfter: true, + }, + }, + }, + { + desc: "frontend with the Infos NotBefore", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + }, + }, + }, + expected: &TLSClientHeaders{ + PEM: false, + Infos: &TLSClientCertificateInfos{ + NotBefore: true, + }, + }, + }, + { + desc: "frontend with the Infos Sans", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Sans: true, + }, + }, + }, + expected: &TLSClientHeaders{ + PEM: false, + Infos: &TLSClientCertificateInfos{ + Sans: true, + }, + }, + }, + { + desc: "frontend with the Infos Subject Organization", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{ + Organization: true, + }, + }, + }, + }, + expected: &TLSClientHeaders{ + PEM: false, + Infos: &TLSClientCertificateInfos{ + Subject: &TLSCLientCertificateSubjectInfos{ + Organization: true, + }, + }, + }, + }, + { + desc: "frontend with the Infos Subject Country", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{ + Country: true, + }, + }, + }, + }, + expected: &TLSClientHeaders{ + PEM: false, + Infos: &TLSClientCertificateInfos{ + Subject: &TLSCLientCertificateSubjectInfos{ + Country: true, + }, + }, + }, + }, + { + desc: "frontend with the Infos Subject SerialNumber", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{ + SerialNumber: true, + }, + }, + }, + }, + expected: &TLSClientHeaders{ + PEM: false, + Infos: &TLSClientCertificateInfos{ + Subject: &TLSCLientCertificateSubjectInfos{ + SerialNumber: true, + }, + }, + }, + }, + { + desc: "frontend with the Infos Subject Province", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{ + Province: true, + }, + }, + }, + }, + expected: &TLSClientHeaders{ + PEM: false, + Infos: &TLSClientCertificateInfos{ + Subject: &TLSCLientCertificateSubjectInfos{ + Province: true, + }, + }, + }, + }, + { + desc: "frontend with the Infos Subject Locality", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{ + Locality: true, + }, + }, + }, + }, + expected: &TLSClientHeaders{ + PEM: false, + Infos: &TLSClientCertificateInfos{ + Subject: &TLSCLientCertificateSubjectInfos{ + Locality: true, + }, + }, + }, + }, + { + desc: "frontend with the Infos Subject CommonName", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + }, + }, + }, + }, + expected: &TLSClientHeaders{ + PEM: false, + Infos: &TLSClientCertificateInfos{ + Subject: &TLSCLientCertificateSubjectInfos{ + CommonName: true, + }, + }, + }, + }, + { + desc: "frontend with the Infos NotBefore", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Sans: true, + }, + }, + }, + expected: &TLSClientHeaders{ + PEM: false, + Infos: &TLSClientCertificateInfos{ + Sans: true, + }, + }, + }, + { + desc: "frontend with the Infos all", + frontend: &types.Frontend{ + PassTLSClientCert: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + NotAfter: true, + NotBefore: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + Sans: true, + }, + }, + }, + expected: &TLSClientHeaders{ + PEM: false, + Infos: &TLSClientCertificateInfos{ + NotBefore: true, + NotAfter: true, + Sans: true, + Subject: &TLSCLientCertificateSubjectInfos{ + Province: true, + Organization: true, + Locality: true, + Country: true, + CommonName: true, + SerialNumber: true, + }, + }}, + }, + } + + for _, test := range testCases { + test := test + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + require.Equal(t, test.expected, NewTLSClientHeaders(test.frontend)) + }) + } + +} diff --git a/provider/consulcatalog/config.go b/provider/consulcatalog/config.go index 94020e40f..f148a73a0 100644 --- a/provider/consulcatalog/config.go +++ b/provider/consulcatalog/config.go @@ -44,6 +44,7 @@ func (p *Provider) buildConfigurationV2(catalog []catalogUpdate) *types.Configur "getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority), "getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader), "getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert), + "getPassTLSClientCert": label.GetTLSClientCert, "getWhiteList": label.GetWhiteList, "getRedirect": label.GetRedirect, "getErrorPages": label.GetErrorPages, diff --git a/provider/consulcatalog/config_test.go b/provider/consulcatalog/config_test.go index 11d7f440c..f45a655fe 100644 --- a/provider/consulcatalog/config_test.go +++ b/provider/consulcatalog/config_test.go @@ -319,82 +319,6 @@ func TestProviderBuildConfiguration(t *testing.T) { }, }, }, - { - desc: "Should build config with a forward auth", - nodes: []catalogUpdate{ - { - Service: &serviceUpdate{ - ServiceName: "test", - Attributes: []string{ - "random.foo=bar", - label.TraefikFrontendAuthForwardAddress + "=auth.server", - label.TraefikFrontendAuthForwardTrustForwardHeader + "=true", - label.TraefikFrontendAuthForwardTLSCa + "=ca.crt", - label.TraefikFrontendAuthForwardTLSCaOptional + "=true", - label.TraefikFrontendAuthForwardTLSCert + "=server.crt", - label.TraefikFrontendAuthForwardTLSKey + "=server.key", - label.TraefikFrontendAuthForwardTLSInsecureSkipVerify + "=true", - label.TraefikFrontendAuthHeaderField + "=X-WebAuth-User", - }, - }, - Nodes: []*api.ServiceEntry{ - { - Service: &api.AgentService{ - Service: "test", - Address: "127.0.0.1", - Port: 80, - Tags: []string{ - "random.foo=bar", - label.Prefix + "backend.weight=42", // Deprecated label - label.TraefikFrontendPassHostHeader + "=true", - label.TraefikProtocol + "=https", - }, - }, - Node: &api.Node{ - Node: "localhost", - Address: "127.0.0.1", - }, - }, - }, - }, - }, - expectedFrontends: map[string]*types.Frontend{ - "frontend-test": { - Backend: "backend-test", - PassHostHeader: true, - Routes: map[string]types.Route{ - "route-host-test": { - Rule: "Host:test.localhost", - }, - }, - Auth: &types.Auth{ - HeaderField: "X-WebAuth-User", - Forward: &types.Forward{ - Address: "auth.server", - TrustForwardHeader: true, - TLS: &types.ClientTLS{ - CA: "ca.crt", - CAOptional: true, - InsecureSkipVerify: true, - Cert: "server.crt", - Key: "server.key", - }, - }, - }, - EntryPoints: []string{}, - }, - }, - expectedBackends: map[string]*types.Backend{ - "backend-test": { - Servers: map[string]types.Server{ - "test-0-us4-27hAOu2ARV7nNrmv6GoKlcA": { - URL: "https://127.0.0.1:80", - Weight: 42, - }, - }, - }, - }, - }, { desc: "when all labels are set", nodes: []catalogUpdate{ @@ -423,6 +347,17 @@ func TestProviderBuildConfiguration(t *testing.T) { label.TraefikBackendBufferingMemRequestBodyBytes + "=2097152", label.TraefikBackendBufferingRetryExpression + "=IsNetworkError() && Attempts() <= 2", + label.TraefikFrontendPassTLSClientCertPem + "=true", + label.TraefikFrontendPassTLSClientCertInfosNotBefore + "=true", + label.TraefikFrontendPassTLSClientCertInfosNotAfter + "=true", + label.TraefikFrontendPassTLSClientCertInfosSans + "=true", + label.TraefikFrontendPassTLSClientCertInfosSubjectCommonName + "=true", + label.TraefikFrontendPassTLSClientCertInfosSubjectCountry + "=true", + label.TraefikFrontendPassTLSClientCertInfosSubjectLocality + "=true", + label.TraefikFrontendPassTLSClientCertInfosSubjectOrganization + "=true", + label.TraefikFrontendPassTLSClientCertInfosSubjectProvince + "=true", + label.TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber + "=true", + label.TraefikFrontendAuthBasic + "=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", label.TraefikFrontendAuthBasicRemoveHeader + "=true", label.TraefikFrontendAuthBasicUsers + "=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", @@ -539,6 +474,22 @@ func TestProviderBuildConfiguration(t *testing.T) { PassHostHeader: true, PassTLSCert: true, Priority: 666, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, Auth: &types.Auth{ HeaderField: "X-WebAuth-User", Basic: &types.Basic{ diff --git a/provider/docker/config.go b/provider/docker/config.go index 546e34c1e..0e0713d6b 100644 --- a/provider/docker/config.go +++ b/provider/docker/config.go @@ -42,19 +42,20 @@ func (p *Provider) buildConfigurationV2(containersInspected []dockerData) *types "getLoadBalancer": label.GetLoadBalancer, // Frontend functions - "getBackendName": getBackendName, - "getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority), - "getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader), - "getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert), - "getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints), - "getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated - "getAuth": label.GetAuth, - "getFrontendRule": p.getFrontendRule, - "getRedirect": label.GetRedirect, - "getErrorPages": label.GetErrorPages, - "getRateLimit": label.GetRateLimit, - "getHeaders": label.GetHeaders, - "getWhiteList": label.GetWhiteList, + "getBackendName": getBackendName, + "getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority), + "getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader), + "getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert), + "getPassTLSClientCert": label.GetTLSClientCert, + "getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints), + "getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated + "getAuth": label.GetAuth, + "getFrontendRule": p.getFrontendRule, + "getRedirect": label.GetRedirect, + "getErrorPages": label.GetErrorPages, + "getRateLimit": label.GetRateLimit, + "getHeaders": label.GetHeaders, + "getWhiteList": label.GetWhiteList, } // filter containers diff --git a/provider/docker/config_container_docker_test.go b/provider/docker/config_container_docker_test.go index 6e340c74a..89aa7d910 100644 --- a/provider/docker/config_container_docker_test.go +++ b/provider/docker/config_container_docker_test.go @@ -111,6 +111,69 @@ func TestDockerBuildConfiguration(t *testing.T) { }, }, }, + { + desc: "when pass tls client certificate", + containers: []docker.ContainerJSON{ + containerJSON( + name("test"), + labels(map[string]string{ + label.TraefikFrontendPassTLSClientCertPem: "true", + label.TraefikFrontendPassTLSClientCertInfosNotBefore: "true", + label.TraefikFrontendPassTLSClientCertInfosNotAfter: "true", + label.TraefikFrontendPassTLSClientCertInfosSans: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectCommonName: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectCountry: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectLocality: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectOrganization: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectProvince: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber: "true", + }), + ports(nat.PortMap{ + "80/tcp": {}, + }), + withNetwork("bridge", ipv4("127.0.0.1")), + ), + }, + expectedFrontends: map[string]*types.Frontend{ + "frontend-Host-test-docker-localhost-0": { + Backend: "backend-test", + PassHostHeader: true, + EntryPoints: []string{}, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, + Routes: map[string]types.Route{ + "route-frontend-Host-test-docker-localhost-0": { + Rule: "Host:test.docker.localhost", + }, + }, + }, + }, + expectedBackends: map[string]*types.Backend{ + "backend-test": { + Servers: map[string]types.Server{ + "server-test-842895ca2aca17f6ee36ddb2f621194d": { + URL: "http://127.0.0.1:80", + Weight: label.DefaultWeight, + }, + }, + CircuitBreaker: nil, + }, + }, + }, { desc: "when frontend basic auth backward compatibility", containers: []docker.ContainerJSON{ @@ -388,6 +451,17 @@ func TestDockerBuildConfiguration(t *testing.T) { label.TraefikBackendBufferingMemRequestBodyBytes: "2097152", label.TraefikBackendBufferingRetryExpression: "IsNetworkError() && Attempts() <= 2", + label.TraefikFrontendPassTLSClientCertPem: "true", + label.TraefikFrontendPassTLSClientCertInfosNotBefore: "true", + label.TraefikFrontendPassTLSClientCertInfosNotAfter: "true", + label.TraefikFrontendPassTLSClientCertInfosSans: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectCommonName: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectCountry: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectLocality: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectOrganization: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectProvince: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber: "true", + label.TraefikFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", label.TraefikFrontendAuthBasicRemoveHeader: "true", label.TraefikFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", @@ -475,6 +549,22 @@ func TestDockerBuildConfiguration(t *testing.T) { PassHostHeader: true, PassTLSCert: true, Priority: 666, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, Auth: &types.Auth{ HeaderField: "X-WebAuth-User", Basic: &types.Basic{ diff --git a/provider/docker/config_container_swarm_test.go b/provider/docker/config_container_swarm_test.go index a8cbdca4e..187e5aa41 100644 --- a/provider/docker/config_container_swarm_test.go +++ b/provider/docker/config_container_swarm_test.go @@ -93,6 +93,72 @@ func TestSwarmBuildConfiguration(t *testing.T) { }, }, }, + { + desc: "when pass tls client cert configuration", + services: []swarm.Service{ + swarmService( + serviceName("test"), + serviceLabels(map[string]string{ + label.TraefikPort: "80", + label.TraefikFrontendPassTLSClientCertPem: "true", + label.TraefikFrontendPassTLSClientCertInfosNotBefore: "true", + label.TraefikFrontendPassTLSClientCertInfosNotAfter: "true", + label.TraefikFrontendPassTLSClientCertInfosSans: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectCommonName: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectCountry: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectLocality: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectOrganization: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectProvince: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber: "true", + }), + withEndpointSpec(modeVIP), + withEndpoint(virtualIP("1", "127.0.0.1/24")), + ), + }, + expectedFrontends: map[string]*types.Frontend{ + "frontend-Host-test-docker-localhost-0": { + Backend: "backend-test", + PassHostHeader: true, + EntryPoints: []string{}, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, + Routes: map[string]types.Route{ + "route-frontend-Host-test-docker-localhost-0": { + Rule: "Host:test.docker.localhost", + }, + }, + }, + }, + expectedBackends: map[string]*types.Backend{ + "backend-test": { + Servers: map[string]types.Server{ + "server-test-842895ca2aca17f6ee36ddb2f621194d": { + URL: "http://127.0.0.1:80", + Weight: label.DefaultWeight, + }, + }, + }, + }, + networks: map[string]*docker.NetworkResource{ + "1": { + Name: "foo", + }, + }, + }, { desc: "when frontend basic auth configuration", services: []swarm.Service{ diff --git a/provider/docker/config_segment_test.go b/provider/docker/config_segment_test.go index 1452b5fb3..5a0340c66 100644 --- a/provider/docker/config_segment_test.go +++ b/provider/docker/config_segment_test.go @@ -65,6 +65,71 @@ func TestSegmentBuildConfiguration(t *testing.T) { }, }, }, + { + desc: "pass tls client cert", + containers: []docker.ContainerJSON{ + containerJSON( + name("foo"), + labels(map[string]string{ + "traefik.sauternes.port": "2503", + "traefik.sauternes.frontend.entryPoints": "http,https", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertPem: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosNotAfter: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosNotBefore: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSans: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectCommonName: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectCountry: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectLocality: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectOrganization: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectProvince: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectSerialNumber: "true", + }), + ports(nat.PortMap{ + "80/tcp": {}, + }), + withNetwork("bridge", ipv4("127.0.0.1")), + ), + }, + expectedFrontends: map[string]*types.Frontend{ + "frontend-sauternes-foo-sauternes": { + Backend: "backend-foo-sauternes", + PassHostHeader: true, + EntryPoints: []string{"http", "https"}, + Routes: map[string]types.Route{ + "route-frontend-sauternes-foo-sauternes": { + Rule: "Host:foo.docker.localhost", + }, + }, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, + }, + }, + expectedBackends: map[string]*types.Backend{ + "backend-foo-sauternes": { + Servers: map[string]types.Server{ + "server-foo-863563a2e23c95502862016417ee95ea": { + URL: "http://127.0.0.1:2503", + Weight: label.DefaultWeight, + }, + }, + CircuitBreaker: nil, + }, + }, + }, { desc: "auth basic", containers: []docker.ContainerJSON{ @@ -286,6 +351,17 @@ func TestSegmentBuildConfiguration(t *testing.T) { label.Prefix + "sauternes." + label.SuffixProtocol: "https", label.Prefix + "sauternes." + label.SuffixWeight: "12", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertPem: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosNotAfter: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosNotBefore: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSans: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectCommonName: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectCountry: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectLocality: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectOrganization: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectProvince: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectSerialNumber: "true", + label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicRemoveHeader: "true", label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsersFile: ".htpasswd", @@ -367,6 +443,22 @@ func TestSegmentBuildConfiguration(t *testing.T) { PassHostHeader: true, PassTLSCert: true, Priority: 666, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, Auth: &types.Auth{ HeaderField: "X-WebAuth-User", Basic: &types.Basic{ diff --git a/provider/ecs/config.go b/provider/ecs/config.go index c22ea3f45..fcc0ab1ee 100644 --- a/provider/ecs/config.go +++ b/provider/ecs/config.go @@ -31,20 +31,21 @@ func (p *Provider) buildConfigurationV2(instances []ecsInstance) (*types.Configu "getServers": getServers, // Frontend functions - "filterFrontends": filterFrontends, - "getFrontendRule": p.getFrontendRule, - "getFrontendName": p.getFrontendName, - "getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader), - "getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert), - "getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority), - "getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated - "getAuth": label.GetAuth, - "getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints), - "getRedirect": label.GetRedirect, - "getErrorPages": label.GetErrorPages, - "getRateLimit": label.GetRateLimit, - "getHeaders": label.GetHeaders, - "getWhiteList": label.GetWhiteList, + "filterFrontends": filterFrontends, + "getFrontendRule": p.getFrontendRule, + "getFrontendName": p.getFrontendName, + "getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader), + "getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert), + "getPassTLSClientCert": label.GetTLSClientCert, + "getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority), + "getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated + "getAuth": label.GetAuth, + "getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints), + "getRedirect": label.GetRedirect, + "getErrorPages": label.GetErrorPages, + "getRateLimit": label.GetRateLimit, + "getHeaders": label.GetHeaders, + "getWhiteList": label.GetWhiteList, } services := make(map[string][]ecsInstance) diff --git a/provider/ecs/config_segment_test.go b/provider/ecs/config_segment_test.go index bd6efa29a..cf08747b1 100644 --- a/provider/ecs/config_segment_test.go +++ b/provider/ecs/config_segment_test.go @@ -326,6 +326,17 @@ func TestSegmentBuildConfiguration(t *testing.T) { label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTLSInsecureSkipVerify: "true", label.Prefix + "sauternes." + label.SuffixFrontendAuthHeaderField: "X-WebAuth-User", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertPem: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosNotBefore: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosNotAfter: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSans: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectCommonName: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectCountry: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectLocality: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectOrganization: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectProvince: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectSerialNumber: "true", + label.Prefix + "sauternes." + label.SuffixFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", label.Prefix + "sauternes." + label.SuffixFrontendEntryPoints: "http,https", label.Prefix + "sauternes." + label.SuffixFrontendPassHostHeader: "true", @@ -396,6 +407,22 @@ func TestSegmentBuildConfiguration(t *testing.T) { PassHostHeader: true, PassTLSCert: true, Priority: 666, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, Auth: &types.Auth{ HeaderField: "X-WebAuth-User", Basic: &types.Basic{ diff --git a/provider/ecs/config_test.go b/provider/ecs/config_test.go index 0d9ff28a6..0aa7e2ce6 100644 --- a/provider/ecs/config_test.go +++ b/provider/ecs/config_test.go @@ -357,6 +357,17 @@ func TestBuildConfiguration(t *testing.T) { label.TraefikBackendBufferingMemRequestBodyBytes: aws.String("2097152"), label.TraefikBackendBufferingRetryExpression: aws.String("IsNetworkError() && Attempts() <= 2"), + label.TraefikFrontendPassTLSClientCertPem: aws.String("true"), + label.TraefikFrontendPassTLSClientCertInfosNotBefore: aws.String("true"), + label.TraefikFrontendPassTLSClientCertInfosNotAfter: aws.String("true"), + label.TraefikFrontendPassTLSClientCertInfosSans: aws.String("true"), + label.TraefikFrontendPassTLSClientCertInfosSubjectCommonName: aws.String("true"), + label.TraefikFrontendPassTLSClientCertInfosSubjectCountry: aws.String("true"), + label.TraefikFrontendPassTLSClientCertInfosSubjectLocality: aws.String("true"), + label.TraefikFrontendPassTLSClientCertInfosSubjectOrganization: aws.String("true"), + label.TraefikFrontendPassTLSClientCertInfosSubjectProvince: aws.String("true"), + label.TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber: aws.String("true"), + label.TraefikFrontendAuthBasic: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"), label.TraefikFrontendAuthBasicRemoveHeader: aws.String("true"), label.TraefikFrontendAuthBasicUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"), @@ -490,6 +501,22 @@ func TestBuildConfiguration(t *testing.T) { PassHostHeader: true, PassTLSCert: true, Priority: 666, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, Auth: &types.Auth{ HeaderField: "X-WebAuth-User", Basic: &types.Basic{ diff --git a/provider/kv/keynames.go b/provider/kv/keynames.go index 27c1bdb4e..f021e1eef 100644 --- a/provider/kv/keynames.go +++ b/provider/kv/keynames.go @@ -25,14 +25,27 @@ const ( pathBackendBufferingMemRequestBodyBytes = pathBackendBuffering + "memrequestbodybytes" pathBackendBufferingRetryExpression = pathBackendBuffering + "retryexpression" - pathFrontends = "/frontends/" - pathFrontendBackend = "/backend" - pathFrontendPriority = "/priority" - pathFrontendPassHostHeaderDeprecated = "/passHostHeader" // Deprecated - pathFrontendPassHostHeader = "/passhostheader" - pathFrontendPassTLSCert = "/passtlscert" - pathFrontendWhiteListSourceRange = "/whitelist/sourcerange" - pathFrontendWhiteListUseXForwardedFor = "/whitelist/usexforwardedfor" + pathFrontends = "/frontends/" + pathFrontendBackend = "/backend" + pathFrontendPriority = "/priority" + pathFrontendPassHostHeaderDeprecated = "/passHostHeader" // Deprecated + pathFrontendPassHostHeader = "/passhostheader" + pathFrontendPassTLSClientCert = "/passTLSClientCert" + pathFrontendPassTLSClientCertPem = pathFrontendPassTLSClientCert + "/pem" + pathFrontendPassTLSClientCertInfos = pathFrontendPassTLSClientCert + "/infos" + pathFrontendPassTLSClientCertInfosNotAfter = pathFrontendPassTLSClientCertInfos + "/notAfter" + pathFrontendPassTLSClientCertInfosNotBefore = pathFrontendPassTLSClientCertInfos + "/notBefore" + pathFrontendPassTLSClientCertInfosSans = pathFrontendPassTLSClientCertInfos + "/sans" + pathFrontendPassTLSClientCertInfosSubject = pathFrontendPassTLSClientCertInfos + "/subject" + pathFrontendPassTLSClientCertInfosSubjectCommonName = pathFrontendPassTLSClientCertInfosSubject + "/commonName" + pathFrontendPassTLSClientCertInfosSubjectCountry = pathFrontendPassTLSClientCertInfosSubject + "/country" + pathFrontendPassTLSClientCertInfosSubjectLocality = pathFrontendPassTLSClientCertInfosSubject + "/locality" + pathFrontendPassTLSClientCertInfosSubjectOrganization = pathFrontendPassTLSClientCertInfosSubject + "/organization" + pathFrontendPassTLSClientCertInfosSubjectProvince = pathFrontendPassTLSClientCertInfosSubject + "/province" + pathFrontendPassTLSClientCertInfosSubjectSerialNumber = pathFrontendPassTLSClientCertInfosSubject + "/serialNumber" + pathFrontendPassTLSCert = "/passtlscert" + pathFrontendWhiteListSourceRange = "/whitelist/sourcerange" + pathFrontendWhiteListUseXForwardedFor = "/whitelist/usexforwardedfor" pathFrontendBasicAuth = "/basicauth" // Deprecated pathFrontendAuth = "/auth/" diff --git a/provider/kv/kv_config.go b/provider/kv/kv_config.go index ed7680780..bf02ce4b7 100644 --- a/provider/kv/kv_config.go +++ b/provider/kv/kv_config.go @@ -41,19 +41,20 @@ func (p *Provider) buildConfiguration() *types.Configuration { "getTLSSection": p.getTLSSection, // Frontend functions - "getBackendName": p.getFuncString(pathFrontendBackend, ""), - "getPriority": p.getFuncInt(pathFrontendPriority, label.DefaultFrontendPriority), - "getPassHostHeader": p.getPassHostHeader(), - "getPassTLSCert": p.getFuncBool(pathFrontendPassTLSCert, label.DefaultPassTLSCert), - "getEntryPoints": p.getFuncList(pathFrontendEntryPoints), - "getBasicAuth": p.getFuncList(pathFrontendBasicAuth), // Deprecated - "getAuth": p.getAuth, - "getRoutes": p.getRoutes, - "getRedirect": p.getRedirect, - "getErrorPages": p.getErrorPages, - "getRateLimit": p.getRateLimit, - "getHeaders": p.getHeaders, - "getWhiteList": p.getWhiteList, + "getBackendName": p.getFuncString(pathFrontendBackend, ""), + "getPriority": p.getFuncInt(pathFrontendPriority, label.DefaultFrontendPriority), + "getPassHostHeader": p.getPassHostHeader(), + "getPassTLSCert": p.getFuncBool(pathFrontendPassTLSCert, label.DefaultPassTLSCert), + "getPassTLSClientCert": p.getTLSClientCert, + "getEntryPoints": p.getFuncList(pathFrontendEntryPoints), + "getBasicAuth": p.getFuncList(pathFrontendBasicAuth), // Deprecated + "getAuth": p.getAuth, + "getRoutes": p.getRoutes, + "getRedirect": p.getRedirect, + "getErrorPages": p.getErrorPages, + "getRateLimit": p.getRateLimit, + "getHeaders": p.getHeaders, + "getWhiteList": p.getWhiteList, // Backend functions "getServers": p.getServers, @@ -369,6 +370,39 @@ func (p *Provider) getTLSSection(prefix string) []*tls.Configuration { return tlsSection } +// getTLSClientCert create TLS client header configuration from labels +func (p *Provider) getTLSClientCert(rootPath string) *types.TLSClientHeaders { + if !p.hasPrefix(rootPath, pathFrontendPassTLSClientCert) { + return nil + } + + tlsClientHeaders := &types.TLSClientHeaders{ + PEM: p.getBool(false, rootPath, pathFrontendPassTLSClientCertPem), + } + + if p.hasPrefix(rootPath, pathFrontendPassTLSClientCertInfos) { + infos := &types.TLSClientCertificateInfos{ + NotAfter: p.getBool(false, rootPath, pathFrontendPassTLSClientCertInfosNotAfter), + NotBefore: p.getBool(false, rootPath, pathFrontendPassTLSClientCertInfosNotBefore), + Sans: p.getBool(false, rootPath, pathFrontendPassTLSClientCertInfosSans), + } + + if p.hasPrefix(rootPath, pathFrontendPassTLSClientCertInfosSubject) { + subject := &types.TLSCLientCertificateSubjectInfos{ + CommonName: p.getBool(false, rootPath, pathFrontendPassTLSClientCertInfosSubjectCommonName), + Country: p.getBool(false, rootPath, pathFrontendPassTLSClientCertInfosSubjectCountry), + Locality: p.getBool(false, rootPath, pathFrontendPassTLSClientCertInfosSubjectLocality), + Organization: p.getBool(false, rootPath, pathFrontendPassTLSClientCertInfosSubjectOrganization), + Province: p.getBool(false, rootPath, pathFrontendPassTLSClientCertInfosSubjectProvince), + SerialNumber: p.getBool(false, rootPath, pathFrontendPassTLSClientCertInfosSubjectSerialNumber), + } + infos.Subject = subject + } + tlsClientHeaders.Infos = infos + } + return tlsClientHeaders +} + // hasDeprecatedBasicAuth check if the frontend basic auth use the deprecated configuration func (p *Provider) hasDeprecatedBasicAuth(rootPath string) bool { return len(p.getList(rootPath, pathFrontendBasicAuth)) > 0 diff --git a/provider/kv/kv_config_test.go b/provider/kv/kv_config_test.go index e1f604d24..b41e4653e 100644 --- a/provider/kv/kv_config_test.go +++ b/provider/kv/kv_config_test.go @@ -277,6 +277,18 @@ func TestProviderBuildConfiguration(t *testing.T) { withPair(pathFrontendBackend, "backend1"), withPair(pathFrontendPriority, "6"), withPair(pathFrontendPassHostHeader, "false"), + + withPair(pathFrontendPassTLSClientCertPem, "true"), + withPair(pathFrontendPassTLSClientCertInfosNotBefore, "true"), + withPair(pathFrontendPassTLSClientCertInfosNotAfter, "true"), + withPair(pathFrontendPassTLSClientCertInfosSans, "true"), + withPair(pathFrontendPassTLSClientCertInfosSubjectCommonName, "true"), + withPair(pathFrontendPassTLSClientCertInfosSubjectCountry, "true"), + withPair(pathFrontendPassTLSClientCertInfosSubjectLocality, "true"), + withPair(pathFrontendPassTLSClientCertInfosSubjectOrganization, "true"), + withPair(pathFrontendPassTLSClientCertInfosSubjectProvince, "true"), + withPair(pathFrontendPassTLSClientCertInfosSubjectSerialNumber, "true"), + withPair(pathFrontendPassTLSCert, "true"), withList(pathFrontendEntryPoints, "http", "https"), withList(pathFrontendWhiteListSourceRange, "1.1.1.1/24", "1234:abcd::42/32"), @@ -401,6 +413,22 @@ func TestProviderBuildConfiguration(t *testing.T) { SourceRange: []string{"1.1.1.1/24", "1234:abcd::42/32"}, UseXForwardedFor: true, }, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, Auth: &types.Auth{ HeaderField: "X-WebAuth-User", Basic: &types.Basic{ diff --git a/provider/label/names.go b/provider/label/names.go index bafa49c61..59a8c7684 100644 --- a/provider/label/names.go +++ b/provider/label/names.go @@ -2,187 +2,213 @@ 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" - 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" - 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" - SuffixFrontendPassTLSCert = "frontend.passTLSCert" - 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 - TraefikBackendMaxConnAmount = Prefix + SuffixBackendMaxConnAmount - TraefikBackendMaxConnExtractorFunc = Prefix + SuffixBackendMaxConnExtractorFunc - TraefikBackendBuffering = Prefix + SuffixBackendBuffering - TraefikBackendBufferingMaxRequestBodyBytes = Prefix + SuffixBackendBufferingMaxRequestBodyBytes - TraefikBackendBufferingMemRequestBodyBytes = Prefix + SuffixBackendBufferingMemRequestBodyBytes - TraefikBackendBufferingMaxResponseBodyBytes = Prefix + SuffixBackendBufferingMaxResponseBodyBytes - TraefikBackendBufferingMemResponseBodyBytes = Prefix + SuffixBackendBufferingMemResponseBodyBytes - TraefikBackendBufferingRetryExpression = Prefix + SuffixBackendBufferingRetryExpression - TraefikFrontend = Prefix + SuffixFrontend - TraefikFrontendAuth = Prefix + SuffixFrontendAuth - TraefikFrontendAuthBasic = Prefix + SuffixFrontendAuthBasic - TraefikFrontendAuthBasicRemoveHeader = Prefix + SuffixFrontendAuthBasicRemoveHeader - TraefikFrontendAuthBasicUsers = Prefix + SuffixFrontendAuthBasicUsers - TraefikFrontendAuthBasicUsersFile = Prefix + SuffixFrontendAuthBasicUsersFile - TraefikFrontendAuthDigest = Prefix + SuffixFrontendAuthDigest - TraefikFrontendAuthDigestRemoveHeader = Prefix + SuffixFrontendAuthDigestRemoveHeader - TraefikFrontendAuthDigestUsers = Prefix + SuffixFrontendAuthDigestUsers - TraefikFrontendAuthDigestUsersFile = Prefix + SuffixFrontendAuthDigestUsersFile - TraefikFrontendAuthForward = Prefix + SuffixFrontendAuthForward - TraefikFrontendAuthForwardAddress = Prefix + SuffixFrontendAuthForwardAddress - TraefikFrontendAuthForwardTLS = Prefix + SuffixFrontendAuthForwardTLS - TraefikFrontendAuthForwardTLSCa = Prefix + SuffixFrontendAuthForwardTLSCa - TraefikFrontendAuthForwardTLSCaOptional = Prefix + SuffixFrontendAuthForwardTLSCaOptional - TraefikFrontendAuthForwardTLSCert = Prefix + SuffixFrontendAuthForwardTLSCert - TraefikFrontendAuthForwardTLSInsecureSkipVerify = Prefix + SuffixFrontendAuthForwardTLSInsecureSkipVerify - TraefikFrontendAuthForwardTLSKey = Prefix + SuffixFrontendAuthForwardTLSKey - TraefikFrontendAuthForwardTrustForwardHeader = Prefix + SuffixFrontendAuthForwardTrustForwardHeader - TraefikFrontendAuthHeaderField = Prefix + SuffixFrontendAuthHeaderField - TraefikFrontendEntryPoints = Prefix + SuffixFrontendEntryPoints - TraefikFrontendPassHostHeader = Prefix + SuffixFrontendPassHostHeader - TraefikFrontendPassTLSCert = Prefix + SuffixFrontendPassTLSCert - TraefikFrontendPriority = Prefix + SuffixFrontendPriority - TraefikFrontendRateLimitExtractorFunc = Prefix + SuffixFrontendRateLimitExtractorFunc - TraefikFrontendRedirectEntryPoint = Prefix + SuffixFrontendRedirectEntryPoint - TraefikFrontendRedirectRegex = Prefix + SuffixFrontendRedirectRegex - TraefikFrontendRedirectReplacement = Prefix + SuffixFrontendRedirectReplacement - TraefikFrontendRedirectPermanent = Prefix + SuffixFrontendRedirectPermanent - TraefikFrontendRule = Prefix + SuffixFrontendRule - TraefikFrontendWhitelistSourceRange = Prefix + SuffixFrontendWhitelistSourceRange // Deprecated - TraefikFrontendWhiteListSourceRange = Prefix + SuffixFrontendWhiteListSourceRange - TraefikFrontendWhiteListUseXForwardedFor = Prefix + SuffixFrontendWhiteListUseXForwardedFor - TraefikFrontendRequestHeaders = Prefix + SuffixFrontendRequestHeaders - TraefikFrontendResponseHeaders = Prefix + SuffixFrontendResponseHeaders - TraefikFrontendAllowedHosts = Prefix + SuffixFrontendHeadersAllowedHosts - TraefikFrontendHostsProxyHeaders = Prefix + SuffixFrontendHeadersHostsProxyHeaders - TraefikFrontendSSLForceHost = Prefix + SuffixFrontendHeadersSSLForceHost - TraefikFrontendSSLRedirect = Prefix + SuffixFrontendHeadersSSLRedirect - TraefikFrontendSSLTemporaryRedirect = Prefix + SuffixFrontendHeadersSSLTemporaryRedirect - TraefikFrontendSSLHost = Prefix + SuffixFrontendHeadersSSLHost - TraefikFrontendSSLProxyHeaders = Prefix + SuffixFrontendHeadersSSLProxyHeaders - TraefikFrontendSTSSeconds = Prefix + SuffixFrontendHeadersSTSSeconds - TraefikFrontendSTSIncludeSubdomains = Prefix + SuffixFrontendHeadersSTSIncludeSubdomains - TraefikFrontendSTSPreload = Prefix + SuffixFrontendHeadersSTSPreload - TraefikFrontendForceSTSHeader = Prefix + SuffixFrontendHeadersForceSTSHeader - TraefikFrontendFrameDeny = Prefix + SuffixFrontendHeadersFrameDeny - TraefikFrontendCustomFrameOptionsValue = Prefix + SuffixFrontendHeadersCustomFrameOptionsValue - TraefikFrontendContentTypeNosniff = Prefix + SuffixFrontendHeadersContentTypeNosniff - TraefikFrontendBrowserXSSFilter = Prefix + SuffixFrontendHeadersBrowserXSSFilter - TraefikFrontendCustomBrowserXSSValue = Prefix + SuffixFrontendHeadersCustomBrowserXSSValue - TraefikFrontendContentSecurityPolicy = Prefix + SuffixFrontendHeadersContentSecurityPolicy - TraefikFrontendPublicKey = Prefix + SuffixFrontendHeadersPublicKey - TraefikFrontendReferrerPolicy = Prefix + SuffixFrontendHeadersReferrerPolicy - TraefikFrontendIsDevelopment = Prefix + SuffixFrontendHeadersIsDevelopment - BaseFrontendErrorPage = "frontend.errors." - SuffixErrorPageBackend = "backend" - SuffixErrorPageQuery = "query" - SuffixErrorPageStatus = "status" - BaseFrontendRateLimit = "frontend.rateLimit.rateSet." - SuffixRateLimitPeriod = "period" - SuffixRateLimitAverage = "average" - SuffixRateLimitBurst = "burst" + 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" + 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" + 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" + SuffixFrontendPassTLSClientCertInfosNotAfter = SuffixFrontendPassTLSClientCertInfos + ".notAfter" + SuffixFrontendPassTLSClientCertInfosNotBefore = SuffixFrontendPassTLSClientCertInfos + ".notBefore" + SuffixFrontendPassTLSClientCertInfosSans = SuffixFrontendPassTLSClientCertInfos + ".sans" + SuffixFrontendPassTLSClientCertInfosSubject = SuffixFrontendPassTLSClientCertInfos + ".subject" + SuffixFrontendPassTLSClientCertInfosSubjectCommonName = SuffixFrontendPassTLSClientCertInfosSubject + ".commonName" + SuffixFrontendPassTLSClientCertInfosSubjectCountry = SuffixFrontendPassTLSClientCertInfosSubject + ".country" + 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 + TraefikBackendMaxConnAmount = Prefix + SuffixBackendMaxConnAmount + TraefikBackendMaxConnExtractorFunc = Prefix + SuffixBackendMaxConnExtractorFunc + TraefikBackendBuffering = Prefix + SuffixBackendBuffering + TraefikBackendBufferingMaxRequestBodyBytes = Prefix + SuffixBackendBufferingMaxRequestBodyBytes + TraefikBackendBufferingMemRequestBodyBytes = Prefix + SuffixBackendBufferingMemRequestBodyBytes + TraefikBackendBufferingMaxResponseBodyBytes = Prefix + SuffixBackendBufferingMaxResponseBodyBytes + TraefikBackendBufferingMemResponseBodyBytes = Prefix + SuffixBackendBufferingMemResponseBodyBytes + TraefikBackendBufferingRetryExpression = Prefix + SuffixBackendBufferingRetryExpression + TraefikFrontend = Prefix + SuffixFrontend + TraefikFrontendAuth = Prefix + SuffixFrontendAuth + TraefikFrontendAuthBasic = Prefix + SuffixFrontendAuthBasic + TraefikFrontendAuthBasicRemoveHeader = Prefix + SuffixFrontendAuthBasicRemoveHeader + TraefikFrontendAuthBasicUsers = Prefix + SuffixFrontendAuthBasicUsers + TraefikFrontendAuthBasicUsersFile = Prefix + SuffixFrontendAuthBasicUsersFile + TraefikFrontendAuthDigest = Prefix + SuffixFrontendAuthDigest + TraefikFrontendAuthDigestRemoveHeader = Prefix + SuffixFrontendAuthDigestRemoveHeader + TraefikFrontendAuthDigestUsers = Prefix + SuffixFrontendAuthDigestUsers + TraefikFrontendAuthDigestUsersFile = Prefix + SuffixFrontendAuthDigestUsersFile + TraefikFrontendAuthForward = Prefix + SuffixFrontendAuthForward + TraefikFrontendAuthForwardAddress = Prefix + SuffixFrontendAuthForwardAddress + TraefikFrontendAuthForwardTLS = Prefix + SuffixFrontendAuthForwardTLS + TraefikFrontendAuthForwardTLSCa = Prefix + SuffixFrontendAuthForwardTLSCa + TraefikFrontendAuthForwardTLSCaOptional = Prefix + SuffixFrontendAuthForwardTLSCaOptional + TraefikFrontendAuthForwardTLSCert = Prefix + SuffixFrontendAuthForwardTLSCert + TraefikFrontendAuthForwardTLSInsecureSkipVerify = Prefix + SuffixFrontendAuthForwardTLSInsecureSkipVerify + TraefikFrontendAuthForwardTLSKey = Prefix + SuffixFrontendAuthForwardTLSKey + TraefikFrontendAuthForwardTrustForwardHeader = Prefix + SuffixFrontendAuthForwardTrustForwardHeader + TraefikFrontendAuthHeaderField = Prefix + SuffixFrontendAuthHeaderField + TraefikFrontendEntryPoints = Prefix + SuffixFrontendEntryPoints + TraefikFrontendPassHostHeader = Prefix + SuffixFrontendPassHostHeader + TraefikFrontendPassTLSClientCert = Prefix + SuffixFrontendPassTLSClientCert + TraefikFrontendPassTLSClientCertPem = Prefix + SuffixFrontendPassTLSClientCertPem + TraefikFrontendPassTLSClientCertInfos = Prefix + SuffixFrontendPassTLSClientCertInfos + TraefikFrontendPassTLSClientCertInfosNotAfter = Prefix + SuffixFrontendPassTLSClientCertInfosNotAfter + TraefikFrontendPassTLSClientCertInfosNotBefore = Prefix + SuffixFrontendPassTLSClientCertInfosNotBefore + TraefikFrontendPassTLSClientCertInfosSans = Prefix + SuffixFrontendPassTLSClientCertInfosSans + TraefikFrontendPassTLSClientCertInfosSubject = Prefix + SuffixFrontendPassTLSClientCertInfosSubject + TraefikFrontendPassTLSClientCertInfosSubjectCommonName = Prefix + SuffixFrontendPassTLSClientCertInfosSubjectCommonName + TraefikFrontendPassTLSClientCertInfosSubjectCountry = Prefix + SuffixFrontendPassTLSClientCertInfosSubjectCountry + TraefikFrontendPassTLSClientCertInfosSubjectLocality = Prefix + SuffixFrontendPassTLSClientCertInfosSubjectLocality + TraefikFrontendPassTLSClientCertInfosSubjectOrganization = Prefix + SuffixFrontendPassTLSClientCertInfosSubjectOrganization + TraefikFrontendPassTLSClientCertInfosSubjectProvince = Prefix + SuffixFrontendPassTLSClientCertInfosSubjectProvince + TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber = Prefix + SuffixFrontendPassTLSClientCertInfosSubjectSerialNumber + TraefikFrontendPassTLSCert = Prefix + SuffixFrontendPassTLSCert // Deprecated + TraefikFrontendPriority = Prefix + SuffixFrontendPriority + TraefikFrontendRateLimitExtractorFunc = Prefix + SuffixFrontendRateLimitExtractorFunc + TraefikFrontendRedirectEntryPoint = Prefix + SuffixFrontendRedirectEntryPoint + TraefikFrontendRedirectRegex = Prefix + SuffixFrontendRedirectRegex + TraefikFrontendRedirectReplacement = Prefix + SuffixFrontendRedirectReplacement + TraefikFrontendRedirectPermanent = Prefix + SuffixFrontendRedirectPermanent + TraefikFrontendRule = Prefix + SuffixFrontendRule + TraefikFrontendWhitelistSourceRange = Prefix + SuffixFrontendWhitelistSourceRange // Deprecated + TraefikFrontendWhiteListSourceRange = Prefix + SuffixFrontendWhiteListSourceRange + TraefikFrontendWhiteListUseXForwardedFor = Prefix + SuffixFrontendWhiteListUseXForwardedFor + TraefikFrontendRequestHeaders = Prefix + SuffixFrontendRequestHeaders + TraefikFrontendResponseHeaders = Prefix + SuffixFrontendResponseHeaders + TraefikFrontendAllowedHosts = Prefix + SuffixFrontendHeadersAllowedHosts + TraefikFrontendHostsProxyHeaders = Prefix + SuffixFrontendHeadersHostsProxyHeaders + TraefikFrontendSSLForceHost = Prefix + SuffixFrontendHeadersSSLForceHost + TraefikFrontendSSLRedirect = Prefix + SuffixFrontendHeadersSSLRedirect + TraefikFrontendSSLTemporaryRedirect = Prefix + SuffixFrontendHeadersSSLTemporaryRedirect + TraefikFrontendSSLHost = Prefix + SuffixFrontendHeadersSSLHost + TraefikFrontendSSLProxyHeaders = Prefix + SuffixFrontendHeadersSSLProxyHeaders + TraefikFrontendSTSSeconds = Prefix + SuffixFrontendHeadersSTSSeconds + TraefikFrontendSTSIncludeSubdomains = Prefix + SuffixFrontendHeadersSTSIncludeSubdomains + TraefikFrontendSTSPreload = Prefix + SuffixFrontendHeadersSTSPreload + TraefikFrontendForceSTSHeader = Prefix + SuffixFrontendHeadersForceSTSHeader + TraefikFrontendFrameDeny = Prefix + SuffixFrontendHeadersFrameDeny + TraefikFrontendCustomFrameOptionsValue = Prefix + SuffixFrontendHeadersCustomFrameOptionsValue + TraefikFrontendContentTypeNosniff = Prefix + SuffixFrontendHeadersContentTypeNosniff + TraefikFrontendBrowserXSSFilter = Prefix + SuffixFrontendHeadersBrowserXSSFilter + TraefikFrontendCustomBrowserXSSValue = Prefix + SuffixFrontendHeadersCustomBrowserXSSValue + TraefikFrontendContentSecurityPolicy = Prefix + SuffixFrontendHeadersContentSecurityPolicy + TraefikFrontendPublicKey = Prefix + SuffixFrontendHeadersPublicKey + TraefikFrontendReferrerPolicy = Prefix + SuffixFrontendHeadersReferrerPolicy + TraefikFrontendIsDevelopment = Prefix + SuffixFrontendHeadersIsDevelopment + BaseFrontendErrorPage = "frontend.errors." + SuffixErrorPageBackend = "backend" + SuffixErrorPageQuery = "query" + SuffixErrorPageStatus = "status" + BaseFrontendRateLimit = "frontend.rateLimit.rateSet." + SuffixRateLimitPeriod = "period" + SuffixRateLimitAverage = "average" + SuffixRateLimitBurst = "burst" ) diff --git a/provider/label/partial.go b/provider/label/partial.go index aec443edd..39289cc3b 100644 --- a/provider/label/partial.go +++ b/provider/label/partial.go @@ -60,6 +60,39 @@ func GetRedirect(labels map[string]string) *types.Redirect { return nil } +// GetTLSClientCert create TLS client header configuration from labels +func GetTLSClientCert(labels map[string]string) *types.TLSClientHeaders { + if !HasPrefix(labels, TraefikFrontendPassTLSClientCert) { + return nil + } + + tlsClientHeaders := &types.TLSClientHeaders{ + PEM: GetBoolValue(labels, TraefikFrontendPassTLSClientCertPem, false), + } + + if HasPrefix(labels, TraefikFrontendPassTLSClientCertInfos) { + infos := &types.TLSClientCertificateInfos{ + NotAfter: GetBoolValue(labels, TraefikFrontendPassTLSClientCertInfosNotAfter, false), + NotBefore: GetBoolValue(labels, TraefikFrontendPassTLSClientCertInfosNotBefore, false), + Sans: GetBoolValue(labels, TraefikFrontendPassTLSClientCertInfosSans, false), + } + + if HasPrefix(labels, TraefikFrontendPassTLSClientCertInfosSubject) { + subject := &types.TLSCLientCertificateSubjectInfos{ + CommonName: GetBoolValue(labels, TraefikFrontendPassTLSClientCertInfosSubjectCommonName, false), + Country: GetBoolValue(labels, TraefikFrontendPassTLSClientCertInfosSubjectCountry, false), + Locality: GetBoolValue(labels, TraefikFrontendPassTLSClientCertInfosSubjectLocality, false), + Organization: GetBoolValue(labels, TraefikFrontendPassTLSClientCertInfosSubjectOrganization, false), + Province: GetBoolValue(labels, TraefikFrontendPassTLSClientCertInfosSubjectProvince, false), + SerialNumber: GetBoolValue(labels, TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber, false), + } + infos.Subject = subject + } + tlsClientHeaders.Infos = infos + } + return tlsClientHeaders +} + // GetAuth Create auth from labels func GetAuth(labels map[string]string) *types.Auth { if !HasPrefix(labels, TraefikFrontendAuth) { diff --git a/provider/label/partial_test.go b/provider/label/partial_test.go index 796acfe15..5ffa6415c 100644 --- a/provider/label/partial_test.go +++ b/provider/label/partial_test.go @@ -798,3 +798,178 @@ func TestGetAuth(t *testing.T) { }) } } +func TestGetPassTLSClientCert(t *testing.T) { + testCases := []struct { + desc string + labels map[string]string + expected *types.TLSClientHeaders + }{ + { + desc: "should return nil when no tags", + labels: map[string]string{}, + expected: nil, + }, + { + desc: "should return tlsClientHeaders with true pem flag", + labels: map[string]string{ + TraefikFrontendPassTLSClientCertPem: "true", + }, + expected: &types.TLSClientHeaders{ + PEM: true, + }, + }, + { + desc: "should return tlsClientHeaders with infos and NotAfter true", + labels: map[string]string{ + TraefikFrontendPassTLSClientCertInfosNotAfter: "true", + }, + expected: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + NotAfter: true, + }, + }, + }, + { + desc: "should return tlsClientHeaders with infos and NotBefore true", + labels: map[string]string{ + TraefikFrontendPassTLSClientCertInfosNotBefore: "true", + }, + expected: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + }, + }, + }, + { + desc: "should return tlsClientHeaders with infos and sans true", + labels: map[string]string{ + TraefikFrontendPassTLSClientCertInfosSans: "true", + }, + expected: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Sans: true, + }, + }, + }, + { + desc: "should return tlsClientHeaders with infos and subject with commonName true", + labels: map[string]string{ + TraefikFrontendPassTLSClientCertInfosSubjectCommonName: "true", + }, + expected: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + }, + }, + }, + }, + { + desc: "should return tlsClientHeaders with infos and subject with country true", + labels: map[string]string{ + TraefikFrontendPassTLSClientCertInfosSubjectCountry: "true", + }, + expected: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{ + Country: true, + }, + }, + }, + }, + { + desc: "should return tlsClientHeaders with infos and subject with locality true", + labels: map[string]string{ + TraefikFrontendPassTLSClientCertInfosSubjectLocality: "true", + }, + expected: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{ + Locality: true, + }, + }, + }, + }, + { + desc: "should return tlsClientHeaders with infos and subject with organization true", + labels: map[string]string{ + TraefikFrontendPassTLSClientCertInfosSubjectOrganization: "true", + }, + expected: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{ + Organization: true, + }, + }, + }, + }, + { + desc: "should return tlsClientHeaders with infos and subject with province true", + labels: map[string]string{ + TraefikFrontendPassTLSClientCertInfosSubjectProvince: "true", + }, + expected: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{ + Province: true, + }, + }, + }, + }, + { + desc: "should return tlsClientHeaders with infos and subject with serialNumber true", + labels: map[string]string{ + TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber: "true", + }, + expected: &types.TLSClientHeaders{ + Infos: &types.TLSClientCertificateInfos{ + Subject: &types.TLSCLientCertificateSubjectInfos{ + SerialNumber: true, + }, + }, + }, + }, + { + desc: "should return tlsClientHeaders with all infos", + labels: map[string]string{ + TraefikFrontendPassTLSClientCertPem: "true", + TraefikFrontendPassTLSClientCertInfosNotAfter: "true", + TraefikFrontendPassTLSClientCertInfosNotBefore: "true", + TraefikFrontendPassTLSClientCertInfosSans: "true", + TraefikFrontendPassTLSClientCertInfosSubjectCommonName: "true", + TraefikFrontendPassTLSClientCertInfosSubjectCountry: "true", + TraefikFrontendPassTLSClientCertInfosSubjectLocality: "true", + TraefikFrontendPassTLSClientCertInfosSubjectOrganization: "true", + TraefikFrontendPassTLSClientCertInfosSubjectProvince: "true", + TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber: "true", + }, + expected: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + Sans: true, + NotBefore: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + Province: true, + Organization: true, + Locality: true, + Country: true, + CommonName: true, + SerialNumber: true, + }, + }, + }, + }, + } + + for _, test := range testCases { + test := test + t.Run(test.desc, func(t *testing.T) { + t.Parallel() + + result := GetTLSClientCert(test.labels) + + assert.Equal(t, test.expected, result) + }) + } +} diff --git a/provider/marathon/config.go b/provider/marathon/config.go index 8b0f61af9..0194ba4c6 100644 --- a/provider/marathon/config.go +++ b/provider/marathon/config.go @@ -46,6 +46,7 @@ func (p *Provider) buildConfigurationV2(applications *marathon.Applications) *ty "getFrontendName": p.getFrontendName, "getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader), "getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert), + "getPassTLSClientCert": label.GetTLSClientCert, "getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority), "getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints), "getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated diff --git a/provider/marathon/config_test.go b/provider/marathon/config_test.go index f6a5d3c9a..e7471c649 100644 --- a/provider/marathon/config_test.go +++ b/provider/marathon/config_test.go @@ -374,6 +374,17 @@ func TestBuildConfiguration(t *testing.T) { withLabel(label.TraefikBackendBufferingMemRequestBodyBytes, "2097152"), withLabel(label.TraefikBackendBufferingRetryExpression, "IsNetworkError() && Attempts() <= 2"), + withLabel(label.TraefikFrontendPassTLSClientCertPem, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosNotBefore, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosNotAfter, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSans, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectCommonName, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectCountry, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectLocality, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectOrganization, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectProvince, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber, "true"), + withLabel(label.TraefikFrontendAuthBasic, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"), withLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true"), withLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"), @@ -401,7 +412,6 @@ func TestBuildConfiguration(t *testing.T) { withLabel(label.TraefikFrontendRule, "Host:traefik.io"), withLabel(label.TraefikFrontendWhiteListSourceRange, "10.10.10.10"), withLabel(label.TraefikFrontendWhiteListUseXForwardedFor, "true"), - withLabel(label.TraefikFrontendRequestHeaders, "Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"), withLabel(label.TraefikFrontendResponseHeaders, "Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"), withLabel(label.TraefikFrontendSSLProxyHeaders, "Access-Control-Allow-Methods:POST,GET,OPTIONS || Content-type: application/json; charset=utf-8"), @@ -455,6 +465,22 @@ func TestBuildConfiguration(t *testing.T) { PassHostHeader: true, PassTLSCert: true, Priority: 666, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, Auth: &types.Auth{ HeaderField: "X-WebAuth-User", Basic: &types.Basic{ @@ -766,6 +792,17 @@ func TestBuildConfigurationSegments(t *testing.T) { withSegmentLabel(label.TraefikProtocol, "https", "containous"), withSegmentLabel(label.TraefikWeight, "12", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertPem, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosNotBefore, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosNotAfter, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSans, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectCommonName, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectCountry, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectLocality, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectOrganization, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectProvince, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber, "true", "containous"), + withSegmentLabel(label.TraefikFrontendAuthBasic, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "containous"), withSegmentLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true", "containous"), withSegmentLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "containous"), @@ -847,6 +884,22 @@ func TestBuildConfigurationSegments(t *testing.T) { PassHostHeader: true, PassTLSCert: true, Priority: 666, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, Auth: &types.Auth{ HeaderField: "X-WebAuth-User", Basic: &types.Basic{ diff --git a/provider/mesos/config.go b/provider/mesos/config.go index 7a379b3a1..47a5ef9ce 100644 --- a/provider/mesos/config.go +++ b/provider/mesos/config.go @@ -48,6 +48,7 @@ func (p *Provider) buildConfigurationV2(tasks []state.Task) *types.Configuration "getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority), "getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader), "getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert), + "getPassTLSClientCert": label.GetTLSClientCert, "getFrontendRule": p.getFrontendRule, "getRedirect": label.GetRedirect, "getErrorPages": label.GetErrorPages, diff --git a/provider/mesos/config_test.go b/provider/mesos/config_test.go index 6b5af71d7..13d195b4e 100644 --- a/provider/mesos/config_test.go +++ b/provider/mesos/config_test.go @@ -330,6 +330,17 @@ func TestBuildConfiguration(t *testing.T) { withLabel(label.TraefikBackendBufferingMemRequestBodyBytes, "2097152"), withLabel(label.TraefikBackendBufferingRetryExpression, "IsNetworkError() && Attempts() <= 2"), + withLabel(label.TraefikFrontendPassTLSClientCertPem, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosNotBefore, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosNotAfter, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSans, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectCommonName, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectCountry, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectLocality, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectOrganization, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectProvince, "true"), + withLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber, "true"), + withLabel(label.TraefikFrontendAuthBasic, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"), withLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true"), withLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"), @@ -417,6 +428,22 @@ func TestBuildConfiguration(t *testing.T) { PassHostHeader: true, PassTLSCert: true, Priority: 666, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, Auth: &types.Auth{ HeaderField: "X-WebAuth-User", Basic: &types.Basic{ @@ -684,6 +711,17 @@ func TestBuildConfigurationSegments(t *testing.T) { withSegmentLabel(label.TraefikProtocol, "https", "containous"), withSegmentLabel(label.TraefikWeight, "12", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertPem, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosNotBefore, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosNotAfter, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSans, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectCommonName, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectCountry, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectLocality, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectOrganization, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectProvince, "true", "containous"), + withSegmentLabel(label.TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber, "true", "containous"), + withSegmentLabel(label.TraefikFrontendAuthBasic, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "containous"), withSegmentLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true", "containous"), withSegmentLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "containous"), @@ -766,6 +804,22 @@ func TestBuildConfigurationSegments(t *testing.T) { PassHostHeader: true, PassTLSCert: true, Priority: 666, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, Auth: &types.Auth{ HeaderField: "X-WebAuth-User", Basic: &types.Basic{ diff --git a/provider/rancher/config.go b/provider/rancher/config.go index 6b913333d..ccd8a43d1 100644 --- a/provider/rancher/config.go +++ b/provider/rancher/config.go @@ -28,19 +28,20 @@ func (p *Provider) buildConfigurationV2(services []rancherData) *types.Configura "getServers": getServers, // Frontend functions - "getBackendName": getBackendName, - "getFrontendRule": p.getFrontendRule, - "getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority), - "getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader), - "getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert), - "getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints), - "getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated - "getAuth": label.GetAuth, - "getErrorPages": label.GetErrorPages, - "getRateLimit": label.GetRateLimit, - "getRedirect": label.GetRedirect, - "getHeaders": label.GetHeaders, - "getWhiteList": label.GetWhiteList, + "getBackendName": getBackendName, + "getFrontendRule": p.getFrontendRule, + "getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority), + "getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader), + "getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert), + "getPassTLSClientCert": label.GetTLSClientCert, + "getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints), + "getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated + "getAuth": label.GetAuth, + "getErrorPages": label.GetErrorPages, + "getRateLimit": label.GetRateLimit, + "getRedirect": label.GetRedirect, + "getHeaders": label.GetHeaders, + "getWhiteList": label.GetWhiteList, } // filter services diff --git a/provider/rancher/config_test.go b/provider/rancher/config_test.go index 600813e19..a73150ed0 100644 --- a/provider/rancher/config_test.go +++ b/provider/rancher/config_test.go @@ -59,6 +59,17 @@ func TestProviderBuildConfiguration(t *testing.T) { label.TraefikBackendBufferingMemRequestBodyBytes: "2097152", label.TraefikBackendBufferingRetryExpression: "IsNetworkError() && Attempts() <= 2", + label.TraefikFrontendPassTLSClientCertPem: "true", + label.TraefikFrontendPassTLSClientCertInfosNotBefore: "true", + label.TraefikFrontendPassTLSClientCertInfosNotAfter: "true", + label.TraefikFrontendPassTLSClientCertInfosSans: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectCommonName: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectCountry: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectLocality: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectOrganization: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectProvince: "true", + label.TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber: "true", + label.TraefikFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", label.TraefikFrontendAuthBasicRemoveHeader: "true", label.TraefikFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", @@ -144,6 +155,22 @@ func TestProviderBuildConfiguration(t *testing.T) { PassHostHeader: true, PassTLSCert: true, Priority: 666, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, Auth: &types.Auth{ HeaderField: "X-WebAuth-User", Basic: &types.Basic{ @@ -291,6 +318,17 @@ func TestProviderBuildConfiguration(t *testing.T) { label.Prefix + "sauternes." + label.SuffixProtocol: "https", label.Prefix + "sauternes." + label.SuffixWeight: "12", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertPem: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosNotAfter: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosNotBefore: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSans: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectCommonName: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectCountry: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectLocality: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectOrganization: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectProvince: "true", + label.Prefix + "sauternes." + label.SuffixFrontendPassTLSClientCertInfosSubjectSerialNumber: "true", + label.Prefix + "sauternes." + label.SuffixFrontendRule: "Host:traefik.wtf", label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicRemoveHeader: "true", label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", @@ -372,6 +410,22 @@ func TestProviderBuildConfiguration(t *testing.T) { PassHostHeader: true, PassTLSCert: true, Priority: 666, + PassTLSClientCert: &types.TLSClientHeaders{ + PEM: true, + Infos: &types.TLSClientCertificateInfos{ + NotBefore: true, + Sans: true, + NotAfter: true, + Subject: &types.TLSCLientCertificateSubjectInfos{ + CommonName: true, + Country: true, + Locality: true, + Organization: true, + Province: true, + SerialNumber: true, + }, + }, + }, Auth: &types.Auth{ HeaderField: "X-WebAuth-User", Basic: &types.Basic{ diff --git a/server/server.go b/server/server.go index 1f82e0759..53583281a 100644 --- a/server/server.go +++ b/server/server.go @@ -6,7 +6,6 @@ import ( "crypto/x509" "encoding/json" "fmt" - "io/ioutil" stdlog "log" "net" "net/http" @@ -438,7 +437,7 @@ func (s *Server) createTLSConfig(entryPointName string, tlsOption *traefiktls.TL if len(tlsOption.ClientCA.Files) > 0 { pool := x509.NewCertPool() for _, caFile := range tlsOption.ClientCA.Files { - data, err := ioutil.ReadFile(caFile) + data, err := caFile.Read() if err != nil { return nil, err } diff --git a/server/server_loadbalancer.go b/server/server_loadbalancer.go index 861f8f010..7d7efc6de 100644 --- a/server/server_loadbalancer.go +++ b/server/server_loadbalancer.go @@ -5,7 +5,6 @@ import ( "crypto/x509" "errors" "fmt" - "io/ioutil" "net" "net/http" "net/url" @@ -280,7 +279,7 @@ func createHTTPTransport(globalConfiguration configuration.GlobalConfiguration) return transport, nil } -func createRootCACertPool(rootCAs traefiktls.RootCAs) *x509.CertPool { +func createRootCACertPool(rootCAs traefiktls.FilesOrContents) *x509.CertPool { roots := x509.NewCertPool() for _, cert := range rootCAs { @@ -314,7 +313,7 @@ func createClientTLSConfig(entryPointName string, tlsOption *traefiktls.TLS) (*t if len(tlsOption.ClientCA.Files) > 0 { pool := x509.NewCertPool() for _, caFile := range tlsOption.ClientCA.Files { - data, err := ioutil.ReadFile(caFile) + data, err := caFile.Read() if err != nil { return nil, err } diff --git a/server/server_middlewares.go b/server/server_middlewares.go index 1a1a1a89e..4ab3938f9 100644 --- a/server/server_middlewares.go +++ b/server/server_middlewares.go @@ -119,6 +119,15 @@ func (s *Server) buildMiddlewares(frontendName string, frontend *types.Frontend, middle = append(middle, handler) } + // TLSClientHeaders + tlsClientHeadersMiddleware := middlewares.NewTLSClientHeaders(frontend) + if tlsClientHeadersMiddleware != nil { + log.Debugf("Adding TLSClientHeaders middleware for frontend %s", frontendName) + + handler := s.tracingMiddleware.NewNegroniHandlerWrapper("TLSClientHeaders", tlsClientHeadersMiddleware, false) + middle = append(middle, handler) + } + return middle, buildModifyResponse(secureMiddleware, headerMiddleware), postConfig, nil } diff --git a/templates/consul_catalog.tmpl b/templates/consul_catalog.tmpl index a7ee338ae..12d762efe 100644 --- a/templates/consul_catalog.tmpl +++ b/templates/consul_catalog.tmpl @@ -74,8 +74,30 @@ "{{.}}", {{end}}] - {{ $auth := getAuth $service.TraefikLabels }} + {{ $tlsClientCert := getPassTLSClientCert $service.TraefikLabels }} + {{if $tlsClientCert }} + [frontends."frontend-{{ $service.ServiceName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."frontend-{{ $service.ServiceName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."frontend-{{ $service.ServiceName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + {{ $auth := getAuth $service.TraefikLabels }} {{if $auth }} [frontends."frontend-{{ $service.ServiceName }}".auth] headerField = "{{ $auth.HeaderField }}" diff --git a/templates/docker.tmpl b/templates/docker.tmpl index c200551c5..83b379b9b 100644 --- a/templates/docker.tmpl +++ b/templates/docker.tmpl @@ -75,6 +75,29 @@ "{{.}}", {{end}}] + {{ $tlsClientCert := getPassTLSClientCert $container.SegmentLabels }} + {{if $tlsClientCert }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + {{ $auth := getAuth $container.SegmentLabels }} {{if $auth }} [frontends."frontend-{{ $frontendName }}".auth] diff --git a/templates/ecs.tmpl b/templates/ecs.tmpl index 256e300fb..59c040792 100644 --- a/templates/ecs.tmpl +++ b/templates/ecs.tmpl @@ -76,6 +76,29 @@ "{{.}}", {{end}}] + {{ $tlsClientCert := getPassTLSClientCert $instance.SegmentLabels }} + {{if $tlsClientCert }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + {{ $auth := getAuth $instance.SegmentLabels }} {{if $auth }} [frontends."frontend-{{ $frontendName }}".auth] diff --git a/templates/kv.tmpl b/templates/kv.tmpl index afeebdabc..f4315cf04 100644 --- a/templates/kv.tmpl +++ b/templates/kv.tmpl @@ -74,6 +74,29 @@ "{{.}}", {{end}}] + {{ $tlsClientCert := getPassTLSClientCert $frontend }} + {{if $tlsClientCert }} + [frontends."{{ $frontendName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."{{ $frontendName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."{{ $frontendName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + {{ $auth := getAuth $frontend }} {{if $auth }} [frontends."{{ $frontendName }}".auth] diff --git a/templates/marathon.tmpl b/templates/marathon.tmpl index 01b1b09ad..21ec75a9f 100644 --- a/templates/marathon.tmpl +++ b/templates/marathon.tmpl @@ -77,7 +77,30 @@ "{{.}}", {{end}}] - {{ $auth := getAuth $app.SegmentLabels }} + {{ $tlsClientCert := getPassTLSClientCert $app.SegmentLabels }} + {{if $tlsClientCert }} + [frontends."{{ $frontendName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."{{ $frontendName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."{{ $frontendName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + + {{ $auth := getAuth $app.SegmentLabels }} {{if $auth }} [frontends."{{ $frontendName }}".auth] headerField = "{{ $auth.HeaderField }}" diff --git a/templates/mesos.tmpl b/templates/mesos.tmpl index 1927e694d..8df2c5939 100644 --- a/templates/mesos.tmpl +++ b/templates/mesos.tmpl @@ -77,6 +77,29 @@ "{{.}}", {{end}}] + {{ $tlsClientCert := getPassTLSClientCert $app.TraefikLabels }} + {{if $tlsClientCert }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + {{ $auth := getAuth $app.TraefikLabels }} {{if $auth }} [frontends."frontend-{{ $frontendName }}".auth] diff --git a/templates/rancher.tmpl b/templates/rancher.tmpl index 96500c41b..ca594a11b 100644 --- a/templates/rancher.tmpl +++ b/templates/rancher.tmpl @@ -75,6 +75,29 @@ "{{.}}", {{end}}] + {{ $tlsClientCert := getPassTLSClientCert $service.SegmentLabels }} + {{if $tlsClientCert }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert] + pem = {{ $tlsClientCert.PEM }} + {{ $infos := $tlsClientCert.Infos }} + {{if $infos }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos] + notAfter = {{ $infos.NotAfter }} + notBefore = {{ $infos.NotBefore }} + sans = {{ $infos.Sans }} + {{ $subject := $infos.Subject }} + {{if $subject }} + [frontends."frontend-{{ $frontendName }}".passTLSClientCert.infos.subject] + country = {{ $subject.Country }} + province = {{ $subject.Province }} + locality = {{ $subject.Locality }} + organization = {{ $subject.Organization }} + commonName = {{ $subject.CommonName }} + serialNumber = {{ $subject.SerialNumber }} + {{end}} + {{end}} + {{end}} + {{ $auth := getAuth $service.SegmentLabels }} {{if $auth }} [frontends."frontend-{{ $frontendName }}".auth] diff --git a/tls/tls.go b/tls/tls.go index 0760c870a..32a7583de 100644 --- a/tls/tls.go +++ b/tls/tls.go @@ -16,7 +16,7 @@ const ( // ClientCA defines traefik CA files for a entryPoint // and it indicates if they are mandatory or have just to be analyzed if provided type ClientCA struct { - Files []string + Files FilesOrContents Optional bool } @@ -25,14 +25,14 @@ type TLS struct { MinVersion string `export:"true"` CipherSuites []string Certificates Certificates - ClientCAFiles []string // Deprecated + ClientCAFiles FilesOrContents // Deprecated ClientCA ClientCA DefaultCertificate *Certificate SniStrict bool `export:"true"` } -// RootCAs hold the CA we want to have in root -type RootCAs []FileOrContent +// FilesOrContents hold the CA we want to have in root +type FilesOrContents []FileOrContent // Configuration allows mapping a TLS certificate to a list of entrypoints type Configuration struct { @@ -42,7 +42,7 @@ type Configuration struct { // String is the method to format the flag's value, part of the flag.Value interface. // The String method's output will be used in diagnostics. -func (r *RootCAs) String() string { +func (r *FilesOrContents) String() string { sliceOfString := make([]string, len([]FileOrContent(*r))) for key, value := range *r { sliceOfString[key] = value.String() @@ -53,30 +53,30 @@ func (r *RootCAs) String() string { // Set is the method to set the flag value, part of the flag.Value interface. // Set's argument is a string to be parsed to set the flag. // It's a comma-separated list, so we split it. -func (r *RootCAs) Set(value string) error { - rootCAs := strings.Split(value, ",") - if len(rootCAs) == 0 { - return fmt.Errorf("bad RootCAs format: %s", value) +func (r *FilesOrContents) Set(value string) error { + filesOrContents := strings.Split(value, ",") + if len(filesOrContents) == 0 { + return fmt.Errorf("bad FilesOrContents format: %s", value) } - for _, rootCA := range rootCAs { - *r = append(*r, FileOrContent(rootCA)) + for _, fileOrContent := range filesOrContents { + *r = append(*r, FileOrContent(fileOrContent)) } return nil } -// Get return the RootCAs list -func (r *RootCAs) Get() interface{} { +// Get return the FilesOrContents list +func (r *FilesOrContents) Get() interface{} { return *r } -// SetValue sets the RootCAs with val -func (r *RootCAs) SetValue(val interface{}) { - *r = val.(RootCAs) +// SetValue sets the FilesOrContents with val +func (r *FilesOrContents) SetValue(val interface{}) { + *r = val.(FilesOrContents) } // Type is type of the struct -func (r *RootCAs) Type() string { - return "rootcas" +func (r *FilesOrContents) Type() string { + return "filesorcontents" } // SortTLSPerEntryPoints converts TLS configuration sorted by Certificates into TLS configuration sorted by EntryPoints diff --git a/types/types.go b/types/types.go index b92557afb..a3dd62078 100644 --- a/types/types.go +++ b/types/types.go @@ -182,7 +182,8 @@ type Frontend struct { Backend string `json:"backend,omitempty"` Routes map[string]Route `json:"routes,omitempty" hash:"ignore"` PassHostHeader bool `json:"passHostHeader,omitempty"` - PassTLSCert bool `json:"passTLSCert,omitempty"` + PassTLSCert bool `json:"passTLSCert,omitempty"` // Deprecated use PassTLSClientCert instead + PassTLSClientCert *TLSClientHeaders `json:"passTLSClientCert,omitempty"` Priority int `json:"priority"` BasicAuth []string `json:"basicAuth"` // Deprecated WhitelistSourceRange []string `json:"whitelistSourceRange,omitempty"` // Deprecated @@ -611,3 +612,27 @@ func (h HTTPCodeRanges) Contains(statusCode int) bool { } return false } + +// TLSClientHeaders holds the TLS client cert headers configuration. +type TLSClientHeaders struct { + PEM bool `description:"Enable header with escaped client pem" json:"pem"` + Infos *TLSClientCertificateInfos `description:"Enable header with configured client cert infos" json:"infos,omitempty"` +} + +// TLSClientCertificateInfos holds the client TLS certificate infos configuration +type TLSClientCertificateInfos struct { + NotAfter bool `description:"Add NotAfter info in header" json:"notAfter"` + NotBefore bool `description:"Add NotBefore info in header" json:"notBefore"` + Subject *TLSCLientCertificateSubjectInfos `description:"Add Subject info in header" json:"subject,omitempty"` + Sans bool `description:"Add Sans info in header" json:"sans"` +} + +// TLSCLientCertificateSubjectInfos holds the client TLS certificate subject infos configuration +type TLSCLientCertificateSubjectInfos struct { + Country bool `description:"Add Country info in header" json:"country"` + Province bool `description:"Add Province info in header" json:"province"` + Locality bool `description:"Add Locality info in header" json:"locality"` + Organization bool `description:"Add Organization info in header" json:"organization"` + CommonName bool `description:"Add CommonName info in header" json:"commonName"` + SerialNumber bool `description:"Add SerialNumber info in header" json:"serialNumber"` +}