Merge branch 'v1.7' into master
This commit is contained in:
commit
bd4846aa9c
82 changed files with 3573 additions and 877 deletions
39
CHANGELOG.md
39
CHANGELOG.md
|
@ -1,5 +1,44 @@
|
||||||
# Change Log
|
# 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)
|
## [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)
|
[All Commits](https://github.com/containous/traefik/compare/v1.6.5...v1.6.6)
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ You need to run the `binary` target. This will create binaries for Linux platfor
|
||||||
$ make binary
|
$ make binary
|
||||||
docker build -t "traefik-dev:no-more-godep-ever" -f build.Dockerfile .
|
docker build -t "traefik-dev:no-more-godep-ever" -f build.Dockerfile .
|
||||||
Sending build context to Docker daemon 295.3 MB
|
Sending build context to Docker daemon 295.3 MB
|
||||||
Step 0 : FROM golang:1.10-alpine
|
Step 0 : FROM golang:1.11-alpine
|
||||||
---> 8c6473912976
|
---> 8c6473912976
|
||||||
Step 1 : RUN go get github.com/golang/dep/cmd/dep
|
Step 1 : RUN go get github.com/golang/dep/cmd/dep
|
||||||
[...]
|
[...]
|
||||||
|
|
2
Gopkg.lock
generated
2
Gopkg.lock
generated
|
@ -1263,7 +1263,7 @@
|
||||||
"roundrobin",
|
"roundrobin",
|
||||||
"utils"
|
"utils"
|
||||||
]
|
]
|
||||||
revision = "f6bbeac6d5c4c06f88ba07ed42983ff36a5b407e"
|
revision = "77148e9694210e5f5610328f1cd7cf65583014c2"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/vulcand/predicate"
|
name = "github.com/vulcand/predicate"
|
||||||
|
|
|
@ -51,7 +51,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
|
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
|
||||||
},
|
},
|
||||||
ClientCA: traefiktls.ClientCA{
|
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,
|
Optional: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -100,7 +100,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
|
{CertFile: "CertFile 2", KeyFile: "KeyFile 2"},
|
||||||
},
|
},
|
||||||
ClientCA: traefiktls.ClientCA{
|
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,
|
Optional: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -185,7 +185,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
config.ProvidersThrottleDuration = parse.Duration(666 * time.Second)
|
config.ProvidersThrottleDuration = parse.Duration(666 * time.Second)
|
||||||
config.MaxIdleConnsPerHost = 666
|
config.MaxIdleConnsPerHost = 666
|
||||||
config.InsecureSkipVerify = true
|
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{
|
config.Retry = &configuration.Retry{
|
||||||
Attempts: 666,
|
Attempts: 666,
|
||||||
}
|
}
|
||||||
|
@ -217,7 +217,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
Endpoint: "docker Endpoint",
|
Endpoint: "docker Endpoint",
|
||||||
|
@ -248,7 +248,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
Directory: "file Directory",
|
Directory: "file Directory",
|
||||||
|
@ -269,7 +269,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
Endpoint: "",
|
Endpoint: "",
|
||||||
|
@ -309,7 +309,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
Endpoint: "ConsulCatalog Endpoint",
|
Endpoint: "ConsulCatalog Endpoint",
|
||||||
|
@ -334,7 +334,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
Endpoint: "k8s Endpoint",
|
Endpoint: "k8s Endpoint",
|
||||||
|
@ -360,7 +360,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
Endpoint: "mesos Endpoint",
|
Endpoint: "mesos Endpoint",
|
||||||
|
@ -389,7 +389,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
Endpoint: "eureka Endpoint",
|
Endpoint: "eureka Endpoint",
|
||||||
|
@ -411,7 +411,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
Domain: "ecs Domain",
|
Domain: "ecs Domain",
|
||||||
|
@ -439,7 +439,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
APIConfiguration: rancher.APIConfiguration{
|
APIConfiguration: rancher.APIConfiguration{
|
||||||
|
@ -477,7 +477,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
AccessKeyID: "dynamodb AccessKeyID",
|
AccessKeyID: "dynamodb AccessKeyID",
|
||||||
|
@ -504,7 +504,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
Endpoint: "etcd Endpoint",
|
Endpoint: "etcd Endpoint",
|
||||||
|
@ -536,7 +536,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
Endpoint: "zk Endpoint",
|
Endpoint: "zk Endpoint",
|
||||||
|
@ -568,7 +568,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
Endpoint: "boltdb Endpoint",
|
Endpoint: "boltdb Endpoint",
|
||||||
|
@ -600,7 +600,7 @@ func TestDo_globalConfiguration(t *testing.T) {
|
||||||
MustMatch: true,
|
MustMatch: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Trace: true,
|
Trace: true,
|
||||||
DebugLogGeneratedTemplate: true,
|
DebugLogGeneratedTemplate: true,
|
||||||
},
|
},
|
||||||
Endpoint: "consul Endpoint",
|
Endpoint: "consul Endpoint",
|
||||||
|
|
|
@ -129,8 +129,30 @@ var _templatesConsul_catalogTmpl = []byte(`[backends]
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{if $auth }}
|
||||||
[frontends."frontend-{{ $service.ServiceName }}".auth]
|
[frontends."frontend-{{ $service.ServiceName }}".auth]
|
||||||
headerField = "{{ $auth.HeaderField }}"
|
headerField = "{{ $auth.HeaderField }}"
|
||||||
|
@ -375,6 +397,29 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{ $auth := getAuth $container.SegmentLabels }}
|
||||||
{{if $auth }}
|
{{if $auth }}
|
||||||
[frontends."frontend-{{ $frontendName }}".auth]
|
[frontends."frontend-{{ $frontendName }}".auth]
|
||||||
|
@ -622,6 +667,29 @@ var _templatesEcsTmpl = []byte(`[backends]
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{ $auth := getAuth $instance.SegmentLabels }}
|
||||||
{{if $auth }}
|
{{if $auth }}
|
||||||
[frontends."frontend-{{ $frontendName }}".auth]
|
[frontends."frontend-{{ $frontendName }}".auth]
|
||||||
|
@ -1125,6 +1193,29 @@ var _templatesKvTmpl = []byte(`[backends]
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{ $auth := getAuth $frontend }}
|
||||||
{{if $auth }}
|
{{if $auth }}
|
||||||
[frontends."{{ $frontendName }}".auth]
|
[frontends."{{ $frontendName }}".auth]
|
||||||
|
@ -1387,7 +1478,30 @@ var _templatesMarathonTmpl = []byte(`{{ $apps := .Applications }}
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{if $auth }}
|
||||||
[frontends."{{ $frontendName }}".auth]
|
[frontends."{{ $frontendName }}".auth]
|
||||||
headerField = "{{ $auth.HeaderField }}"
|
headerField = "{{ $auth.HeaderField }}"
|
||||||
|
@ -1634,6 +1748,29 @@ var _templatesMesosTmpl = []byte(`[backends]
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{ $auth := getAuth $app.TraefikLabels }}
|
||||||
{{if $auth }}
|
{{if $auth }}
|
||||||
[frontends."frontend-{{ $frontendName }}".auth]
|
[frontends."frontend-{{ $frontendName }}".auth]
|
||||||
|
@ -1903,6 +2040,29 @@ var _templatesRancherTmpl = []byte(`{{ $backendServers := .Backends }}
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{ $auth := getAuth $service.SegmentLabels }}
|
||||||
{{if $auth }}
|
{{if $auth }}
|
||||||
[frontends."frontend-{{ $frontendName }}".auth]
|
[frontends."frontend-{{ $frontendName }}".auth]
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
FROM golang:1.10-alpine
|
FROM golang:1.11-alpine
|
||||||
|
|
||||||
RUN apk --update upgrade \
|
RUN apk --update upgrade \
|
||||||
&& apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar \
|
&& apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar \
|
||||||
|
|
|
@ -94,7 +94,7 @@ func NewCmd(traefikConfiguration *cmd.TraefikConfiguration, traefikPointersConfi
|
||||||
Description: `Report an issue on Traefik bugtracker`,
|
Description: `Report an issue on Traefik bugtracker`,
|
||||||
Config: traefikConfiguration,
|
Config: traefikConfiguration,
|
||||||
DefaultPointersConfig: traefikPointersConfiguration,
|
DefaultPointersConfig: traefikPointersConfiguration,
|
||||||
Run: runCmd(traefikConfiguration),
|
Run: runCmd(traefikConfiguration),
|
||||||
Metadata: map[string]string{
|
Metadata: map[string]string{
|
||||||
"parseAllSources": "true",
|
"parseAllSources": "true",
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,7 +34,7 @@ func Test_createReport(t *testing.T) {
|
||||||
File: &file.Provider{
|
File: &file.Provider{
|
||||||
Directory: "BAR",
|
Directory: "BAR",
|
||||||
},
|
},
|
||||||
RootCAs: tls.RootCAs{"fllf"},
|
RootCAs: tls.FilesOrContents{"fllf"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ func NewCmd(traefikConfiguration *cmd.TraefikConfiguration, traefikPointersConfi
|
||||||
Description: `Calls traefik /ping to check health (web provider must be enabled)`,
|
Description: `Calls traefik /ping to check health (web provider must be enabled)`,
|
||||||
Config: traefikConfiguration,
|
Config: traefikConfiguration,
|
||||||
DefaultPointersConfig: traefikPointersConfiguration,
|
DefaultPointersConfig: traefikPointersConfiguration,
|
||||||
Run: runCmd(traefikConfiguration),
|
Run: runCmd(traefikConfiguration),
|
||||||
Metadata: map[string]string{
|
Metadata: map[string]string{
|
||||||
"parseAllSources": "true",
|
"parseAllSources": "true",
|
||||||
},
|
},
|
||||||
|
|
|
@ -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
|
// 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
|
// Store the ACME Account into the KV Store
|
||||||
// Certificates in KV Store will be overridden
|
// 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
|
// migrateACMEData allows migrating data from acme.json file to KV store in function of the file format
|
||||||
func migrateACMEData(fileName string) (*acme.Account, error) {
|
func migrateACMEData(fileName string) (*acme.Account, error) {
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ Complete documentation is available at https://traefik.io`,
|
||||||
// add custom parsers
|
// add custom parsers
|
||||||
f.AddParser(reflect.TypeOf(configuration.EntryPoints{}), &configuration.EntryPoints{})
|
f.AddParser(reflect.TypeOf(configuration.EntryPoints{}), &configuration.EntryPoints{})
|
||||||
f.AddParser(reflect.TypeOf(configuration.DefaultEntryPoints{}), &configuration.DefaultEntryPoints{})
|
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(types.Constraints{}), &types.Constraints{})
|
||||||
f.AddParser(reflect.TypeOf(kubernetes.Namespaces{}), &kubernetes.Namespaces{})
|
f.AddParser(reflect.TypeOf(kubernetes.Namespaces{}), &kubernetes.Namespaces{})
|
||||||
f.AddParser(reflect.TypeOf(ecs.Clusters{}), &ecs.Clusters{})
|
f.AddParser(reflect.TypeOf(ecs.Clusters{}), &ecs.Clusters{})
|
||||||
|
|
|
@ -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"`
|
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"`
|
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"`
|
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"`
|
Retry *Retry `description:"Enable retry sending request if network error" export:"true"`
|
||||||
HealthCheck *HealthCheckConfig `description:"Health check parameters" export:"true"`
|
HealthCheck *HealthCheckConfig `description:"Health check parameters" export:"true"`
|
||||||
RespondingTimeouts *RespondingTimeouts `description:"Timeouts for incoming requests to the Traefik instance" export:"true"`
|
RespondingTimeouts *RespondingTimeouts `description:"Timeouts for incoming requests to the Traefik instance" export:"true"`
|
||||||
|
|
|
@ -248,7 +248,8 @@ func makeEntryPointTLS(result map[string]string) (*tls.TLS, error) {
|
||||||
|
|
||||||
if configTLS != nil {
|
if configTLS != nil {
|
||||||
if len(result["ca"]) > 0 {
|
if len(result["ca"]) > 0 {
|
||||||
files := strings.Split(result["ca"], ",")
|
files := tls.FilesOrContents{}
|
||||||
|
files.Set(result["ca"])
|
||||||
optional := toBool(result, "ca_optional")
|
optional := toBool(result, "ca_optional")
|
||||||
configTLS.ClientCA = tls.ClientCA{
|
configTLS.ClientCA = tls.ClientCA{
|
||||||
Files: files,
|
Files: files,
|
||||||
|
|
|
@ -69,21 +69,21 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
|
||||||
"ca_optional": "true",
|
"ca_optional": "true",
|
||||||
"compress": "true",
|
"compress": "true",
|
||||||
"forwardedheaders_trustedips": "10.0.0.3/24,20.0.0.3/24",
|
"forwardedheaders_trustedips": "10.0.0.3/24,20.0.0.3/24",
|
||||||
"name": "foo",
|
"name": "foo",
|
||||||
"proxyprotocol_trustedips": "192.168.0.1",
|
"proxyprotocol_trustedips": "192.168.0.1",
|
||||||
"redirect_entrypoint": "https",
|
"redirect_entrypoint": "https",
|
||||||
"redirect_permanent": "true",
|
"redirect_permanent": "true",
|
||||||
"redirect_regex": "http://localhost/(.*)",
|
"redirect_regex": "http://localhost/(.*)",
|
||||||
"redirect_replacement": "http://mydomain/$1",
|
"redirect_replacement": "http://mydomain/$1",
|
||||||
"tls": "goo,gii",
|
"tls": "goo,gii",
|
||||||
"tls_acme": "TLS",
|
"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_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",
|
"tls_minversion": "VersionTLS11",
|
||||||
"whitelist_sourcerange": "10.42.0.0/16,152.89.1.33/32,afed:be44::/16",
|
"whitelist_sourcerange": "10.42.0.0/16,152.89.1.33/32,afed:be44::/16",
|
||||||
"whitelist_ipstrategy_depth": "3",
|
"whitelist_ipstrategy_depth": "3",
|
||||||
"whitelist_ipstrategy_excludedips": "10.0.0.3/24,20.0.0.3/24",
|
"whitelist_ipstrategy_excludedips": "10.0.0.3/24,20.0.0.3/24",
|
||||||
"clientipstrategy_depth": "3",
|
"clientipstrategy_depth": "3",
|
||||||
"clientipstrategy_excludedips": "10.0.0.3/24,20.0.0.3/24",
|
"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{
|
ClientCA: tls.ClientCA{
|
||||||
Files: []string{"car"},
|
Files: tls.FilesOrContents{"car"},
|
||||||
Optional: true,
|
Optional: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -352,7 +352,7 @@ func TestEntryPoints_Set(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ClientCA: tls.ClientCA{
|
ClientCA: tls.ClientCA{
|
||||||
Files: []string{"car"},
|
Files: tls.FilesOrContents{"car"},
|
||||||
Optional: true,
|
Optional: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -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.
|
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 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
|
##### Path Matcher Usage Guidelines
|
||||||
|
|
||||||
|
@ -157,7 +157,8 @@ Here is an example of frontends definition:
|
||||||
[frontends.frontend2]
|
[frontends.frontend2]
|
||||||
backend = "backend1"
|
backend = "backend1"
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
passTLSCert = true
|
[frontends.frontend2.passTLSClientCert]
|
||||||
|
pem = true
|
||||||
priority = 10
|
priority = 10
|
||||||
entrypoints = ["https"] # overrides defaultEntryPoints
|
entrypoints = ["https"] # overrides defaultEntryPoints
|
||||||
[frontends.frontend2.routes.test_1]
|
[frontends.frontend2.routes.test_1]
|
||||||
|
|
|
@ -31,7 +31,7 @@ exposedByDefault = false
|
||||||
#
|
#
|
||||||
stale = false
|
stale = false
|
||||||
|
|
||||||
# Default domain used.
|
# Default base domain used for the frontend rules.
|
||||||
#
|
#
|
||||||
# Optional
|
# Optional
|
||||||
#
|
#
|
||||||
|
@ -94,63 +94,73 @@ Additional settings can be defined using Consul Catalog tags.
|
||||||
!!! note
|
!!! note
|
||||||
The default prefix is `traefik`.
|
The default prefix is `traefik`.
|
||||||
|
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|--------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|----------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `<prefix>.enable=false` | Disables this container in Træfik. |
|
| `<prefix>.enable=false` | Disables this container in Træfik. |
|
||||||
| `<prefix>.protocol=https` | Overrides the default `http` protocol. |
|
| `<prefix>.protocol=https` | Overrides the default `http` protocol. |
|
||||||
| `<prefix>.weight=10` | Assigns this weight to the container. |
|
| `<prefix>.weight=10` | Assigns this weight to the container. |
|
||||||
| `traefik.backend.buffering.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
| `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.maxResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.memRequestBodyBytes=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.memResponseBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.retryExpression=EXPR` | 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.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.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.interval=1s` | Defines the health check interval. |
|
||||||
| `<prefix>.backend.healthcheck.port=8080` | Sets a different port for the health check. |
|
| `<prefix>.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.scheme=http` | Overrides the server URL scheme. |
|
||||||
| `<prefix>.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |
|
| `<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||HEADER2:value2</code> |
|
| `<prefix>.backend.healthcheck.headers=EXPR` | Defines the health check request headers <br>Format: <code>HEADER:value||HEADER2:value2</code> |
|
||||||
| `<prefix>.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm. |
|
| `<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=true` | Enables backend sticky sessions. |
|
||||||
| `<prefix>.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for 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.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>.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=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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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>.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>.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.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.passHostHeader=true` | Forwards client `Host` header to the backend. |
|
||||||
| `<prefix>.frontend.passTLSCert=true` | Forwards TLS Client certificates 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.priority=10` | Overrides default frontend priority. |
|
| `<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.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `<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.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `<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.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `<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.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `<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.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS). |
|
| `<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.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
|
| `<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.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
|
| `<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.redirect.permanent=true` | Returns 301 instead of 302. |
|
| `<prefix>.frontend.passTLSClientCert.pem=true` | Pass the escaped pem in the `X-Forwarded-Ssl-Client-Cert` header. |
|
||||||
| `<prefix>.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{{.ServiceName}}.{{.Domain}}`. |
|
| `<prefix>.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
|
||||||
| `<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.priority=10` | Overrides default frontend priority. |
|
||||||
| `<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.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
||||||
| `<prefix>.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
| `<prefix>.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
||||||
| `<prefix>.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
| `<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
|
### 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.STSIncludeSubdomains=true` | Adds the `IncludeSubdomains` section of the STS header. |
|
||||||
| `<prefix>.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. |
|
| `<prefix>.frontend.headers.STSPreload=true` | Adds the preload flag to the STS header. |
|
||||||
|
|
||||||
|
|
||||||
### Examples
|
### Examples
|
||||||
|
|
||||||
If you want that Træfik uses Consul tags correctly you need to defined them like that:
|
If you want that Træfik uses Consul tags correctly you need to defined them like that:
|
||||||
|
|
|
@ -207,68 +207,78 @@ services:
|
||||||
|
|
||||||
Labels can be used on containers to override default behavior.
|
Labels can be used on containers to override default behavior.
|
||||||
|
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|-------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `traefik.docker.network` | Overrides the default docker network to use for connections to the container. [1] |
|
| `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.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.enable=false` | Disables this container in Træfik. |
|
||||||
| `traefik.port=80` | Registers this port. Useful when the container exposes multiples ports. |
|
| `traefik.port=80` | Registers this port. Useful when the container exposes multiples ports. |
|
||||||
| `traefik.protocol=https` | Overrides the default `http` protocol |
|
| `traefik.protocol=https` | Overrides the default `http` protocol |
|
||||||
| `traefik.weight=10` | Assigns this weight to the container |
|
| `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=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.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.maxResponseBodyBytes=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.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.memResponseBodyBytes=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.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.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.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.interval=1s` | Defines the health check interval. |
|
||||||
| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. |
|
| `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.scheme=http` | Overrides the server URL scheme. |
|
||||||
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |
|
| `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||HEADER2:value2</code> |
|
| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers <br>Format: <code>HEADER:value||HEADER2:value2</code> |
|
||||||
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
|
| `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=true` | Enables backend sticky sessions |
|
||||||
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for 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.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.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.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=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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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>.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>.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.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.passHostHeader=true` | Forwards client `Host` header to the backend. |
|
||||||
| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates 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.priority=10` | Overrides default frontend priority |
|
| `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.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) |
|
| `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.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
|
| `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.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
|
| `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.redirect.permanent=true` | Returns 301 instead of 302. |
|
| `traefik.frontend.passTLSClientCert.pem=true` | Pass the escaped pem in the `X-Forwarded-Ssl-Client-Cert` header. |
|
||||||
| `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.passTLSCert=true` | Forwards TLS Client certificates to the backend (DEPRECATED). |
|
||||||
| `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.priority=10` | Overrides default frontend priority |
|
||||||
| `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.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
||||||
| `traefik.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
||||||
| `traefik.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
| `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`:
|
[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).
|
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.
|
Segment labels override the default behavior.
|
||||||
|
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|------------------------------------------------------------------------------|----------------------------------------------------------------|
|
|------------------------------------------------------------------------------------|------------------------------------------------------------------------|
|
||||||
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
|
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
|
||||||
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
|
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
|
||||||
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
|
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
|
||||||
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
|
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
|
||||||
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
|
| `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=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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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>.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>.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.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.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
|
||||||
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` |
|
||||||
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` |
|
||||||
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` |
|
||||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` |
|
||||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` |
|
||||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` |
|
||||||
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.organization=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.organization`|
|
||||||
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` |
|
||||||
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.serialNumber=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber`|
|
||||||
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` |
|
||||||
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
|
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
|
||||||
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
|
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
|
||||||
| `traefik.<segment_name>.frontend.whiteList.ipStrategy=true` | Same as `traefik.frontend.whiteList.ipStrategy` |
|
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
|
||||||
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.depth=5` | Same as `traefik.frontend.whiteList.ipStrategy.depth` |
|
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
|
||||||
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | Same as `traefik.frontend.whiteList.ipStrategy.excludedIPs` |
|
| `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
|
#### Custom Headers
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ clusters = ["default"]
|
||||||
#
|
#
|
||||||
watch = true
|
watch = true
|
||||||
|
|
||||||
# Default domain used.
|
# Default base domain used for the frontend rules.
|
||||||
# Can be overridden by setting the "traefik.domain" label.
|
# Can be overridden by setting the "traefik.domain" label.
|
||||||
#
|
#
|
||||||
# Optional
|
# 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:
|
Labels can be used on task containers to override default behavior:
|
||||||
|
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|-------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `traefik.domain` | Sets the default domain for frontend rules. |
|
| `traefik.domain` | Sets the default domain for frontend rules. |
|
||||||
| `traefik.enable=false` | Disables this container in Træfik. |
|
| `traefik.enable=false` | Disables this container in Træfik. |
|
||||||
| `traefik.port=80` | Overrides the default `port` value. Overrides `NetworkBindings` from Docker Container |
|
| `traefik.port=80` | Overrides the default `port` value. Overrides `NetworkBindings` from Docker Container |
|
||||||
| `traefik.protocol=https` | Overrides the default `http` protocol |
|
| `traefik.protocol=https` | Overrides the default `http` protocol |
|
||||||
| `traefik.weight=10` | Assigns this weight to the container |
|
| `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=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.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.maxResponseBodyBytes=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.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.memResponseBodyBytes=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.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.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.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.interval=1s` | Defines the health check interval. (Default: 30s) |
|
||||||
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
|
| `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.port=8080` | Sets a different port for the health check. |
|
||||||
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |
|
| `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||HEADER2:value2</code> |
|
| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers <br>Format: <code>HEADER:value||HEADER2:value2</code> |
|
||||||
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
|
| `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=true` | Enables backend sticky sessions |
|
||||||
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie manually name for 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.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.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=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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.passTLSClientCert.infos.notAfter=true` | Add the noAfter field in a escaped client infos in the `X-Forwarded-Ssl-Client-Cert-Infos` header. |
|
||||||
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
|
| `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.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
|
| `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.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
|
| `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.passHostHeader=true` | Forwards client `Host` header to the backend. |
|
| `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.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
|
| `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.priority=10` | Overrides default frontend priority |
|
| `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.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `traefik.frontend.passTLSClientCert.pem=true` | Pass the escaped pem in the `X-Forwarded-Ssl-Client-Cert` header. |
|
||||||
| `traefik.frontend.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
|
||||||
| `traefik.frontend.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) |
|
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
|
||||||
| `traefik.frontend.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
|
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
|
||||||
| `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.errors.<name>.status=RANGE` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
|
||||||
| `traefik.frontend.redirect.permanent=true` | Returns 301 instead of 302. |
|
| `traefik.frontend.passHostHeader=true` | Forwards client `Host` header to the backend. |
|
||||||
| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{instance_name}.{domain}`. |
|
| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
|
||||||
| `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.priority=10` | Overrides default frontend priority |
|
||||||
| `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.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
||||||
| `traefik.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
||||||
| `traefik.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
| `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
|
### Custom Headers
|
||||||
|
|
||||||
|
@ -232,50 +242,60 @@ You can define as many segments as ports exposed in an application.
|
||||||
|
|
||||||
Segment labels override the default behavior.
|
Segment labels override the default behavior.
|
||||||
|
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|------------------------------------------------------------------------------|----------------------------------------------------------------|
|
|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------|
|
||||||
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
|
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
|
||||||
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
|
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
|
||||||
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
|
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
|
||||||
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
|
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
|
||||||
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
|
| `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=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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.auth.removeHeader=true` | Same as `traefik.frontend.auth.removeHeader` |
|
||||||
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
|
| `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>.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>.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.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.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
|
||||||
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` |
|
||||||
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` |
|
||||||
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` |
|
||||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` |
|
||||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` |
|
||||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` |
|
||||||
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.organization=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.organization` |
|
||||||
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` |
|
||||||
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.serialNumber=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber` |
|
||||||
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` |
|
||||||
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
|
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
|
||||||
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
|
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
|
||||||
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` |
|
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
|
||||||
| `traefik.<segment_name>.frontend.whiteList.ipStrategy=true` | Same as `traefik.frontend.whiteList.ipStrategy` |
|
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
|
||||||
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.depth=5` | Same as `traefik.frontend.whiteList.ipStrategy.depth` |
|
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
|
||||||
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | Same as `traefik.frontend.whiteList.ipStrategy.excludedIPs` |
|
| `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
|
#### Custom Headers
|
||||||
|
|
||||||
|
|
|
@ -53,9 +53,24 @@ Træfik can be configured with a file.
|
||||||
entryPoints = ["http", "https"]
|
entryPoints = ["http", "https"]
|
||||||
backend = "backend1"
|
backend = "backend1"
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
passTLSCert = true
|
|
||||||
priority = 42
|
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]
|
[frontends.frontend1.auth]
|
||||||
headerField = "X-WebAuth-User"
|
headerField = "X-WebAuth-User"
|
||||||
[frontends.frontend1.auth.basic]
|
[frontends.frontend1.auth.basic]
|
||||||
|
|
|
@ -31,7 +31,7 @@ endpoint = "http://127.0.0.1:8080"
|
||||||
#
|
#
|
||||||
watch = true
|
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.
|
# Can be overridden by setting the "traefik.domain" label on an application.
|
||||||
#
|
#
|
||||||
# Required
|
# 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.
|
The following labels can be defined on Marathon applications. They adjust the behavior for the entire application.
|
||||||
|
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|-----------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `traefik.domain` | Sets the default domain used for the frontend rules. |
|
| `traefik.domain` | Sets the default base domain used for the frontend rules. |
|
||||||
| `traefik.enable=false` | Disables this container in Træfik. |
|
| `traefik.enable=false` | Disables this container in Træfik. |
|
||||||
| `traefik.port=80` | Registers this port. Useful when the container exposes multiples ports. |
|
| `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.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.protocol=https` | Overrides the default `http` protocol. |
|
||||||
| `traefik.weight=10` | Assigns this weight to the container. |
|
| `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=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.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.maxResponseBodyBytes=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.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.memResponseBodyBytes=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.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.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.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.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.port=8080` | Sets a different port for the health check. |
|
||||||
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
|
| `traefik.backend.healthcheck.scheme=http` | Overrides the server URL scheme. |
|
||||||
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |
|
| `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||HEADER2:value2</code> |
|
| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers <br>Format: <code>HEADER:value||HEADER2:value2</code> |
|
||||||
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
|
| `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=true` | Enables backend sticky sessions |
|
||||||
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for 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.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.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=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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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>.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>.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.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.passHostHeader=true` | Forwards client `Host` header to the backend. |
|
||||||
| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates 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.priority=10` | Overrides default frontend priority |
|
| `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.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) |
|
| `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.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
|
| `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.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
|
| `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.redirect.permanent=true` | Returns 301 instead of 302. |
|
| `traefik.frontend.passTLSClientCert.pem=true` | Pass the escaped pem in the `X-Forwarded-Ssl-Client-Cert` header. |
|
||||||
| `traefik.frontend.rule=EXPR` | Overrides the default frontend rule. Default: `Host:{sub_domain}.{domain}`. |
|
| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
|
||||||
| `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.priority=10` | Overrides default frontend priority |
|
||||||
| `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.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
||||||
| `traefik.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
||||||
| `traefik.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
| `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
|
#### 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>.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.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.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.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
|
||||||
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
|
| `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.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
|
||||||
|
|
|
@ -27,7 +27,7 @@ endpoint = "http://127.0.0.1:8080"
|
||||||
#
|
#
|
||||||
watch = true
|
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.
|
# Can be overridden by setting the "traefik.domain" label on an application.
|
||||||
#
|
#
|
||||||
# Required
|
# 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>.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.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.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.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
|
||||||
| `traefik.frontend.priority=10` | Overrides default frontend priority |
|
| `traefik.frontend.priority=10` | Overrides default frontend priority |
|
||||||
| `traefik.frontend.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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>.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.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.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.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
|
||||||
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
|
| `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.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
|
||||||
|
|
|
@ -12,7 +12,7 @@ Træfik can be configured to use Rancher as a provider.
|
||||||
# Enable Rancher Provider.
|
# Enable Rancher Provider.
|
||||||
[rancher]
|
[rancher]
|
||||||
|
|
||||||
# Default domain used.
|
# Default base domain used for the frontend rules.
|
||||||
# Can be overridden by setting the "traefik.domain" label on an service.
|
# Can be overridden by setting the "traefik.domain" label on an service.
|
||||||
#
|
#
|
||||||
# Required
|
# Required
|
||||||
|
@ -138,66 +138,76 @@ secretKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
|
||||||
Labels can be used on task containers to override default behavior:
|
Labels can be used on task containers to override default behavior:
|
||||||
|
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|-----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|---------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| `traefik.domain` | Sets the default domain for the frontend rules. |
|
| `traefik.domain` | Sets the default domain for the frontend rules. |
|
||||||
| `traefik.enable=false` | Disables this container in Træfik. |
|
| `traefik.enable=false` | Disables this container in Træfik. |
|
||||||
| `traefik.port=80` | Registers this port. Useful when the container exposes multiple ports. |
|
| `traefik.port=80` | Registers this port. Useful when the container exposes multiple ports. |
|
||||||
| `traefik.protocol=https` | Overrides the default `http` protocol. |
|
| `traefik.protocol=https` | Overrides the default `http` protocol. |
|
||||||
| `traefik.weight=10` | Assigns this weight to the container. |
|
| `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=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.maxRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.maxResponseBodyBytes=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.memRequestBodyBytes=0` | See [buffering](/configuration/commons/#buffering) section. |
|
||||||
| `traefik.backend.buffering.memResponseBodyBytes=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.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.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.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.interval=1s` | Defines the health check interval. |
|
||||||
| `traefik.backend.healthcheck.port=8080` | Sets a different port for the health check. |
|
| `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.scheme=http` | Overrides the server URL scheme. |
|
||||||
| `traefik.backend.healthcheck.hostname=foobar.com` | Defines the health check hostname. |
|
| `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||HEADER2:value2</code> |
|
| `traefik.backend.healthcheck.headers=EXPR` | Defines the health check request headers <br>Format: <code>HEADER:value||HEADER2:value2</code> |
|
||||||
| `traefik.backend.loadbalancer.method=drr` | Overrides the default `wrr` load balancer algorithm |
|
| `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=true` | Enables backend sticky sessions |
|
||||||
| `traefik.backend.loadbalancer.stickiness.cookieName=NAME` | Sets the cookie name manually for 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.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.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=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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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>.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>.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.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.passHostHeader=true` | Forwards client `Host` header to the backend. |
|
||||||
| `traefik.frontend.passTLSCert=true` | Forwards TLS Client certificates 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.priority=10` | Overrides default frontend priority |
|
| `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.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.rateLimit.rateSet.<name>.average=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.rateLimit.rateSet.<name>.burst=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
| `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.redirect.entryPoint=https` | Enables Redirect to another entryPoint to this frontend (e.g. HTTPS) |
|
| `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.redirect.regex=^http://localhost/(.*)` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.replacement`. |
|
| `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.redirect.replacement=http://mydomain/$1` | Redirects to another URL to this frontend.<br>Must be set with `traefik.frontend.redirect.regex`. |
|
| `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.redirect.permanent=true` | Returns 301 instead of 302. |
|
| `traefik.frontend.passTLSClientCert.pem=true` | Pass the escaped pem in the `X-Forwarded-Ssl-Client-Cert` header. |
|
||||||
| `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.passTLSCert=true` | Forwards TLS Client certificates to the backend. |
|
||||||
| `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.priority=10` | Overrides default frontend priority |
|
||||||
| `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.rateLimit.extractorFunc=EXP` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
||||||
| `traefik.frontend.whiteList.ipStrategy.depth=5` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
| `traefik.frontend.rateLimit.rateSet.<name>.period=6` | See [rate limiting](/configuration/commons/#rate-limiting) section. |
|
||||||
| `traefik.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | See [whitelist](/configuration/entrypoints/#white-listing) |
|
| `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
|
#### Custom Headers
|
||||||
|
|
||||||
|
@ -239,48 +249,58 @@ You can define as many segments as ports exposed in a container.
|
||||||
|
|
||||||
Segment labels override the default behavior.
|
Segment labels override the default behavior.
|
||||||
|
|
||||||
| Label | Description |
|
| Label | Description |
|
||||||
|------------------------------------------------------------------------------|----------------------------------------------------------------|
|
|------------------------------------------------------------------------------------|------------------------------------------------------------------------|
|
||||||
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
|
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
|
||||||
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
|
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
|
||||||
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
|
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
|
||||||
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
|
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
|
||||||
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
|
| `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=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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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>.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>.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.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.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
|
||||||
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notAfter=true` | Same as `traefik.frontend.passTLSClientCert.infos.notAfter` |
|
||||||
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.notBefore=true` | Same as `traefik.frontend.passTLSClientCert.infos.notBefore` |
|
||||||
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.sans=true` | Same as `traefik.frontend.passTLSClientCert.infos.sans` |
|
||||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.commonName=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.commonName` |
|
||||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.country=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.country` |
|
||||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.locality=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.locality` |
|
||||||
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.organization=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.organization`|
|
||||||
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.province=true` | Same as `traefik.frontend.passTLSClientCert.infos.subject.province` |
|
||||||
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.infos.subject.serialNumber=true`| Same as `traefik.frontend.passTLSClientCert.infos.subject.serialNumber`|
|
||||||
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
|
| `traefik.<segment_name>.frontend.passTLSClientCert.pem=true` | Same as `traefik.frontend.passTLSClientCert.infos.pem` |
|
||||||
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
|
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
|
||||||
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
|
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
|
||||||
| `traefik.<segment_name>.frontend.whiteList.ipStrategy=true` | Same as `traefik.frontend.whiteList.ipStrategy` |
|
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
|
||||||
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.depth=5` | Same as `traefik.frontend.whiteList.ipStrategy.depth` |
|
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
|
||||||
| `traefik.<segment_name>.frontend.whiteList.ipStrategy.excludedIPs=127.0.0.1` | Same as `traefik.frontend.whiteList.ipStrategy.excludedIPs` |
|
| `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
|
#### Custom Headers
|
||||||
|
|
||||||
|
|
|
@ -311,7 +311,6 @@ The `consul` provider contains the configuration.
|
||||||
[frontends.frontend2]
|
[frontends.frontend2]
|
||||||
backend = "backend1"
|
backend = "backend1"
|
||||||
passHostHeader = true
|
passHostHeader = true
|
||||||
passTLSCert = true
|
|
||||||
entrypoints = ["https"] # overrides defaultEntryPoints
|
entrypoints = ["https"] # overrides defaultEntryPoints
|
||||||
[frontends.frontend2.routes.test_1]
|
[frontends.frontend2.routes.test_1]
|
||||||
rule = "Host:{subdomain:[a-z]+}.localhost"
|
rule = "Host:{subdomain:[a-z]+}.localhost"
|
||||||
|
|
|
@ -118,7 +118,7 @@ func (hc *HealthCheck) execute(ctx context.Context, backend *BackendConfig) {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
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
|
return
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
log.Debugf("Refreshing health check for backend: %s", backend.name)
|
log.Debugf("Refreshing health check for backend: %s", backend.name)
|
||||||
|
|
21
integration/fixtures/tlsclientheaders/root.pem
Normal file
21
integration/fixtures/tlsclientheaders/root.pem
Normal 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-----
|
27
integration/fixtures/tlsclientheaders/server.key
Normal file
27
integration/fixtures/tlsclientheaders/server.key
Normal 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-----
|
19
integration/fixtures/tlsclientheaders/server.pem
Normal file
19
integration/fixtures/tlsclientheaders/server.pem
Normal 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-----
|
24
integration/fixtures/tlsclientheaders/simple.toml
Normal file
24
integration/fixtures/tlsclientheaders/simple.toml
Normal 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
|
|
@ -59,6 +59,7 @@ func init() {
|
||||||
check.Suite(&RateLimitSuite{})
|
check.Suite(&RateLimitSuite{})
|
||||||
check.Suite(&RetrySuite{})
|
check.Suite(&RetrySuite{})
|
||||||
check.Suite(&SimpleSuite{})
|
check.Suite(&SimpleSuite{})
|
||||||
|
check.Suite(&TLSClientHeadersSuite{})
|
||||||
check.Suite(&TimeoutSuite{})
|
check.Suite(&TimeoutSuite{})
|
||||||
check.Suite(&TracingSuite{})
|
check.Suite(&TracingSuite{})
|
||||||
check.Suite(&WebsocketSuite{})
|
check.Suite(&WebsocketSuite{})
|
||||||
|
|
6
integration/resources/compose/tlsclientheaders.yml
Normal file
6
integration/resources/compose/tlsclientheaders.yml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
whoami:
|
||||||
|
image: containous/whoami
|
||||||
|
labels:
|
||||||
|
- traefik.frontend.passTLSClientCert.pem=true
|
||||||
|
- traefik.frontend.rule=PathPrefix:/
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/containous/traefik/integration/try"
|
"github.com/containous/traefik/integration/try"
|
||||||
"github.com/go-check/check"
|
"github.com/go-check/check"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
checker "github.com/vdemeester/shakers"
|
checker "github.com/vdemeester/shakers"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,3 +39,29 @@ func (s *RetrySuite) TestRetry(c *check.C) {
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
|
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)
|
||||||
|
}
|
||||||
|
|
71
integration/tls_client_headers_test.go
Normal file
71
integration/tls_client_headers_test.go
Normal 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)
|
||||||
|
}
|
|
@ -193,26 +193,26 @@ func TestLoggerJSON(t *testing.T) {
|
||||||
Format: JSONFormat,
|
Format: JSONFormat,
|
||||||
},
|
},
|
||||||
expected: map[string]func(t *testing.T, value interface{}){
|
expected: map[string]func(t *testing.T, value interface{}){
|
||||||
RequestHost: assertString(testHostname),
|
RequestHost: assertString(testHostname),
|
||||||
RequestAddr: assertString(testHostname),
|
RequestAddr: assertString(testHostname),
|
||||||
RequestMethod: assertString(testMethod),
|
RequestMethod: assertString(testMethod),
|
||||||
RequestPath: assertString(testPath),
|
RequestPath: assertString(testPath),
|
||||||
RequestProtocol: assertString(testProto),
|
RequestProtocol: assertString(testProto),
|
||||||
RequestPort: assertString("-"),
|
RequestPort: assertString("-"),
|
||||||
DownstreamStatus: assertFloat64(float64(testStatus)),
|
DownstreamStatus: assertFloat64(float64(testStatus)),
|
||||||
DownstreamContentSize: assertFloat64(float64(len(testContent))),
|
DownstreamContentSize: assertFloat64(float64(len(testContent))),
|
||||||
OriginContentSize: assertFloat64(float64(len(testContent))),
|
OriginContentSize: assertFloat64(float64(len(testContent))),
|
||||||
OriginStatus: assertFloat64(float64(testStatus)),
|
OriginStatus: assertFloat64(float64(testStatus)),
|
||||||
RequestRefererHeader: assertString(testReferer),
|
RequestRefererHeader: assertString(testReferer),
|
||||||
RequestUserAgentHeader: assertString(testUserAgent),
|
RequestUserAgentHeader: assertString(testUserAgent),
|
||||||
FrontendName: assertString(testFrontendName),
|
FrontendName: assertString(testFrontendName),
|
||||||
BackendURL: assertString(testBackendName),
|
BackendURL: assertString(testBackendName),
|
||||||
ClientUsername: assertString(testUsername),
|
ClientUsername: assertString(testUsername),
|
||||||
ClientHost: assertString(testHostname),
|
ClientHost: assertString(testHostname),
|
||||||
ClientPort: assertString(fmt.Sprintf("%d", testPort)),
|
ClientPort: assertString(fmt.Sprintf("%d", testPort)),
|
||||||
ClientAddr: assertString(fmt.Sprintf("%s:%d", testHostname, testPort)),
|
ClientAddr: assertString(fmt.Sprintf("%s:%d", testHostname, testPort)),
|
||||||
"level": assertString("info"),
|
"level": assertString("info"),
|
||||||
"msg": assertString(""),
|
"msg": assertString(""),
|
||||||
"downstream_Content-Type": assertString("text/plain; charset=utf-8"),
|
"downstream_Content-Type": assertString("text/plain; charset=utf-8"),
|
||||||
RequestCount: assertFloat64NotZero(),
|
RequestCount: assertFloat64NotZero(),
|
||||||
Duration: assertFloat64NotZero(),
|
Duration: assertFloat64NotZero(),
|
||||||
|
@ -233,9 +233,9 @@ func TestLoggerJSON(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: map[string]func(t *testing.T, value interface{}){
|
expected: map[string]func(t *testing.T, value interface{}){
|
||||||
"level": assertString("info"),
|
"level": assertString("info"),
|
||||||
"msg": assertString(""),
|
"msg": assertString(""),
|
||||||
"time": assertNotEqual(""),
|
"time": assertNotEqual(""),
|
||||||
"downstream_Content-Type": assertString("text/plain; charset=utf-8"),
|
"downstream_Content-Type": assertString("text/plain; charset=utf-8"),
|
||||||
RequestRefererHeader: assertString(testReferer),
|
RequestRefererHeader: assertString(testReferer),
|
||||||
RequestUserAgentHeader: assertString(testUserAgent),
|
RequestUserAgentHeader: assertString(testUserAgent),
|
||||||
|
@ -272,9 +272,9 @@ func TestLoggerJSON(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expected: map[string]func(t *testing.T, value interface{}){
|
expected: map[string]func(t *testing.T, value interface{}){
|
||||||
"level": assertString("info"),
|
"level": assertString("info"),
|
||||||
"msg": assertString(""),
|
"msg": assertString(""),
|
||||||
"time": assertNotEqual(""),
|
"time": assertNotEqual(""),
|
||||||
"downstream_Content-Type": assertString("REDACTED"),
|
"downstream_Content-Type": assertString("REDACTED"),
|
||||||
RequestRefererHeader: assertString("REDACTED"),
|
RequestRefererHeader: assertString("REDACTED"),
|
||||||
RequestUserAgentHeader: assertString("REDACTED"),
|
RequestUserAgentHeader: assertString("REDACTED"),
|
||||||
|
|
|
@ -48,7 +48,7 @@ func (wl *IPWhiteLister) handle(w http.ResponseWriter, r *http.Request, next htt
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Debugf("Accept %s: %+v", wl.strategy.GetIP(r), r)
|
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)
|
next.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package middlewares
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -41,11 +42,8 @@ func (retry *Retry) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
|
||||||
attempts := 1
|
attempts := 1
|
||||||
for {
|
for {
|
||||||
attemptsExhausted := attempts >= retry.attempts
|
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
|
shouldRetry := !attemptsExhausted
|
||||||
// context and so we don't get httptrace information.
|
|
||||||
// Websocket clients should however retry on their own anyway.
|
|
||||||
shouldRetry := !attemptsExhausted && !isWebsocketRequest(r)
|
|
||||||
retryResponseWriter := newRetryResponseWriter(rw, shouldRetry)
|
retryResponseWriter := newRetryResponseWriter(rw, shouldRetry)
|
||||||
|
|
||||||
// Disable retries when the backend already received request data
|
// 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) {
|
func (rr *retryResponseWriterWithoutCloseNotify) Write(buf []byte) (int, error) {
|
||||||
if rr.ShouldRetry() {
|
if rr.ShouldRetry() {
|
||||||
return 0, nil
|
return len(buf), nil
|
||||||
}
|
}
|
||||||
return rr.responseWriter.Write(buf)
|
return rr.responseWriter.Write(buf)
|
||||||
}
|
}
|
||||||
|
@ -150,7 +148,11 @@ func (rr *retryResponseWriterWithoutCloseNotify) WriteHeader(code int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rr *retryResponseWriterWithoutCloseNotify) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
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() {
|
func (rr *retryResponseWriterWithoutCloseNotify) Flush() {
|
||||||
|
|
|
@ -3,22 +3,24 @@ package middlewares
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/containous/traefik/testhelpers"
|
"github.com/containous/traefik/testhelpers"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/vulcand/oxy/forward"
|
"github.com/vulcand/oxy/forward"
|
||||||
"github.com/vulcand/oxy/roundrobin"
|
"github.com/vulcand/oxy/roundrobin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRetry(t *testing.T) {
|
func TestRetry(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
desc string
|
desc string
|
||||||
maxRequestAttempts int
|
maxRequestAttempts int
|
||||||
wantRetryAttempts int
|
wantRetryAttempts int
|
||||||
wantResponseStatus int
|
wantResponseStatus int
|
||||||
amountFaultyEndpoints int
|
amountFaultyEndpoints int
|
||||||
isWebsocketHandshakeRequest bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "no retry on success",
|
desc: "no retry on success",
|
||||||
|
@ -55,14 +57,6 @@ func TestRetry(t *testing.T) {
|
||||||
wantResponseStatus: http.StatusInternalServerError,
|
wantResponseStatus: http.StatusInternalServerError,
|
||||||
amountFaultyEndpoints: 3,
|
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) {
|
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)
|
t.Fatalf("Error creating forwarder: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, test := range testCases {
|
||||||
tc := tc
|
test := test
|
||||||
|
|
||||||
t.Run(tc.desc, func(t *testing.T) {
|
t.Run(test.desc, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
loadBalancer, err := roundrobin.New(forwarder)
|
loadBalancer, err := roundrobin.New(forwarder)
|
||||||
|
@ -87,7 +81,7 @@ func TestRetry(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
basePort := 33444
|
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.
|
// 192.0.2.0 is a non-routable IP for testing purposes.
|
||||||
// See: https://stackoverflow.com/questions/528538/non-routable-ip-address/18436928#18436928
|
// 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
|
// 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)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
retryListener := &countingRetryListener{}
|
retryListener := &countingRetryListener{}
|
||||||
retry := NewRetry(tc.maxRequestAttempts, loadBalancer, retryListener)
|
retry := NewRetry(test.maxRequestAttempts, loadBalancer, retryListener)
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
req := httptest.NewRequest(http.MethodGet, "http://localhost:3000/ok", nil)
|
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)
|
retry.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
if tc.wantResponseStatus != recorder.Code {
|
assert.Equal(t, test.wantResponseStatus, recorder.Code)
|
||||||
t.Errorf("got status code %d, want %d", recorder.Code, tc.wantResponseStatus)
|
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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
251
middlewares/tlsClientHeaders.go
Normal file
251
middlewares/tlsClientHeaders.go
Normal 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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
799
middlewares/tlsClientHeaders_test.go
Normal file
799
middlewares/tlsClientHeaders_test.go
Normal 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))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -338,7 +338,7 @@ func (p *Provider) watchNewDomains() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(domains) == 0 {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@ func (p *Provider) buildConfiguration(catalog []catalogUpdate) *types.Configurat
|
||||||
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
||||||
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
||||||
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
|
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
|
||||||
|
"getPassTLSClientCert": label.GetTLSClientCert,
|
||||||
"getWhiteList": label.GetWhiteList,
|
"getWhiteList": label.GetWhiteList,
|
||||||
"getRedirect": label.GetRedirect,
|
"getRedirect": label.GetRedirect,
|
||||||
"getErrorPages": label.GetErrorPages,
|
"getErrorPages": label.GetErrorPages,
|
||||||
|
|
|
@ -423,6 +423,17 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
||||||
label.TraefikBackendBufferingMemRequestBodyBytes + "=2097152",
|
label.TraefikBackendBufferingMemRequestBodyBytes + "=2097152",
|
||||||
label.TraefikBackendBufferingRetryExpression + "=IsNetworkError() && Attempts() <= 2",
|
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.TraefikFrontendAuthBasic + "=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
label.TraefikFrontendAuthBasicRemoveHeader + "=true",
|
label.TraefikFrontendAuthBasicRemoveHeader + "=true",
|
||||||
label.TraefikFrontendAuthBasicUsers + "=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
label.TraefikFrontendAuthBasicUsers + "=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
|
@ -540,6 +551,22 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
PassTLSCert: true,
|
PassTLSCert: true,
|
||||||
Priority: 666,
|
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{
|
Auth: &types.Auth{
|
||||||
HeaderField: "X-WebAuth-User",
|
HeaderField: "X-WebAuth-User",
|
||||||
Basic: &types.Basic{
|
Basic: &types.Basic{
|
||||||
|
|
|
@ -42,19 +42,20 @@ func (p *Provider) buildConfiguration(containersInspected []dockerData) *types.C
|
||||||
"getLoadBalancer": label.GetLoadBalancer,
|
"getLoadBalancer": label.GetLoadBalancer,
|
||||||
|
|
||||||
// Frontend functions
|
// Frontend functions
|
||||||
"getBackendName": getBackendName,
|
"getBackendName": getBackendName,
|
||||||
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
||||||
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
||||||
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
|
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
|
||||||
"getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints),
|
"getPassTLSClientCert": label.GetTLSClientCert,
|
||||||
"getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated
|
"getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints),
|
||||||
"getAuth": label.GetAuth,
|
"getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated
|
||||||
"getFrontendRule": p.getFrontendRule,
|
"getAuth": label.GetAuth,
|
||||||
"getRedirect": label.GetRedirect,
|
"getFrontendRule": p.getFrontendRule,
|
||||||
"getErrorPages": label.GetErrorPages,
|
"getRedirect": label.GetRedirect,
|
||||||
"getRateLimit": label.GetRateLimit,
|
"getErrorPages": label.GetErrorPages,
|
||||||
"getHeaders": label.GetHeaders,
|
"getRateLimit": label.GetRateLimit,
|
||||||
"getWhiteList": label.GetWhiteList,
|
"getHeaders": label.GetHeaders,
|
||||||
|
"getWhiteList": label.GetWhiteList,
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter containers
|
// filter containers
|
||||||
|
|
|
@ -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",
|
desc: "when frontend basic auth backward compatibility",
|
||||||
containers: []docker.ContainerJSON{
|
containers: []docker.ContainerJSON{
|
||||||
|
@ -387,6 +450,17 @@ func TestDockerBuildConfiguration(t *testing.T) {
|
||||||
label.TraefikBackendBufferingMemRequestBodyBytes: "2097152",
|
label.TraefikBackendBufferingMemRequestBodyBytes: "2097152",
|
||||||
label.TraefikBackendBufferingRetryExpression: "IsNetworkError() && Attempts() <= 2",
|
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.TraefikFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
label.TraefikFrontendAuthBasicRemoveHeader: "true",
|
label.TraefikFrontendAuthBasicRemoveHeader: "true",
|
||||||
label.TraefikFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
label.TraefikFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
|
@ -475,6 +549,22 @@ func TestDockerBuildConfiguration(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
PassTLSCert: true,
|
PassTLSCert: true,
|
||||||
Priority: 666,
|
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{
|
Auth: &types.Auth{
|
||||||
HeaderField: "X-WebAuth-User",
|
HeaderField: "X-WebAuth-User",
|
||||||
Basic: &types.Basic{
|
Basic: &types.Basic{
|
||||||
|
|
|
@ -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",
|
desc: "when frontend basic auth configuration",
|
||||||
services: []swarm.Service{
|
services: []swarm.Service{
|
||||||
|
|
|
@ -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",
|
desc: "auth basic",
|
||||||
containers: []docker.ContainerJSON{
|
containers: []docker.ContainerJSON{
|
||||||
|
@ -286,6 +351,17 @@ func TestSegmentBuildConfiguration(t *testing.T) {
|
||||||
label.Prefix + "sauternes." + label.SuffixProtocol: "https",
|
label.Prefix + "sauternes." + label.SuffixProtocol: "https",
|
||||||
label.Prefix + "sauternes." + label.SuffixWeight: "12",
|
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.SuffixFrontendAuthBasicRemoveHeader: "true",
|
||||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsersFile: ".htpasswd",
|
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsersFile: ".htpasswd",
|
||||||
|
@ -368,6 +444,22 @@ func TestSegmentBuildConfiguration(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
PassTLSCert: true,
|
PassTLSCert: true,
|
||||||
Priority: 666,
|
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{
|
Auth: &types.Auth{
|
||||||
HeaderField: "X-WebAuth-User",
|
HeaderField: "X-WebAuth-User",
|
||||||
Basic: &types.Basic{
|
Basic: &types.Basic{
|
||||||
|
|
|
@ -31,20 +31,21 @@ func (p *Provider) buildConfiguration(instances []ecsInstance) (*types.Configura
|
||||||
"getServers": getServers,
|
"getServers": getServers,
|
||||||
|
|
||||||
// Frontend functions
|
// Frontend functions
|
||||||
"filterFrontends": filterFrontends,
|
"filterFrontends": filterFrontends,
|
||||||
"getFrontendRule": p.getFrontendRule,
|
"getFrontendRule": p.getFrontendRule,
|
||||||
"getFrontendName": p.getFrontendName,
|
"getFrontendName": p.getFrontendName,
|
||||||
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
||||||
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
|
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
|
||||||
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
"getPassTLSClientCert": label.GetTLSClientCert,
|
||||||
"getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated
|
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
||||||
"getAuth": label.GetAuth,
|
"getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated
|
||||||
"getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints),
|
"getAuth": label.GetAuth,
|
||||||
"getRedirect": label.GetRedirect,
|
"getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints),
|
||||||
"getErrorPages": label.GetErrorPages,
|
"getRedirect": label.GetRedirect,
|
||||||
"getRateLimit": label.GetRateLimit,
|
"getErrorPages": label.GetErrorPages,
|
||||||
"getHeaders": label.GetHeaders,
|
"getRateLimit": label.GetRateLimit,
|
||||||
"getWhiteList": label.GetWhiteList,
|
"getHeaders": label.GetHeaders,
|
||||||
|
"getWhiteList": label.GetWhiteList,
|
||||||
}
|
}
|
||||||
|
|
||||||
services := make(map[string][]ecsInstance)
|
services := make(map[string][]ecsInstance)
|
||||||
|
|
|
@ -321,6 +321,17 @@ func TestSegmentBuildConfiguration(t *testing.T) {
|
||||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTLSInsecureSkipVerify: "true",
|
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardTLSInsecureSkipVerify: "true",
|
||||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthHeaderField: "X-WebAuth-User",
|
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.SuffixFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
label.Prefix + "sauternes." + label.SuffixFrontendEntryPoints: "http,https",
|
label.Prefix + "sauternes." + label.SuffixFrontendEntryPoints: "http,https",
|
||||||
label.Prefix + "sauternes." + label.SuffixFrontendPassHostHeader: "true",
|
label.Prefix + "sauternes." + label.SuffixFrontendPassHostHeader: "true",
|
||||||
|
@ -391,6 +402,22 @@ func TestSegmentBuildConfiguration(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
PassTLSCert: true,
|
PassTLSCert: true,
|
||||||
Priority: 666,
|
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{
|
Auth: &types.Auth{
|
||||||
HeaderField: "X-WebAuth-User",
|
HeaderField: "X-WebAuth-User",
|
||||||
Basic: &types.Basic{
|
Basic: &types.Basic{
|
||||||
|
|
|
@ -356,6 +356,17 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
label.TraefikBackendBufferingMemRequestBodyBytes: aws.String("2097152"),
|
label.TraefikBackendBufferingMemRequestBodyBytes: aws.String("2097152"),
|
||||||
label.TraefikBackendBufferingRetryExpression: aws.String("IsNetworkError() && Attempts() <= 2"),
|
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.TraefikFrontendAuthBasic: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||||
label.TraefikFrontendAuthBasicRemoveHeader: aws.String("true"),
|
label.TraefikFrontendAuthBasicRemoveHeader: aws.String("true"),
|
||||||
label.TraefikFrontendAuthBasicUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
label.TraefikFrontendAuthBasicUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||||
|
@ -489,6 +500,22 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
PassTLSCert: true,
|
PassTLSCert: true,
|
||||||
Priority: 666,
|
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{
|
Auth: &types.Auth{
|
||||||
HeaderField: "X-WebAuth-User",
|
HeaderField: "X-WebAuth-User",
|
||||||
Basic: &types.Basic{
|
Basic: &types.Basic{
|
||||||
|
|
|
@ -380,7 +380,7 @@ func (p *Provider) lookupEc2Instances(ctx context.Context, client *awsClient, cl
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Unable to describe instances [%s]: %v", err)
|
log.Errorf("Unable to describe instances: %v", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -516,37 +516,37 @@ func TestModifierType(t *testing.T) {
|
||||||
expectedModifierRule string
|
expectedModifierRule string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "Request modifier annotation missing",
|
desc: "Request modifier annotation missing",
|
||||||
requestModifierAnnotation: "",
|
requestModifierAnnotation: "",
|
||||||
expectedModifierRule: "",
|
expectedModifierRule: "",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "AddPrefix modifier annotation",
|
desc: "AddPrefix modifier annotation",
|
||||||
requestModifierAnnotation: " AddPrefix: /foo",
|
requestModifierAnnotation: " AddPrefix: /foo",
|
||||||
expectedModifierRule: "AddPrefix:/foo",
|
expectedModifierRule: "AddPrefix:/foo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "ReplacePath modifier annotation",
|
desc: "ReplacePath modifier annotation",
|
||||||
requestModifierAnnotation: " ReplacePath: /foo",
|
requestModifierAnnotation: " ReplacePath: /foo",
|
||||||
expectedModifierRule: "ReplacePath:/foo",
|
expectedModifierRule: "ReplacePath:/foo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "ReplacePathRegex modifier annotation",
|
desc: "ReplacePathRegex modifier annotation",
|
||||||
requestModifierAnnotation: " ReplacePathRegex: /foo /bar",
|
requestModifierAnnotation: " ReplacePathRegex: /foo /bar",
|
||||||
expectedModifierRule: "ReplacePathRegex:/foo /bar",
|
expectedModifierRule: "ReplacePathRegex:/foo /bar",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "AddPrefix modifier annotation",
|
desc: "AddPrefix modifier annotation",
|
||||||
requestModifierAnnotation: "AddPrefix:/foo",
|
requestModifierAnnotation: "AddPrefix:/foo",
|
||||||
expectedModifierRule: "AddPrefix:/foo",
|
expectedModifierRule: "AddPrefix:/foo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "ReplacePath modifier annotation",
|
desc: "ReplacePath modifier annotation",
|
||||||
requestModifierAnnotation: "ReplacePath:/foo",
|
requestModifierAnnotation: "ReplacePath:/foo",
|
||||||
expectedModifierRule: "ReplacePath:/foo",
|
expectedModifierRule: "ReplacePath:/foo",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "ReplacePathRegex modifier annotation",
|
desc: "ReplacePathRegex modifier annotation",
|
||||||
requestModifierAnnotation: "ReplacePathRegex:/foo /bar",
|
requestModifierAnnotation: "ReplacePathRegex:/foo /bar",
|
||||||
expectedModifierRule: "ReplacePathRegex:/foo /bar",
|
expectedModifierRule: "ReplacePathRegex:/foo /bar",
|
||||||
},
|
},
|
||||||
|
@ -608,23 +608,23 @@ func TestModifierFails(t *testing.T) {
|
||||||
requestModifierAnnotation string
|
requestModifierAnnotation string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
desc: "Request modifier missing part of annotation",
|
desc: "Request modifier missing part of annotation",
|
||||||
requestModifierAnnotation: "AddPrefix: ",
|
requestModifierAnnotation: "AddPrefix: ",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Request modifier full of spaces annotation",
|
desc: "Request modifier full of spaces annotation",
|
||||||
requestModifierAnnotation: " ",
|
requestModifierAnnotation: " ",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Request modifier missing both parts of annotation",
|
desc: "Request modifier missing both parts of annotation",
|
||||||
requestModifierAnnotation: " : ",
|
requestModifierAnnotation: " : ",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Request modifier using unknown rule",
|
desc: "Request modifier using unknown rule",
|
||||||
requestModifierAnnotation: "Foo: /bar",
|
requestModifierAnnotation: "Foo: /bar",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
desc: "Missing Rule",
|
desc: "Missing Rule",
|
||||||
requestModifierAnnotation: " : /bar",
|
requestModifierAnnotation: " : /bar",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,15 +24,28 @@ const (
|
||||||
pathBackendBufferingMemRequestBodyBytes = pathBackendBuffering + "memrequestbodybytes"
|
pathBackendBufferingMemRequestBodyBytes = pathBackendBuffering + "memrequestbodybytes"
|
||||||
pathBackendBufferingRetryExpression = pathBackendBuffering + "retryexpression"
|
pathBackendBufferingRetryExpression = pathBackendBuffering + "retryexpression"
|
||||||
|
|
||||||
pathFrontends = "/frontends/"
|
pathFrontends = "/frontends/"
|
||||||
pathFrontendBackend = "/backend"
|
pathFrontendBackend = "/backend"
|
||||||
pathFrontendPriority = "/priority"
|
pathFrontendPriority = "/priority"
|
||||||
pathFrontendPassHostHeader = "/passhostheader"
|
pathFrontendPassHostHeader = "/passhostheader"
|
||||||
pathFrontendPassTLSCert = "/passtlscert"
|
pathFrontendPassTLSClientCert = "/passTLSClientCert"
|
||||||
pathFrontendWhiteListSourceRange = "/whitelist/sourcerange"
|
pathFrontendPassTLSClientCertPem = pathFrontendPassTLSClientCert + "/pem"
|
||||||
pathFrontendWhiteListIPStrategy = "/whitelist/ipstrategy"
|
pathFrontendPassTLSClientCertInfos = pathFrontendPassTLSClientCert + "/infos"
|
||||||
pathFrontendWhiteListIPStrategyDepth = pathFrontendWhiteListIPStrategy + "/depth"
|
pathFrontendPassTLSClientCertInfosNotAfter = pathFrontendPassTLSClientCertInfos + "/notAfter"
|
||||||
pathFrontendWhiteListIPStrategyExcludedIPs = pathFrontendWhiteListIPStrategy + "/excludedips"
|
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/"
|
pathFrontendAuth = "/auth/"
|
||||||
pathFrontendAuthBasic = pathFrontendAuth + "basic/"
|
pathFrontendAuthBasic = pathFrontendAuth + "basic/"
|
||||||
|
|
|
@ -41,18 +41,19 @@ func (p *Provider) buildConfiguration() *types.Configuration {
|
||||||
"getTLSSection": p.getTLSSection,
|
"getTLSSection": p.getTLSSection,
|
||||||
|
|
||||||
// Frontend functions
|
// Frontend functions
|
||||||
"getBackendName": p.getFuncString(pathFrontendBackend, ""),
|
"getBackendName": p.getFuncString(pathFrontendBackend, ""),
|
||||||
"getPriority": p.getFuncInt(pathFrontendPriority, label.DefaultFrontendPriority),
|
"getPriority": p.getFuncInt(pathFrontendPriority, label.DefaultFrontendPriority),
|
||||||
"getPassHostHeader": p.getFuncBool(pathFrontendPassHostHeader, label.DefaultPassHostHeader),
|
"getPassHostHeader": p.getFuncBool(pathFrontendPassHostHeader, label.DefaultPassHostHeader),
|
||||||
"getPassTLSCert": p.getFuncBool(pathFrontendPassTLSCert, label.DefaultPassTLSCert),
|
"getPassTLSCert": p.getFuncBool(pathFrontendPassTLSCert, label.DefaultPassTLSCert),
|
||||||
"getEntryPoints": p.getFuncList(pathFrontendEntryPoints),
|
"getPassTLSClientCert": p.getTLSClientCert,
|
||||||
"getAuth": p.getAuth,
|
"getEntryPoints": p.getFuncList(pathFrontendEntryPoints),
|
||||||
"getRoutes": p.getRoutes,
|
"getAuth": p.getAuth,
|
||||||
"getRedirect": p.getRedirect,
|
"getRoutes": p.getRoutes,
|
||||||
"getErrorPages": p.getErrorPages,
|
"getRedirect": p.getRedirect,
|
||||||
"getRateLimit": p.getRateLimit,
|
"getErrorPages": p.getErrorPages,
|
||||||
"getHeaders": p.getHeaders,
|
"getRateLimit": p.getRateLimit,
|
||||||
"getWhiteList": p.getWhiteList,
|
"getHeaders": p.getHeaders,
|
||||||
|
"getWhiteList": p.getWhiteList,
|
||||||
|
|
||||||
// Backend functions
|
// Backend functions
|
||||||
"getServers": p.getServers,
|
"getServers": p.getServers,
|
||||||
|
@ -334,6 +335,39 @@ func (p *Provider) getTLSSection(prefix string) []*tls.Configuration {
|
||||||
return tlsSection
|
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
|
// GetAuth Create auth from path
|
||||||
func (p *Provider) getAuth(rootPath string) *types.Auth {
|
func (p *Provider) getAuth(rootPath string) *types.Auth {
|
||||||
if p.hasPrefix(rootPath, pathFrontendAuth) {
|
if p.hasPrefix(rootPath, pathFrontendAuth) {
|
||||||
|
|
|
@ -277,6 +277,18 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
||||||
withPair(pathFrontendBackend, "backend1"),
|
withPair(pathFrontendBackend, "backend1"),
|
||||||
withPair(pathFrontendPriority, "6"),
|
withPair(pathFrontendPriority, "6"),
|
||||||
withPair(pathFrontendPassHostHeader, "false"),
|
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"),
|
withPair(pathFrontendPassTLSCert, "true"),
|
||||||
withList(pathFrontendEntryPoints, "http", "https"),
|
withList(pathFrontendEntryPoints, "http", "https"),
|
||||||
withList(pathFrontendWhiteListSourceRange, "1.1.1.1/24", "1234:abcd::42/32"),
|
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"},
|
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{
|
Auth: &types.Auth{
|
||||||
HeaderField: "X-WebAuth-User",
|
HeaderField: "X-WebAuth-User",
|
||||||
Basic: &types.Basic{
|
Basic: &types.Basic{
|
||||||
|
|
|
@ -2,187 +2,213 @@ package label
|
||||||
|
|
||||||
// Traefik labels
|
// Traefik labels
|
||||||
const (
|
const (
|
||||||
Prefix = "traefik."
|
Prefix = "traefik."
|
||||||
SuffixBackend = "backend"
|
SuffixBackend = "backend"
|
||||||
SuffixDomain = "domain"
|
SuffixDomain = "domain"
|
||||||
SuffixEnable = "enable"
|
SuffixEnable = "enable"
|
||||||
SuffixPort = "port"
|
SuffixPort = "port"
|
||||||
SuffixPortName = "portName"
|
SuffixPortName = "portName"
|
||||||
SuffixPortIndex = "portIndex"
|
SuffixPortIndex = "portIndex"
|
||||||
SuffixProtocol = "protocol"
|
SuffixProtocol = "protocol"
|
||||||
SuffixTags = "tags"
|
SuffixTags = "tags"
|
||||||
SuffixWeight = "weight"
|
SuffixWeight = "weight"
|
||||||
SuffixBackendID = "backend.id"
|
SuffixBackendID = "backend.id"
|
||||||
SuffixBackendCircuitBreaker = "backend.circuitbreaker"
|
SuffixBackendCircuitBreaker = "backend.circuitbreaker"
|
||||||
SuffixBackendCircuitBreakerExpression = "backend.circuitbreaker.expression"
|
SuffixBackendCircuitBreakerExpression = "backend.circuitbreaker.expression"
|
||||||
SuffixBackendHealthCheckScheme = "backend.healthcheck.scheme"
|
SuffixBackendHealthCheckScheme = "backend.healthcheck.scheme"
|
||||||
SuffixBackendHealthCheckPath = "backend.healthcheck.path"
|
SuffixBackendHealthCheckPath = "backend.healthcheck.path"
|
||||||
SuffixBackendHealthCheckPort = "backend.healthcheck.port"
|
SuffixBackendHealthCheckPort = "backend.healthcheck.port"
|
||||||
SuffixBackendHealthCheckInterval = "backend.healthcheck.interval"
|
SuffixBackendHealthCheckInterval = "backend.healthcheck.interval"
|
||||||
SuffixBackendHealthCheckHostname = "backend.healthcheck.hostname"
|
SuffixBackendHealthCheckHostname = "backend.healthcheck.hostname"
|
||||||
SuffixBackendHealthCheckHeaders = "backend.healthcheck.headers"
|
SuffixBackendHealthCheckHeaders = "backend.healthcheck.headers"
|
||||||
SuffixBackendLoadBalancer = "backend.loadbalancer"
|
SuffixBackendLoadBalancer = "backend.loadbalancer"
|
||||||
SuffixBackendLoadBalancerMethod = SuffixBackendLoadBalancer + ".method"
|
SuffixBackendLoadBalancerMethod = SuffixBackendLoadBalancer + ".method"
|
||||||
SuffixBackendLoadBalancerStickiness = SuffixBackendLoadBalancer + ".stickiness"
|
SuffixBackendLoadBalancerStickiness = SuffixBackendLoadBalancer + ".stickiness"
|
||||||
SuffixBackendLoadBalancerStickinessCookieName = SuffixBackendLoadBalancer + ".stickiness.cookieName"
|
SuffixBackendLoadBalancerStickinessCookieName = SuffixBackendLoadBalancer + ".stickiness.cookieName"
|
||||||
SuffixBackendMaxConnAmount = "backend.maxconn.amount"
|
SuffixBackendMaxConnAmount = "backend.maxconn.amount"
|
||||||
SuffixBackendMaxConnExtractorFunc = "backend.maxconn.extractorfunc"
|
SuffixBackendMaxConnExtractorFunc = "backend.maxconn.extractorfunc"
|
||||||
SuffixBackendBuffering = "backend.buffering"
|
SuffixBackendBuffering = "backend.buffering"
|
||||||
SuffixBackendBufferingMaxRequestBodyBytes = SuffixBackendBuffering + ".maxRequestBodyBytes"
|
SuffixBackendBufferingMaxRequestBodyBytes = SuffixBackendBuffering + ".maxRequestBodyBytes"
|
||||||
SuffixBackendBufferingMemRequestBodyBytes = SuffixBackendBuffering + ".memRequestBodyBytes"
|
SuffixBackendBufferingMemRequestBodyBytes = SuffixBackendBuffering + ".memRequestBodyBytes"
|
||||||
SuffixBackendBufferingMaxResponseBodyBytes = SuffixBackendBuffering + ".maxResponseBodyBytes"
|
SuffixBackendBufferingMaxResponseBodyBytes = SuffixBackendBuffering + ".maxResponseBodyBytes"
|
||||||
SuffixBackendBufferingMemResponseBodyBytes = SuffixBackendBuffering + ".memResponseBodyBytes"
|
SuffixBackendBufferingMemResponseBodyBytes = SuffixBackendBuffering + ".memResponseBodyBytes"
|
||||||
SuffixBackendBufferingRetryExpression = SuffixBackendBuffering + ".retryExpression"
|
SuffixBackendBufferingRetryExpression = SuffixBackendBuffering + ".retryExpression"
|
||||||
SuffixFrontend = "frontend"
|
SuffixFrontend = "frontend"
|
||||||
SuffixFrontendAuth = SuffixFrontend + ".auth"
|
SuffixFrontendAuth = SuffixFrontend + ".auth"
|
||||||
SuffixFrontendAuthBasic = SuffixFrontendAuth + ".basic"
|
SuffixFrontendAuthBasic = SuffixFrontendAuth + ".basic"
|
||||||
SuffixFrontendAuthBasicRemoveHeader = SuffixFrontendAuthBasic + ".removeHeader"
|
SuffixFrontendAuthBasicRemoveHeader = SuffixFrontendAuthBasic + ".removeHeader"
|
||||||
SuffixFrontendAuthBasicUsers = SuffixFrontendAuthBasic + ".users"
|
SuffixFrontendAuthBasicUsers = SuffixFrontendAuthBasic + ".users"
|
||||||
SuffixFrontendAuthBasicUsersFile = SuffixFrontendAuthBasic + ".usersFile"
|
SuffixFrontendAuthBasicUsersFile = SuffixFrontendAuthBasic + ".usersFile"
|
||||||
SuffixFrontendAuthDigest = SuffixFrontendAuth + ".digest"
|
SuffixFrontendAuthDigest = SuffixFrontendAuth + ".digest"
|
||||||
SuffixFrontendAuthDigestRemoveHeader = SuffixFrontendAuthDigest + ".removeHeader"
|
SuffixFrontendAuthDigestRemoveHeader = SuffixFrontendAuthDigest + ".removeHeader"
|
||||||
SuffixFrontendAuthDigestUsers = SuffixFrontendAuthDigest + ".users"
|
SuffixFrontendAuthDigestUsers = SuffixFrontendAuthDigest + ".users"
|
||||||
SuffixFrontendAuthDigestUsersFile = SuffixFrontendAuthDigest + ".usersFile"
|
SuffixFrontendAuthDigestUsersFile = SuffixFrontendAuthDigest + ".usersFile"
|
||||||
SuffixFrontendAuthForward = SuffixFrontendAuth + ".forward"
|
SuffixFrontendAuthForward = SuffixFrontendAuth + ".forward"
|
||||||
SuffixFrontendAuthForwardAddress = SuffixFrontendAuthForward + ".address"
|
SuffixFrontendAuthForwardAddress = SuffixFrontendAuthForward + ".address"
|
||||||
SuffixFrontendAuthForwardTLS = SuffixFrontendAuthForward + ".tls"
|
SuffixFrontendAuthForwardTLS = SuffixFrontendAuthForward + ".tls"
|
||||||
SuffixFrontendAuthForwardTLSCa = SuffixFrontendAuthForwardTLS + ".ca"
|
SuffixFrontendAuthForwardTLSCa = SuffixFrontendAuthForwardTLS + ".ca"
|
||||||
SuffixFrontendAuthForwardTLSCaOptional = SuffixFrontendAuthForwardTLS + ".caOptional"
|
SuffixFrontendAuthForwardTLSCaOptional = SuffixFrontendAuthForwardTLS + ".caOptional"
|
||||||
SuffixFrontendAuthForwardTLSCert = SuffixFrontendAuthForwardTLS + ".cert"
|
SuffixFrontendAuthForwardTLSCert = SuffixFrontendAuthForwardTLS + ".cert"
|
||||||
SuffixFrontendAuthForwardTLSInsecureSkipVerify = SuffixFrontendAuthForwardTLS + ".insecureSkipVerify"
|
SuffixFrontendAuthForwardTLSInsecureSkipVerify = SuffixFrontendAuthForwardTLS + ".insecureSkipVerify"
|
||||||
SuffixFrontendAuthForwardTLSKey = SuffixFrontendAuthForwardTLS + ".key"
|
SuffixFrontendAuthForwardTLSKey = SuffixFrontendAuthForwardTLS + ".key"
|
||||||
SuffixFrontendAuthForwardTrustForwardHeader = SuffixFrontendAuthForward + ".trustForwardHeader"
|
SuffixFrontendAuthForwardTrustForwardHeader = SuffixFrontendAuthForward + ".trustForwardHeader"
|
||||||
SuffixFrontendAuthHeaderField = SuffixFrontendAuth + ".headerField"
|
SuffixFrontendAuthHeaderField = SuffixFrontendAuth + ".headerField"
|
||||||
SuffixFrontendEntryPoints = "frontend.entryPoints"
|
SuffixFrontendEntryPoints = "frontend.entryPoints"
|
||||||
SuffixFrontendHeaders = "frontend.headers."
|
SuffixFrontendHeaders = "frontend.headers."
|
||||||
SuffixFrontendRequestHeaders = SuffixFrontendHeaders + "customRequestHeaders"
|
SuffixFrontendRequestHeaders = SuffixFrontendHeaders + "customRequestHeaders"
|
||||||
SuffixFrontendResponseHeaders = SuffixFrontendHeaders + "customResponseHeaders"
|
SuffixFrontendResponseHeaders = SuffixFrontendHeaders + "customResponseHeaders"
|
||||||
SuffixFrontendHeadersAllowedHosts = SuffixFrontendHeaders + "allowedHosts"
|
SuffixFrontendHeadersAllowedHosts = SuffixFrontendHeaders + "allowedHosts"
|
||||||
SuffixFrontendHeadersHostsProxyHeaders = SuffixFrontendHeaders + "hostsProxyHeaders"
|
SuffixFrontendHeadersHostsProxyHeaders = SuffixFrontendHeaders + "hostsProxyHeaders"
|
||||||
SuffixFrontendHeadersSSLForceHost = SuffixFrontendHeaders + "SSLForceHost"
|
SuffixFrontendHeadersSSLForceHost = SuffixFrontendHeaders + "SSLForceHost"
|
||||||
SuffixFrontendHeadersSSLRedirect = SuffixFrontendHeaders + "SSLRedirect"
|
SuffixFrontendHeadersSSLRedirect = SuffixFrontendHeaders + "SSLRedirect"
|
||||||
SuffixFrontendHeadersSSLTemporaryRedirect = SuffixFrontendHeaders + "SSLTemporaryRedirect"
|
SuffixFrontendHeadersSSLTemporaryRedirect = SuffixFrontendHeaders + "SSLTemporaryRedirect"
|
||||||
SuffixFrontendHeadersSSLHost = SuffixFrontendHeaders + "SSLHost"
|
SuffixFrontendHeadersSSLHost = SuffixFrontendHeaders + "SSLHost"
|
||||||
SuffixFrontendHeadersSSLProxyHeaders = SuffixFrontendHeaders + "SSLProxyHeaders"
|
SuffixFrontendHeadersSSLProxyHeaders = SuffixFrontendHeaders + "SSLProxyHeaders"
|
||||||
SuffixFrontendHeadersSTSSeconds = SuffixFrontendHeaders + "STSSeconds"
|
SuffixFrontendHeadersSTSSeconds = SuffixFrontendHeaders + "STSSeconds"
|
||||||
SuffixFrontendHeadersSTSIncludeSubdomains = SuffixFrontendHeaders + "STSIncludeSubdomains"
|
SuffixFrontendHeadersSTSIncludeSubdomains = SuffixFrontendHeaders + "STSIncludeSubdomains"
|
||||||
SuffixFrontendHeadersSTSPreload = SuffixFrontendHeaders + "STSPreload"
|
SuffixFrontendHeadersSTSPreload = SuffixFrontendHeaders + "STSPreload"
|
||||||
SuffixFrontendHeadersForceSTSHeader = SuffixFrontendHeaders + "forceSTSHeader"
|
SuffixFrontendHeadersForceSTSHeader = SuffixFrontendHeaders + "forceSTSHeader"
|
||||||
SuffixFrontendHeadersFrameDeny = SuffixFrontendHeaders + "frameDeny"
|
SuffixFrontendHeadersFrameDeny = SuffixFrontendHeaders + "frameDeny"
|
||||||
SuffixFrontendHeadersCustomFrameOptionsValue = SuffixFrontendHeaders + "customFrameOptionsValue"
|
SuffixFrontendHeadersCustomFrameOptionsValue = SuffixFrontendHeaders + "customFrameOptionsValue"
|
||||||
SuffixFrontendHeadersContentTypeNosniff = SuffixFrontendHeaders + "contentTypeNosniff"
|
SuffixFrontendHeadersContentTypeNosniff = SuffixFrontendHeaders + "contentTypeNosniff"
|
||||||
SuffixFrontendHeadersBrowserXSSFilter = SuffixFrontendHeaders + "browserXSSFilter"
|
SuffixFrontendHeadersBrowserXSSFilter = SuffixFrontendHeaders + "browserXSSFilter"
|
||||||
SuffixFrontendHeadersCustomBrowserXSSValue = SuffixFrontendHeaders + "customBrowserXSSValue"
|
SuffixFrontendHeadersCustomBrowserXSSValue = SuffixFrontendHeaders + "customBrowserXSSValue"
|
||||||
SuffixFrontendHeadersContentSecurityPolicy = SuffixFrontendHeaders + "contentSecurityPolicy"
|
SuffixFrontendHeadersContentSecurityPolicy = SuffixFrontendHeaders + "contentSecurityPolicy"
|
||||||
SuffixFrontendHeadersPublicKey = SuffixFrontendHeaders + "publicKey"
|
SuffixFrontendHeadersPublicKey = SuffixFrontendHeaders + "publicKey"
|
||||||
SuffixFrontendHeadersReferrerPolicy = SuffixFrontendHeaders + "referrerPolicy"
|
SuffixFrontendHeadersReferrerPolicy = SuffixFrontendHeaders + "referrerPolicy"
|
||||||
SuffixFrontendHeadersIsDevelopment = SuffixFrontendHeaders + "isDevelopment"
|
SuffixFrontendHeadersIsDevelopment = SuffixFrontendHeaders + "isDevelopment"
|
||||||
SuffixFrontendPassHostHeader = "frontend.passHostHeader"
|
SuffixFrontendPassHostHeader = "frontend.passHostHeader"
|
||||||
SuffixFrontendPassTLSCert = "frontend.passTLSCert"
|
SuffixFrontendPassTLSClientCert = "frontend.passTLSClientCert"
|
||||||
SuffixFrontendPriority = "frontend.priority"
|
SuffixFrontendPassTLSClientCertPem = SuffixFrontendPassTLSClientCert + ".pem"
|
||||||
SuffixFrontendRateLimitExtractorFunc = "frontend.rateLimit.extractorFunc"
|
SuffixFrontendPassTLSClientCertInfos = SuffixFrontendPassTLSClientCert + ".infos"
|
||||||
SuffixFrontendRedirectEntryPoint = "frontend.redirect.entryPoint"
|
SuffixFrontendPassTLSClientCertInfosNotAfter = SuffixFrontendPassTLSClientCertInfos + ".notAfter"
|
||||||
SuffixFrontendRedirectRegex = "frontend.redirect.regex"
|
SuffixFrontendPassTLSClientCertInfosNotBefore = SuffixFrontendPassTLSClientCertInfos + ".notBefore"
|
||||||
SuffixFrontendRedirectReplacement = "frontend.redirect.replacement"
|
SuffixFrontendPassTLSClientCertInfosSans = SuffixFrontendPassTLSClientCertInfos + ".sans"
|
||||||
SuffixFrontendRedirectPermanent = "frontend.redirect.permanent"
|
SuffixFrontendPassTLSClientCertInfosSubject = SuffixFrontendPassTLSClientCertInfos + ".subject"
|
||||||
SuffixFrontendRule = "frontend.rule"
|
SuffixFrontendPassTLSClientCertInfosSubjectCommonName = SuffixFrontendPassTLSClientCertInfosSubject + ".commonName"
|
||||||
SuffixFrontendWhiteList = "frontend.whiteList."
|
SuffixFrontendPassTLSClientCertInfosSubjectCountry = SuffixFrontendPassTLSClientCertInfosSubject + ".country"
|
||||||
SuffixFrontendWhiteListSourceRange = SuffixFrontendWhiteList + "sourceRange"
|
SuffixFrontendPassTLSClientCertInfosSubjectLocality = SuffixFrontendPassTLSClientCertInfosSubject + ".locality"
|
||||||
SuffixFrontendWhiteListIPStrategy = SuffixFrontendWhiteList + "ipStrategy"
|
SuffixFrontendPassTLSClientCertInfosSubjectOrganization = SuffixFrontendPassTLSClientCertInfosSubject + ".organization"
|
||||||
SuffixFrontendWhiteListIPStrategyDepth = SuffixFrontendWhiteListIPStrategy + ".depth"
|
SuffixFrontendPassTLSClientCertInfosSubjectProvince = SuffixFrontendPassTLSClientCertInfosSubject + ".province"
|
||||||
SuffixFrontendWhiteListIPStrategyExcludedIPS = SuffixFrontendWhiteListIPStrategy + ".excludedIPs"
|
SuffixFrontendPassTLSClientCertInfosSubjectSerialNumber = SuffixFrontendPassTLSClientCertInfosSubject + ".serialNumber"
|
||||||
TraefikDomain = Prefix + SuffixDomain
|
SuffixFrontendPassTLSCert = "frontend.passTLSCert" // Deprecated
|
||||||
TraefikEnable = Prefix + SuffixEnable
|
SuffixFrontendPriority = "frontend.priority"
|
||||||
TraefikPort = Prefix + SuffixPort
|
SuffixFrontendRateLimitExtractorFunc = "frontend.rateLimit.extractorFunc"
|
||||||
TraefikPortName = Prefix + SuffixPortName
|
SuffixFrontendRedirectEntryPoint = "frontend.redirect.entryPoint"
|
||||||
TraefikPortIndex = Prefix + SuffixPortIndex
|
SuffixFrontendRedirectRegex = "frontend.redirect.regex"
|
||||||
TraefikProtocol = Prefix + SuffixProtocol
|
SuffixFrontendRedirectReplacement = "frontend.redirect.replacement"
|
||||||
TraefikTags = Prefix + SuffixTags
|
SuffixFrontendRedirectPermanent = "frontend.redirect.permanent"
|
||||||
TraefikWeight = Prefix + SuffixWeight
|
SuffixFrontendRule = "frontend.rule"
|
||||||
TraefikBackend = Prefix + SuffixBackend
|
SuffixFrontendWhiteList = "frontend.whiteList."
|
||||||
TraefikBackendID = Prefix + SuffixBackendID
|
SuffixFrontendWhiteListSourceRange = SuffixFrontendWhiteList + "sourceRange"
|
||||||
TraefikBackendCircuitBreaker = Prefix + SuffixBackendCircuitBreaker
|
SuffixFrontendWhiteListIPStrategy = SuffixFrontendWhiteList + "ipStrategy"
|
||||||
TraefikBackendCircuitBreakerExpression = Prefix + SuffixBackendCircuitBreakerExpression
|
SuffixFrontendWhiteListIPStrategyDepth = SuffixFrontendWhiteListIPStrategy + ".depth"
|
||||||
TraefikBackendHealthCheckScheme = Prefix + SuffixBackendHealthCheckScheme
|
SuffixFrontendWhiteListIPStrategyExcludedIPS = SuffixFrontendWhiteListIPStrategy + ".excludedIPs"
|
||||||
TraefikBackendHealthCheckPath = Prefix + SuffixBackendHealthCheckPath
|
TraefikDomain = Prefix + SuffixDomain
|
||||||
TraefikBackendHealthCheckPort = Prefix + SuffixBackendHealthCheckPort
|
TraefikEnable = Prefix + SuffixEnable
|
||||||
TraefikBackendHealthCheckInterval = Prefix + SuffixBackendHealthCheckInterval
|
TraefikPort = Prefix + SuffixPort
|
||||||
TraefikBackendHealthCheckHostname = Prefix + SuffixBackendHealthCheckHostname
|
TraefikPortName = Prefix + SuffixPortName
|
||||||
TraefikBackendHealthCheckHeaders = Prefix + SuffixBackendHealthCheckHeaders
|
TraefikPortIndex = Prefix + SuffixPortIndex
|
||||||
TraefikBackendLoadBalancer = Prefix + SuffixBackendLoadBalancer
|
TraefikProtocol = Prefix + SuffixProtocol
|
||||||
TraefikBackendLoadBalancerMethod = Prefix + SuffixBackendLoadBalancerMethod
|
TraefikTags = Prefix + SuffixTags
|
||||||
TraefikBackendLoadBalancerStickiness = Prefix + SuffixBackendLoadBalancerStickiness
|
TraefikWeight = Prefix + SuffixWeight
|
||||||
TraefikBackendLoadBalancerStickinessCookieName = Prefix + SuffixBackendLoadBalancerStickinessCookieName
|
TraefikBackend = Prefix + SuffixBackend
|
||||||
TraefikBackendMaxConnAmount = Prefix + SuffixBackendMaxConnAmount
|
TraefikBackendID = Prefix + SuffixBackendID
|
||||||
TraefikBackendMaxConnExtractorFunc = Prefix + SuffixBackendMaxConnExtractorFunc
|
TraefikBackendCircuitBreaker = Prefix + SuffixBackendCircuitBreaker
|
||||||
TraefikBackendBuffering = Prefix + SuffixBackendBuffering
|
TraefikBackendCircuitBreakerExpression = Prefix + SuffixBackendCircuitBreakerExpression
|
||||||
TraefikBackendBufferingMaxRequestBodyBytes = Prefix + SuffixBackendBufferingMaxRequestBodyBytes
|
TraefikBackendHealthCheckScheme = Prefix + SuffixBackendHealthCheckScheme
|
||||||
TraefikBackendBufferingMemRequestBodyBytes = Prefix + SuffixBackendBufferingMemRequestBodyBytes
|
TraefikBackendHealthCheckPath = Prefix + SuffixBackendHealthCheckPath
|
||||||
TraefikBackendBufferingMaxResponseBodyBytes = Prefix + SuffixBackendBufferingMaxResponseBodyBytes
|
TraefikBackendHealthCheckPort = Prefix + SuffixBackendHealthCheckPort
|
||||||
TraefikBackendBufferingMemResponseBodyBytes = Prefix + SuffixBackendBufferingMemResponseBodyBytes
|
TraefikBackendHealthCheckInterval = Prefix + SuffixBackendHealthCheckInterval
|
||||||
TraefikBackendBufferingRetryExpression = Prefix + SuffixBackendBufferingRetryExpression
|
TraefikBackendHealthCheckHostname = Prefix + SuffixBackendHealthCheckHostname
|
||||||
TraefikFrontend = Prefix + SuffixFrontend
|
TraefikBackendHealthCheckHeaders = Prefix + SuffixBackendHealthCheckHeaders
|
||||||
TraefikFrontendAuth = Prefix + SuffixFrontendAuth
|
TraefikBackendLoadBalancer = Prefix + SuffixBackendLoadBalancer
|
||||||
TraefikFrontendAuthBasic = Prefix + SuffixFrontendAuthBasic
|
TraefikBackendLoadBalancerMethod = Prefix + SuffixBackendLoadBalancerMethod
|
||||||
TraefikFrontendAuthBasicRemoveHeader = Prefix + SuffixFrontendAuthBasicRemoveHeader
|
TraefikBackendLoadBalancerStickiness = Prefix + SuffixBackendLoadBalancerStickiness
|
||||||
TraefikFrontendAuthBasicUsers = Prefix + SuffixFrontendAuthBasicUsers
|
TraefikBackendLoadBalancerStickinessCookieName = Prefix + SuffixBackendLoadBalancerStickinessCookieName
|
||||||
TraefikFrontendAuthBasicUsersFile = Prefix + SuffixFrontendAuthBasicUsersFile
|
TraefikBackendMaxConnAmount = Prefix + SuffixBackendMaxConnAmount
|
||||||
TraefikFrontendAuthDigest = Prefix + SuffixFrontendAuthDigest
|
TraefikBackendMaxConnExtractorFunc = Prefix + SuffixBackendMaxConnExtractorFunc
|
||||||
TraefikFrontendAuthDigestRemoveHeader = Prefix + SuffixFrontendAuthDigestRemoveHeader
|
TraefikBackendBuffering = Prefix + SuffixBackendBuffering
|
||||||
TraefikFrontendAuthDigestUsers = Prefix + SuffixFrontendAuthDigestUsers
|
TraefikBackendBufferingMaxRequestBodyBytes = Prefix + SuffixBackendBufferingMaxRequestBodyBytes
|
||||||
TraefikFrontendAuthDigestUsersFile = Prefix + SuffixFrontendAuthDigestUsersFile
|
TraefikBackendBufferingMemRequestBodyBytes = Prefix + SuffixBackendBufferingMemRequestBodyBytes
|
||||||
TraefikFrontendAuthForward = Prefix + SuffixFrontendAuthForward
|
TraefikBackendBufferingMaxResponseBodyBytes = Prefix + SuffixBackendBufferingMaxResponseBodyBytes
|
||||||
TraefikFrontendAuthForwardAddress = Prefix + SuffixFrontendAuthForwardAddress
|
TraefikBackendBufferingMemResponseBodyBytes = Prefix + SuffixBackendBufferingMemResponseBodyBytes
|
||||||
TraefikFrontendAuthForwardTLS = Prefix + SuffixFrontendAuthForwardTLS
|
TraefikBackendBufferingRetryExpression = Prefix + SuffixBackendBufferingRetryExpression
|
||||||
TraefikFrontendAuthForwardTLSCa = Prefix + SuffixFrontendAuthForwardTLSCa
|
TraefikFrontend = Prefix + SuffixFrontend
|
||||||
TraefikFrontendAuthForwardTLSCaOptional = Prefix + SuffixFrontendAuthForwardTLSCaOptional
|
TraefikFrontendAuth = Prefix + SuffixFrontendAuth
|
||||||
TraefikFrontendAuthForwardTLSCert = Prefix + SuffixFrontendAuthForwardTLSCert
|
TraefikFrontendAuthBasic = Prefix + SuffixFrontendAuthBasic
|
||||||
TraefikFrontendAuthForwardTLSInsecureSkipVerify = Prefix + SuffixFrontendAuthForwardTLSInsecureSkipVerify
|
TraefikFrontendAuthBasicRemoveHeader = Prefix + SuffixFrontendAuthBasicRemoveHeader
|
||||||
TraefikFrontendAuthForwardTLSKey = Prefix + SuffixFrontendAuthForwardTLSKey
|
TraefikFrontendAuthBasicUsers = Prefix + SuffixFrontendAuthBasicUsers
|
||||||
TraefikFrontendAuthForwardTrustForwardHeader = Prefix + SuffixFrontendAuthForwardTrustForwardHeader
|
TraefikFrontendAuthBasicUsersFile = Prefix + SuffixFrontendAuthBasicUsersFile
|
||||||
TraefikFrontendAuthHeaderField = Prefix + SuffixFrontendAuthHeaderField
|
TraefikFrontendAuthDigest = Prefix + SuffixFrontendAuthDigest
|
||||||
TraefikFrontendEntryPoints = Prefix + SuffixFrontendEntryPoints
|
TraefikFrontendAuthDigestRemoveHeader = Prefix + SuffixFrontendAuthDigestRemoveHeader
|
||||||
TraefikFrontendPassHostHeader = Prefix + SuffixFrontendPassHostHeader
|
TraefikFrontendAuthDigestUsers = Prefix + SuffixFrontendAuthDigestUsers
|
||||||
TraefikFrontendPassTLSCert = Prefix + SuffixFrontendPassTLSCert
|
TraefikFrontendAuthDigestUsersFile = Prefix + SuffixFrontendAuthDigestUsersFile
|
||||||
TraefikFrontendPriority = Prefix + SuffixFrontendPriority
|
TraefikFrontendAuthForward = Prefix + SuffixFrontendAuthForward
|
||||||
TraefikFrontendRateLimitExtractorFunc = Prefix + SuffixFrontendRateLimitExtractorFunc
|
TraefikFrontendAuthForwardAddress = Prefix + SuffixFrontendAuthForwardAddress
|
||||||
TraefikFrontendRedirectEntryPoint = Prefix + SuffixFrontendRedirectEntryPoint
|
TraefikFrontendAuthForwardTLS = Prefix + SuffixFrontendAuthForwardTLS
|
||||||
TraefikFrontendRedirectRegex = Prefix + SuffixFrontendRedirectRegex
|
TraefikFrontendAuthForwardTLSCa = Prefix + SuffixFrontendAuthForwardTLSCa
|
||||||
TraefikFrontendRedirectReplacement = Prefix + SuffixFrontendRedirectReplacement
|
TraefikFrontendAuthForwardTLSCaOptional = Prefix + SuffixFrontendAuthForwardTLSCaOptional
|
||||||
TraefikFrontendRedirectPermanent = Prefix + SuffixFrontendRedirectPermanent
|
TraefikFrontendAuthForwardTLSCert = Prefix + SuffixFrontendAuthForwardTLSCert
|
||||||
TraefikFrontendRule = Prefix + SuffixFrontendRule
|
TraefikFrontendAuthForwardTLSInsecureSkipVerify = Prefix + SuffixFrontendAuthForwardTLSInsecureSkipVerify
|
||||||
TraefikFrontendWhiteListSourceRange = Prefix + SuffixFrontendWhiteListSourceRange
|
TraefikFrontendAuthForwardTLSKey = Prefix + SuffixFrontendAuthForwardTLSKey
|
||||||
TraefikFrontendWhiteListIPStrategy = Prefix + SuffixFrontendWhiteListIPStrategy
|
TraefikFrontendAuthForwardTrustForwardHeader = Prefix + SuffixFrontendAuthForwardTrustForwardHeader
|
||||||
TraefikFrontendWhiteListIPStrategyDepth = Prefix + SuffixFrontendWhiteListIPStrategyDepth
|
TraefikFrontendAuthHeaderField = Prefix + SuffixFrontendAuthHeaderField
|
||||||
TraefikFrontendWhiteListIPStrategyExcludedIPS = Prefix + SuffixFrontendWhiteListIPStrategyExcludedIPS
|
TraefikFrontendEntryPoints = Prefix + SuffixFrontendEntryPoints
|
||||||
TraefikFrontendRequestHeaders = Prefix + SuffixFrontendRequestHeaders
|
TraefikFrontendPassHostHeader = Prefix + SuffixFrontendPassHostHeader
|
||||||
TraefikFrontendResponseHeaders = Prefix + SuffixFrontendResponseHeaders
|
TraefikFrontendPassTLSClientCert = Prefix + SuffixFrontendPassTLSClientCert
|
||||||
TraefikFrontendAllowedHosts = Prefix + SuffixFrontendHeadersAllowedHosts
|
TraefikFrontendPassTLSClientCertPem = Prefix + SuffixFrontendPassTLSClientCertPem
|
||||||
TraefikFrontendHostsProxyHeaders = Prefix + SuffixFrontendHeadersHostsProxyHeaders
|
TraefikFrontendPassTLSClientCertInfos = Prefix + SuffixFrontendPassTLSClientCertInfos
|
||||||
TraefikFrontendSSLForceHost = Prefix + SuffixFrontendHeadersSSLForceHost
|
TraefikFrontendPassTLSClientCertInfosNotAfter = Prefix + SuffixFrontendPassTLSClientCertInfosNotAfter
|
||||||
TraefikFrontendSSLRedirect = Prefix + SuffixFrontendHeadersSSLRedirect
|
TraefikFrontendPassTLSClientCertInfosNotBefore = Prefix + SuffixFrontendPassTLSClientCertInfosNotBefore
|
||||||
TraefikFrontendSSLTemporaryRedirect = Prefix + SuffixFrontendHeadersSSLTemporaryRedirect
|
TraefikFrontendPassTLSClientCertInfosSans = Prefix + SuffixFrontendPassTLSClientCertInfosSans
|
||||||
TraefikFrontendSSLHost = Prefix + SuffixFrontendHeadersSSLHost
|
TraefikFrontendPassTLSClientCertInfosSubject = Prefix + SuffixFrontendPassTLSClientCertInfosSubject
|
||||||
TraefikFrontendSSLProxyHeaders = Prefix + SuffixFrontendHeadersSSLProxyHeaders
|
TraefikFrontendPassTLSClientCertInfosSubjectCommonName = Prefix + SuffixFrontendPassTLSClientCertInfosSubjectCommonName
|
||||||
TraefikFrontendSTSSeconds = Prefix + SuffixFrontendHeadersSTSSeconds
|
TraefikFrontendPassTLSClientCertInfosSubjectCountry = Prefix + SuffixFrontendPassTLSClientCertInfosSubjectCountry
|
||||||
TraefikFrontendSTSIncludeSubdomains = Prefix + SuffixFrontendHeadersSTSIncludeSubdomains
|
TraefikFrontendPassTLSClientCertInfosSubjectLocality = Prefix + SuffixFrontendPassTLSClientCertInfosSubjectLocality
|
||||||
TraefikFrontendSTSPreload = Prefix + SuffixFrontendHeadersSTSPreload
|
TraefikFrontendPassTLSClientCertInfosSubjectOrganization = Prefix + SuffixFrontendPassTLSClientCertInfosSubjectOrganization
|
||||||
TraefikFrontendForceSTSHeader = Prefix + SuffixFrontendHeadersForceSTSHeader
|
TraefikFrontendPassTLSClientCertInfosSubjectProvince = Prefix + SuffixFrontendPassTLSClientCertInfosSubjectProvince
|
||||||
TraefikFrontendFrameDeny = Prefix + SuffixFrontendHeadersFrameDeny
|
TraefikFrontendPassTLSClientCertInfosSubjectSerialNumber = Prefix + SuffixFrontendPassTLSClientCertInfosSubjectSerialNumber
|
||||||
TraefikFrontendCustomFrameOptionsValue = Prefix + SuffixFrontendHeadersCustomFrameOptionsValue
|
TraefikFrontendPassTLSCert = Prefix + SuffixFrontendPassTLSCert // Deprecated
|
||||||
TraefikFrontendContentTypeNosniff = Prefix + SuffixFrontendHeadersContentTypeNosniff
|
TraefikFrontendPriority = Prefix + SuffixFrontendPriority
|
||||||
TraefikFrontendBrowserXSSFilter = Prefix + SuffixFrontendHeadersBrowserXSSFilter
|
TraefikFrontendRateLimitExtractorFunc = Prefix + SuffixFrontendRateLimitExtractorFunc
|
||||||
TraefikFrontendCustomBrowserXSSValue = Prefix + SuffixFrontendHeadersCustomBrowserXSSValue
|
TraefikFrontendRedirectEntryPoint = Prefix + SuffixFrontendRedirectEntryPoint
|
||||||
TraefikFrontendContentSecurityPolicy = Prefix + SuffixFrontendHeadersContentSecurityPolicy
|
TraefikFrontendRedirectRegex = Prefix + SuffixFrontendRedirectRegex
|
||||||
TraefikFrontendPublicKey = Prefix + SuffixFrontendHeadersPublicKey
|
TraefikFrontendRedirectReplacement = Prefix + SuffixFrontendRedirectReplacement
|
||||||
TraefikFrontendReferrerPolicy = Prefix + SuffixFrontendHeadersReferrerPolicy
|
TraefikFrontendRedirectPermanent = Prefix + SuffixFrontendRedirectPermanent
|
||||||
TraefikFrontendIsDevelopment = Prefix + SuffixFrontendHeadersIsDevelopment
|
TraefikFrontendRule = Prefix + SuffixFrontendRule
|
||||||
BaseFrontendErrorPage = "frontend.errors."
|
TraefikFrontendWhiteListSourceRange = Prefix + SuffixFrontendWhiteListSourceRange
|
||||||
SuffixErrorPageBackend = "backend"
|
TraefikFrontendWhiteListIPStrategy = Prefix + SuffixFrontendWhiteListIPStrategy
|
||||||
SuffixErrorPageQuery = "query"
|
TraefikFrontendWhiteListIPStrategyDepth = Prefix + SuffixFrontendWhiteListIPStrategyDepth
|
||||||
SuffixErrorPageStatus = "status"
|
TraefikFrontendWhiteListIPStrategyExcludedIPS = Prefix + SuffixFrontendWhiteListIPStrategyExcludedIPS
|
||||||
BaseFrontendRateLimit = "frontend.rateLimit.rateSet."
|
TraefikFrontendRequestHeaders = Prefix + SuffixFrontendRequestHeaders
|
||||||
SuffixRateLimitPeriod = "period"
|
TraefikFrontendResponseHeaders = Prefix + SuffixFrontendResponseHeaders
|
||||||
SuffixRateLimitAverage = "average"
|
TraefikFrontendAllowedHosts = Prefix + SuffixFrontendHeadersAllowedHosts
|
||||||
SuffixRateLimitBurst = "burst"
|
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"
|
||||||
)
|
)
|
||||||
|
|
|
@ -62,6 +62,39 @@ func GetRedirect(labels map[string]string) *types.Redirect {
|
||||||
return nil
|
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
|
// GetAuth Create auth from labels
|
||||||
func GetAuth(labels map[string]string) *types.Auth {
|
func GetAuth(labels map[string]string) *types.Auth {
|
||||||
if !HasPrefix(labels, TraefikFrontendAuth) {
|
if !HasPrefix(labels, TraefikFrontendAuth) {
|
||||||
|
|
|
@ -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)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ func (p *Provider) buildConfiguration(applications *marathon.Applications) *type
|
||||||
"getFrontendName": p.getFrontendName,
|
"getFrontendName": p.getFrontendName,
|
||||||
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
||||||
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
|
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
|
||||||
|
"getPassTLSClientCert": label.GetTLSClientCert,
|
||||||
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
||||||
"getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints),
|
"getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints),
|
||||||
"getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated
|
"getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated
|
||||||
|
|
|
@ -373,6 +373,17 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
withLabel(label.TraefikBackendBufferingMemRequestBodyBytes, "2097152"),
|
withLabel(label.TraefikBackendBufferingMemRequestBodyBytes, "2097152"),
|
||||||
withLabel(label.TraefikBackendBufferingRetryExpression, "IsNetworkError() && Attempts() <= 2"),
|
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.TraefikFrontendAuthBasic, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||||
withLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true"),
|
withLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true"),
|
||||||
withLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
withLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||||
|
@ -455,6 +466,22 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
PassTLSCert: true,
|
PassTLSCert: true,
|
||||||
Priority: 666,
|
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{
|
Auth: &types.Auth{
|
||||||
HeaderField: "X-WebAuth-User",
|
HeaderField: "X-WebAuth-User",
|
||||||
Basic: &types.Basic{
|
Basic: &types.Basic{
|
||||||
|
@ -767,6 +794,17 @@ func TestBuildConfigurationSegments(t *testing.T) {
|
||||||
withSegmentLabel(label.TraefikProtocol, "https", "containous"),
|
withSegmentLabel(label.TraefikProtocol, "https", "containous"),
|
||||||
withSegmentLabel(label.TraefikWeight, "12", "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.TraefikFrontendAuthBasic, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "containous"),
|
||||||
withSegmentLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true", "containous"),
|
withSegmentLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true", "containous"),
|
||||||
withSegmentLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "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,
|
PassHostHeader: true,
|
||||||
PassTLSCert: true,
|
PassTLSCert: true,
|
||||||
Priority: 666,
|
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{
|
Auth: &types.Auth{
|
||||||
HeaderField: "X-WebAuth-User",
|
HeaderField: "X-WebAuth-User",
|
||||||
Basic: &types.Basic{
|
Basic: &types.Basic{
|
||||||
|
|
|
@ -48,6 +48,7 @@ func (p *Provider) buildConfiguration(tasks []state.Task) *types.Configuration {
|
||||||
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
||||||
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
||||||
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
|
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
|
||||||
|
"getPassTLSClientCert": label.GetTLSClientCert,
|
||||||
"getFrontendRule": p.getFrontendRule,
|
"getFrontendRule": p.getFrontendRule,
|
||||||
"getRedirect": label.GetRedirect,
|
"getRedirect": label.GetRedirect,
|
||||||
"getErrorPages": label.GetErrorPages,
|
"getErrorPages": label.GetErrorPages,
|
||||||
|
|
|
@ -330,6 +330,17 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
withLabel(label.TraefikBackendBufferingMemRequestBodyBytes, "2097152"),
|
withLabel(label.TraefikBackendBufferingMemRequestBodyBytes, "2097152"),
|
||||||
withLabel(label.TraefikBackendBufferingRetryExpression, "IsNetworkError() && Attempts() <= 2"),
|
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.TraefikFrontendAuthBasic, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||||
withLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true"),
|
withLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true"),
|
||||||
withLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
withLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||||
|
@ -418,6 +429,22 @@ func TestBuildConfiguration(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
PassTLSCert: true,
|
PassTLSCert: true,
|
||||||
Priority: 666,
|
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{
|
Auth: &types.Auth{
|
||||||
HeaderField: "X-WebAuth-User",
|
HeaderField: "X-WebAuth-User",
|
||||||
Basic: &types.Basic{
|
Basic: &types.Basic{
|
||||||
|
@ -687,6 +714,17 @@ func TestBuildConfigurationSegments(t *testing.T) {
|
||||||
withSegmentLabel(label.TraefikProtocol, "https", "containous"),
|
withSegmentLabel(label.TraefikProtocol, "https", "containous"),
|
||||||
withSegmentLabel(label.TraefikWeight, "12", "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.TraefikFrontendAuthBasic, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "containous"),
|
||||||
withSegmentLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true", "containous"),
|
withSegmentLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true", "containous"),
|
||||||
withSegmentLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "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,
|
PassHostHeader: true,
|
||||||
PassTLSCert: true,
|
PassTLSCert: true,
|
||||||
Priority: 666,
|
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{
|
Auth: &types.Auth{
|
||||||
HeaderField: "X-WebAuth-User",
|
HeaderField: "X-WebAuth-User",
|
||||||
Basic: &types.Basic{
|
Basic: &types.Basic{
|
||||||
|
|
|
@ -128,7 +128,7 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
||||||
func detectMasters(zk string, masters []string) <-chan []string {
|
func detectMasters(zk string, masters []string) <-chan []string {
|
||||||
changed := make(chan []string, 1)
|
changed := make(chan []string, 1)
|
||||||
if zk != "" {
|
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 {
|
if md, err := detector.New(zk); err != nil {
|
||||||
log.Errorf("Failed to create master detector: %v", err)
|
log.Errorf("Failed to create master detector: %v", err)
|
||||||
} else if err := md.Detect(detect.NewMasters(masters, changed)); err != nil {
|
} else if err := md.Detect(detect.NewMasters(masters, changed)); err != nil {
|
||||||
|
|
|
@ -28,19 +28,20 @@ func (p *Provider) buildConfiguration(services []rancherData) *types.Configurati
|
||||||
"getServers": getServers,
|
"getServers": getServers,
|
||||||
|
|
||||||
// Frontend functions
|
// Frontend functions
|
||||||
"getBackendName": getBackendName,
|
"getBackendName": getBackendName,
|
||||||
"getFrontendRule": p.getFrontendRule,
|
"getFrontendRule": p.getFrontendRule,
|
||||||
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
"getPriority": label.GetFuncInt(label.TraefikFrontendPriority, label.DefaultFrontendPriority),
|
||||||
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
"getPassHostHeader": label.GetFuncBool(label.TraefikFrontendPassHostHeader, label.DefaultPassHostHeader),
|
||||||
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
|
"getPassTLSCert": label.GetFuncBool(label.TraefikFrontendPassTLSCert, label.DefaultPassTLSCert),
|
||||||
"getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints),
|
"getPassTLSClientCert": label.GetTLSClientCert,
|
||||||
"getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated
|
"getEntryPoints": label.GetFuncSliceString(label.TraefikFrontendEntryPoints),
|
||||||
"getAuth": label.GetAuth,
|
"getBasicAuth": label.GetFuncSliceString(label.TraefikFrontendAuthBasic), // Deprecated
|
||||||
"getErrorPages": label.GetErrorPages,
|
"getAuth": label.GetAuth,
|
||||||
"getRateLimit": label.GetRateLimit,
|
"getErrorPages": label.GetErrorPages,
|
||||||
"getRedirect": label.GetRedirect,
|
"getRateLimit": label.GetRateLimit,
|
||||||
"getHeaders": label.GetHeaders,
|
"getRedirect": label.GetRedirect,
|
||||||
"getWhiteList": label.GetWhiteList,
|
"getHeaders": label.GetHeaders,
|
||||||
|
"getWhiteList": label.GetWhiteList,
|
||||||
}
|
}
|
||||||
|
|
||||||
// filter services
|
// filter services
|
||||||
|
|
|
@ -58,6 +58,17 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
||||||
label.TraefikBackendBufferingMemRequestBodyBytes: "2097152",
|
label.TraefikBackendBufferingMemRequestBodyBytes: "2097152",
|
||||||
label.TraefikBackendBufferingRetryExpression: "IsNetworkError() && Attempts() <= 2",
|
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.TraefikFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
label.TraefikFrontendAuthBasicRemoveHeader: "true",
|
label.TraefikFrontendAuthBasicRemoveHeader: "true",
|
||||||
label.TraefikFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
label.TraefikFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
|
@ -144,6 +155,22 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
PassTLSCert: true,
|
PassTLSCert: true,
|
||||||
Priority: 666,
|
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{
|
Auth: &types.Auth{
|
||||||
HeaderField: "X-WebAuth-User",
|
HeaderField: "X-WebAuth-User",
|
||||||
Basic: &types.Basic{
|
Basic: &types.Basic{
|
||||||
|
@ -293,6 +320,17 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
||||||
label.Prefix + "sauternes." + label.SuffixProtocol: "https",
|
label.Prefix + "sauternes." + label.SuffixProtocol: "https",
|
||||||
label.Prefix + "sauternes." + label.SuffixWeight: "12",
|
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.SuffixFrontendRule: "Host:traefik.wtf",
|
||||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicRemoveHeader: "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.SuffixFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||||
|
@ -373,6 +411,22 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
||||||
PassHostHeader: true,
|
PassHostHeader: true,
|
||||||
PassTLSCert: true,
|
PassTLSCert: true,
|
||||||
Priority: 666,
|
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{
|
Auth: &types.Auth{
|
||||||
HeaderField: "X-WebAuth-User",
|
HeaderField: "X-WebAuth-User",
|
||||||
Basic: &types.Basic{
|
Basic: &types.Basic{
|
||||||
|
@ -689,7 +743,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
||||||
|
|
||||||
func TestProviderServiceFilter(t *testing.T) {
|
func TestProviderServiceFilter(t *testing.T) {
|
||||||
provider := &Provider{
|
provider := &Provider{
|
||||||
Domain: "rancher.localhost",
|
Domain: "rancher.localhost",
|
||||||
EnableServiceHealthFilter: true,
|
EnableServiceHealthFilter: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ func (p *Provider) metadataProvide(configurationChan chan<- types.ConfigMessage,
|
||||||
operation := func() error {
|
operation := func() error {
|
||||||
client, err := rancher.NewClientAndWait(metadataServiceURL)
|
client, err := rancher.NewClientAndWait(metadataServiceURL)
|
||||||
if err != nil {
|
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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ func (p *Provider) metadataProvide(configurationChan chan<- types.ConfigMessage,
|
||||||
|
|
||||||
stacks, err := client.GetStacks()
|
stacks, err := client.GetStacks()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Failed to query Rancher metadata service: %s", err)
|
log.Errorf("Failed to query Rancher metadata service: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/BurntSushi/ty/fun"
|
|
||||||
"github.com/containous/mux"
|
"github.com/containous/mux"
|
||||||
"github.com/containous/traefik/hostresolver"
|
"github.com/containous/traefik/hostresolver"
|
||||||
"github.com/containous/traefik/log"
|
"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
|
// ParseDomains parses rules expressions and returns domains
|
||||||
func (r *Rules) ParseDomains(expression string) ([]string, error) {
|
func (r *Rules) ParseDomains(expression string) ([]string, error) {
|
||||||
var domains []string
|
var domains []string
|
||||||
|
isHostRule := false
|
||||||
|
|
||||||
err := r.parseRules(expression, func(functionName string, function interface{}, arguments []string) error {
|
err := r.parseRules(expression, func(functionName string, function interface{}, arguments []string) error {
|
||||||
if functionName == "Host" {
|
if functionName == "Host" {
|
||||||
|
isHostRule = true
|
||||||
domains = append(domains, arguments...)
|
domains = append(domains, arguments...)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -299,5 +300,18 @@ func (r *Rules) ParseDomains(expression string) ([]string, error) {
|
||||||
return nil, fmt.Errorf("error parsing domains: %v", err)
|
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
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,24 +64,38 @@ func TestParseDomains(t *testing.T) {
|
||||||
rules := &Rules{}
|
rules := &Rules{}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
expression string
|
description string
|
||||||
domain []string
|
expression string
|
||||||
|
domain []string
|
||||||
|
errorExpected bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
expression: "Host:foo.bar,test.bar",
|
description: "Many host rules",
|
||||||
domain: []string{"foo.bar", "test.bar"},
|
expression: "Host:foo.bar,test.bar",
|
||||||
|
domain: []string{"foo.bar", "test.bar"},
|
||||||
|
errorExpected: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expression: "Path:/test",
|
description: "No host rule",
|
||||||
domain: []string{},
|
expression: "Path:/test",
|
||||||
|
errorExpected: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expression: "Host:foo.bar;Path:/test",
|
description: "Host rule and another rule",
|
||||||
domain: []string{"foo.bar"},
|
expression: "Host:foo.bar;Path:/test",
|
||||||
|
domain: []string{"foo.bar"},
|
||||||
|
errorExpected: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
expression: "Host: Foo.Bar ;Path:/test",
|
description: "Host rule to trim and another rule",
|
||||||
domain: []string{"foo.bar"},
|
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()
|
t.Parallel()
|
||||||
|
|
||||||
domains, err := rules.ParseDomains(test.expression)
|
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)
|
assert.EqualValues(t, test.domain, domains, "%s: Error parsing domains from expression.", test.expression)
|
||||||
})
|
})
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
stdlog "log"
|
stdlog "log"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -244,7 +243,9 @@ func (s *Server) Start() {
|
||||||
s.listenConfigurations(stop)
|
s.listenConfigurations(stop)
|
||||||
})
|
})
|
||||||
s.startProvider()
|
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
|
// 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 {
|
if len(tlsOption.ClientCA.Files) > 0 {
|
||||||
pool := x509.NewCertPool()
|
pool := x509.NewCertPool()
|
||||||
for _, caFile := range tlsOption.ClientCA.Files {
|
for _, caFile := range tlsOption.ClientCA.Files {
|
||||||
data, err := ioutil.ReadFile(caFile)
|
data, err := caFile.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -424,8 +424,10 @@ func (s *Server) throttleProviderConfigReload(throttle time.Duration, publish ch
|
||||||
case <-stop:
|
case <-stop:
|
||||||
return
|
return
|
||||||
case nextConfig := <-ring.Out():
|
case nextConfig := <-ring.Out():
|
||||||
publish <- nextConfig.(types.ConfigMessage)
|
if config, ok := nextConfig.(types.ConfigMessage); ok {
|
||||||
time.Sleep(throttle)
|
publish <- config
|
||||||
|
time.Sleep(throttle)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -515,6 +517,8 @@ func (s *Server) postLoadConfiguration() {
|
||||||
domains, err := rls.ParseDomains(route.Rule)
|
domains, err := rls.ParseDomains(route.Rule)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Error parsing domains: %v", err)
|
log.Errorf("Error parsing domains: %v", err)
|
||||||
|
} else if len(domains) == 0 {
|
||||||
|
log.Debugf("No domain parsed in rule %q", route.Rule)
|
||||||
} else {
|
} else {
|
||||||
s.globalConfiguration.ACME.LoadCertificateForDomains(domains)
|
s.globalConfiguration.ACME.LoadCertificateForDomains(domains)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
@ -280,7 +279,7 @@ func createHTTPTransport(globalConfiguration configuration.GlobalConfiguration)
|
||||||
return transport, nil
|
return transport, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRootCACertPool(rootCAs traefiktls.RootCAs) *x509.CertPool {
|
func createRootCACertPool(rootCAs traefiktls.FilesOrContents) *x509.CertPool {
|
||||||
roots := x509.NewCertPool()
|
roots := x509.NewCertPool()
|
||||||
|
|
||||||
for _, cert := range rootCAs {
|
for _, cert := range rootCAs {
|
||||||
|
@ -308,7 +307,7 @@ func createClientTLSConfig(entryPointName string, tlsOption *traefiktls.TLS) (*t
|
||||||
if len(tlsOption.ClientCA.Files) > 0 {
|
if len(tlsOption.ClientCA.Files) > 0 {
|
||||||
pool := x509.NewCertPool()
|
pool := x509.NewCertPool()
|
||||||
for _, caFile := range tlsOption.ClientCA.Files {
|
for _, caFile := range tlsOption.ClientCA.Files {
|
||||||
data, err := ioutil.ReadFile(caFile)
|
data, err := caFile.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,6 +104,15 @@ func (s *Server) buildMiddlewares(frontendName string, frontend *types.Frontend,
|
||||||
middle = append(middle, handler)
|
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
|
return middle, buildModifyResponse(secureMiddleware, headerMiddleware), postConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,21 +13,25 @@ func (s *Server) configureSignals() {
|
||||||
signal.Notify(s.signals, syscall.SIGUSR1)
|
signal.Notify(s.signals, syscall.SIGUSR1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) listenSignals() {
|
func (s *Server) listenSignals(stop chan bool) {
|
||||||
for {
|
for {
|
||||||
sig := <-s.signals
|
select {
|
||||||
switch sig {
|
case <-stop:
|
||||||
case syscall.SIGUSR1:
|
return
|
||||||
log.Infof("Closing and re-opening log files for rotation: %+v", sig)
|
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 s.accessLoggerMiddleware != nil {
|
||||||
if err := s.accessLoggerMiddleware.Rotate(); err != nil {
|
if err := s.accessLoggerMiddleware.Rotate(); err != nil {
|
||||||
log.Errorf("Error rotating access log: %v", err)
|
log.Errorf("Error rotating access log: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if err := log.RotateFile(); err != nil {
|
if err := log.RotateFile(); err != nil {
|
||||||
log.Errorf("Error rotating traefik log: %v", err)
|
log.Errorf("Error rotating traefik log: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,4 +4,4 @@ package server
|
||||||
|
|
||||||
func (s *Server) configureSignals() {}
|
func (s *Server) configureSignals() {}
|
||||||
|
|
||||||
func (s *Server) listenSignals() {}
|
func (s *Server) listenSignals(stop chan bool) {}
|
||||||
|
|
|
@ -73,8 +73,30 @@
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{if $auth }}
|
||||||
[frontends."frontend-{{ $service.ServiceName }}".auth]
|
[frontends."frontend-{{ $service.ServiceName }}".auth]
|
||||||
headerField = "{{ $auth.HeaderField }}"
|
headerField = "{{ $auth.HeaderField }}"
|
||||||
|
|
|
@ -74,6 +74,29 @@
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{ $auth := getAuth $container.SegmentLabels }}
|
||||||
{{if $auth }}
|
{{if $auth }}
|
||||||
[frontends."frontend-{{ $frontendName }}".auth]
|
[frontends."frontend-{{ $frontendName }}".auth]
|
||||||
|
|
|
@ -75,6 +75,29 @@
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{ $auth := getAuth $instance.SegmentLabels }}
|
||||||
{{if $auth }}
|
{{if $auth }}
|
||||||
[frontends."frontend-{{ $frontendName }}".auth]
|
[frontends."frontend-{{ $frontendName }}".auth]
|
||||||
|
|
|
@ -73,6 +73,29 @@
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{ $auth := getAuth $frontend }}
|
||||||
{{if $auth }}
|
{{if $auth }}
|
||||||
[frontends."{{ $frontendName }}".auth]
|
[frontends."{{ $frontendName }}".auth]
|
||||||
|
|
|
@ -76,7 +76,30 @@
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{if $auth }}
|
||||||
[frontends."{{ $frontendName }}".auth]
|
[frontends."{{ $frontendName }}".auth]
|
||||||
headerField = "{{ $auth.HeaderField }}"
|
headerField = "{{ $auth.HeaderField }}"
|
||||||
|
|
|
@ -76,6 +76,29 @@
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{ $auth := getAuth $app.TraefikLabels }}
|
||||||
{{if $auth }}
|
{{if $auth }}
|
||||||
[frontends."frontend-{{ $frontendName }}".auth]
|
[frontends."frontend-{{ $frontendName }}".auth]
|
||||||
|
|
|
@ -74,6 +74,29 @@
|
||||||
"{{.}}",
|
"{{.}}",
|
||||||
{{end}}]
|
{{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 }}
|
{{ $auth := getAuth $service.SegmentLabels }}
|
||||||
{{if $auth }}
|
{{if $auth }}
|
||||||
[frontends."frontend-{{ $frontendName }}".auth]
|
[frontends."frontend-{{ $frontendName }}".auth]
|
||||||
|
|
34
tls/tls.go
34
tls/tls.go
|
@ -16,7 +16,7 @@ const (
|
||||||
// ClientCA defines traefik CA files for a entryPoint
|
// ClientCA defines traefik CA files for a entryPoint
|
||||||
// and it indicates if they are mandatory or have just to be analyzed if provided
|
// and it indicates if they are mandatory or have just to be analyzed if provided
|
||||||
type ClientCA struct {
|
type ClientCA struct {
|
||||||
Files []string
|
Files FilesOrContents
|
||||||
Optional bool
|
Optional bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ type TLS struct {
|
||||||
SniStrict bool `export:"true"`
|
SniStrict bool `export:"true"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RootCAs hold the CA we want to have in root
|
// FilesOrContents hold the CA we want to have in root
|
||||||
type RootCAs []FileOrContent
|
type FilesOrContents []FileOrContent
|
||||||
|
|
||||||
// Configuration allows mapping a TLS certificate to a list of entrypoints
|
// Configuration allows mapping a TLS certificate to a list of entrypoints
|
||||||
type Configuration struct {
|
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.
|
// 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.
|
// 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)))
|
sliceOfString := make([]string, len([]FileOrContent(*r)))
|
||||||
for key, value := range *r {
|
for key, value := range *r {
|
||||||
sliceOfString[key] = value.String()
|
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 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.
|
// Set's argument is a string to be parsed to set the flag.
|
||||||
// It's a comma-separated list, so we split it.
|
// It's a comma-separated list, so we split it.
|
||||||
func (r *RootCAs) Set(value string) error {
|
func (r *FilesOrContents) Set(value string) error {
|
||||||
rootCAs := strings.Split(value, ",")
|
filesOrContents := strings.Split(value, ",")
|
||||||
if len(rootCAs) == 0 {
|
if len(filesOrContents) == 0 {
|
||||||
return fmt.Errorf("bad RootCAs format: %s", value)
|
return fmt.Errorf("bad FilesOrContents format: %s", value)
|
||||||
}
|
}
|
||||||
for _, rootCA := range rootCAs {
|
for _, fileOrContent := range filesOrContents {
|
||||||
*r = append(*r, FileOrContent(rootCA))
|
*r = append(*r, FileOrContent(fileOrContent))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get return the RootCAs list
|
// Get return the FilesOrContents list
|
||||||
func (r *RootCAs) Get() interface{} {
|
func (r *FilesOrContents) Get() interface{} {
|
||||||
return *r
|
return *r
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetValue sets the RootCAs with val
|
// SetValue sets the FilesOrContents with val
|
||||||
func (r *RootCAs) SetValue(val interface{}) {
|
func (r *FilesOrContents) SetValue(val interface{}) {
|
||||||
*r = val.(RootCAs)
|
*r = val.(FilesOrContents)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type is type of the struct
|
// Type is type of the struct
|
||||||
func (r *RootCAs) Type() string {
|
func (r *FilesOrContents) Type() string {
|
||||||
return "rootcas"
|
return "filesorcontents"
|
||||||
}
|
}
|
||||||
|
|
||||||
// SortTLSPerEntryPoints converts TLS configuration sorted by Certificates into TLS configuration sorted by EntryPoints
|
// SortTLSPerEntryPoints converts TLS configuration sorted by Certificates into TLS configuration sorted by EntryPoints
|
||||||
|
|
|
@ -178,18 +178,19 @@ func (h *Headers) HasSecureHeadersDefined() bool {
|
||||||
|
|
||||||
// Frontend holds frontend configuration.
|
// Frontend holds frontend configuration.
|
||||||
type Frontend struct {
|
type Frontend struct {
|
||||||
EntryPoints []string `json:"entryPoints,omitempty" hash:"ignore"`
|
EntryPoints []string `json:"entryPoints,omitempty" hash:"ignore"`
|
||||||
Backend string `json:"backend,omitempty"`
|
Backend string `json:"backend,omitempty"`
|
||||||
Routes map[string]Route `json:"routes,omitempty" hash:"ignore"`
|
Routes map[string]Route `json:"routes,omitempty" hash:"ignore"`
|
||||||
PassHostHeader bool `json:"passHostHeader,omitempty"`
|
PassHostHeader bool `json:"passHostHeader,omitempty"`
|
||||||
PassTLSCert bool `json:"passTLSCert,omitempty"`
|
PassTLSCert bool `json:"passTLSCert,omitempty"` // Deprecated use PassTLSClientCert instead
|
||||||
Priority int `json:"priority"`
|
PassTLSClientCert *TLSClientHeaders `json:"passTLSClientCert,omitempty"`
|
||||||
WhiteList *WhiteList `json:"whiteList,omitempty"`
|
Priority int `json:"priority"`
|
||||||
Headers *Headers `json:"headers,omitempty"`
|
WhiteList *WhiteList `json:"whiteList,omitempty"`
|
||||||
Errors map[string]*ErrorPage `json:"errors,omitempty"`
|
Headers *Headers `json:"headers,omitempty"`
|
||||||
RateLimit *RateLimit `json:"ratelimit,omitempty"`
|
Errors map[string]*ErrorPage `json:"errors,omitempty"`
|
||||||
Redirect *Redirect `json:"redirect,omitempty"`
|
RateLimit *RateLimit `json:"ratelimit,omitempty"`
|
||||||
Auth *Auth `json:"auth,omitempty"`
|
Redirect *Redirect `json:"redirect,omitempty"`
|
||||||
|
Auth *Auth `json:"auth,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hash returns the hash value of a Frontend struct.
|
// Hash returns the hash value of a Frontend struct.
|
||||||
|
@ -645,3 +646,27 @@ func (s *IPStrategy) Get() (ip.Strategy, error) {
|
||||||
|
|
||||||
return &ip.RemoteAddrStrategy{}, nil
|
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"`
|
||||||
|
}
|
||||||
|
|
11
vendor/github.com/vulcand/oxy/buffer/buffer.go
generated
vendored
11
vendor/github.com/vulcand/oxy/buffer/buffer.go
generated
vendored
|
@ -383,7 +383,14 @@ func (b *bufferWriter) Header() http.Header {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *bufferWriter) Write(buf []byte) (int, error) {
|
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.
|
// WriteHeader sets rw.Code.
|
||||||
|
@ -410,7 +417,7 @@ func (b *bufferWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
|
||||||
return conn, rw, err
|
return conn, rw, err
|
||||||
}
|
}
|
||||||
b.log.Warningf("Upstream ResponseWriter of type %v does not implement http.Hijacker. Returning dummy channel.", reflect.TypeOf(b.responseWriter))
|
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
|
// SizeErrHandler Size error handler
|
||||||
|
|
Loading…
Reference in a new issue