Merge branch 'v1.7' into master

This commit is contained in:
Fernandez Ludovic 2018-09-07 18:19:32 +02:00
commit bd4846aa9c
82 changed files with 3573 additions and 877 deletions

View file

@ -1,5 +1,44 @@
# Change Log
## [v1.7.0-rc4](https://github.com/containous/traefik/tree/v1.7.0-rc4) (2018-09-07)
[All Commits](https://github.com/containous/traefik/compare/v1.7.0-rc3...v1.7.0-rc4)
**Enhancements:**
- **[acme]** Use official Pebble Image. ([#3708](https://github.com/containous/traefik/pull/3708) by [ldez](https://github.com/ldez))
- **[consulcatalog]** Multiple frontends for consulcatalog ([#3796](https://github.com/containous/traefik/pull/3796) by [hsmade](https://github.com/hsmade))
- **[ecs]** Add segment support for ECS ([#3817](https://github.com/containous/traefik/pull/3817) by [mmatur](https://github.com/mmatur))
- **[k8s]** Remove unnecessary loop ([#3799](https://github.com/containous/traefik/pull/3799) by [ZloyDyadka](https://github.com/ZloyDyadka))
- **[middleware,consulcatalog,docker,ecs,kv,marathon,mesos,rancher]** Pass the TLS Cert infos in headers ([#3826](https://github.com/containous/traefik/pull/3826) by [jbdoumenjou](https://github.com/jbdoumenjou))
**Bug fixes:**
- **[acme,cluster]** StoreConfig always initializes the account if it is missing ([#3844](https://github.com/containous/traefik/pull/3844) by [geraldcroes](https://github.com/geraldcroes))
- **[acme]** Set a keyType to ACME if the account is stored with no KeyType ([#3733](https://github.com/containous/traefik/pull/3733) by [nmengin](https://github.com/nmengin))
- **[authentication,consulcatalog,docker,ecs,k8s,kv,marathon,mesos,rancher]** Auth Forward with certificates in templates. ([#3804](https://github.com/containous/traefik/pull/3804) by [ldez](https://github.com/ldez))
- **[k8s]** Prevent unparsable strings from being rendered in the Kubernetes template ([#3753](https://github.com/containous/traefik/pull/3753) by [dtomcej](https://github.com/dtomcej))
- **[k8s]** Don't merge kubernetes ingresses when priority is set ([#3743](https://github.com/containous/traefik/pull/3743) by [dtomcej](https://github.com/dtomcej))
- **[kv]** Include missing key in error message for KV store ([#3779](https://github.com/containous/traefik/pull/3779) by [camelpunch](https://github.com/camelpunch))
- **[metrics]** Avoid a panic during Prometheus registering ([#3717](https://github.com/containous/traefik/pull/3717) by [nmengin](https://github.com/nmengin))
- **[middleware,websocket]** Enable retry on websocket ([#3825](https://github.com/containous/traefik/pull/3825) by [Juliens](https://github.com/Juliens))
- **[middleware]** Extend https redirection tests, and fix incorrect behavior ([#3742](https://github.com/containous/traefik/pull/3742) by [dtomcej](https://github.com/dtomcej))
- **[oxy]** Handle Te header when http2 ([#3824](https://github.com/containous/traefik/pull/3824) by [Juliens](https://github.com/Juliens))
- **[server]** Avoid goroutine leak in server ([#3851](https://github.com/containous/traefik/pull/3851) by [nmengin](https://github.com/nmengin))
**Documentation:**
- **[acme]** Fix documentation for route53 acme provider ([#3811](https://github.com/containous/traefik/pull/3811) by [A-Shleifman](https://github.com/A-Shleifman))
- **[acme]** Update ACME documentation about TLS-ALPN challenge ([#3756](https://github.com/containous/traefik/pull/3756) by [ldez](https://github.com/ldez))
- **[docker]** Change syntax in quick start guide ([#3726](https://github.com/containous/traefik/pull/3726) by [trotro](https://github.com/trotro))
- **[docker]** Improve the wording in the documentation for Docker and fix title for Docker User Guide ([#3797](https://github.com/containous/traefik/pull/3797) by [dduportal](https://github.com/dduportal))
- **[docker]** Typo in docker-and-lets-encrypt.md ([#3724](https://github.com/containous/traefik/pull/3724) by [A-Shleifman](https://github.com/A-Shleifman))
- **[k8s]** Update kubernetes docs to reflect https options ([#3807](https://github.com/containous/traefik/pull/3807) by [dtomcej](https://github.com/dtomcej))
- **[k8s]** Update kubernetes.md ([#3719](https://github.com/containous/traefik/pull/3719) by [kmaris](https://github.com/kmaris))
- **[k8s]** Improve Connection Limit Kubernetes Documentation ([#3711](https://github.com/containous/traefik/pull/3711) by [dtomcej](https://github.com/dtomcej))
- **[provider]** Typo in auth labels. ([#3730](https://github.com/containous/traefik/pull/3730) by [ldez](https://github.com/ldez))
- **[tracing]** Simple documentation grammar update in tracing ([#3720](https://github.com/containous/traefik/pull/3720) by [loadstar81](https://github.com/loadstar81))
- Make the "base domain" on all providers ([#3835](https://github.com/containous/traefik/pull/3835) by [dduportal](https://github.com/dduportal))
**Misc:**
- Merge v1.6.6 into v1.7 ([#3802](https://github.com/containous/traefik/pull/3802) by [ldez](https://github.com/ldez))
## [v1.6.6](https://github.com/containous/traefik/tree/v1.6.6) (2018-08-20)
[All Commits](https://github.com/containous/traefik/compare/v1.6.5...v1.6.6)

View file

@ -13,7 +13,7 @@ You need to run the `binary` target. This will create binaries for Linux platfor
$ make binary
docker build -t "traefik-dev:no-more-godep-ever" -f build.Dockerfile .
Sending build context to Docker daemon 295.3 MB
Step 0 : FROM golang:1.10-alpine
Step 0 : FROM golang:1.11-alpine
---> 8c6473912976
Step 1 : RUN go get github.com/golang/dep/cmd/dep
[...]

2
Gopkg.lock generated
View file

@ -1263,7 +1263,7 @@
"roundrobin",
"utils"
]
revision = "f6bbeac6d5c4c06f88ba07ed42983ff36a5b407e"
revision = "77148e9694210e5f5610328f1cd7cf65583014c2"
[[projects]]
name = "github.com/vulcand/predicate"

View file

@ -51,7 +51,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,
},
},
@ -100,7 +100,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,
},
},
@ -185,7 +185,7 @@ func TestDo_globalConfiguration(t *testing.T) {
config.ProvidersThrottleDuration = parse.Duration(666 * time.Second)
config.MaxIdleConnsPerHost = 666
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,
}
@ -217,7 +217,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "docker Endpoint",
@ -248,7 +248,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
Directory: "file Directory",
@ -269,7 +269,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "",
@ -309,7 +309,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "ConsulCatalog Endpoint",
@ -334,7 +334,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "k8s Endpoint",
@ -360,7 +360,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "mesos Endpoint",
@ -389,7 +389,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "eureka Endpoint",
@ -411,7 +411,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
Domain: "ecs Domain",
@ -439,7 +439,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
APIConfiguration: rancher.APIConfiguration{
@ -477,7 +477,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
AccessKeyID: "dynamodb AccessKeyID",
@ -504,7 +504,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "etcd Endpoint",
@ -536,7 +536,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "zk Endpoint",
@ -568,7 +568,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "boltdb Endpoint",
@ -600,7 +600,7 @@ func TestDo_globalConfiguration(t *testing.T) {
MustMatch: true,
},
},
Trace: true,
Trace: true,
DebugLogGeneratedTemplate: true,
},
Endpoint: "consul Endpoint",

View file

@ -129,8 +129,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 }}"
@ -375,6 +397,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]
@ -622,6 +667,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]
@ -1125,6 +1193,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]
@ -1387,7 +1478,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 }}"
@ -1634,6 +1748,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]
@ -1903,6 +2040,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]

View file

@ -1,4 +1,4 @@
FROM golang:1.10-alpine
FROM golang:1.11-alpine
RUN apk --update upgrade \
&& apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar \

View file

@ -94,7 +94,7 @@ func NewCmd(traefikConfiguration *cmd.TraefikConfiguration, traefikPointersConfi
Description: `Report an issue on Traefik bugtracker`,
Config: traefikConfiguration,
DefaultPointersConfig: traefikPointersConfiguration,
Run: runCmd(traefikConfiguration),
Run: runCmd(traefikConfiguration),
Metadata: map[string]string{
"parseAllSources": "true",
},

View file

@ -34,7 +34,7 @@ func Test_createReport(t *testing.T) {
File: &file.Provider{
Directory: "BAR",
},
RootCAs: tls.RootCAs{"fllf"},
RootCAs: tls.FilesOrContents{"fllf"},
},
}

View file

@ -20,7 +20,7 @@ func NewCmd(traefikConfiguration *cmd.TraefikConfiguration, traefikPointersConfi
Description: `Calls traefik /ping to check health (web provider must be enabled)`,
Config: traefikConfiguration,
DefaultPointersConfig: traefikPointersConfiguration,
Run: runCmd(traefikConfiguration),
Run: runCmd(traefikConfiguration),
Metadata: map[string]string{
"parseAllSources": "true",
},

View file

@ -85,8 +85,13 @@ func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) fu
}
}
accountInitialized, err := keyExists(kv, traefikConfiguration.GlobalConfiguration.ACME.Storage)
if err != nil {
return err
}
// Check to see if ACME account object is already in kv store
if traefikConfiguration.GlobalConfiguration.ACME.OverrideCertificates {
if traefikConfiguration.GlobalConfiguration.ACME.OverrideCertificates || !accountInitialized {
// Store the ACME Account into the KV Store
// Certificates in KV Store will be overridden
@ -114,6 +119,15 @@ func Run(kv *staert.KvSource, traefikConfiguration *cmd.TraefikConfiguration) fu
}
}
func keyExists(source *staert.KvSource, key string) (bool, error) {
list, err := source.List(key, nil)
if err != nil {
return false, err
}
return len(list) > 0, nil
}
// migrateACMEData allows migrating data from acme.json file to KV store in function of the file format
func migrateACMEData(fileName string) (*acme.Account, error) {

View file

@ -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{})

View file

@ -75,7 +75,7 @@ type GlobalConfiguration struct {
ProvidersThrottleDuration parse.Duration `description:"Backends throttle duration: minimum duration between 2 events from providers before applying a new configuration. It avoids unnecessary reloads if multiples events are sent in a short amount of time." export:"true"`
MaxIdleConnsPerHost int `description:"If non-zero, controls the maximum idle (keep-alive) to keep per-host. If zero, DefaultMaxIdleConnsPerHost is used" export:"true"`
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"`

View file

@ -248,7 +248,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,

View file

@ -69,21 +69,21 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
"ca_optional": "true",
"compress": "true",
"forwardedheaders_trustedips": "10.0.0.3/24,20.0.0.3/24",
"name": "foo",
"proxyprotocol_trustedips": "192.168.0.1",
"redirect_entrypoint": "https",
"redirect_permanent": "true",
"redirect_regex": "http://localhost/(.*)",
"redirect_replacement": "http://mydomain/$1",
"tls": "goo,gii",
"tls_acme": "TLS",
"tls_ciphersuites": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"tls_minversion": "VersionTLS11",
"whitelist_sourcerange": "10.42.0.0/16,152.89.1.33/32,afed:be44::/16",
"whitelist_ipstrategy_depth": "3",
"whitelist_ipstrategy_excludedips": "10.0.0.3/24,20.0.0.3/24",
"clientipstrategy_depth": "3",
"clientipstrategy_excludedips": "10.0.0.3/24,20.0.0.3/24",
"name": "foo",
"proxyprotocol_trustedips": "192.168.0.1",
"redirect_entrypoint": "https",
"redirect_permanent": "true",
"redirect_regex": "http://localhost/(.*)",
"redirect_replacement": "http://mydomain/$1",
"tls": "goo,gii",
"tls_acme": "TLS",
"tls_ciphersuites": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"tls_minversion": "VersionTLS11",
"whitelist_sourcerange": "10.42.0.0/16,152.89.1.33/32,afed:be44::/16",
"whitelist_ipstrategy_depth": "3",
"whitelist_ipstrategy_excludedips": "10.0.0.3/24,20.0.0.3/24",
"clientipstrategy_depth": "3",
"clientipstrategy_excludedips": "10.0.0.3/24,20.0.0.3/24",
},
},
{
@ -232,7 +232,7 @@ func TestEntryPoints_Set(t *testing.T) {
},
},
ClientCA: tls.ClientCA{
Files: []string{"car"},
Files: tls.FilesOrContents{"car"},
Optional: true,
},
},
@ -352,7 +352,7 @@ func TestEntryPoints_Set(t *testing.T) {
},
},
ClientCA: tls.ClientCA{
Files: []string{"car"},
Files: tls.FilesOrContents{"car"},
Optional: true,
},
},

View file

@ -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]

View file

@ -31,7 +31,7 @@ exposedByDefault = false
#
stale = false
# Default domain used.
# Default base domain used for the frontend rules.
#
# Optional
#
@ -94,63 +94,73 @@ Additional settings can be defined using Consul Catalog tags.
!!! note
The default prefix is `traefik`.
| Label | Description |
|--------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `<prefix>.enable=false` | Disables this container in Træfik. |
| `<prefix>.protocol=https` | Overrides the default `http` protocol. |
| `<prefix>.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. |
| `<prefix>.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend. ex: `NetworkErrorRatio() > 0.` |
| `<prefix>.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `<prefix>.backend.healthcheck.interval=1s` | Defines the health check interval. |
| `<prefix>.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `<prefix>.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |
| `<prefix>.backend.healthcheck.headers=EXPR` | Defines the health check request headers <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `<prefix>.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm. |
| `<prefix>.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions. |
| `<prefix>.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for sticky sessions. |
| `<prefix>.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `<prefix>.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `<prefix>.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
| `<prefix>.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `<prefix>.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. |
| `<prefix>.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. |
| `<prefix>.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `<prefix>.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
| `<prefix>.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. |
| `<prefix>.frontend.auth.forward.address=https://example.com` | Sets the URL of the authentication server. |
| `<prefix>.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. |
| `<prefix>.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). |
| `<prefix>.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. |
| `<prefix>.frontend.auth.forward.tls.insecureSkipVerify=true` | If set to true invalid SSL certificates are accepted. |
| `<prefix>.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. |
| `<prefix>.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. |
| `<prefix>.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. |
| `<prefix>.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `<prefix>.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `<prefix>.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `<prefix>.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `<prefix>.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. |
| `<prefix>.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
| `<prefix>.frontend.priority=10` | Overrides default frontend priority. |
| `<prefix>.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS). |
| `<prefix>.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `<prefix>.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `<prefix>.frontend.redirect.permanent=true` | Returns 301 instead of 302. |
| `<prefix>.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{{.ServiceName}}.{{.Domain}}`. |
| `<prefix>.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.<br>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. |
| `<prefix>.frontend.whiteList.ipStrategy=true` | Uses the default IPStrategy.<br>Can be used when there is an existing `clientIPStrategy` but you want the remote address for whitelisting. |
| `<prefix>.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
| `<prefix>.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
| Label | Description |
|----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `<prefix>.enable=false` | Disables this container in Træfik. |
| `<prefix>.protocol=https` | Overrides the default `http` protocol. |
| `<prefix>.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. |
| `<prefix>.backend.circuitbreaker.expression=EXPR` | Creates a [circuit breaker](/basics/#backends) to be used against the backend. ex: `NetworkErrorRatio() > 0.` |
| `<prefix>.backend.healthcheck.path=/health` | Enables health check for the backend, hitting the container at `path`. |
| `<prefix>.backend.healthcheck.interval=1s` | Defines the health check interval. |
| `<prefix>.backend.healthcheck.port=8080` | Sets a different port for the health check. |
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
| `<prefix>.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |
| `<prefix>.backend.healthcheck.headers=EXPR` | Defines the health check request headers <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `<prefix>.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm. |
| `<prefix>.backend.loadbalancer.stickiness=true` | Enables backend sticky sessions. |
| `<prefix>.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for sticky sessions. |
| `<prefix>.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `<prefix>.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `<prefix>.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
| `<prefix>.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `<prefix>.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. |
| `<prefix>.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. |
| `<prefix>.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
| `<prefix>.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
| `<prefix>.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. |
| `<prefix>.frontend.auth.forward.address=https://example.com` | Sets the URL of the authentication server. |
| `<prefix>.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. |
| `<prefix>.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). |
| `<prefix>.frontend.auth.forward.tls.cert=/path/server.pem` | Sets the Certificate for the TLS connection with the authentication server. |
| `<prefix>.frontend.auth.forward.tls.insecureSkipVerify=true` | If set to true invalid SSL certificates are accepted. |
| `<prefix>.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. |
| `<prefix>.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. |
| `<prefix>.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. |
| `<prefix>.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
| `<prefix>.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `<prefix>.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `<prefix>.frontend.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `<prefix>.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. |
| `<prefix>.frontend.passTLSClientCert.infos.notAfter=true` | Add the noAfter field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. |
| `<prefix>.frontend.passTLSClientCert.infos.notBefore=true` | Add the noBefore field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. |
| `<prefix>.frontend.passTLSClientCert.infos.sans=true` | Add the sans field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. |
| `<prefix>.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. |
| `<prefix>.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. |
| `<prefix>.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. |
| `<prefix>.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. |
| `<prefix>.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. |
| `<prefix>.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. |
| `<prefix>.frontend.passTLSClientCert.pem=true` | Pass the escaped pem in the `X-Forwarded-Ssl-Client-Cert` header. |
| `<prefix>.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
| `<prefix>.frontend.priority=10` | Overrides default frontend priority. |
| `<prefix>.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `<prefix>.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS). |
| `<prefix>.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `<prefix>.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
| `<prefix>.frontend.redirect.permanent=true` | Returns 301 instead of 302. |
| `<prefix>.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{{.ServiceName}}.{{.Domain}}`. |
| `<prefix>.frontend.whiteList.sourceRange=RANGE` | Sets a list of IP-Ranges which are allowed to access.<br>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. |
| `<prefix>.frontend.whiteList.ipStrategy=true` | Uses the default IPStrategy.<br>Can be used when there is an existing `clientIPStrategy` but you want the remote address for whitelisting. |
| `<prefix>.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
| `<prefix>.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
### Multiple frontends for a single service
@ -201,7 +211,7 @@ If you need to support multiple frontends for a service, for example when having
| `<prefix>.frontend.headers.STSIncludeSubdomains=true` | Adds the `IncludeSubdomains` section of the STS header. |
| `<prefix>.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. |
### Examples
If you want that Træfik uses Consul tags correctly you need to defined them like that:

View file

@ -207,68 +207,78 @@ 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 <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `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.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.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets 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`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.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.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.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.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>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.<br>An unset or empty list allows all Source-IPs to access.<br>If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.ipStrategy=true` | Uses the default IPStrategy.<br>Can be used when there is an existing `clientIPStrategy` but you want the remote address for whitelisting. |
| `traefik.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
| `traefik.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
| 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 <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `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.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.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets 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`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.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.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.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.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>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.<br>An unset or empty list allows all Source-IPs to access.<br>If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.ipStrategy=true` | Uses the default IPStrategy.<br>Can be used when there is an existing `clientIPStrategy` but you want the remote address for whitelisting. |
| `traefik.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
| `traefik.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
[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 <container_id>`) otherwise it will randomly pick one (depending on how docker is returning them).
@ -320,48 +330,58 @@ You can define as many segments as ports exposed in a container.
Segment labels override the default behavior.
| Label | Description |
|------------------------------------------------------------------------------|----------------------------------------------------------------|
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
| `traefik.<segment_name>.frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` |
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
| `traefik.<segment_name>.frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` |
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com` | Same as `traefik.frontend.auth.forward.address` |
| `traefik.<segment_name>.frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
| `traefik.<segment_name>.frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
| `traefik.<segment_name>.frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
| `traefik.<segment_name>.frontend.auth.forward.tls.insecureSkipVerify=true` | Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` |
| `traefik.<segment_name>.frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
| `traefik.<segment_name>.frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
| `traefik.<segment_name>.frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy=true` | Same as `traefik.frontend.whiteList.ipStrategy` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.depth=5` | Same as `traefik.frontend.whiteList.ipStrategy.depth` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | Same as `traefik.frontend.whiteList.ipStrategy.excludedIPs` |
| Label | Description |
|------------------------------------------------------------------------------------|------------------------------------------------------------------------|
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
| `traefik.<segment_name>.frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` |
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
| `traefik.<segment_name>.frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` |
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com` | Same as `traefik.frontend.auth.forward.address` |
| `traefik.<segment_name>.frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
| `traefik.<segment_name>.frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
| `traefik.<segment_name>.frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
| `traefik.<segment_name>.frontend.auth.forward.tls.insecureSkipVerify=true` | Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` |
| `traefik.<segment_name>.frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
| `traefik.<segment_name>.frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
| `traefik.<segment_name>.frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.organization=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.organization`|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.serialNumber=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber`|
| `traefik.<segment_name>.frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` |
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy=true` | Same as `traefik.frontend.whiteList.ipStrategy` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.depth=5` | Same as `traefik.frontend.whiteList.ipStrategy.depth` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | Same as `traefik.frontend.whiteList.ipStrategy.excludedIPs` |
#### Custom Headers

View file

@ -26,7 +26,7 @@ clusters = ["default"]
#
watch = true
# Default domain used.
# Default base domain used for the frontend rules.
# Can be overridden by setting the "traefik.domain" label.
#
# Optional
@ -130,67 +130,77 @@ Træfik needs the following policy to read ECS information:
Labels can be used on task containers to override default behavior:
| 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 <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `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.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
| `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`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.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.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.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.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>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.<br>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.ipStrategy=true` | Uses the default IPStrategy.<br>Can be used when there is an existing `clientIPStrategy` but you want the remote address for whitelisting. |
| `traefik.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
| `traefik.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
| 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 <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `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.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
| `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`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.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.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.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.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>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.<br>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.ipStrategy=true` | Uses the default IPStrategy.<br>Can be used when there is an existing `clientIPStrategy` but you want the remote address for whitelisting. |
| `traefik.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
| `traefik.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
### Custom Headers
@ -232,50 +242,60 @@ You can define as many segments as ports exposed in an application.
Segment labels override the default behavior.
| Label | Description |
|------------------------------------------------------------------------------|----------------------------------------------------------------|
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
| `traefik.<segment_name>.frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` |
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
| `traefik.<segment_name>.frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` |
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com` | Same as `traefik.frontend.auth.forward.address` |
| `traefik.<segment_name>.frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
| `traefik.<segment_name>.frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
| `traefik.<segment_name>.frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
| `traefik.<segment_name>.frontend.auth.forward.tls.insecureSkipVerify=true` | Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` |
| `traefik.<segment_name>.frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
| `traefik.<segment_name>.frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
| `traefik.<segment_name>.frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
| `traefik.<segment_name>.frontend.auth.removeHeader=true` | Same as `traefik.frontend.auth.removeHeader` |
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy=true` | Same as `traefik.frontend.whiteList.ipStrategy` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.depth=5` | Same as `traefik.frontend.whiteList.ipStrategy.depth` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | Same as `traefik.frontend.whiteList.ipStrategy.excludedIPs` |
| Label | Description |
|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------|
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
| `traefik.<segment_name>.frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` |
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
| `traefik.<segment_name>.frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` |
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com` | Same as `traefik.frontend.auth.forward.address` |
| `traefik.<segment_name>.frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
| `traefik.<segment_name>.frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
| `traefik.<segment_name>.frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
| `traefik.<segment_name>.frontend.auth.forward.tls.insecureSkipVerify=true` | Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` |
| `traefik.<segment_name>.frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
| `traefik.<segment_name>.frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
| `traefik.<segment_name>.frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
| `traefik.<segment_name>.frontend.auth.removeHeader=true` | Same as `traefik.frontend.auth.removeHeader` |
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.organization=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.organization` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.serialNumber=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber` |
| `traefik.<segment_name>.frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` |
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy=true` | Same as `traefik.frontend.whiteList.ipStrategy` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.depth=5` | Same as `traefik.frontend.whiteList.ipStrategy.depth` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | Same as `traefik.frontend.whiteList.ipStrategy.excludedIPs` |
#### Custom Headers

View file

@ -53,9 +53,24 @@ Træfik can be configured with a file.
entryPoints = ["http", "https"]
backend = "backend1"
passHostHeader = true
passTLSCert = true
priority = 42
[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]

View file

@ -31,7 +31,7 @@ endpoint = "http://127.0.0.1:8080"
#
watch = true
# Default domain used.
# Default base domain used for the frontend rules.
# Can be overridden by setting the "traefik.domain" label on an application.
#
# Required
@ -193,68 +193,78 @@ 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 <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `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.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
| `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`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.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.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.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.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>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.<br>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.ipStrategy=true` | Uses the default IPStrategy.<br>Can be used when there is an existing `clientIPStrategy` but you want the remote address for whitelisting. |
| `traefik.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
| `traefik.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
| Label | Description |
|---------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `traefik.domain` | Sets the default base 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 <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `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.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
| `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`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.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.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.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.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>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.<br>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.ipStrategy=true` | Uses the default IPStrategy.<br>Can be used when there is an existing `clientIPStrategy` but you want the remote address for whitelisting. |
| `traefik.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
| `traefik.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
#### Custom Headers
@ -326,6 +336,16 @@ Segment labels override the default behavior.
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.organization=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.organization`|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.serialNumber=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber`|
| `traefik.<segment_name>.frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` |
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |

View file

@ -27,7 +27,7 @@ endpoint = "http://127.0.0.1:8080"
#
watch = true
# Default domain used.
# Default base domain used for the frontend rules.
# Can be overridden by setting the "traefik.domain" label on an application.
#
# Required
@ -154,6 +154,16 @@ The following labels can be defined on Mesos tasks. They adjust the behavior for
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.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. |
@ -242,6 +252,16 @@ Segment labels override the default behavior.
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.organization=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.organization`|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.serialNumber=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber`|
| `traefik.<segment_name>.frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` |
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |

View file

@ -12,7 +12,7 @@ Træfik can be configured to use Rancher as a provider.
# Enable Rancher Provider.
[rancher]
# Default domain used.
# Default base domain used for the frontend rules.
# Can be overridden by setting the "traefik.domain" label on an service.
#
# Required
@ -138,66 +138,76 @@ 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 <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `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.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets 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`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.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.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.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.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>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.<br>An unset or empty list allows all Source-IPs to access.<br>If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.ipStrategy=true` | Uses the default IPStrategy.<br>Can be used when there is an existing `clientIPStrategy` but you want the remote address for whitelisting. |
| `traefik.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
| `traefik.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
| 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 <br>Format: <code>HEADER:value&vert;&vert;HEADER2:value2</code> |
| `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.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
| `traefik.frontend.auth.basic=EXPR` | Sets 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`.<br>Overrides `defaultEntryPoints` |
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
| `traefik.frontend.errors.<name>.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.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
| `traefik.frontend.rateLimit.rateSet.<name>.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.<br>Must be set with `traefik.frontend.redirect.replacement`. |
| `traefik.frontend.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>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.<br>An unset or empty list allows all Source-IPs to access.<br>If one of the Net-Specifications are invalid, the whole list is invalid and allows all Source-IPs to access. |
| `traefik.frontend.whiteList.ipStrategy=true` | Uses the default IPStrategy.<br>Can be used when there is an existing `clientIPStrategy` but you want the remote address for whitelisting. |
| `traefik.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
| `traefik.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
#### Custom Headers
@ -239,48 +249,58 @@ You can define as many segments as ports exposed in a container.
Segment labels override the default behavior.
| Label | Description |
|------------------------------------------------------------------------------|----------------------------------------------------------------|
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
| `traefik.<segment_name>.frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` |
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
| `traefik.<segment_name>.frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` |
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com` | Same as `traefik.frontend.auth.forward.address` |
| `traefik.<segment_name>.frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
| `traefik.<segment_name>.frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
| `traefik.<segment_name>.frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
| `traefik.<segment_name>.frontend.auth.forward.tls.insecureSkipVerify=true` | Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` |
| `traefik.<segment_name>.frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
| `traefik.<segment_name>.frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
| `traefik.<segment_name>.frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy=true` | Same as `traefik.frontend.whiteList.ipStrategy` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.depth=5` | Same as `traefik.frontend.whiteList.ipStrategy.depth` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | Same as `traefik.frontend.whiteList.ipStrategy.excludedIPs` |
| Label | Description |
|------------------------------------------------------------------------------------|------------------------------------------------------------------------|
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
| `traefik.<segment_name>.frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` |
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
| `traefik.<segment_name>.frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` |
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com` | Same as `traefik.frontend.auth.forward.address` |
| `traefik.<segment_name>.frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
| `traefik.<segment_name>.frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
| `traefik.<segment_name>.frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
| `traefik.<segment_name>.frontend.auth.forward.tls.insecureSkipVerify=true` | Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` |
| `traefik.<segment_name>.frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
| `traefik.<segment_name>.frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
| `traefik.<segment_name>.frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.organization=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.organization`|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` |
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.serialNumber=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber`|
| `traefik.<segment_name>.frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` |
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy=true` | Same as `traefik.frontend.whiteList.ipStrategy` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.depth=5` | Same as `traefik.frontend.whiteList.ipStrategy.depth` |
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | Same as `traefik.frontend.whiteList.ipStrategy.excludedIPs` |
#### Custom Headers

View file

@ -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"

View file

@ -118,7 +118,7 @@ func (hc *HealthCheck) execute(ctx context.Context, backend *BackendConfig) {
for {
select {
case <-ctx.Done():
log.Debug("Stopping current health check goroutines of backend: %s", backend.name)
log.Debugf("Stopping current health check goroutines of backend: %s", backend.name)
return
case <-ticker.C:
log.Debugf("Refreshing health check for backend: %s", backend.name)

View file

@ -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-----

View file

@ -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-----

View file

@ -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-----

View file

@ -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

View file

@ -59,6 +59,7 @@ func init() {
check.Suite(&RateLimitSuite{})
check.Suite(&RetrySuite{})
check.Suite(&SimpleSuite{})
check.Suite(&TLSClientHeadersSuite{})
check.Suite(&TimeoutSuite{})
check.Suite(&TracingSuite{})
check.Suite(&WebsocketSuite{})

View file

@ -0,0 +1,6 @@
whoami:
image: containous/whoami
labels:
- traefik.frontend.passTLSClientCert.pem=true
- traefik.frontend.rule=PathPrefix:/

View file

@ -7,6 +7,7 @@ import (
"github.com/containous/traefik/integration/try"
"github.com/go-check/check"
"github.com/gorilla/websocket"
checker "github.com/vdemeester/shakers"
)
@ -38,3 +39,29 @@ func (s *RetrySuite) TestRetry(c *check.C) {
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
}
func (s *RetrySuite) TestRetryWebsocket(c *check.C) {
whoamiEndpoint := s.composeProject.Container(c, "whoami").NetworkSettings.IPAddress
file := s.adaptFile(c, "fixtures/retry/simple.toml", struct {
WhoamiEndpoint string
}{whoamiEndpoint})
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", 60*time.Second, try.BodyContains("PathPrefix:/"))
c.Assert(err, checker.IsNil)
// This simulates a DialTimeout when connecting to the backend server.
_, response, err := websocket.DefaultDialer.Dial("ws://127.0.0.1:8000/echo", nil)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusSwitchingProtocols)
_, response, err = websocket.DefaultDialer.Dial("ws://127.0.0.1:8000/echo", nil)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusSwitchingProtocols)
}

View file

@ -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)
}

View file

@ -193,26 +193,26 @@ func TestLoggerJSON(t *testing.T) {
Format: JSONFormat,
},
expected: map[string]func(t *testing.T, value interface{}){
RequestHost: assertString(testHostname),
RequestAddr: assertString(testHostname),
RequestMethod: assertString(testMethod),
RequestPath: assertString(testPath),
RequestProtocol: assertString(testProto),
RequestPort: assertString("-"),
DownstreamStatus: assertFloat64(float64(testStatus)),
DownstreamContentSize: assertFloat64(float64(len(testContent))),
OriginContentSize: assertFloat64(float64(len(testContent))),
OriginStatus: assertFloat64(float64(testStatus)),
RequestRefererHeader: assertString(testReferer),
RequestUserAgentHeader: assertString(testUserAgent),
FrontendName: assertString(testFrontendName),
BackendURL: assertString(testBackendName),
ClientUsername: assertString(testUsername),
ClientHost: assertString(testHostname),
ClientPort: assertString(fmt.Sprintf("%d", testPort)),
ClientAddr: assertString(fmt.Sprintf("%s:%d", testHostname, testPort)),
"level": assertString("info"),
"msg": assertString(""),
RequestHost: assertString(testHostname),
RequestAddr: assertString(testHostname),
RequestMethod: assertString(testMethod),
RequestPath: assertString(testPath),
RequestProtocol: assertString(testProto),
RequestPort: assertString("-"),
DownstreamStatus: assertFloat64(float64(testStatus)),
DownstreamContentSize: assertFloat64(float64(len(testContent))),
OriginContentSize: assertFloat64(float64(len(testContent))),
OriginStatus: assertFloat64(float64(testStatus)),
RequestRefererHeader: assertString(testReferer),
RequestUserAgentHeader: assertString(testUserAgent),
FrontendName: assertString(testFrontendName),
BackendURL: assertString(testBackendName),
ClientUsername: assertString(testUsername),
ClientHost: assertString(testHostname),
ClientPort: assertString(fmt.Sprintf("%d", testPort)),
ClientAddr: assertString(fmt.Sprintf("%s:%d", testHostname, testPort)),
"level": assertString("info"),
"msg": assertString(""),
"downstream_Content-Type": assertString("text/plain; charset=utf-8"),
RequestCount: assertFloat64NotZero(),
Duration: assertFloat64NotZero(),
@ -233,9 +233,9 @@ func TestLoggerJSON(t *testing.T) {
},
},
expected: map[string]func(t *testing.T, value interface{}){
"level": assertString("info"),
"msg": assertString(""),
"time": assertNotEqual(""),
"level": assertString("info"),
"msg": assertString(""),
"time": assertNotEqual(""),
"downstream_Content-Type": assertString("text/plain; charset=utf-8"),
RequestRefererHeader: assertString(testReferer),
RequestUserAgentHeader: assertString(testUserAgent),
@ -272,9 +272,9 @@ func TestLoggerJSON(t *testing.T) {
},
},
expected: map[string]func(t *testing.T, value interface{}){
"level": assertString("info"),
"msg": assertString(""),
"time": assertNotEqual(""),
"level": assertString("info"),
"msg": assertString(""),
"time": assertNotEqual(""),
"downstream_Content-Type": assertString("REDACTED"),
RequestRefererHeader: assertString("REDACTED"),
RequestUserAgentHeader: assertString("REDACTED"),

View file

@ -48,7 +48,7 @@ func (wl *IPWhiteLister) handle(w http.ResponseWriter, r *http.Request, next htt
return
}
log.Debugf("Accept %s: %+v", wl.strategy.GetIP(r), r)
tracing.SetErrorAndDebugLog(r, "request %+v matched white list %s - passing", r, wl.whiteLister)
tracing.SetErrorAndDebugLog(r, "request %+v matched white list %v - passing", r, wl.whiteLister)
next.ServeHTTP(w, r)
}

View file

@ -2,6 +2,7 @@ package middlewares
import (
"bufio"
"fmt"
"io/ioutil"
"net"
"net/http"
@ -41,11 +42,8 @@ func (retry *Retry) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
attempts := 1
for {
attemptsExhausted := attempts >= retry.attempts
// Websocket requests can't be retried at this point in time.
// This is due to the fact that gorilla/websocket doesn't use the request
// context and so we don't get httptrace information.
// Websocket clients should however retry on their own anyway.
shouldRetry := !attemptsExhausted && !isWebsocketRequest(r)
shouldRetry := !attemptsExhausted
retryResponseWriter := newRetryResponseWriter(rw, shouldRetry)
// Disable retries when the backend already received request data
@ -128,7 +126,7 @@ func (rr *retryResponseWriterWithoutCloseNotify) Header() http.Header {
func (rr *retryResponseWriterWithoutCloseNotify) Write(buf []byte) (int, error) {
if rr.ShouldRetry() {
return 0, nil
return len(buf), nil
}
return rr.responseWriter.Write(buf)
}
@ -150,7 +148,11 @@ func (rr *retryResponseWriterWithoutCloseNotify) WriteHeader(code int) {
}
func (rr *retryResponseWriterWithoutCloseNotify) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return rr.responseWriter.(http.Hijacker).Hijack()
hijacker, ok := rr.responseWriter.(http.Hijacker)
if !ok {
return nil, nil, fmt.Errorf("%T is not a http.Hijacker", rr.responseWriter)
}
return hijacker.Hijack()
}
func (rr *retryResponseWriterWithoutCloseNotify) Flush() {

View file

@ -3,22 +3,24 @@ package middlewares
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/containous/traefik/testhelpers"
"github.com/gorilla/websocket"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/vulcand/oxy/forward"
"github.com/vulcand/oxy/roundrobin"
)
func TestRetry(t *testing.T) {
testCases := []struct {
desc string
maxRequestAttempts int
wantRetryAttempts int
wantResponseStatus int
amountFaultyEndpoints int
isWebsocketHandshakeRequest bool
desc string
maxRequestAttempts int
wantRetryAttempts int
wantResponseStatus int
amountFaultyEndpoints int
}{
{
desc: "no retry on success",
@ -55,14 +57,6 @@ func TestRetry(t *testing.T) {
wantResponseStatus: http.StatusInternalServerError,
amountFaultyEndpoints: 3,
},
{
desc: "websocket request should not be retried",
maxRequestAttempts: 3,
wantRetryAttempts: 0,
wantResponseStatus: http.StatusBadGateway,
amountFaultyEndpoints: 1,
isWebsocketHandshakeRequest: true,
},
}
backendServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
@ -75,10 +69,10 @@ func TestRetry(t *testing.T) {
t.Fatalf("Error creating forwarder: %s", err)
}
for _, tc := range testCases {
tc := tc
for _, test := range testCases {
test := test
t.Run(tc.desc, func(t *testing.T) {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
loadBalancer, err := roundrobin.New(forwarder)
@ -87,7 +81,7 @@ func TestRetry(t *testing.T) {
}
basePort := 33444
for i := 0; i < tc.amountFaultyEndpoints; i++ {
for i := 0; i < test.amountFaultyEndpoints; i++ {
// 192.0.2.0 is a non-routable IP for testing purposes.
// See: https://stackoverflow.com/questions/528538/non-routable-ip-address/18436928#18436928
// We only use the port specification here because the URL is used as identifier
@ -101,24 +95,91 @@ func TestRetry(t *testing.T) {
assert.NoError(t, err)
retryListener := &countingRetryListener{}
retry := NewRetry(tc.maxRequestAttempts, loadBalancer, retryListener)
retry := NewRetry(test.maxRequestAttempts, loadBalancer, retryListener)
recorder := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "http://localhost:3000/ok", nil)
if tc.isWebsocketHandshakeRequest {
req.Header.Add("Connection", "Upgrade")
req.Header.Add("Upgrade", "websocket")
}
retry.ServeHTTP(recorder, req)
if tc.wantResponseStatus != recorder.Code {
t.Errorf("got status code %d, want %d", recorder.Code, tc.wantResponseStatus)
assert.Equal(t, test.wantResponseStatus, recorder.Code)
assert.Equal(t, test.wantRetryAttempts, retryListener.timesCalled)
})
}
}
func TestRetryWebsocket(t *testing.T) {
testCases := []struct {
desc string
maxRequestAttempts int
expectedRetryAttempts int
expectedResponseStatus int
expectedError bool
amountFaultyEndpoints int
}{
{
desc: "Switching ok after 2 retries",
maxRequestAttempts: 3,
expectedRetryAttempts: 2,
amountFaultyEndpoints: 2,
expectedResponseStatus: http.StatusSwitchingProtocols,
},
{
desc: "Switching failed",
maxRequestAttempts: 2,
expectedRetryAttempts: 1,
amountFaultyEndpoints: 2,
expectedResponseStatus: http.StatusBadGateway,
expectedError: true,
},
}
forwarder, err := forward.New()
if err != nil {
t.Fatalf("Error creating forwarder: %s", err)
}
backendServer := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
upgrader := websocket.Upgrader{}
upgrader.Upgrade(rw, req, nil)
}))
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
loadBalancer, err := roundrobin.New(forwarder)
if err != nil {
t.Fatalf("Error creating load balancer: %s", err)
}
if tc.wantRetryAttempts != retryListener.timesCalled {
t.Errorf("retry listener called %d time(s), want %d time(s)", retryListener.timesCalled, tc.wantRetryAttempts)
basePort := 33444
for i := 0; i < test.amountFaultyEndpoints; i++ {
// 192.0.2.0 is a non-routable IP for testing purposes.
// See: https://stackoverflow.com/questions/528538/non-routable-ip-address/18436928#18436928
// We only use the port specification here because the URL is used as identifier
// in the load balancer and using the exact same URL would not add a new server.
loadBalancer.UpsertServer(testhelpers.MustParseURL("http://192.0.2.0:" + string(basePort+i)))
}
// add the functioning server to the end of the load balancer list
loadBalancer.UpsertServer(testhelpers.MustParseURL(backendServer.URL))
retryListener := &countingRetryListener{}
retry := NewRetry(test.maxRequestAttempts, loadBalancer, retryListener)
retryServer := httptest.NewServer(retry)
url := strings.Replace(retryServer.URL, "http", "ws", 1)
_, response, err := websocket.DefaultDialer.Dial(url, nil)
if !test.expectedError {
require.NoError(t, err)
}
assert.Equal(t, test.expectedResponseStatus, response.StatusCode)
assert.Equal(t, test.expectedRetryAttempts, retryListener.timesCalled)
})
}
}

View file

@ -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")
}
}
}

View file

@ -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))
})
}
}

View file

@ -338,7 +338,7 @@ func (p *Provider) watchNewDomains() {
}
if len(domains) == 0 {
log.Debugf("No domain parsed in rule %q", route.Rule)
log.Debugf("No domain parsed in rule %q in provider ACME", route.Rule)
continue
}

View file

@ -44,6 +44,7 @@ func (p *Provider) buildConfiguration(catalog []catalogUpdate) *types.Configurat
"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,

View file

@ -423,6 +423,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",
@ -540,6 +551,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{

View file

@ -42,19 +42,20 @@ func (p *Provider) buildConfiguration(containersInspected []dockerData) *types.C
"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

View file

@ -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{
@ -387,6 +450,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{

View file

@ -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{

View file

@ -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",
@ -368,6 +444,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{

View file

@ -31,20 +31,21 @@ func (p *Provider) buildConfiguration(instances []ecsInstance) (*types.Configura
"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)

View file

@ -321,6 +321,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",
@ -391,6 +402,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{

View file

@ -356,6 +356,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"),
@ -489,6 +500,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{

View file

@ -380,7 +380,7 @@ func (p *Provider) lookupEc2Instances(ctx context.Context, client *awsClient, cl
})
if err != nil {
log.Errorf("Unable to describe instances [%s]: %v", err)
log.Errorf("Unable to describe instances: %v", err)
return nil, err
}
}

View file

@ -516,37 +516,37 @@ func TestModifierType(t *testing.T) {
expectedModifierRule string
}{
{
desc: "Request modifier annotation missing",
desc: "Request modifier annotation missing",
requestModifierAnnotation: "",
expectedModifierRule: "",
},
{
desc: "AddPrefix modifier annotation",
desc: "AddPrefix modifier annotation",
requestModifierAnnotation: " AddPrefix: /foo",
expectedModifierRule: "AddPrefix:/foo",
},
{
desc: "ReplacePath modifier annotation",
desc: "ReplacePath modifier annotation",
requestModifierAnnotation: " ReplacePath: /foo",
expectedModifierRule: "ReplacePath:/foo",
},
{
desc: "ReplacePathRegex modifier annotation",
desc: "ReplacePathRegex modifier annotation",
requestModifierAnnotation: " ReplacePathRegex: /foo /bar",
expectedModifierRule: "ReplacePathRegex:/foo /bar",
},
{
desc: "AddPrefix modifier annotation",
desc: "AddPrefix modifier annotation",
requestModifierAnnotation: "AddPrefix:/foo",
expectedModifierRule: "AddPrefix:/foo",
},
{
desc: "ReplacePath modifier annotation",
desc: "ReplacePath modifier annotation",
requestModifierAnnotation: "ReplacePath:/foo",
expectedModifierRule: "ReplacePath:/foo",
},
{
desc: "ReplacePathRegex modifier annotation",
desc: "ReplacePathRegex modifier annotation",
requestModifierAnnotation: "ReplacePathRegex:/foo /bar",
expectedModifierRule: "ReplacePathRegex:/foo /bar",
},
@ -608,23 +608,23 @@ func TestModifierFails(t *testing.T) {
requestModifierAnnotation string
}{
{
desc: "Request modifier missing part of annotation",
desc: "Request modifier missing part of annotation",
requestModifierAnnotation: "AddPrefix: ",
},
{
desc: "Request modifier full of spaces annotation",
desc: "Request modifier full of spaces annotation",
requestModifierAnnotation: " ",
},
{
desc: "Request modifier missing both parts of annotation",
desc: "Request modifier missing both parts of annotation",
requestModifierAnnotation: " : ",
},
{
desc: "Request modifier using unknown rule",
desc: "Request modifier using unknown rule",
requestModifierAnnotation: "Foo: /bar",
},
{
desc: "Missing Rule",
desc: "Missing Rule",
requestModifierAnnotation: " : /bar",
},
}

View file

@ -24,15 +24,28 @@ const (
pathBackendBufferingMemRequestBodyBytes = pathBackendBuffering + "memrequestbodybytes"
pathBackendBufferingRetryExpression = pathBackendBuffering + "retryexpression"
pathFrontends = "/frontends/"
pathFrontendBackend = "/backend"
pathFrontendPriority = "/priority"
pathFrontendPassHostHeader = "/passhostheader"
pathFrontendPassTLSCert = "/passtlscert"
pathFrontendWhiteListSourceRange = "/whitelist/sourcerange"
pathFrontendWhiteListIPStrategy = "/whitelist/ipstrategy"
pathFrontendWhiteListIPStrategyDepth = pathFrontendWhiteListIPStrategy + "/depth"
pathFrontendWhiteListIPStrategyExcludedIPs = pathFrontendWhiteListIPStrategy + "/excludedips"
pathFrontends = "/frontends/"
pathFrontendBackend = "/backend"
pathFrontendPriority = "/priority"
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"
pathFrontendWhiteListIPStrategy = "/whitelist/ipstrategy"
pathFrontendWhiteListIPStrategyDepth = pathFrontendWhiteListIPStrategy + "/depth"
pathFrontendWhiteListIPStrategyExcludedIPs = pathFrontendWhiteListIPStrategy + "/excludedips"
pathFrontendAuth = "/auth/"
pathFrontendAuthBasic = pathFrontendAuth + "basic/"

View file

@ -41,18 +41,19 @@ func (p *Provider) buildConfiguration() *types.Configuration {
"getTLSSection": p.getTLSSection,
// Frontend functions
"getBackendName": p.getFuncString(pathFrontendBackend, ""),
"getPriority": p.getFuncInt(pathFrontendPriority, label.DefaultFrontendPriority),
"getPassHostHeader": p.getFuncBool(pathFrontendPassHostHeader, label.DefaultPassHostHeader),
"getPassTLSCert": p.getFuncBool(pathFrontendPassTLSCert, label.DefaultPassTLSCert),
"getEntryPoints": p.getFuncList(pathFrontendEntryPoints),
"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.getFuncBool(pathFrontendPassHostHeader, label.DefaultPassHostHeader),
"getPassTLSCert": p.getFuncBool(pathFrontendPassTLSCert, label.DefaultPassTLSCert),
"getPassTLSClientCert": p.getTLSClientCert,
"getEntryPoints": p.getFuncList(pathFrontendEntryPoints),
"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,
@ -334,6 +335,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
}
// GetAuth Create auth from path
func (p *Provider) getAuth(rootPath string) *types.Auth {
if p.hasPrefix(rootPath, pathFrontendAuth) {

View file

@ -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"),
@ -403,6 +415,22 @@ func TestProviderBuildConfiguration(t *testing.T) {
ExcludedIPs: []string{"1.1.1.1/24", "1234:abcd::42/32"},
},
},
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{

View file

@ -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"
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"
SuffixFrontendWhiteList = "frontend.whiteList."
SuffixFrontendWhiteListSourceRange = SuffixFrontendWhiteList + "sourceRange"
SuffixFrontendWhiteListIPStrategy = SuffixFrontendWhiteList + "ipStrategy"
SuffixFrontendWhiteListIPStrategyDepth = SuffixFrontendWhiteListIPStrategy + ".depth"
SuffixFrontendWhiteListIPStrategyExcludedIPS = SuffixFrontendWhiteListIPStrategy + ".excludedIPs"
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
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
TraefikFrontendWhiteListIPStrategy = Prefix + SuffixFrontendWhiteListIPStrategy
TraefikFrontendWhiteListIPStrategyDepth = Prefix + SuffixFrontendWhiteListIPStrategyDepth
TraefikFrontendWhiteListIPStrategyExcludedIPS = Prefix + SuffixFrontendWhiteListIPStrategyExcludedIPS
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"
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"
SuffixFrontendWhiteList = "frontend.whiteList."
SuffixFrontendWhiteListSourceRange = SuffixFrontendWhiteList + "sourceRange"
SuffixFrontendWhiteListIPStrategy = SuffixFrontendWhiteList + "ipStrategy"
SuffixFrontendWhiteListIPStrategyDepth = SuffixFrontendWhiteListIPStrategy + ".depth"
SuffixFrontendWhiteListIPStrategyExcludedIPS = SuffixFrontendWhiteListIPStrategy + ".excludedIPs"
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
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
TraefikFrontendWhiteListIPStrategy = Prefix + SuffixFrontendWhiteListIPStrategy
TraefikFrontendWhiteListIPStrategyDepth = Prefix + SuffixFrontendWhiteListIPStrategyDepth
TraefikFrontendWhiteListIPStrategyExcludedIPS = Prefix + SuffixFrontendWhiteListIPStrategyExcludedIPS
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"
)

View file

@ -62,6 +62,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) {

View file

@ -815,3 +815,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)
})
}
}

View file

@ -44,6 +44,7 @@ func (p *Provider) buildConfiguration(applications *marathon.Applications) *type
"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

View file

@ -373,6 +373,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"),
@ -455,6 +466,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{
@ -767,6 +794,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 +885,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{

View file

@ -48,6 +48,7 @@ func (p *Provider) buildConfiguration(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,

View file

@ -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"),
@ -418,6 +429,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{
@ -687,6 +714,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"),
@ -768,6 +806,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{

View file

@ -128,7 +128,7 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
func detectMasters(zk string, masters []string) <-chan []string {
changed := make(chan []string, 1)
if zk != "" {
log.Debugf("Starting master detector for ZK ", zk)
log.Debugf("Starting master detector for ZK %s", zk)
if md, err := detector.New(zk); err != nil {
log.Errorf("Failed to create master detector: %v", err)
} else if err := md.Detect(detect.NewMasters(masters, changed)); err != nil {

View file

@ -28,19 +28,20 @@ func (p *Provider) buildConfiguration(services []rancherData) *types.Configurati
"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

View file

@ -58,6 +58,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{
@ -293,6 +320,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",
@ -373,6 +411,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{
@ -689,7 +743,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
func TestProviderServiceFilter(t *testing.T) {
provider := &Provider{
Domain: "rancher.localhost",
Domain: "rancher.localhost",
EnableServiceHealthFilter: true,
}

View file

@ -29,7 +29,7 @@ func (p *Provider) metadataProvide(configurationChan chan<- types.ConfigMessage,
operation := func() error {
client, err := rancher.NewClientAndWait(metadataServiceURL)
if err != nil {
log.Errorln("Failed to create Rancher metadata service client: %s", err)
log.Errorf("Failed to create Rancher metadata service client: %v", err)
return err
}
@ -38,7 +38,7 @@ func (p *Provider) metadataProvide(configurationChan chan<- types.ConfigMessage,
stacks, err := client.GetStacks()
if err != nil {
log.Errorf("Failed to query Rancher metadata service: %s", err)
log.Errorf("Failed to query Rancher metadata service: %v", err)
return
}

View file

@ -8,7 +8,6 @@ import (
"sort"
"strings"
"github.com/BurntSushi/ty/fun"
"github.com/containous/mux"
"github.com/containous/traefik/hostresolver"
"github.com/containous/traefik/log"
@ -288,9 +287,11 @@ func (r *Rules) Parse(expression string) (*mux.Route, error) {
// ParseDomains parses rules expressions and returns domains
func (r *Rules) ParseDomains(expression string) ([]string, error) {
var domains []string
isHostRule := false
err := r.parseRules(expression, func(functionName string, function interface{}, arguments []string) error {
if functionName == "Host" {
isHostRule = true
domains = append(domains, arguments...)
}
return nil
@ -299,5 +300,18 @@ func (r *Rules) ParseDomains(expression string) ([]string, error) {
return nil, fmt.Errorf("error parsing domains: %v", err)
}
return fun.Map(strings.ToLower, domains).([]string), nil
var cleanDomains []string
for _, domain := range domains {
canonicalDomain := strings.ToLower(domain)
if len(canonicalDomain) > 0 {
cleanDomains = append(cleanDomains, canonicalDomain)
}
}
// Return an error if an Host rule is detected but no domain are parsed
if isHostRule && len(cleanDomains) == 0 {
return nil, fmt.Errorf("unable to parse correctly the domains in the Host rule from %q", expression)
}
return cleanDomains, nil
}

View file

@ -64,24 +64,38 @@ func TestParseDomains(t *testing.T) {
rules := &Rules{}
tests := []struct {
expression string
domain []string
description string
expression string
domain []string
errorExpected bool
}{
{
expression: "Host:foo.bar,test.bar",
domain: []string{"foo.bar", "test.bar"},
description: "Many host rules",
expression: "Host:foo.bar,test.bar",
domain: []string{"foo.bar", "test.bar"},
errorExpected: false,
},
{
expression: "Path:/test",
domain: []string{},
description: "No host rule",
expression: "Path:/test",
errorExpected: false,
},
{
expression: "Host:foo.bar;Path:/test",
domain: []string{"foo.bar"},
description: "Host rule and another rule",
expression: "Host:foo.bar;Path:/test",
domain: []string{"foo.bar"},
errorExpected: false,
},
{
expression: "Host: Foo.Bar ;Path:/test",
domain: []string{"foo.bar"},
description: "Host rule to trim and another rule",
expression: "Host: Foo.Bar ;Path:/test",
domain: []string{"foo.bar"},
errorExpected: false,
},
{
description: "Host rule with no domain",
expression: "Host: ;Path:/test",
errorExpected: true,
},
}
@ -91,7 +105,12 @@ func TestParseDomains(t *testing.T) {
t.Parallel()
domains, err := rules.ParseDomains(test.expression)
require.NoError(t, err, "%s: Error while parsing domain.", test.expression)
if test.errorExpected {
require.Errorf(t, err, "unable to parse correctly the domains in the Host rule from %q", test.expression)
} else {
require.NoError(t, err, "%s: Error while parsing domain.", test.expression)
}
assert.EqualValues(t, test.domain, domains, "%s: Error parsing domains from expression.", test.expression)
})

View file

@ -6,7 +6,6 @@ import (
"crypto/x509"
"encoding/json"
"fmt"
"io/ioutil"
stdlog "log"
"net"
"net/http"
@ -244,7 +243,9 @@ func (s *Server) Start() {
s.listenConfigurations(stop)
})
s.startProvider()
go s.listenSignals()
s.routinesPool.Go(func(stop chan bool) {
s.listenSignals(stop)
})
}
// StartWithContext starts the server and Stop/Close it when context is Done
@ -427,7 +428,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
}

View file

@ -424,8 +424,10 @@ func (s *Server) throttleProviderConfigReload(throttle time.Duration, publish ch
case <-stop:
return
case nextConfig := <-ring.Out():
publish <- nextConfig.(types.ConfigMessage)
time.Sleep(throttle)
if config, ok := nextConfig.(types.ConfigMessage); ok {
publish <- config
time.Sleep(throttle)
}
}
}
})
@ -515,6 +517,8 @@ func (s *Server) postLoadConfiguration() {
domains, err := rls.ParseDomains(route.Rule)
if err != nil {
log.Errorf("Error parsing domains: %v", err)
} else if len(domains) == 0 {
log.Debugf("No domain parsed in rule %q", route.Rule)
} else {
s.globalConfiguration.ACME.LoadCertificateForDomains(domains)
}

View file

@ -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 {
@ -308,7 +307,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
}

View file

@ -104,6 +104,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
}

View file

@ -13,21 +13,25 @@ func (s *Server) configureSignals() {
signal.Notify(s.signals, syscall.SIGUSR1)
}
func (s *Server) listenSignals() {
func (s *Server) listenSignals(stop chan bool) {
for {
sig := <-s.signals
switch sig {
case syscall.SIGUSR1:
log.Infof("Closing and re-opening log files for rotation: %+v", sig)
select {
case <-stop:
return
case sig := <-s.signals:
switch sig {
case syscall.SIGUSR1:
log.Infof("Closing and re-opening log files for rotation: %+v", sig)
if s.accessLoggerMiddleware != nil {
if err := s.accessLoggerMiddleware.Rotate(); err != nil {
log.Errorf("Error rotating access log: %v", err)
if s.accessLoggerMiddleware != nil {
if err := s.accessLoggerMiddleware.Rotate(); err != nil {
log.Errorf("Error rotating access log: %v", err)
}
}
}
if err := log.RotateFile(); err != nil {
log.Errorf("Error rotating traefik log: %v", err)
if err := log.RotateFile(); err != nil {
log.Errorf("Error rotating traefik log: %v", err)
}
}
}
}

View file

@ -4,4 +4,4 @@ package server
func (s *Server) configureSignals() {}
func (s *Server) listenSignals() {}
func (s *Server) listenSignals(stop chan bool) {}

View file

@ -73,8 +73,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 }}"

View file

@ -74,6 +74,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]

View file

@ -75,6 +75,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]

View file

@ -73,6 +73,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]

View file

@ -76,7 +76,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 }}"

View file

@ -76,6 +76,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]

View file

@ -74,6 +74,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]

View file

@ -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
}
@ -30,8 +30,8 @@ type TLS struct {
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 {
@ -41,7 +41,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()
@ -52,30 +52,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

View file

@ -178,18 +178,19 @@ func (h *Headers) HasSecureHeadersDefined() bool {
// Frontend holds frontend configuration.
type Frontend struct {
EntryPoints []string `json:"entryPoints,omitempty" hash:"ignore"`
Backend string `json:"backend,omitempty"`
Routes map[string]Route `json:"routes,omitempty" hash:"ignore"`
PassHostHeader bool `json:"passHostHeader,omitempty"`
PassTLSCert bool `json:"passTLSCert,omitempty"`
Priority int `json:"priority"`
WhiteList *WhiteList `json:"whiteList,omitempty"`
Headers *Headers `json:"headers,omitempty"`
Errors map[string]*ErrorPage `json:"errors,omitempty"`
RateLimit *RateLimit `json:"ratelimit,omitempty"`
Redirect *Redirect `json:"redirect,omitempty"`
Auth *Auth `json:"auth,omitempty"`
EntryPoints []string `json:"entryPoints,omitempty" hash:"ignore"`
Backend string `json:"backend,omitempty"`
Routes map[string]Route `json:"routes,omitempty" hash:"ignore"`
PassHostHeader bool `json:"passHostHeader,omitempty"`
PassTLSCert bool `json:"passTLSCert,omitempty"` // Deprecated use PassTLSClientCert instead
PassTLSClientCert *TLSClientHeaders `json:"passTLSClientCert,omitempty"`
Priority int `json:"priority"`
WhiteList *WhiteList `json:"whiteList,omitempty"`
Headers *Headers `json:"headers,omitempty"`
Errors map[string]*ErrorPage `json:"errors,omitempty"`
RateLimit *RateLimit `json:"ratelimit,omitempty"`
Redirect *Redirect `json:"redirect,omitempty"`
Auth *Auth `json:"auth,omitempty"`
}
// Hash returns the hash value of a Frontend struct.
@ -645,3 +646,27 @@ func (s *IPStrategy) Get() (ip.Strategy, error) {
return &ip.RemoteAddrStrategy{}, nil
}
// 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"`
}

View file

@ -383,7 +383,14 @@ func (b *bufferWriter) Header() http.Header {
}
func (b *bufferWriter) Write(buf []byte) (int, error) {
return b.buffer.Write(buf)
length, err := b.buffer.Write(buf)
if err != nil {
// Since go1.11 (https://github.com/golang/go/commit/8f38f28222abccc505b9a1992deecfe3e2cb85de)
// if the writer returns an error, the reverse proxy panics
b.log.Error(err)
length = len(buf)
}
return length, nil
}
// WriteHeader sets rw.Code.
@ -410,7 +417,7 @@ func (b *bufferWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return conn, rw, err
}
b.log.Warningf("Upstream ResponseWriter of type %v does not implement http.Hijacker. Returning dummy channel.", reflect.TypeOf(b.responseWriter))
return nil, nil, fmt.Errorf("The response writer that was wrapped in this proxy, does not implement http.Hijacker. It is of type: %v", reflect.TypeOf(b.responseWriter))
return nil, nil, fmt.Errorf("the response writer wrapped in this proxy does not implement http.Hijacker. Its type is: %v”", reflect.TypeOf(b.responseWriter))
}
// SizeErrHandler Size error handler