Merge branch 'v1.7' into master
This commit is contained in:
commit
d53fbb9d7f
72 changed files with 965 additions and 293 deletions
|
@ -16,6 +16,7 @@ env:
|
|||
|
||||
script:
|
||||
- echo "Skipping tests... (Tests are executed on SemaphoreCI)"
|
||||
- if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then make docs-verify; fi
|
||||
|
||||
before_deploy:
|
||||
- >
|
||||
|
|
22
CHANGELOG.md
22
CHANGELOG.md
|
@ -1,5 +1,27 @@
|
|||
# Change Log
|
||||
|
||||
## [v1.7.0-rc2](https://github.com/containous/traefik/tree/v1.7.0-rc2) (2018-07-17)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.7.0-rc1...v1.7.0-rc2)
|
||||
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme,provider]** Create init method on provider interface ([#3580](https://github.com/containous/traefik/pull/3580) by [Juliens](https://github.com/Juliens))
|
||||
- **[acme]** Serve TLS-Challenge certificate in first ([#3605](https://github.com/containous/traefik/pull/3605) by [nmengin](https://github.com/nmengin))
|
||||
- **[api,authentication,webui]** Auth section in web UI. ([#3628](https://github.com/containous/traefik/pull/3628) by [ldez](https://github.com/ldez))
|
||||
- **[authentication,middleware,provider]** Don't pass the Authorization header to the backends ([#3606](https://github.com/containous/traefik/pull/3606) by [jbdoumenjou](https://github.com/jbdoumenjou))
|
||||
- **[ecs]** Fix 400 bad request on AWS ECS API ([#3629](https://github.com/containous/traefik/pull/3629) by [mmatur](https://github.com/mmatur))
|
||||
- **[k8s]** Fix rewrite-target Annotation behavior ([#3582](https://github.com/containous/traefik/pull/3582) by [dtomcej](https://github.com/dtomcej))
|
||||
- **[k8s]** Correct App-Root kubernetes behavior ([#3592](https://github.com/containous/traefik/pull/3592) by [dtomcej](https://github.com/dtomcej))
|
||||
- **[k8s]** Add more K8s Unit Tests ([#3583](https://github.com/containous/traefik/pull/3583) by [dtomcej](https://github.com/dtomcej))
|
||||
- **[kv]** KV and authentication ([#3615](https://github.com/containous/traefik/pull/3615) by [ldez](https://github.com/ldez))
|
||||
- **[middleware]** Send 'Retry-After' to comply with RFC6585. ([#3593](https://github.com/containous/traefik/pull/3593) by [ldez](https://github.com/ldez))
|
||||
|
||||
**Documentation:**
|
||||
- **[k8s]** Correct Modifier in Kubernetes Documentation ([#3610](https://github.com/containous/traefik/pull/3610) by [dtomcej](https://github.com/dtomcej))
|
||||
|
||||
**Misc:**
|
||||
- Merge v1.6.5 into v1.7 ([#3595](https://github.com/containous/traefik/pull/3595) by [ldez](https://github.com/ldez))
|
||||
|
||||
## [v1.6.5](https://github.com/containous/traefik/tree/v1.6.5) (2018-07-09)
|
||||
[All Commits](https://github.com/containous/traefik/compare/v1.6.4...v1.6.5)
|
||||
|
||||
|
|
|
@ -160,9 +160,11 @@ Integration tests must be run from the `integration/` directory and require the
|
|||
|
||||
The [documentation site](http://docs.traefik.io/) is built with [mkdocs](http://mkdocs.org/)
|
||||
|
||||
### Method 1: `Docker` and `make`
|
||||
### Building Documentation
|
||||
|
||||
You can test documentation using the `docs` target.
|
||||
#### Method 1: `Docker` and `make`
|
||||
|
||||
You can build the documentation and serve it locally with livereloading, using the `docs` target:
|
||||
|
||||
```bash
|
||||
$ make docs
|
||||
|
@ -177,11 +179,18 @@ docker run --rm -v /home/user/go/github/containous/traefik:/mkdocs -p 8000:8000
|
|||
|
||||
And go to [http://127.0.0.1:8000](http://127.0.0.1:8000).
|
||||
|
||||
### Method 2: `mkdocs`
|
||||
If you only want to build the documentation without serving it locally, you can use the following command:
|
||||
|
||||
```bash
|
||||
$ make docs-build
|
||||
...
|
||||
```
|
||||
|
||||
#### Method 2: `mkdocs`
|
||||
|
||||
First make sure you have python and pip installed
|
||||
|
||||
```shell
|
||||
```bash
|
||||
$ python --version
|
||||
Python 2.7.2
|
||||
$ pip --version
|
||||
|
@ -190,22 +199,42 @@ pip 1.5.2
|
|||
|
||||
Then install mkdocs with pip
|
||||
|
||||
```shell
|
||||
```bash
|
||||
pip install --user -r requirements.txt
|
||||
```
|
||||
|
||||
To test documentation locally run `mkdocs serve` in the root directory, this should start a server locally to preview your changes.
|
||||
To build documentation locally and serve it locally,
|
||||
run `mkdocs serve` in the root directory,
|
||||
this should start a server locally to preview your changes.
|
||||
|
||||
```shell
|
||||
```bash
|
||||
$ mkdocs serve
|
||||
INFO - Building documentation...
|
||||
WARNING - Config value: 'theme'. Warning: The theme 'united' will be removed in an upcoming MkDocs release. See http://www.mkdocs.org/about/release-notes/ for more details
|
||||
INFO - Cleaning site directory
|
||||
[I 160505 22:31:24 server:281] Serving on http://127.0.0.1:8000
|
||||
[I 160505 22:31:24 handlers:59] Start watching changes
|
||||
[I 160505 22:31:24 handlers:61] Start detecting changes
|
||||
```
|
||||
|
||||
### Verify Documentation
|
||||
|
||||
You can verify that the documentation meets some expectations, as checking for dead links, html markup validity.
|
||||
|
||||
```bash
|
||||
$ make docs-verify
|
||||
docker build -t traefik-docs-verify ./script/docs-verify-docker-image ## Build Validator image
|
||||
...
|
||||
docker run --rm -v /home/travis/build/containous/traefik:/app traefik-docs-verify ## Check for dead links and w3c compliance
|
||||
=== Checking HTML content...
|
||||
Running ["HtmlCheck", "ImageCheck", "ScriptCheck", "LinkCheck"] on /app/site/basics/index.html on *.html...
|
||||
```
|
||||
|
||||
If you recently changed the documentation, do not forget to clean it to have it rebuilt:
|
||||
|
||||
```bash
|
||||
$ make docs-clean docs-verify
|
||||
...
|
||||
```
|
||||
|
||||
## How to Write a Good Issue
|
||||
|
||||
|
|
7
Gopkg.lock
generated
7
Gopkg.lock
generated
|
@ -276,10 +276,10 @@
|
|||
version = "v3.1.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "init-provider"
|
||||
name = "github.com/containous/traefik-extra-service-fabric"
|
||||
packages = ["."]
|
||||
revision = "eb4d5cf161b3213bf45be611dc1f56e8b2161e46"
|
||||
revision = "6e90a9eef2ac9d320e55d6e994d169673a8d8b0f"
|
||||
version = "v1.3.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/coreos/bbolt"
|
||||
|
@ -781,7 +781,6 @@
|
|||
revision = "9b66602d496a139e4722bdde32f0f1ac1c12d4a8"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/jjcollinge/servicefabric"
|
||||
packages = ["."]
|
||||
revision = "8eebe170fa1ba25d3dfb928b3f86a7313b13b9fe"
|
||||
|
@ -1756,6 +1755,6 @@
|
|||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "c228c6029e36e15b6c74bdfa587ee0fa39787af0dc0d4047752d80ee2fb690c1"
|
||||
inputs-digest = "2b7ffb1d01d8a14224fcc9964900fb5a39fbf38cfacba45f49b931136e4fee9b"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
|
|
@ -66,7 +66,7 @@
|
|||
|
||||
[[constraint]]
|
||||
name = "github.com/containous/traefik-extra-service-fabric"
|
||||
branch = "init-provider"
|
||||
version = "1.3.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/coreos/go-systemd"
|
||||
|
|
19
Makefile
19
Makefile
|
@ -1,4 +1,4 @@
|
|||
.PHONY: all
|
||||
.PHONY: all docs-verify docs docs-clean docs-build
|
||||
|
||||
TRAEFIK_ENVS := \
|
||||
-e OS_ARCH_ARG \
|
||||
|
@ -22,6 +22,7 @@ REPONAME := $(shell echo $(REPO) | tr '[:upper:]' '[:lower:]')
|
|||
TRAEFIK_IMAGE := $(if $(REPONAME),$(REPONAME),"containous/traefik")
|
||||
INTEGRATION_OPTS := $(if $(MAKE_DOCKER_HOST),-e "DOCKER_HOST=$(MAKE_DOCKER_HOST)", -e "TEST_CONTAINER=1" -v "/var/run/docker.sock:/var/run/docker.sock")
|
||||
TRAEFIK_DOC_IMAGE := traefik-docs
|
||||
TRAEFIK_DOC_VERIFY_IMAGE := $(TRAEFIK_DOC_IMAGE)-verify
|
||||
|
||||
DOCKER_BUILD_ARGS := $(if $(DOCKER_VERSION), "--build-arg=DOCKER_VERSION=$(DOCKER_VERSION)",)
|
||||
DOCKER_RUN_OPTS := $(TRAEFIK_ENVS) $(TRAEFIK_MOUNT) "$(TRAEFIK_DEV_IMAGE)"
|
||||
|
@ -94,11 +95,23 @@ image-dirty: binary ## build a docker traefik image
|
|||
image: clear-static binary ## clean up static directory and build a docker traefik image
|
||||
docker build -t $(TRAEFIK_IMAGE) .
|
||||
|
||||
docs-image:
|
||||
docker build -t $(TRAEFIK_DOC_IMAGE) -f docs.Dockerfile .
|
||||
|
||||
docs: docs-image
|
||||
docker run $(DOCKER_RUN_DOC_OPTS) $(TRAEFIK_DOC_IMAGE) mkdocs serve
|
||||
|
||||
docs-image:
|
||||
docker build -t $(TRAEFIK_DOC_IMAGE) -f docs.Dockerfile .
|
||||
docs-build: site
|
||||
|
||||
docs-verify: site
|
||||
docker build -t $(TRAEFIK_DOC_VERIFY_IMAGE) ./script/docs-verify-docker-image ## Build Validator image
|
||||
docker run --rm -v $(CURDIR):/app $(TRAEFIK_DOC_VERIFY_IMAGE) ## Check for dead links and w3c compliance
|
||||
|
||||
site: docs-image
|
||||
docker run $(DOCKER_RUN_DOC_OPTS) $(TRAEFIK_DOC_IMAGE) mkdocs build
|
||||
|
||||
docs-clean:
|
||||
rm -rf $(CURDIR)/site
|
||||
|
||||
clear-static:
|
||||
rm -rf static
|
||||
|
|
|
@ -234,15 +234,15 @@ func (a *ACME) getCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificat
|
|||
domain := types.CanonicalDomain(clientHello.ServerName)
|
||||
account := a.store.Get().(*Account)
|
||||
|
||||
if providedCertificate := a.getProvidedCertificate(domain); providedCertificate != nil {
|
||||
return providedCertificate, nil
|
||||
}
|
||||
|
||||
if challengeCert, ok := a.challengeTLSProvider.getCertificate(domain); ok {
|
||||
log.Debugf("ACME got challenge %s", domain)
|
||||
return challengeCert, nil
|
||||
}
|
||||
|
||||
if providedCertificate := a.getProvidedCertificate(domain); providedCertificate != nil {
|
||||
return providedCertificate, nil
|
||||
}
|
||||
|
||||
if domainCert, ok := account.DomainsCertificate.getCertificateForDomain(domain); ok {
|
||||
log.Debugf("ACME got domain cert %s", domain)
|
||||
return domainCert.tlsCert, nil
|
||||
|
|
|
@ -232,6 +232,7 @@ var _templatesConsul_catalogTmpl = []byte(`[backends]
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."frontend-{{ $service.ServiceName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader }}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -242,6 +243,7 @@ var _templatesConsul_catalogTmpl = []byte(`[backends]
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."frontend-{{ $service.ServiceName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader }}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
@ -679,6 +681,7 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."frontend-{{ $frontendName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader }}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -689,6 +692,7 @@ var _templatesDockerTmpl = []byte(`{{$backendServers := .Servers}}
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."frontend-{{ $frontendName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader }}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
@ -977,6 +981,7 @@ var _templatesEcsTmpl = []byte(`[backends]
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."frontend-{{ $serviceName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader }}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -987,6 +992,7 @@ var _templatesEcsTmpl = []byte(`[backends]
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."frontend-{{ $serviceName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader }}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
@ -1217,6 +1223,7 @@ var _templatesKubernetesTmpl = []byte(`[backends]
|
|||
|
||||
{{if $frontend.Auth.Basic }}
|
||||
[frontends."{{ $frontendName }}".auth.basic]
|
||||
removeHeader = {{$frontend.Auth.Basic.RemoveHeader}}
|
||||
users = [{{range $frontend.Auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
@ -1224,6 +1231,7 @@ var _templatesKubernetesTmpl = []byte(`[backends]
|
|||
|
||||
{{if $frontend.Auth.Digest }}
|
||||
[frontends."{{ $frontendName }}".auth.digest]
|
||||
removeHeader = {{$frontend.Auth.Digest.RemoveHeader}}
|
||||
users = [{{range $frontend.Auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
@ -1466,6 +1474,7 @@ var _templatesKvTmpl = []byte(`[backends]
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."{{ $frontendName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader }}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -1476,6 +1485,7 @@ var _templatesKvTmpl = []byte(`[backends]
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."{{ $frontendName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader }}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
@ -1806,6 +1816,7 @@ var _templatesMarathonTmpl = []byte(`{{ $apps := .Applications }}
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."{{ $frontendName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader }}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -1816,6 +1827,7 @@ var _templatesMarathonTmpl = []byte(`{{ $apps := .Applications }}
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."{{ $frontendName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader }}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
@ -2090,6 +2102,7 @@ var _templatesMesosTmpl = []byte(`[backends]
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."frontend-{{ $frontendName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader}}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -2100,6 +2113,7 @@ var _templatesMesosTmpl = []byte(`[backends]
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."frontend-{{ $frontendName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader}}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
@ -2427,6 +2441,7 @@ var _templatesRancherTmpl = []byte(`{{ $backendServers := .Backends }}
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."frontend-{{ $frontendName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader }}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -2437,6 +2452,7 @@ var _templatesRancherTmpl = []byte(`{{ $backendServers := .Backends }}
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."frontend-{{ $frontendName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader }}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
|
|
@ -58,19 +58,19 @@ const (
|
|||
// GlobalConfiguration holds global configuration (with providers, etc.).
|
||||
// It's populated from the traefik configuration file passed as an argument to the binary.
|
||||
type GlobalConfiguration struct {
|
||||
LifeCycle *LifeCycle `description:"Timeouts influencing the server life cycle" export:"true"`
|
||||
GraceTimeOut flaeg.Duration `short:"g" description:"(Deprecated) Duration to give active requests a chance to finish before Traefik stops" export:"true"` // Deprecated
|
||||
Debug bool `short:"d" description:"Enable debug mode" export:"true"`
|
||||
CheckNewVersion bool `description:"Periodically check if a new version has been released" export:"true"`
|
||||
SendAnonymousUsage bool `description:"send periodically anonymous usage statistics" export:"true"`
|
||||
AccessLogsFile string `description:"(Deprecated) Access logs file" export:"true"` // Deprecated
|
||||
AccessLog *types.AccessLog `description:"Access log settings" export:"true"`
|
||||
TraefikLogsFile string `description:"(Deprecated) Traefik logs file. Stdout is used when omitted or empty" export:"true"` // Deprecated
|
||||
TraefikLog *types.TraefikLog `description:"Traefik log settings" export:"true"`
|
||||
Tracing *tracing.Tracing `description:"OpenTracing configuration" export:"true"`
|
||||
LogLevel string `short:"l" description:"Log level" export:"true"`
|
||||
EntryPoints EntryPoints `description:"Entrypoints definition using format: --entryPoints='Name:http Address::8000 Redirect.EntryPoint:https' --entryPoints='Name:https Address::4442 TLS:tests/traefik.crt,tests/traefik.key;prod/traefik.crt,prod/traefik.key'" export:"true"`
|
||||
Cluster *types.Cluster `description:"Enable clustering" export:"true"`
|
||||
LifeCycle *LifeCycle `description:"Timeouts influencing the server life cycle" export:"true"`
|
||||
GraceTimeOut flaeg.Duration `short:"g" description:"(Deprecated) Duration to give active requests a chance to finish before Traefik stops" export:"true"` // Deprecated
|
||||
Debug bool `short:"d" description:"Enable debug mode" export:"true"`
|
||||
CheckNewVersion bool `description:"Periodically check if a new version has been released" export:"true"`
|
||||
SendAnonymousUsage bool `description:"send periodically anonymous usage statistics" export:"true"`
|
||||
AccessLogsFile string `description:"(Deprecated) Access logs file" export:"true"` // Deprecated
|
||||
AccessLog *types.AccessLog `description:"Access log settings" export:"true"`
|
||||
TraefikLogsFile string `description:"(Deprecated) Traefik logs file. Stdout is used when omitted or empty" export:"true"` // Deprecated
|
||||
TraefikLog *types.TraefikLog `description:"Traefik log settings" export:"true"`
|
||||
Tracing *tracing.Tracing `description:"OpenTracing configuration" export:"true"`
|
||||
LogLevel string `short:"l" description:"Log level" export:"true"`
|
||||
EntryPoints EntryPoints `description:"Entrypoints definition using format: --entryPoints='Name:http Address::8000 Redirect.EntryPoint:https' --entryPoints='Name:https Address::4442 TLS:tests/traefik.crt,tests/traefik.key;prod/traefik.crt,prod/traefik.key'" export:"true"`
|
||||
Cluster *types.Cluster
|
||||
Constraints types.Constraints `description:"Filter services by constraint, matching with service tags" export:"true"`
|
||||
ACME *acme.ACME `description:"Enable ACME (Let's Encrypt): automatic SSL" export:"true"`
|
||||
DefaultEntryPoints DefaultEntryPoints `description:"Entrypoints to be used by frontends that do not specify any entrypoint" export:"true"`
|
||||
|
|
|
@ -106,14 +106,16 @@ func makeEntryPointAuth(result map[string]string) *types.Auth {
|
|||
var basic *types.Basic
|
||||
if v, ok := result["auth_basic_users"]; ok {
|
||||
basic = &types.Basic{
|
||||
Users: strings.Split(v, ","),
|
||||
Users: strings.Split(v, ","),
|
||||
RemoveHeader: toBool(result, "auth_basic_removeheader"),
|
||||
}
|
||||
}
|
||||
|
||||
var digest *types.Digest
|
||||
if v, ok := result["auth_digest_users"]; ok {
|
||||
digest = &types.Digest{
|
||||
Users: strings.Split(v, ","),
|
||||
Users: strings.Split(v, ","),
|
||||
RemoveHeader: toBool(result, "auth_digest_removeheader"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,9 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
|
|||
"ProxyProtocol.TrustedIPs:192.168.0.1 " +
|
||||
"ForwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24 " +
|
||||
"Auth.Basic.Users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0 " +
|
||||
"Auth.Basic.RemoveHeader:true " +
|
||||
"Auth.Digest.Users:test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e " +
|
||||
"Auth.Digest.RemoveHeader:true " +
|
||||
"Auth.HeaderField:X-WebAuth-User " +
|
||||
"Auth.Forward.Address:https://authserver.com/auth " +
|
||||
"Auth.Forward.AuthResponseHeaders:X-Auth,X-Test,X-Secret " +
|
||||
|
@ -49,7 +51,9 @@ func Test_parseEntryPointsConfiguration(t *testing.T) {
|
|||
expectedResult: map[string]string{
|
||||
"address": ":8000",
|
||||
"auth_basic_users": "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
"auth_basic_removeheader": "true",
|
||||
"auth_digest_users": "test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
|
||||
"auth_digest_removeheader": "true",
|
||||
"auth_forward_address": "https://authserver.com/auth",
|
||||
"auth_forward_authresponseheaders": "X-Auth,X-Test,X-Secret",
|
||||
"auth_forward_tls_ca": "path/to/local.crt",
|
||||
|
@ -190,7 +194,9 @@ func TestEntryPoints_Set(t *testing.T) {
|
|||
"ProxyProtocol.TrustedIPs:192.168.0.1 " +
|
||||
"ForwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24 " +
|
||||
"Auth.Basic.Users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0 " +
|
||||
"Auth.Basic.RemoveHeader:true " +
|
||||
"Auth.Digest.Users:test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e " +
|
||||
"Auth.Digest.RemoveHeader:true " +
|
||||
"Auth.HeaderField:X-WebAuth-User " +
|
||||
"Auth.Forward.Address:https://authserver.com/auth " +
|
||||
"Auth.Forward.AuthResponseHeaders:X-Auth,X-Test,X-Secret " +
|
||||
|
@ -232,12 +238,14 @@ func TestEntryPoints_Set(t *testing.T) {
|
|||
},
|
||||
Auth: &types.Auth{
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: types.Users{
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
},
|
||||
},
|
||||
Digest: &types.Digest{
|
||||
RemoveHeader: true,
|
||||
Users: types.Users{
|
||||
"test:traefik:a2688e031edb4be6a3797f3882655c05",
|
||||
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
FROM alpine
|
||||
FROM alpine:3.7
|
||||
|
||||
ENV PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/.local/bin
|
||||
|
||||
COPY requirements.txt /mkdocs/
|
||||
WORKDIR /mkdocs
|
||||
VOLUME /mkdocs
|
||||
|
||||
RUN apk --update upgrade \
|
||||
&& apk --no-cache --no-progress add py-pip \
|
||||
&& rm -rf /var/cache/apk/* \
|
||||
&& pip install --user -r requirements.txt
|
||||
RUN apk --no-cache --no-progress add py-pip \
|
||||
&& pip install --user -r requirements.txt
|
||||
|
|
|
@ -371,7 +371,7 @@ For example, the rule `Host:test1.traefik.io,test2.traefik.io` will request a ce
|
|||
|
||||
!!! warning
|
||||
`onHostRule` option can not be used to generate wildcard certificates.
|
||||
Refer to [wildcard generation](/configuration/acme/#wildcard-domain) for further information.
|
||||
Refer to [wildcard generation](/configuration/acme/#wildcard-domains) for further information.
|
||||
|
||||
### `storage`
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
# Enable debug mode.
|
||||
# This will install HTTP handlers to expose Go expvars under /debug/vars and
|
||||
# pprof profiling data under /debug/pprof.
|
||||
# pprof profiling data under /debug/pprof/.
|
||||
# Additionally, the log level will be set to DEBUG.
|
||||
#
|
||||
# Optional
|
||||
|
@ -30,7 +30,7 @@
|
|||
debug = true
|
||||
```
|
||||
|
||||
For more customization, see [entry points](/configuration/entrypoints/) documentation and [examples](/user-guide/examples/#ping-health-check).
|
||||
For more customization, see [entry points](/configuration/entrypoints/) documentation and the examples below.
|
||||
|
||||
## Web UI
|
||||
|
||||
|
|
|
@ -118,8 +118,10 @@ Additional settings can be defined using Consul Catalog tags.
|
|||
| `<prefix>.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
|
||||
| `<prefix>.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
|
||||
| `<prefix>.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
|
||||
| `<prefix>.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
|
||||
| `<prefix>.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. |
|
||||
| `<prefix>.frontend.auth.basic.usersfile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `<prefix>.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
|
||||
| `<prefix>.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
|
||||
| `<prefix>.frontend.auth.digest.usersfile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `<prefix>.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. |
|
||||
|
|
|
@ -236,8 +236,10 @@ Labels can be used on containers to override default behavior.
|
|||
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
|
||||
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` [2] (DEPRECATED). |
|
||||
| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
|
||||
| `traefik.frontend.auth.basic.users=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` [2]. |
|
||||
| `traefik.frontend.auth.basic.usersfile=/path/.htpasswd` | Sets the basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
|
||||
| `traefik.frontend.auth.digest.users=EXPR` | Sets the digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
|
||||
| `traefik.frontend.auth.digest.usersfile=/path/.htdigest` | Sets the digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. |
|
||||
|
@ -326,8 +328,10 @@ Segment labels override the default behavior.
|
|||
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
|
||||
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic.usersfile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersfile` |
|
||||
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
|
||||
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
|
||||
| `traefik.<segment_name>.frontend.auth.digest.usersfile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersfile` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com`| Same as `traefik.frontend.auth.forward.address` |
|
||||
|
|
|
@ -163,8 +163,10 @@ Labels can be used on task containers to override default behaviour:
|
|||
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
|
||||
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
|
||||
| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
|
||||
| `traefik.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. |
|
||||
| `traefik.frontend.auth.basic.usersfile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
|
||||
| `traefik.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
|
||||
| `traefik.frontend.auth.digest.usersfile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. |
|
||||
|
@ -175,6 +177,7 @@ Labels can be used on task containers to override default behaviour:
|
|||
| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. |
|
||||
| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. |
|
||||
| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. |
|
||||
| `traefik.frontend.auth.removeHeader=true` | If set to true, removes the Authorization header. |
|
||||
| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
|
||||
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
|
||||
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
|
||||
|
|
|
@ -65,12 +65,14 @@ Træfik can be configured with a file.
|
|||
[frontends.frontend1.auth]
|
||||
headerField = "X-WebAuth-User"
|
||||
[frontends.frontend1.auth.basic]
|
||||
removeHeader = true
|
||||
users = [
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
]
|
||||
usersFile = "/path/to/.htpasswd"
|
||||
[frontends.frontend1.auth.digest]
|
||||
removeHeader = true
|
||||
users = [
|
||||
"test:traefik:a2688e031edb4be6a3797f3882655c05",
|
||||
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
|
||||
|
|
|
@ -155,7 +155,7 @@ The following general annotations are applicable on the Ingress object:
|
|||
| `traefik.ingress.kubernetes.io/redirect-replacement: http://mydomain/$1` | Redirect to another URL for that frontend. Must be set with `traefik.ingress.kubernetes.io/redirect-regex`. |
|
||||
| `traefik.ingress.kubernetes.io/rewrite-target: /users` | Replaces each matched Ingress path with the specified one, and adds the old path to the `X-Replaced-Path` header. |
|
||||
| `traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip` | Override the default frontend rule type. Only path related matchers can be used [(`Path`, `PathPrefix`, `PathStrip`, `PathPrefixStrip`)](/basics/#path-matcher-usage-guidelines). Note: ReplacePath is deprecated in this annotation, use the `traefik.ingress.kubernetes.io/request-modifier` annotation instead. Default: `PathPrefix`. |
|
||||
| `traefik.ingress.kubernetes.io/request-modifier: AddPath: /users` | Add a [request modifier](/basics/#modifiers) to the backend request. |
|
||||
| `traefik.ingress.kubernetes.io/request-modifier: AddPrefix: /users` | Add a [request modifier](/basics/#modifiers) to the backend request. |
|
||||
| `traefik.ingress.kubernetes.io/whitelist-source-range: "1.2.3.0/24, fe80::/16"` | A comma-separated list of IP ranges permitted for access (6). |
|
||||
| `ingress.kubernetes.io/whitelist-x-forwarded-for: "true"` | Use `X-Forwarded-For` header as valid source of IP for the white list. |
|
||||
| `traefik.ingress.kubernetes.io/app-root: "/index.html"` | Redirects all requests for `/` to the defined path. (4) |
|
||||
|
@ -205,8 +205,9 @@ retryexpression: IsNetworkError() && Attempts() <= 2
|
|||
|
||||
<4> `traefik.ingress.kubernetes.io/app-root`:
|
||||
Non-root paths will not be affected by this annotation and handled normally.
|
||||
This annotation may not be combined with the `ReplacePath` rule type or any other annotation leveraging that rule type.
|
||||
Trying to do so leads to an error and the corresponding Ingress object being ignored.
|
||||
This annotation may not be combined with other redirect annotations.
|
||||
Trying to do so will result in the other redirects being ignored.
|
||||
This annotation can be used in combination with `traefik.ingress.kubernetes.io/redirect-permanent` to configure whether the `app-root` redirect is a 301 or a 302.
|
||||
|
||||
<5> `traefik.ingress.kubernetes.io/service-weights`:
|
||||
Service weights enable to split traffic across multiple backing services in a fine-grained manner.
|
||||
|
@ -303,6 +304,7 @@ The source of the authentication is a Secret object that contains the credential
|
|||
|----------------------------------------------------------------------|-------|--------|---------|-------------------------------------------------------------------------------------------------------------|
|
||||
| `ingress.kubernetes.io/auth-type: basic` | x | x | x | Contains the authentication type: `basic`, `digest`, `forward`. |
|
||||
| `ingress.kubernetes.io/auth-secret: mysecret` | x | x | | Name of Secret containing the username and password with access to the paths defined in the Ingress object. |
|
||||
| `ingress.kubernetes.io/auth-remove-header: true` | x | x | | If set to `true` removes the `Authorization` header. |
|
||||
| `ingress.kubernetes.io/auth-header-field: X-WebAuth-User` | x | x | | Pass Authenticated user to application via headers. |
|
||||
| `ingress.kubernetes.io/auth-url: https://example.com` | | | x | [The URL of the authentication server](/configuration/entrypoints/#forward-authentication). |
|
||||
| `ingress.kubernetes.io/auth-trust-headers: false` | | | x | Trust `X-Forwarded-*` headers. |
|
||||
|
|
|
@ -221,10 +221,12 @@ The following labels can be defined on Marathon applications. They adjust the be
|
|||
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
|
||||
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
|
||||
| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
|
||||
| `traefik.frontend.auth.basic.users=EXPR` | Sets basic authentication to this frontend in CSV format: `User:Hash,User:Hash`. |
|
||||
| `traefik.frontend.auth.basic.usersfile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
|
||||
| `traefik.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
|
||||
| `traefik.frontend.auth.digest.usersfile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. |
|
||||
| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. |
|
||||
| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). |
|
||||
|
@ -233,6 +235,7 @@ The following labels can be defined on Marathon applications. They adjust the be
|
|||
| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. |
|
||||
| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. |
|
||||
| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. |
|
||||
| `traefik.frontend.auth.removeHeader=true` | If set to true, removes the Authorization header. |
|
||||
| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
|
||||
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
|
||||
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
|
||||
|
@ -293,33 +296,48 @@ You can define as many segments as ports exposed in an application.
|
|||
|
||||
Segment labels override the default behavior.
|
||||
|
||||
| Label | Description |
|
||||
|---------------------------------------------------------------------------|-------------------------------------------------------------|
|
||||
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
|
||||
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
|
||||
| `traefik.<segment_name>.portIndex=1` | Same as `traefik.portIndex` |
|
||||
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
|
||||
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
|
||||
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
|
||||
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
|
||||
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
|
||||
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
|
||||
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
|
||||
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
|
||||
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
|
||||
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
|
||||
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
|
||||
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
|
||||
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
|
||||
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
|
||||
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
|
||||
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
|
||||
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` |
|
||||
| Label | Description |
|
||||
|---------------------------------------------------------------------------|----------------------------------------------------------------|
|
||||
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
|
||||
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
|
||||
| `traefik.<segment_name>.portIndex=1` | Same as `traefik.portIndex` |
|
||||
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
|
||||
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
|
||||
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` |
|
||||
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
|
||||
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
|
||||
| `traefik.<segment_name>.frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com`| Same as `traefik.frontend.auth.forward.address` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.tls.insecureSkipVerify=true`| Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
|
||||
| `traefik.<segment_name>.frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
|
||||
| `traefik.<segment_name>.frontend.auth.removeHeader=true` | Same as `traefik.frontend.auth.removeHeader` |
|
||||
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
|
||||
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
|
||||
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
|
||||
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
|
||||
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
|
||||
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
|
||||
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
|
||||
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
|
||||
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
|
||||
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
|
||||
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
|
||||
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
|
||||
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
|
||||
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` |
|
||||
|
||||
#### Custom Headers
|
||||
|
||||
|
|
|
@ -135,9 +135,11 @@ The following labels can be defined on Mesos tasks. They adjust the behavior for
|
|||
| `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.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.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
|
||||
| `traefik.frontend.auth.basic.usersFile=/path/.htpasswd` | Sets basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
|
||||
| `traefik.frontend.auth.digest.users=EXPR` | Sets digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
|
||||
| `traefik.frontend.auth.digest.usersfile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `traefik.frontend.auth.digest.usersFile=/path/.htdigest` | Sets digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. |
|
||||
| `traefik.frontend.auth.forward.tls.ca=/path/ca.pem` | Sets the Certificate Authority (CA) for the TLS connection with the authentication server. |
|
||||
| `traefik.frontend.auth.forward.tls.caOptional=true` | Checks the certificates if present but do not force to be signed by a specified Certificate Authority (CA). |
|
||||
|
@ -146,6 +148,7 @@ The following labels can be defined on Mesos tasks. They adjust the behavior for
|
|||
| `traefik.frontend.auth.forward.tls.key=/path/server.key` | Sets the Certificate for the TLS connection with the authentication server. |
|
||||
| `traefik.frontend.auth.forward.trustForwardHeader=true` | Trusts X-Forwarded-* headers. |
|
||||
| `traefik.frontend.auth.headerField=X-WebAuth-User` | Sets the header used to pass the authenticated user to the application. |
|
||||
| `traefik.frontend.auth.removeHeader=true` | If set to true, removes the Authorization header. |
|
||||
| `traefik.frontend.entryPoints=http,https` | Assigns this frontend to entry points `http` and `https`.<br>Overrides `defaultEntryPoints` |
|
||||
| `traefik.frontend.errors.<name>.backend=NAME` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
|
||||
| `traefik.frontend.errors.<name>.query=PATH` | See [custom error pages](/configuration/commons/#custom-error-pages) section. |
|
||||
|
@ -207,34 +210,49 @@ Additionally, if a segment name matches a named port, that port will be used unl
|
|||
|
||||
Segment labels override the default behavior.
|
||||
|
||||
| Label | Description |
|
||||
|---------------------------------------------------------------------------|-------------------------------------------------------------|
|
||||
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
|
||||
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
|
||||
| `traefik.<segment_name>.portIndex=1` | Same as `traefik.portIndex` |
|
||||
| `traefik.<segment_name>.portName=web` | Same as `traefik.portName` |
|
||||
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
|
||||
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
|
||||
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
|
||||
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
|
||||
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
|
||||
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
|
||||
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
|
||||
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
|
||||
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
|
||||
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
|
||||
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
|
||||
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
|
||||
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
|
||||
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
|
||||
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
|
||||
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
|
||||
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` |
|
||||
| Label | Description |
|
||||
|---------------------------------------------------------------------------|----------------------------------------------------------------|
|
||||
| `traefik.<segment_name>.backend=BACKEND` | Same as `traefik.backend` |
|
||||
| `traefik.<segment_name>.domain=DOMAIN` | Same as `traefik.domain` |
|
||||
| `traefik.<segment_name>.portIndex=1` | Same as `traefik.portIndex` |
|
||||
| `traefik.<segment_name>.portName=web` | Same as `traefik.portName` |
|
||||
| `traefik.<segment_name>.port=PORT` | Same as `traefik.port` |
|
||||
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
|
||||
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic.usersFile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersFile` |
|
||||
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
|
||||
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
|
||||
| `traefik.<segment_name>.frontend.auth.digest.usersFile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersFile` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com`| Same as `traefik.frontend.auth.forward.address` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.tls.ca=/path/ca.pem` | Same as `traefik.frontend.auth.forward.tls.ca` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.tls.caOptional=true` | Same as `traefik.frontend.auth.forward.tls.caOptional` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.tls.cert=/path/server.pem` | Same as `traefik.frontend.auth.forward.tls.cert` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.tls.insecureSkipVerify=true`| Same as `traefik.frontend.auth.forward.tls.insecureSkipVerify` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.tls.key=/path/server.key` | Same as `traefik.frontend.auth.forward.tls.key` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.trustForwardHeader=true` | Same as `traefik.frontend.auth.forward.trustForwardHeader` |
|
||||
| `traefik.<segment_name>.frontend.auth.headerField=X-WebAuth-User` | Same as `traefik.frontend.auth.headerField` |
|
||||
| `traefik.<segment_name>.frontend.auth.removeHeader=true` | Same as `traefik.frontend.auth.removeHeader` |
|
||||
| `traefik.<segment_name>.frontend.entryPoints=https` | Same as `traefik.frontend.entryPoints` |
|
||||
| `traefik.<segment_name>.frontend.errors.<name>.backend=NAME` | Same as `traefik.frontend.errors.<name>.backend` |
|
||||
| `traefik.<segment_name>.frontend.errors.<name>.query=PATH` | Same as `traefik.frontend.errors.<name>.query` |
|
||||
| `traefik.<segment_name>.frontend.errors.<name>.status=RANGE` | Same as `traefik.frontend.errors.<name>.status` |
|
||||
| `traefik.<segment_name>.frontend.passHostHeader=true` | Same as `traefik.frontend.passHostHeader` |
|
||||
| `traefik.<segment_name>.frontend.passTLSCert=true` | Same as `traefik.frontend.passTLSCert` |
|
||||
| `traefik.<segment_name>.frontend.priority=10` | Same as `traefik.frontend.priority` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.extractorFunc=EXP` | Same as `traefik.frontend.rateLimit.extractorFunc` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.period=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.period` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.average=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.average` |
|
||||
| `traefik.<segment_name>.frontend.rateLimit.rateSet.<name>.burst=6` | Same as `traefik.frontend.rateLimit.rateSet.<name>.burst` |
|
||||
| `traefik.<segment_name>.frontend.redirect.entryPoint=https` | Same as `traefik.frontend.redirect.entryPoint` |
|
||||
| `traefik.<segment_name>.frontend.redirect.regex=^http://localhost/(.*)` | Same as `traefik.frontend.redirect.regex` |
|
||||
| `traefik.<segment_name>.frontend.redirect.replacement=http://mydomain/$1` | Same as `traefik.frontend.redirect.replacement` |
|
||||
| `traefik.<segment_name>.frontend.redirect.permanent=true` | Same as `traefik.frontend.redirect.permanent` |
|
||||
| `traefik.<segment_name>.frontend.rule=EXP` | Same as `traefik.frontend.rule` |
|
||||
| `traefik.<segment_name>.frontend.whiteList.sourceRange=RANGE` | Same as `traefik.frontend.whiteList.sourceRange` |
|
||||
| `traefik.<segment_name>.frontend.whiteList.useXForwardedFor=true` | Same as `traefik.frontend.whiteList.useXForwardedFor` |
|
||||
|
||||
#### Custom Headers
|
||||
|
||||
|
|
|
@ -142,7 +142,7 @@ Labels can be used on task containers to override default behavior:
|
|||
|------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `traefik.domain` | Sets the default domain for the frontend rules. |
|
||||
| `traefik.enable=false` | Disables this container in Træfik. |
|
||||
| `traefik.port=80` | Registers this port. Useful when the container exposes multiple ports. |
|
||||
| `traefik.port=80` | Registers this port. Useful when the container exposes multiple ports. |
|
||||
| `traefik.protocol=https` | Overrides the default `http` protocol. |
|
||||
| `traefik.weight=10` | Assigns this weight to the container. |
|
||||
| `traefik.backend=foo` | Gives the name `foo` to the generated backend for this container. |
|
||||
|
@ -165,8 +165,10 @@ Labels can be used on task containers to override default behavior:
|
|||
| `traefik.backend.maxconn.amount=10` | Sets a maximum number of connections to the backend.<br>Must be used in conjunction with the below label to take effect. |
|
||||
| `traefik.backend.maxconn.extractorfunc=client.ip` | Sets the function to be used against the request to determine what to limit maximum connections to the backend by.<br>Must be used in conjunction with the above label to take effect. |
|
||||
| `traefik.frontend.auth.basic=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` (DEPRECATED). |
|
||||
| `traefik.frontend.auth.basic.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
|
||||
| `traefik.frontend.auth.basic.users=EXPR` | Sets the basic authentication to this frontend in CSV format: `User:Hash,User:Hash` . |
|
||||
| `traefik.frontend.auth.basic.usersfile=/path/.htpasswd` | Sets the basic authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `traefik.frontend.auth.digest.removeHeader=true` | If set to `true`, removes the `Authorization` header. |
|
||||
| `traefik.frontend.auth.digest.users=EXPR` | Sets the digest authentication to this frontend in CSV format: `User:Realm:Hash,User:Realm:Hash`. |
|
||||
| `traefik.frontend.auth.digest.usersfile=/path/.htdigest` | Sets the digest authentication with an external file; if users and usersFile are provided, both are merged, with external file contents having precedence. |
|
||||
| `traefik.frontend.auth.forward.address=https://example.com`| Sets the URL of the authentication server. |
|
||||
|
@ -244,8 +246,10 @@ Segment labels override the default behavior.
|
|||
| `traefik.<segment_name>.protocol=http` | Same as `traefik.protocol` |
|
||||
| `traefik.<segment_name>.weight=10` | Same as `traefik.weight` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic=EXPR` | Same as `traefik.frontend.auth.basic` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic.removeHeader=true` | Same as `traefik.frontend.auth.basic.removeHeader` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic.users=EXPR` | Same as `traefik.frontend.auth.basic.users` |
|
||||
| `traefik.<segment_name>.frontend.auth.basic.usersfile=/path/.htpasswd` | Same as `traefik.frontend.auth.basic.usersfile` |
|
||||
| `traefik.<segment_name>.frontend.auth.digest.removeHeader=true` | Same as `traefik.frontend.auth.digest.removeHeader` |
|
||||
| `traefik.<segment_name>.frontend.auth.digest.users=EXPR` | Same as `traefik.frontend.auth.digest.users` |
|
||||
| `traefik.<segment_name>.frontend.auth.digest.usersfile=/path/.htdigest` | Same as `traefik.frontend.auth.digest.usersfile` |
|
||||
| `traefik.<segment_name>.frontend.auth.forward.address=https://example.com`| Same as `traefik.frontend.auth.forward.address` |
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
# Enable debug mode.
|
||||
# This will install HTTP handlers to expose Go expvars under /debug/vars and
|
||||
# pprof profiling data under /debug/pprof.
|
||||
# pprof profiling data under /debug/pprof/.
|
||||
# The log level will be set to DEBUG unless `logLevel` is specified.
|
||||
#
|
||||
# Optional
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
### TOML
|
||||
|
||||
```toml
|
||||
defaultEntryPoints = ["http", "https"]
|
||||
|
||||
# ...
|
||||
# ...
|
||||
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
|
@ -40,12 +45,14 @@
|
|||
[entryPoints.http.auth]
|
||||
headerField = "X-WebAuth-User"
|
||||
[entryPoints.http.auth.basic]
|
||||
removeHeader = true
|
||||
users = [
|
||||
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
]
|
||||
usersFile = "/path/to/.htpasswd"
|
||||
[entryPoints.http.auth.digest]
|
||||
removeHeader = true
|
||||
users = [
|
||||
"test:traefik:a2688e031edb4be6a3797f3882655c05",
|
||||
"test2:traefik:518845800f9e2bfb1f1f740ec24f074e",
|
||||
|
@ -127,7 +134,9 @@ ProxyProtocol.TrustedIPs:192.168.0.1
|
|||
ProxyProtocol.Insecure:true
|
||||
ForwardedHeaders.TrustedIPs:10.0.0.3/24,20.0.0.3/24
|
||||
Auth.Basic.Users:test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0
|
||||
Auth.Basic.Removeheader:true
|
||||
Auth.Digest.Users:test:traefik:a2688e031edb4be6a3797f3882655c05,test2:traefik:518845800f9e2bfb1f1f740ec24f074e
|
||||
Auth.Digest.Removeheader:true
|
||||
Auth.HeaderField:X-WebAuth-User
|
||||
Auth.Forward.Address:https://authserver.com/auth
|
||||
Auth.Forward.AuthResponseHeaders:X-Auth,X-Test,X-Secret
|
||||
|
@ -275,18 +284,32 @@ Users can be specified directly in the TOML file, or indirectly by referencing a
|
|||
usersFile = "/path/to/.htpasswd"
|
||||
```
|
||||
|
||||
Optionally, you can pass authenticated user to application via headers
|
||||
Optionally, you can:
|
||||
|
||||
- pass authenticated user to application via headers
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.http.auth]
|
||||
headerField = "X-WebAuth-User" # <--
|
||||
headerField = "X-WebAuth-User" # <-- header for the authenticated user
|
||||
[entryPoints.http.auth.basic]
|
||||
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
|
||||
```
|
||||
|
||||
- remove the Authorization header
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.http.auth]
|
||||
[entryPoints.http.auth.basic]
|
||||
removeHeader = true # <-- remove the Authorization header
|
||||
users = ["test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"]
|
||||
```
|
||||
|
||||
### Digest Authentication
|
||||
|
||||
You can use `htdigest` to generate them.
|
||||
|
@ -304,18 +327,32 @@ Users can be specified directly in the TOML file, or indirectly by referencing a
|
|||
usersFile = "/path/to/.htdigest"
|
||||
```
|
||||
|
||||
Optionally, you can pass authenticated user to application via headers
|
||||
Optionally, you can!
|
||||
|
||||
- pass authenticated user to application via headers.
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.http.auth]
|
||||
headerField = "X-WebAuth-User" # <--
|
||||
headerField = "X-WebAuth-User" # <-- header for the authenticated user
|
||||
[entryPoints.http.auth.digest]
|
||||
users = ["test:traefik:a2688e031edb4be6a3797f3882655c05", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
|
||||
```
|
||||
|
||||
- remove the Authorization header.
|
||||
|
||||
```toml
|
||||
[entryPoints]
|
||||
[entryPoints.http]
|
||||
address = ":80"
|
||||
[entryPoints.http.auth]
|
||||
[entryPoints.http.auth.digest]
|
||||
removeHeader = true # <-- remove the Authorization header
|
||||
users = ["test:traefik:a2688e031edb4be6a3797f3882655c05", "test2:traefik:518845800f9e2bfb1f1f740ec24f074e"]
|
||||
```
|
||||
|
||||
### Forward Authentication
|
||||
|
||||
This configuration will first forward the request to `http://authserver.com/auth`.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
</p>
|
||||
|
||||
[![Build Status SemaphoreCI](https://semaphoreci.com/api/v1/containous/traefik/branches/master/shields_badge.svg)](https://semaphoreci.com/containous/traefik)
|
||||
[![Docs](https://img.shields.io/badge/docs-current-brightgreen.svg)](https://docs.traefik.io)
|
||||
[![Docs](https://img.shields.io/badge/docs-current-brightgreen.svg)](/)
|
||||
[![Go Report Card](https://goreportcard.com/badge/github.com/containous/traefik)](https://goreportcard.com/report/github.com/containous/traefik)
|
||||
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/containous/traefik/blob/master/LICENSE.md)
|
||||
[![Join the chat at https://slack.traefik.io](https://img.shields.io/badge/style-register-green.svg?style=social&label=Slack)](https://slack.traefik.io)
|
||||
|
|
|
@ -26,7 +26,7 @@ If this instance fails, another manager will be automatically elected.
|
|||
|
||||
## Træfik cluster and Let's Encrypt
|
||||
|
||||
**In cluster mode, ACME certificates have to be stored in [a KV Store entry](/configuration/acme/#storage-kv-entry).**
|
||||
**In cluster mode, ACME certificates have to be stored in [a KV Store entry](/configuration/acme/#as-a-key-value-store-entry).**
|
||||
|
||||
Thanks to the Træfik cluster mode algorithm (based on [the Raft Consensus Algorithm](https://raft.github.io/)), only one instance will contact Let's encrypt to solve the challenges.
|
||||
|
||||
|
|
|
@ -223,7 +223,7 @@ These variables have to be set on the machine/container that host Træfik.
|
|||
|
||||
These variables are described [in this section](/configuration/acme/#provider).
|
||||
|
||||
More information about wildcard certificates are available [in this section](/configuration/acme/#wildcard-domain).
|
||||
More information about wildcard certificates are available [in this section](/configuration/acme/#wildcard-domains).
|
||||
|
||||
### onHostRule option and provided certificates (with HTTP challenge)
|
||||
|
||||
|
|
|
@ -45,9 +45,7 @@ We don't need specific configuration to use gRPC in Træfik, we just need to use
|
|||
|
||||
This section explains how to use Traefik as reverse proxy for gRPC application with self-signed certificates.
|
||||
|
||||
<p align="center">
|
||||
<img src="/img/grpc.svg" alt="gRPC architecture" title="gRPC architecture" />
|
||||
</p>
|
||||
![gRPC architecture](/img/grpc.svg)
|
||||
|
||||
### gRPC Server certificate
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ whoami4:
|
|||
|
||||
### Upload the configuration in the Key-value store
|
||||
|
||||
We should now fill the store with the Træfik global configuration, as we do with a [TOML file configuration](/toml).
|
||||
We should now fill the store with the Træfik global configuration.
|
||||
To do that, we can send the Key-value pairs via [curl commands](https://www.consul.io/intro/getting-started/kv.html) or via the [Web UI](https://www.consul.io/intro/getting-started/ui.html).
|
||||
|
||||
Fortunately, Træfik allows automation of this process using the `storeconfig` subcommand.
|
||||
|
@ -445,4 +445,4 @@ Then remove the line `storageFile = "acme.json"` from your TOML config file.
|
|||
|
||||
That's it!
|
||||
|
||||
![](https://i.giphy.com/ujUdrdpX7Ok5W.gif)
|
||||
![GIF Magica](https://i.giphy.com/ujUdrdpX7Ok5W.gif)
|
||||
|
|
|
@ -30,7 +30,7 @@ Following is the order by which Traefik tries to identify the port (the first on
|
|||
|
||||
## Applications with multiple ports
|
||||
|
||||
Some Marathon applications may expose multiple ports. Traefik supports creating one so-called _service_ per port using [specific labels](/configuration/backends/marathon#service-level).
|
||||
Some Marathon applications may expose multiple ports. Traefik supports creating one so-called _segment_ per port using [segment labels](/configuration/backends/marathon#applications-with-multiple-ports-segment-labels).
|
||||
|
||||
For instance, assume that a Marathon application exposes a web API on port 80 and an admin interface on port 8080. It would then be possible to make each service available by specifying the following Marathon labels:
|
||||
|
||||
|
|
|
@ -330,4 +330,4 @@ X-Forwarded-Proto: http
|
|||
X-Forwarded-Server: 77fc29c69fe4
|
||||
```
|
||||
|
||||
![](https://i.giphy.com/ujUdrdpX7Ok5W.gif)
|
||||
![GIF Magica](https://i.giphy.com/ujUdrdpX7Ok5W.gif)
|
||||
|
|
|
@ -178,4 +178,4 @@ X-Forwarded-Proto: http
|
|||
X-Forwarded-Server: 8fbc39271b4c
|
||||
```
|
||||
|
||||
![](https://i.giphy.com/ujUdrdpX7Ok5W.gif)
|
||||
![GIF Magica](https://i.giphy.com/ujUdrdpX7Ok5W.gif)
|
||||
|
|
|
@ -122,7 +122,7 @@ func (s *AcmeSuite) TearDownSuite(c *check.C) {
|
|||
|
||||
func (s *AcmeSuite) TestHTTP01DomainsAtStart(c *check.C) {
|
||||
testCase := acmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme-base.toml",
|
||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||
template: templateModel{
|
||||
Acme: acme.Configuration{
|
||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
||||
|
@ -140,7 +140,7 @@ func (s *AcmeSuite) TestHTTP01DomainsAtStart(c *check.C) {
|
|||
|
||||
func (s *AcmeSuite) TestHTTP01DomainsInSANAtStart(c *check.C) {
|
||||
testCase := acmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme-base.toml",
|
||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||
template: templateModel{
|
||||
Acme: acme.Configuration{
|
||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
||||
|
@ -159,7 +159,7 @@ func (s *AcmeSuite) TestHTTP01DomainsInSANAtStart(c *check.C) {
|
|||
|
||||
func (s *AcmeSuite) TestHTTP01OnHostRule(c *check.C) {
|
||||
testCase := acmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme-base.toml",
|
||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||
template: templateModel{
|
||||
Acme: acme.Configuration{
|
||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
||||
|
@ -175,7 +175,7 @@ func (s *AcmeSuite) TestHTTP01OnHostRule(c *check.C) {
|
|||
|
||||
func (s *AcmeSuite) TestHTTP01OnHostRuleECDSA(c *check.C) {
|
||||
testCase := acmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme-base.toml",
|
||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||
template: templateModel{
|
||||
Acme: acme.Configuration{
|
||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
||||
|
@ -192,7 +192,7 @@ func (s *AcmeSuite) TestHTTP01OnHostRuleECDSA(c *check.C) {
|
|||
|
||||
func (s *AcmeSuite) TestHTTP01OnHostRuleInvalidAlgo(c *check.C) {
|
||||
testCase := acmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme-base.toml",
|
||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||
template: templateModel{
|
||||
Acme: acme.Configuration{
|
||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
||||
|
@ -257,7 +257,7 @@ func (s *AcmeSuite) TestHTTP01OnHostRuleDynamicCertificatesWithWildcard(c *check
|
|||
|
||||
func (s *AcmeSuite) TestHTTP01OnDemand(c *check.C) {
|
||||
testCase := acmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme-base.toml",
|
||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||
template: templateModel{
|
||||
Acme: acme.Configuration{
|
||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
||||
|
@ -305,7 +305,7 @@ func (s *AcmeSuite) TestHTTP01OnDemandDynamicCertificatesWithWildcard(c *check.C
|
|||
|
||||
func (s *AcmeSuite) TestTLSALPN01OnHostRule(c *check.C) {
|
||||
testCase := acmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme-base.toml",
|
||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||
template: templateModel{
|
||||
Acme: acme.Configuration{
|
||||
TLSChallenge: &acme.TLSChallenge{},
|
||||
|
@ -321,7 +321,7 @@ func (s *AcmeSuite) TestTLSALPN01OnHostRule(c *check.C) {
|
|||
|
||||
func (s *AcmeSuite) TestTLSALPN01OnDemand(c *check.C) {
|
||||
testCase := acmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme-base.toml",
|
||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||
template: templateModel{
|
||||
Acme: acme.Configuration{
|
||||
TLSChallenge: &acme.TLSChallenge{},
|
||||
|
@ -337,7 +337,7 @@ func (s *AcmeSuite) TestTLSALPN01OnDemand(c *check.C) {
|
|||
|
||||
func (s *AcmeSuite) TestTLSALPN01DomainsAtStart(c *check.C) {
|
||||
testCase := acmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme-base.toml",
|
||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||
template: templateModel{
|
||||
Acme: acme.Configuration{
|
||||
TLSChallenge: &acme.TLSChallenge{},
|
||||
|
@ -355,7 +355,7 @@ func (s *AcmeSuite) TestTLSALPN01DomainsAtStart(c *check.C) {
|
|||
|
||||
func (s *AcmeSuite) TestTLSALPN01DomainsInSANAtStart(c *check.C) {
|
||||
testCase := acmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme-base.toml",
|
||||
traefikConfFilePath: "fixtures/acme/acme_base.toml",
|
||||
template: templateModel{
|
||||
Acme: acme.Configuration{
|
||||
TLSChallenge: &acme.TLSChallenge{},
|
||||
|
@ -372,9 +372,27 @@ func (s *AcmeSuite) TestTLSALPN01DomainsInSANAtStart(c *check.C) {
|
|||
s.retrieveAcmeCertificate(c, testCase)
|
||||
}
|
||||
|
||||
func (s *AcmeSuite) TestTLSALPN01DomainsWithProvidedWildcardDomainAtStart(c *check.C) {
|
||||
testCase := acmeTestCase{
|
||||
traefikConfFilePath: "fixtures/acme/acme_tls.toml",
|
||||
template: templateModel{
|
||||
Acme: acme.Configuration{
|
||||
TLSChallenge: &acme.TLSChallenge{},
|
||||
Domains: types.Domains{types.Domain{
|
||||
Main: "traefik.acme.wtf",
|
||||
}},
|
||||
},
|
||||
},
|
||||
expectedCommonName: "traefik.acme.wtf",
|
||||
expectedAlgorithm: x509.RSA,
|
||||
}
|
||||
|
||||
s.retrieveAcmeCertificate(c, testCase)
|
||||
}
|
||||
|
||||
// Test Let's encrypt down
|
||||
func (s *AcmeSuite) TestNoValidLetsEncryptServer(c *check.C) {
|
||||
file := s.adaptFile(c, "fixtures/acme/acme-base.toml", templateModel{
|
||||
file := s.adaptFile(c, "fixtures/acme/acme_base.toml", templateModel{
|
||||
Acme: acme.Configuration{
|
||||
CAServer: "http://wrongurl:4001/directory",
|
||||
HTTPChallenge: &acme.HTTPChallenge{EntryPoint: "http"},
|
||||
|
|
|
@ -27,6 +27,10 @@ defaultEntryPoints = ["http", "https"]
|
|||
entryPoint = "{{ .Acme.HTTPChallenge.EntryPoint }}"
|
||||
{{end}}
|
||||
|
||||
{{if .Acme.TLSChallenge }}
|
||||
[acme.tlsChallenge]
|
||||
{{end}}
|
||||
|
||||
{{range .Acme.Domains}}
|
||||
[[acme.domains]]
|
||||
main = "{{ .Main }}"
|
||||
|
|
|
@ -26,6 +26,10 @@ type tracingAuthenticator struct {
|
|||
clientSpanKind bool
|
||||
}
|
||||
|
||||
const (
|
||||
authorizationHeader = "Authorization"
|
||||
)
|
||||
|
||||
// NewAuthenticator builds a new Authenticator given a config
|
||||
func NewAuthenticator(authConfig *types.Auth, tracingMiddleware *tracing.Tracing) (*Authenticator, error) {
|
||||
if authConfig == nil {
|
||||
|
@ -86,6 +90,10 @@ func createAuthDigestHandler(digestAuth *goauth.DigestAuth, authConfig *types.Au
|
|||
if authConfig.HeaderField != "" {
|
||||
r.Header[authConfig.HeaderField] = []string{username}
|
||||
}
|
||||
if authConfig.Digest.RemoveHeader {
|
||||
log.Debugf("Remove the Authorization header from the Digest auth")
|
||||
r.Header.Del(authorizationHeader)
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
|
@ -101,6 +109,10 @@ func createAuthBasicHandler(basicAuth *goauth.BasicAuth, authConfig *types.Auth)
|
|||
if authConfig.HeaderField != "" {
|
||||
r.Header[authConfig.HeaderField] = []string{username}
|
||||
}
|
||||
if authConfig.Basic.RemoveHeader {
|
||||
log.Debugf("Remove the Authorization header from the Basic auth")
|
||||
r.Header.Del(authorizationHeader)
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/containous/traefik/testhelpers"
|
||||
"github.com/containous/traefik/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/urfave/negroni"
|
||||
)
|
||||
|
||||
|
@ -51,13 +52,16 @@ func TestAuthUsersFromFile(t *testing.T) {
|
|||
t.Run(test.authType, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
usersFile, err := ioutil.TempFile("", "auth-users")
|
||||
assert.NoError(t, err, "there should be no error")
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(usersFile.Name())
|
||||
|
||||
_, err = usersFile.Write([]byte(test.usersStr))
|
||||
assert.NoError(t, err, "there should be no error")
|
||||
require.NoError(t, err)
|
||||
|
||||
users, err := test.parserFunc(usersFile.Name())
|
||||
assert.NoError(t, err, "there should be no error")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 2, len(users), "they should be equal")
|
||||
|
||||
_, ok := users[test.userKeys[0]]
|
||||
assert.True(t, ok, "user test should be found")
|
||||
_, ok = users[test.userKeys[1]]
|
||||
|
@ -79,7 +83,7 @@ func TestBasicAuthFail(t *testing.T) {
|
|||
Users: []string{"test:test"},
|
||||
},
|
||||
}, &tracing.Tracing{})
|
||||
assert.NoError(t, err, "there should be no error")
|
||||
require.NoError(t, err)
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, "traefik")
|
||||
|
@ -93,7 +97,7 @@ func TestBasicAuthFail(t *testing.T) {
|
|||
req := testhelpers.MustNewRequest(http.MethodGet, ts.URL, nil)
|
||||
req.SetBasicAuth("test", "test")
|
||||
res, err := client.Do(req)
|
||||
assert.NoError(t, err, "there should be no error")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, http.StatusUnauthorized, res.StatusCode, "they should be equal")
|
||||
}
|
||||
|
||||
|
@ -103,7 +107,7 @@ func TestBasicAuthSuccess(t *testing.T) {
|
|||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
|
||||
},
|
||||
}, &tracing.Tracing{})
|
||||
assert.NoError(t, err, "there should be no error")
|
||||
require.NoError(t, err)
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, "traefik")
|
||||
|
@ -117,11 +121,11 @@ func TestBasicAuthSuccess(t *testing.T) {
|
|||
req := testhelpers.MustNewRequest(http.MethodGet, ts.URL, nil)
|
||||
req.SetBasicAuth("test", "test")
|
||||
res, err := client.Do(req)
|
||||
assert.NoError(t, err, "there should be no error")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, http.StatusOK, res.StatusCode, "they should be equal")
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
assert.NoError(t, err, "there should be no error")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "traefik\n", string(body), "they should be equal")
|
||||
}
|
||||
|
||||
|
@ -138,7 +142,7 @@ func TestDigestAuthFail(t *testing.T) {
|
|||
Users: []string{"test:traefik:test"},
|
||||
},
|
||||
}, &tracing.Tracing{})
|
||||
assert.NoError(t, err, "there should be no error")
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, authMiddleware, "this should not be nil")
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -153,7 +157,7 @@ func TestDigestAuthFail(t *testing.T) {
|
|||
req := testhelpers.MustNewRequest(http.MethodGet, ts.URL, nil)
|
||||
req.SetBasicAuth("test", "test")
|
||||
res, err := client.Do(req)
|
||||
assert.NoError(t, err, "there should be no error")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, http.StatusUnauthorized, res.StatusCode, "they should be equal")
|
||||
}
|
||||
|
||||
|
@ -164,7 +168,7 @@ func TestBasicAuthUserHeader(t *testing.T) {
|
|||
},
|
||||
HeaderField: "X-Webauth-User",
|
||||
}, &tracing.Tracing{})
|
||||
assert.NoError(t, err, "there should be no error")
|
||||
require.NoError(t, err)
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Equal(t, "test", r.Header["X-Webauth-User"][0], "auth user should be set")
|
||||
|
@ -179,11 +183,72 @@ func TestBasicAuthUserHeader(t *testing.T) {
|
|||
req := testhelpers.MustNewRequest(http.MethodGet, ts.URL, nil)
|
||||
req.SetBasicAuth("test", "test")
|
||||
res, err := client.Do(req)
|
||||
assert.NoError(t, err, "there should be no error")
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, http.StatusOK, res.StatusCode, "they should be equal")
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
assert.NoError(t, err, "there should be no error")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "traefik\n", string(body), "they should be equal")
|
||||
}
|
||||
|
||||
func TestBasicAuthHeaderRemoved(t *testing.T) {
|
||||
middleware, err := NewAuthenticator(&types.Auth{
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
|
||||
},
|
||||
}, &tracing.Tracing{})
|
||||
require.NoError(t, err)
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.Empty(t, r.Header.Get(authorizationHeader))
|
||||
fmt.Fprintln(w, "traefik")
|
||||
})
|
||||
n := negroni.New(middleware)
|
||||
n.UseHandler(handler)
|
||||
ts := httptest.NewServer(n)
|
||||
defer ts.Close()
|
||||
|
||||
client := &http.Client{}
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, ts.URL, nil)
|
||||
req.SetBasicAuth("test", "test")
|
||||
res, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, http.StatusOK, res.StatusCode, "they should be equal")
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "traefik\n", string(body), "they should be equal")
|
||||
}
|
||||
|
||||
func TestBasicAuthHeaderPresent(t *testing.T) {
|
||||
middleware, err := NewAuthenticator(&types.Auth{
|
||||
Basic: &types.Basic{
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"},
|
||||
},
|
||||
}, &tracing.Tracing{})
|
||||
require.NoError(t, err)
|
||||
|
||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
assert.NotEmpty(t, r.Header.Get(authorizationHeader))
|
||||
fmt.Fprintln(w, "traefik")
|
||||
})
|
||||
n := negroni.New(middleware)
|
||||
n.UseHandler(handler)
|
||||
ts := httptest.NewServer(n)
|
||||
defer ts.Close()
|
||||
|
||||
client := &http.Client{}
|
||||
req := testhelpers.MustNewRequest(http.MethodGet, ts.URL, nil)
|
||||
req.SetBasicAuth("test", "test")
|
||||
res, err := client.Do(req)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, http.StatusOK, res.StatusCode, "they should be equal")
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "traefik\n", string(body), "they should be equal")
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ func (rr *retryResponseWriterWithoutCloseNotify) WriteHeader(code int) {
|
|||
if rr.ShouldRetry() && code == http.StatusServiceUnavailable {
|
||||
// We get a 503 HTTP Status Code when there is no backend server in the pool
|
||||
// to which the request could be sent. Also, note that rr.ShouldRetry()
|
||||
// will never return true in case there was a connetion established to
|
||||
// will never return true in case there was a connection established to
|
||||
// the backend server and so we can be sure that the 503 was produced
|
||||
// inside Traefik already and we don't have to retry in this cases.
|
||||
rr.DisableRetries()
|
||||
|
|
|
@ -188,6 +188,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
ServiceName: "test",
|
||||
Attributes: []string{
|
||||
"random.foo=bar",
|
||||
label.TraefikFrontendAuthDigestRemoveHeader + "=true",
|
||||
label.TraefikFrontendAuthDigestUsers + "=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthDigestUsersFile + "=.htpasswd",
|
||||
},
|
||||
|
@ -224,6 +225,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
Auth: &types.Auth{
|
||||
Digest: &types.Digest{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -348,8 +350,10 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
label.TraefikBackendBufferingRetryExpression + "=IsNetworkError() && Attempts() <= 2",
|
||||
|
||||
label.TraefikFrontendAuthBasic + "=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthBasicRemoveHeader + "=true",
|
||||
label.TraefikFrontendAuthBasicUsers + "=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthBasicUsersFile + "=.htpasswd",
|
||||
label.TraefikFrontendAuthDigestRemoveHeader + "=true",
|
||||
label.TraefikFrontendAuthDigestUsers + "=test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthDigestUsersFile + "=.htpasswd",
|
||||
label.TraefikFrontendAuthForwardAddress + "=auth.server",
|
||||
|
@ -464,6 +468,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
|
|
@ -69,8 +69,9 @@ func TestDockerBuildConfiguration(t *testing.T) {
|
|||
containerJSON(
|
||||
name("test"),
|
||||
labels(map[string]string{
|
||||
label.TraefikFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthBasicUsersFile: ".htpasswd",
|
||||
label.TraefikFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthBasicUsersFile: ".htpasswd",
|
||||
label.TraefikFrontendAuthBasicRemoveHeader: "true",
|
||||
}),
|
||||
ports(nat.PortMap{
|
||||
"80/tcp": {},
|
||||
|
@ -85,6 +86,7 @@ func TestDockerBuildConfiguration(t *testing.T) {
|
|||
EntryPoints: []string{},
|
||||
Auth: &types.Auth{
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -159,8 +161,9 @@ func TestDockerBuildConfiguration(t *testing.T) {
|
|||
containerJSON(
|
||||
name("test"),
|
||||
labels(map[string]string{
|
||||
label.TraefikFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
label.TraefikFrontendAuthDigestRemoveHeader: "true",
|
||||
label.TraefikFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
}),
|
||||
ports(nat.PortMap{
|
||||
"80/tcp": {},
|
||||
|
@ -175,6 +178,7 @@ func TestDockerBuildConfiguration(t *testing.T) {
|
|||
EntryPoints: []string{},
|
||||
Auth: &types.Auth{
|
||||
Digest: &types.Digest{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -385,8 +389,10 @@ func TestDockerBuildConfiguration(t *testing.T) {
|
|||
label.TraefikBackendBufferingRetryExpression: "IsNetworkError() && Attempts() <= 2",
|
||||
|
||||
label.TraefikFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthBasicRemoveHeader: "true",
|
||||
label.TraefikFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthBasicUsersFile: ".htpasswd",
|
||||
label.TraefikFrontendAuthDigestRemoveHeader: "true",
|
||||
label.TraefikFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
label.TraefikFrontendAuthForwardAddress: "auth.server",
|
||||
|
@ -472,6 +478,7 @@ func TestDockerBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
|
|
@ -99,9 +99,10 @@ func TestSwarmBuildConfiguration(t *testing.T) {
|
|||
swarmService(
|
||||
serviceName("test"),
|
||||
serviceLabels(map[string]string{
|
||||
label.TraefikPort: "80",
|
||||
label.TraefikFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthBasicUsersFile: ".htpasswd",
|
||||
label.TraefikPort: "80",
|
||||
label.TraefikFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthBasicUsersFile: ".htpasswd",
|
||||
label.TraefikFrontendAuthBasicRemoveHeader: "true",
|
||||
}),
|
||||
withEndpointSpec(modeVIP),
|
||||
withEndpoint(virtualIP("1", "127.0.0.1/24")),
|
||||
|
@ -114,6 +115,7 @@ func TestSwarmBuildConfiguration(t *testing.T) {
|
|||
EntryPoints: []string{},
|
||||
Auth: &types.Auth{
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -195,9 +197,10 @@ func TestSwarmBuildConfiguration(t *testing.T) {
|
|||
swarmService(
|
||||
serviceName("test"),
|
||||
serviceLabels(map[string]string{
|
||||
label.TraefikPort: "80",
|
||||
label.TraefikFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
label.TraefikPort: "80",
|
||||
label.TraefikFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
label.TraefikFrontendAuthDigestRemoveHeader: "true",
|
||||
}),
|
||||
withEndpointSpec(modeVIP),
|
||||
withEndpoint(virtualIP("1", "127.0.0.1/24")),
|
||||
|
@ -210,6 +213,7 @@ func TestSwarmBuildConfiguration(t *testing.T) {
|
|||
EntryPoints: []string{},
|
||||
Auth: &types.Auth{
|
||||
Digest: &types.Digest{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -329,8 +333,10 @@ func TestSwarmBuildConfiguration(t *testing.T) {
|
|||
label.TraefikBackendBufferingMemRequestBodyBytes: "2097152",
|
||||
label.TraefikBackendBufferingRetryExpression: "IsNetworkError() && Attempts() <= 2",
|
||||
|
||||
label.TraefikFrontendAuthBasicRemoveHeader: "true",
|
||||
label.TraefikFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthBasicUsersFile: ".htpasswd",
|
||||
label.TraefikFrontendAuthDigestRemoveHeader: "true",
|
||||
label.TraefikFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
label.TraefikFrontendAuthForwardAddress: "auth.server",
|
||||
|
@ -414,6 +420,7 @@ func TestSwarmBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
|
|
@ -71,11 +71,12 @@ func TestSegmentBuildConfiguration(t *testing.T) {
|
|||
containerJSON(
|
||||
name("foo"),
|
||||
labels(map[string]string{
|
||||
"traefik.sauternes.port": "2503",
|
||||
"traefik.sauternes.frontend.entryPoints": "http,https",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthHeaderField: "X-WebAuth-User",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsersFile: ".htpasswd",
|
||||
"traefik.sauternes.port": "2503",
|
||||
"traefik.sauternes.frontend.entryPoints": "http,https",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthHeaderField: "X-WebAuth-User",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsersFile: ".htpasswd",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicRemoveHeader: "true",
|
||||
}),
|
||||
ports(nat.PortMap{
|
||||
"80/tcp": {},
|
||||
|
@ -96,6 +97,7 @@ func TestSegmentBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -167,11 +169,12 @@ func TestSegmentBuildConfiguration(t *testing.T) {
|
|||
containerJSON(
|
||||
name("foo"),
|
||||
labels(map[string]string{
|
||||
"traefik.sauternes.port": "2503",
|
||||
"traefik.sauternes.frontend.entryPoints": "http,https",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthHeaderField: "X-WebAuth-User",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
"traefik.sauternes.port": "2503",
|
||||
"traefik.sauternes.frontend.entryPoints": "http,https",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthHeaderField: "X-WebAuth-User",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestRemoveHeader: "true",
|
||||
}),
|
||||
ports(nat.PortMap{
|
||||
"80/tcp": {},
|
||||
|
@ -192,6 +195,7 @@ func TestSegmentBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Digest: &types.Digest{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -282,8 +286,10 @@ func TestSegmentBuildConfiguration(t *testing.T) {
|
|||
label.Prefix + "sauternes." + label.SuffixProtocol: "https",
|
||||
label.Prefix + "sauternes." + label.SuffixWeight: "12",
|
||||
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicRemoveHeader: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsersFile: ".htpasswd",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestRemoveHeader: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardAddress: "auth.server",
|
||||
|
@ -364,6 +370,7 @@ func TestSegmentBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
|
|
@ -114,9 +114,10 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
ID: "1",
|
||||
containerDefinition: &ecs.ContainerDefinition{
|
||||
DockerLabels: map[string]*string{
|
||||
label.TraefikFrontendAuthBasicUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthBasicUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthHeaderField: aws.String("X-WebAuth-User"),
|
||||
label.TraefikFrontendAuthBasicUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthBasicUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthBasicRemoveHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthHeaderField: aws.String("X-WebAuth-User"),
|
||||
}},
|
||||
machine: &machine{
|
||||
state: ec2.InstanceStateNameRunning,
|
||||
|
@ -147,6 +148,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -212,9 +214,10 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
ID: "1",
|
||||
containerDefinition: &ecs.ContainerDefinition{
|
||||
DockerLabels: map[string]*string{
|
||||
label.TraefikFrontendAuthDigestUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthDigestUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthHeaderField: aws.String("X-WebAuth-User"),
|
||||
label.TraefikFrontendAuthDigestRemoveHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthDigestUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthDigestUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthHeaderField: aws.String("X-WebAuth-User"),
|
||||
}},
|
||||
machine: &machine{
|
||||
state: ec2.InstanceStateNameRunning,
|
||||
|
@ -245,6 +248,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Digest: &types.Digest{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -350,8 +354,10 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
label.TraefikBackendBufferingRetryExpression: aws.String("IsNetworkError() && Attempts() <= 2"),
|
||||
|
||||
label.TraefikFrontendAuthBasic: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthBasicRemoveHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthBasicUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthBasicUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthDigestRemoveHeader: aws.String("true"),
|
||||
label.TraefikFrontendAuthDigestUsers: aws.String("test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
label.TraefikFrontendAuthDigestUsersFile: aws.String(".htpasswd"),
|
||||
label.TraefikFrontendAuthForwardAddress: aws.String("auth.server"),
|
||||
|
@ -481,6 +487,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
|
|
@ -228,7 +228,7 @@ func getFuncFirstStringValueV1(labelName string, defaultValue string) func(insta
|
|||
// Deprecated
|
||||
func getFuncFirstBoolValueV1(labelName string, defaultValue bool) func(instances []ecsInstance) bool {
|
||||
return func(instances []ecsInstance) bool {
|
||||
if len(instances) < 0 {
|
||||
if len(instances) == 0 {
|
||||
return defaultValue
|
||||
}
|
||||
return getBoolValueV1(instances[0], labelName, defaultValue)
|
||||
|
|
|
@ -347,43 +347,47 @@ func (p *Provider) lookupEc2Instances(ctx context.Context, client *awsClient, cl
|
|||
}
|
||||
}
|
||||
|
||||
resp, err := client.ecs.DescribeContainerInstancesWithContext(ctx, &ecs.DescribeContainerInstancesInput{
|
||||
ContainerInstances: containerInstancesArns,
|
||||
Cluster: clusterName,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Unable to describe container instances: %s", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, container := range resp.ContainerInstances {
|
||||
instanceIds[aws.StringValue(container.Ec2InstanceId)] = aws.StringValue(container.ContainerInstanceArn)
|
||||
instanceArns = append(instanceArns, container.Ec2InstanceId)
|
||||
}
|
||||
|
||||
if len(instanceArns) > 0 {
|
||||
input := &ec2.DescribeInstancesInput{
|
||||
InstanceIds: instanceArns,
|
||||
}
|
||||
|
||||
err = client.ec2.DescribeInstancesPagesWithContext(ctx, input, func(page *ec2.DescribeInstancesOutput, lastPage bool) bool {
|
||||
if len(page.Reservations) > 0 {
|
||||
for _, r := range page.Reservations {
|
||||
for _, i := range r.Instances {
|
||||
if i.InstanceId != nil {
|
||||
ec2Instances[instanceIds[aws.StringValue(i.InstanceId)]] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return !lastPage
|
||||
for _, arns := range p.chunkIDs(containerInstancesArns) {
|
||||
resp, err := client.ecs.DescribeContainerInstancesWithContext(ctx, &ecs.DescribeContainerInstancesInput{
|
||||
ContainerInstances: arns,
|
||||
Cluster: clusterName,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Unable to describe instances: %s", err)
|
||||
log.Errorf("Unable to describe container instances: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, container := range resp.ContainerInstances {
|
||||
instanceIds[aws.StringValue(container.Ec2InstanceId)] = aws.StringValue(container.ContainerInstanceArn)
|
||||
instanceArns = append(instanceArns, container.Ec2InstanceId)
|
||||
}
|
||||
}
|
||||
|
||||
if len(instanceArns) > 0 {
|
||||
for _, ids := range p.chunkIDs(instanceArns) {
|
||||
input := &ec2.DescribeInstancesInput{
|
||||
InstanceIds: ids,
|
||||
}
|
||||
|
||||
err := client.ec2.DescribeInstancesPagesWithContext(ctx, input, func(page *ec2.DescribeInstancesOutput, lastPage bool) bool {
|
||||
if len(page.Reservations) > 0 {
|
||||
for _, r := range page.Reservations {
|
||||
for _, i := range r.Instances {
|
||||
if i.InstanceId != nil {
|
||||
ec2Instances[instanceIds[aws.StringValue(i.InstanceId)]] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return !lastPage
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Unable to describe instances [%s]: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ec2Instances, nil
|
||||
|
@ -414,3 +418,19 @@ func (p *Provider) loadECSConfig(ctx context.Context, client *awsClient) (*types
|
|||
|
||||
return p.buildConfiguration(instances)
|
||||
}
|
||||
|
||||
// chunkIDs ECS expects no more than 100 parameters be passed to a API call;
|
||||
// thus, pack each string into an array capped at 100 elements
|
||||
func (p *Provider) chunkIDs(ids []*string) [][]*string {
|
||||
var chuncked [][]*string
|
||||
for i := 0; i < len(ids); i += 100 {
|
||||
sliceEnd := -1
|
||||
if i+100 < len(ids) {
|
||||
sliceEnd = i + 100
|
||||
} else {
|
||||
sliceEnd = len(ids)
|
||||
}
|
||||
chuncked = append(chuncked, ids[i:sliceEnd])
|
||||
}
|
||||
return chuncked
|
||||
}
|
||||
|
|
88
provider/ecs/ecs_test.go
Normal file
88
provider/ecs/ecs_test.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
package ecs
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestChunkIDs(t *testing.T) {
|
||||
provider := &Provider{}
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
count int
|
||||
expected []int
|
||||
}{
|
||||
{
|
||||
desc: "0 element",
|
||||
count: 0,
|
||||
expected: []int(nil),
|
||||
},
|
||||
{
|
||||
desc: "1 element",
|
||||
count: 1,
|
||||
expected: []int{1},
|
||||
},
|
||||
{
|
||||
desc: "99 elements, 1 chunk",
|
||||
count: 99,
|
||||
expected: []int{99},
|
||||
},
|
||||
{
|
||||
desc: "100 elements, 1 chunk",
|
||||
count: 100,
|
||||
expected: []int{100},
|
||||
},
|
||||
{
|
||||
desc: "101 elements, 2 chunks",
|
||||
count: 101,
|
||||
expected: []int{100, 1},
|
||||
},
|
||||
{
|
||||
desc: "199 elements, 2 chunks",
|
||||
count: 199,
|
||||
expected: []int{100, 99},
|
||||
},
|
||||
{
|
||||
desc: "200 elements, 2 chunks",
|
||||
count: 200,
|
||||
expected: []int{100, 100},
|
||||
},
|
||||
{
|
||||
desc: "201 elements, 3 chunks",
|
||||
count: 201,
|
||||
expected: []int{100, 100, 1},
|
||||
},
|
||||
{
|
||||
desc: "555 elements, 5 chunks",
|
||||
count: 555,
|
||||
expected: []int{100, 100, 100, 100, 100, 55},
|
||||
},
|
||||
{
|
||||
desc: "1001 elements, 11 chunks",
|
||||
count: 1001,
|
||||
expected: []int{100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 1},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
test := test
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
var IDs []*string
|
||||
for v := 0; v < test.count; v++ {
|
||||
IDs = append(IDs, aws.String("a"))
|
||||
}
|
||||
|
||||
var outCount []int
|
||||
for _, el := range provider.chunkIDs(IDs) {
|
||||
outCount = append(outCount, len(el))
|
||||
}
|
||||
|
||||
assert.Equal(t, test.expected, outCount)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ const (
|
|||
annotationKubernetesAuthSecret = "ingress.kubernetes.io/auth-secret"
|
||||
annotationKubernetesAuthHeaderField = "ingress.kubernetes.io/auth-header-field"
|
||||
annotationKubernetesAuthForwardResponseHeaders = "ingress.kubernetes.io/auth-response-headers"
|
||||
annotationKubernetesAuthRemoveHeader = "ingress.kubernetes.io/auth-remove-header"
|
||||
annotationKubernetesAuthForwardURL = "ingress.kubernetes.io/auth-url"
|
||||
annotationKubernetesAuthForwardTrustHeaders = "ingress.kubernetes.io/auth-trust-headers"
|
||||
annotationKubernetesAuthForwardTLSSecret = "ingress.kubernetes.io/auth-tls-secret"
|
||||
|
|
|
@ -258,7 +258,7 @@ func (p *Provider) loadIngresses(k8sClient Client) (*types.Configuration, error)
|
|||
Routes: make(map[string]types.Route),
|
||||
Priority: priority,
|
||||
WhiteList: getWhiteList(i),
|
||||
Redirect: getFrontendRedirect(i),
|
||||
Redirect: getFrontendRedirect(i, baseName, pa.Path),
|
||||
EntryPoints: entryPoints,
|
||||
Headers: getHeader(i),
|
||||
Errors: getErrorPages(i),
|
||||
|
@ -500,7 +500,7 @@ func (p *Provider) addGlobalBackend(cl Client, i *extensionsv1beta1.Ingress, tem
|
|||
Routes: make(map[string]types.Route),
|
||||
Priority: priority,
|
||||
WhiteList: getWhiteList(i),
|
||||
Redirect: getFrontendRedirect(i),
|
||||
Redirect: getFrontendRedirect(i, defaultFrontendName, "/"),
|
||||
EntryPoints: entryPoints,
|
||||
Headers: getHeader(i),
|
||||
Errors: getErrorPages(i),
|
||||
|
@ -531,25 +531,12 @@ func getRuleForPath(pa extensionsv1beta1.HTTPIngressPath, i *extensionsv1beta1.I
|
|||
|
||||
rules := []string{ruleType + ":" + pa.Path}
|
||||
|
||||
var pathReplaceAnnotation string
|
||||
if ruleType == ruleTypeReplacePath {
|
||||
pathReplaceAnnotation = annotationKubernetesRuleType
|
||||
}
|
||||
|
||||
if rewriteTarget := getStringValue(i.Annotations, annotationKubernetesRewriteTarget, ""); rewriteTarget != "" {
|
||||
if pathReplaceAnnotation != "" {
|
||||
return "", fmt.Errorf("rewrite-target must not be used together with annotation %q", pathReplaceAnnotation)
|
||||
if ruleType == ruleTypeReplacePath {
|
||||
return "", fmt.Errorf("rewrite-target must not be used together with annotation %q", annotationKubernetesRuleType)
|
||||
}
|
||||
rewriteTargetRule := fmt.Sprintf("ReplacePathRegex: ^%s/(.*) %s/$1", pa.Path, strings.TrimRight(rewriteTarget, "/"))
|
||||
rules = append(rules, rewriteTargetRule)
|
||||
pathReplaceAnnotation = annotationKubernetesRewriteTarget
|
||||
}
|
||||
|
||||
if rootPath := getStringValue(i.Annotations, annotationKubernetesAppRoot, ""); rootPath != "" && pa.Path == "/" {
|
||||
if pathReplaceAnnotation != "" {
|
||||
return "", fmt.Errorf("app-root must not be used together with annotation %q", pathReplaceAnnotation)
|
||||
}
|
||||
rules = append(rules, ruleTypeReplacePath+":"+rootPath)
|
||||
}
|
||||
|
||||
if requestModifier := getStringValue(i.Annotations, annotationKubernetesRequestModifier, ""); requestModifier != "" {
|
||||
|
@ -750,7 +737,10 @@ func getBasicAuthConfig(i *extensionsv1beta1.Ingress, k8sClient Client) (*types.
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return &types.Basic{Users: credentials}, nil
|
||||
return &types.Basic{
|
||||
Users: credentials,
|
||||
RemoveHeader: getBoolValue(i.Annotations, annotationKubernetesAuthRemoveHeader, false),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getDigestAuthConfig(i *extensionsv1beta1.Ingress, k8sClient Client) (*types.Digest, error) {
|
||||
|
@ -759,7 +749,9 @@ func getDigestAuthConfig(i *extensionsv1beta1.Ingress, k8sClient Client) (*types
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return &types.Digest{Users: credentials}, nil
|
||||
return &types.Digest{Users: credentials,
|
||||
RemoveHeader: getBoolValue(i.Annotations, annotationKubernetesAuthRemoveHeader, false),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getAuthCredentials(i *extensionsv1beta1.Ingress, k8sClient Client) ([]string, error) {
|
||||
|
@ -859,9 +851,17 @@ func loadAuthTLSSecret(namespace, secretName string, k8sClient Client) (string,
|
|||
return getCertificateBlocks(secret, namespace, secretName)
|
||||
}
|
||||
|
||||
func getFrontendRedirect(i *extensionsv1beta1.Ingress) *types.Redirect {
|
||||
func getFrontendRedirect(i *extensionsv1beta1.Ingress, baseName, path string) *types.Redirect {
|
||||
permanent := getBoolValue(i.Annotations, annotationKubernetesRedirectPermanent, false)
|
||||
|
||||
if appRoot := getStringValue(i.Annotations, annotationKubernetesAppRoot, ""); appRoot != "" && path == "/" {
|
||||
return &types.Redirect{
|
||||
Regex: fmt.Sprintf("%s$", baseName),
|
||||
Replacement: fmt.Sprintf("%s/%s", strings.TrimRight(baseName, "/"), strings.TrimLeft(appRoot, "/")),
|
||||
Permanent: permanent,
|
||||
}
|
||||
}
|
||||
|
||||
redirectEntryPoint := getStringValue(i.Annotations, annotationKubernetesRedirectEntryPoint, "")
|
||||
if len(redirectEntryPoint) > 0 {
|
||||
return &types.Redirect{
|
||||
|
|
|
@ -1470,8 +1470,9 @@ rateset:
|
|||
),
|
||||
frontend("root/",
|
||||
passHostHeader(),
|
||||
redirectRegex("root/$", "root/root"),
|
||||
routes(
|
||||
route("/", "PathPrefix:/;ReplacePath:/root"),
|
||||
route("/", "PathPrefix:/"),
|
||||
route("root", "Host:root"),
|
||||
),
|
||||
),
|
||||
|
@ -2047,6 +2048,7 @@ func TestLoadIngressesBasicAuth(t *testing.T) {
|
|||
iNamespace("testing"),
|
||||
iAnnotation(annotationKubernetesAuthType, "basic"),
|
||||
iAnnotation(annotationKubernetesAuthSecret, "mySecret"),
|
||||
iAnnotation(annotationKubernetesAuthRemoveHeader, "true"),
|
||||
iRules(
|
||||
iRule(
|
||||
iHost("basic"),
|
||||
|
@ -2095,8 +2097,9 @@ func TestLoadIngressesBasicAuth(t *testing.T) {
|
|||
|
||||
actual = provider.loadConfig(*actual)
|
||||
require.NotNil(t, actual)
|
||||
got := actual.Frontends["basic/auth"].Auth.Basic.Users
|
||||
assert.Equal(t, types.Users{"myUser:myEncodedPW"}, got)
|
||||
actualBasicAuth := actual.Frontends["basic/auth"].Auth.Basic
|
||||
assert.Equal(t, types.Users{"myUser:myEncodedPW"}, actualBasicAuth.Users)
|
||||
assert.True(t, actualBasicAuth.RemoveHeader, "Bad RemoveHeader flag")
|
||||
}
|
||||
|
||||
func TestLoadIngressesForwardAuth(t *testing.T) {
|
||||
|
|
|
@ -37,9 +37,11 @@ const (
|
|||
pathFrontendBasicAuth = "/basicauth" // Deprecated
|
||||
pathFrontendAuth = "/auth/"
|
||||
pathFrontendAuthBasic = pathFrontendAuth + "basic/"
|
||||
pathFrontendAuthBasicRemoveHeader = pathFrontendAuthBasic + "removeheader"
|
||||
pathFrontendAuthBasicUsers = pathFrontendAuthBasic + "users"
|
||||
pathFrontendAuthBasicUsersFile = pathFrontendAuthBasic + "usersfile"
|
||||
pathFrontendAuthDigest = pathFrontendAuth + "digest/"
|
||||
pathFrontendAuthDigestRemoveHeader = pathFrontendAuthDigest + "removeheader"
|
||||
pathFrontendAuthDigestUsers = pathFrontendAuthDigest + "users"
|
||||
pathFrontendAuthDigestUsersFile = pathFrontendAuthDigest + "usersfile"
|
||||
pathFrontendAuthForward = pathFrontendAuth + "forward/"
|
||||
|
|
|
@ -377,16 +377,16 @@ func (p *Provider) hasDeprecatedBasicAuth(rootPath string) bool {
|
|||
// GetAuth Create auth from path
|
||||
func (p *Provider) getAuth(rootPath string) *types.Auth {
|
||||
hasDeprecatedBasicAuth := p.hasDeprecatedBasicAuth(rootPath)
|
||||
if len(p.getList(rootPath, pathFrontendAuth)) > 0 || hasDeprecatedBasicAuth {
|
||||
if p.hasPrefix(rootPath, pathFrontendAuth) || hasDeprecatedBasicAuth {
|
||||
auth := &types.Auth{
|
||||
HeaderField: p.get("", rootPath, pathFrontendAuthHeaderField),
|
||||
}
|
||||
|
||||
if len(p.getList(rootPath, pathFrontendAuthBasic)) > 0 || hasDeprecatedBasicAuth {
|
||||
if p.hasPrefix(rootPath, pathFrontendAuthBasic) || hasDeprecatedBasicAuth {
|
||||
auth.Basic = p.getAuthBasic(rootPath)
|
||||
} else if len(p.getList(rootPath, pathFrontendAuthDigest)) > 0 {
|
||||
} else if p.hasPrefix(rootPath, pathFrontendAuthDigest) {
|
||||
auth.Digest = p.getAuthDigest(rootPath)
|
||||
} else if len(p.getList(rootPath, pathFrontendAuthForward)) > 0 {
|
||||
} else if p.hasPrefix(rootPath, pathFrontendAuthForward) {
|
||||
auth.Forward = p.getAuthForward(rootPath)
|
||||
}
|
||||
|
||||
|
@ -398,7 +398,8 @@ func (p *Provider) getAuth(rootPath string) *types.Auth {
|
|||
// getAuthBasic Create Basic Auth from path
|
||||
func (p *Provider) getAuthBasic(rootPath string) *types.Basic {
|
||||
basicAuth := &types.Basic{
|
||||
UsersFile: p.get("", rootPath, pathFrontendAuthBasicUsersFile),
|
||||
UsersFile: p.get("", rootPath, pathFrontendAuthBasicUsersFile),
|
||||
RemoveHeader: p.getBool(false, rootPath, pathFrontendAuthBasicRemoveHeader),
|
||||
}
|
||||
|
||||
// backward compatibility
|
||||
|
@ -415,8 +416,9 @@ func (p *Provider) getAuthBasic(rootPath string) *types.Basic {
|
|||
// getAuthDigest Create Digest Auth from path
|
||||
func (p *Provider) getAuthDigest(rootPath string) *types.Digest {
|
||||
return &types.Digest{
|
||||
Users: p.getList(rootPath, pathFrontendAuthDigestUsers),
|
||||
UsersFile: p.get("", rootPath, pathFrontendAuthDigestUsersFile),
|
||||
Users: p.getList(rootPath, pathFrontendAuthDigestUsers),
|
||||
UsersFile: p.get("", rootPath, pathFrontendAuthDigestUsersFile),
|
||||
RemoveHeader: p.getBool(false, rootPath, pathFrontendAuthDigestRemoveHeader),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -588,6 +590,21 @@ func (p *Provider) has(keyParts ...string) bool {
|
|||
return len(value) > 0
|
||||
}
|
||||
|
||||
func (p *Provider) hasPrefix(keyParts ...string) bool {
|
||||
baseKey := strings.Join(keyParts, "")
|
||||
if !strings.HasSuffix(baseKey, "/") {
|
||||
baseKey += "/"
|
||||
}
|
||||
|
||||
listKeys, err := p.kvClient.List(baseKey, nil)
|
||||
if err != nil {
|
||||
log.Debugf("Cannot list keys under %q: %v", baseKey, err)
|
||||
return false
|
||||
}
|
||||
|
||||
return len(listKeys) > 0
|
||||
}
|
||||
|
||||
func (p *Provider) getInt(defaultValue int, keyParts ...string) int {
|
||||
rawValue := p.get("", keyParts...)
|
||||
|
||||
|
|
|
@ -62,12 +62,47 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
desc: "basic auth",
|
||||
desc: "basic auth Users",
|
||||
kvPairs: filler("traefik",
|
||||
frontend("frontend",
|
||||
withPair(pathFrontendBackend, "backend"),
|
||||
withPair(pathFrontendAuthHeaderField, "X-WebAuth-User"),
|
||||
withPair(pathFrontendAuthBasicRemoveHeader, "true"),
|
||||
withList(pathFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
),
|
||||
backend("backend"),
|
||||
),
|
||||
expected: &types.Configuration{
|
||||
Backends: map[string]*types.Backend{
|
||||
"backend": {
|
||||
LoadBalancer: &types.LoadBalancer{
|
||||
Method: "wrr",
|
||||
},
|
||||
},
|
||||
},
|
||||
Frontends: map[string]*types.Frontend{
|
||||
"frontend": {
|
||||
Backend: "backend",
|
||||
PassHostHeader: true,
|
||||
EntryPoints: []string{},
|
||||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "basic auth UsersFile",
|
||||
kvPairs: filler("traefik",
|
||||
frontend("frontend",
|
||||
withPair(pathFrontendBackend, "backend"),
|
||||
withPair(pathFrontendAuthHeaderField, "X-WebAuth-User"),
|
||||
withPair(pathFrontendAuthBasicUsersFile, ".htpasswd"),
|
||||
),
|
||||
backend("backend"),
|
||||
|
@ -88,8 +123,6 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
},
|
||||
},
|
||||
|
@ -135,6 +168,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
frontend("frontend",
|
||||
withPair(pathFrontendBackend, "backend"),
|
||||
withPair(pathFrontendAuthHeaderField, "X-WebAuth-User"),
|
||||
withPair(pathFrontendAuthDigestRemoveHeader, "true"),
|
||||
withList(pathFrontendAuthDigestUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withPair(pathFrontendAuthDigestUsersFile, ".htpasswd"),
|
||||
),
|
||||
|
@ -156,6 +190,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Digest: &types.Digest{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -248,8 +283,10 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
withPair(pathFrontendWhiteListUseXForwardedFor, "true"),
|
||||
|
||||
withList(pathFrontendBasicAuth, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withPair(pathFrontendAuthBasicRemoveHeader, "true"),
|
||||
withList(pathFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withPair(pathFrontendAuthBasicUsersFile, ".htpasswd"),
|
||||
withPair(pathFrontendAuthDigestRemoveHeader, "true"),
|
||||
withList(pathFrontendAuthDigestUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withPair(pathFrontendAuthDigestUsersFile, ".htpasswd"),
|
||||
withPair(pathFrontendAuthForwardAddress, "auth.server"),
|
||||
|
@ -367,6 +404,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -2126,12 +2164,14 @@ func TestProviderGetAuth(t *testing.T) {
|
|||
rootPath: "traefik/frontends/foo",
|
||||
kvPairs: filler("traefik",
|
||||
frontend("foo",
|
||||
withPair(pathFrontendAuthBasicRemoveHeader, "true"),
|
||||
withList(pathFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/", "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withPair(pathFrontendAuthBasicUsersFile, ".htpasswd"),
|
||||
withPair(pathFrontendAuthHeaderField, "X-WebAuth-User"))),
|
||||
expected: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
|
|
@ -37,9 +37,11 @@ const (
|
|||
SuffixFrontend = "frontend"
|
||||
SuffixFrontendAuth = SuffixFrontend + ".auth"
|
||||
SuffixFrontendAuthBasic = SuffixFrontendAuth + ".basic"
|
||||
SuffixFrontendAuthBasicRemoveHeader = SuffixFrontendAuthBasic + ".removeHeader"
|
||||
SuffixFrontendAuthBasicUsers = SuffixFrontendAuthBasic + ".users"
|
||||
SuffixFrontendAuthBasicUsersFile = SuffixFrontendAuthBasic + ".usersFile"
|
||||
SuffixFrontendAuthDigest = SuffixFrontendAuth + ".digest"
|
||||
SuffixFrontendAuthDigestRemoveHeader = SuffixFrontendAuthDigest + ".removeHeader"
|
||||
SuffixFrontendAuthDigestUsers = SuffixFrontendAuthDigest + ".users"
|
||||
SuffixFrontendAuthDigestUsersFile = SuffixFrontendAuthDigest + ".usersFile"
|
||||
SuffixFrontendAuthForward = SuffixFrontendAuth + ".forward"
|
||||
|
@ -123,9 +125,11 @@ const (
|
|||
TraefikFrontend = Prefix + SuffixFrontend
|
||||
TraefikFrontendAuth = Prefix + SuffixFrontendAuth
|
||||
TraefikFrontendAuthBasic = Prefix + SuffixFrontendAuthBasic
|
||||
TraefikFrontendAuthBasicRemoveHeader = Prefix + SuffixFrontendAuthBasicRemoveHeader
|
||||
TraefikFrontendAuthBasicUsers = Prefix + SuffixFrontendAuthBasicUsers
|
||||
TraefikFrontendAuthBasicUsersFile = Prefix + SuffixFrontendAuthBasicUsersFile
|
||||
TraefikFrontendAuthDigest = Prefix + SuffixFrontendAuthDigest
|
||||
TraefikFrontendAuthDigestRemoveHeader = Prefix + SuffixFrontendAuthDigestRemoveHeader
|
||||
TraefikFrontendAuthDigestUsers = Prefix + SuffixFrontendAuthDigestUsers
|
||||
TraefikFrontendAuthDigestUsersFile = Prefix + SuffixFrontendAuthDigestUsersFile
|
||||
TraefikFrontendAuthForward = Prefix + SuffixFrontendAuthForward
|
||||
|
|
|
@ -84,7 +84,8 @@ func GetAuth(labels map[string]string) *types.Auth {
|
|||
// getAuthBasic Create Basic Auth from labels
|
||||
func getAuthBasic(labels map[string]string) *types.Basic {
|
||||
basicAuth := &types.Basic{
|
||||
UsersFile: GetStringValue(labels, TraefikFrontendAuthBasicUsersFile, ""),
|
||||
UsersFile: GetStringValue(labels, TraefikFrontendAuthBasicUsersFile, ""),
|
||||
RemoveHeader: GetBoolValue(labels, TraefikFrontendAuthBasicRemoveHeader, false),
|
||||
}
|
||||
|
||||
// backward compatibility
|
||||
|
@ -101,8 +102,9 @@ func getAuthBasic(labels map[string]string) *types.Basic {
|
|||
// getAuthDigest Create Digest Auth from labels
|
||||
func getAuthDigest(labels map[string]string) *types.Digest {
|
||||
return &types.Digest{
|
||||
Users: GetSliceStringValue(labels, TraefikFrontendAuthDigestUsers),
|
||||
UsersFile: GetStringValue(labels, TraefikFrontendAuthDigestUsersFile, ""),
|
||||
Users: GetSliceStringValue(labels, TraefikFrontendAuthDigestUsers),
|
||||
UsersFile: GetStringValue(labels, TraefikFrontendAuthDigestUsersFile, ""),
|
||||
RemoveHeader: GetBoolValue(labels, TraefikFrontendAuthDigestRemoveHeader, false),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -735,25 +735,27 @@ func TestGetAuth(t *testing.T) {
|
|||
{
|
||||
desc: "should return a basic auth",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendAuthHeaderField: "myHeaderField",
|
||||
TraefikFrontendAuthBasicUsers: "user:pwd,user2:pwd2",
|
||||
TraefikFrontendAuthBasicUsersFile: "myUsersFile",
|
||||
TraefikFrontendAuthHeaderField: "myHeaderField",
|
||||
TraefikFrontendAuthBasicUsers: "user:pwd,user2:pwd2",
|
||||
TraefikFrontendAuthBasicUsersFile: "myUsersFile",
|
||||
TraefikFrontendAuthBasicRemoveHeader: "true",
|
||||
},
|
||||
expected: &types.Auth{
|
||||
HeaderField: "myHeaderField",
|
||||
Basic: &types.Basic{UsersFile: "myUsersFile", Users: []string{"user:pwd", "user2:pwd2"}},
|
||||
Basic: &types.Basic{UsersFile: "myUsersFile", Users: []string{"user:pwd", "user2:pwd2"}, RemoveHeader: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "should return a digest auth",
|
||||
labels: map[string]string{
|
||||
TraefikFrontendAuthHeaderField: "myHeaderField",
|
||||
TraefikFrontendAuthDigestUsers: "user:pwd,user2:pwd2",
|
||||
TraefikFrontendAuthDigestUsersFile: "myUsersFile",
|
||||
TraefikFrontendAuthDigestRemoveHeader: "true",
|
||||
TraefikFrontendAuthHeaderField: "myHeaderField",
|
||||
TraefikFrontendAuthDigestUsers: "user:pwd,user2:pwd2",
|
||||
TraefikFrontendAuthDigestUsersFile: "myUsersFile",
|
||||
},
|
||||
expected: &types.Auth{
|
||||
HeaderField: "myHeaderField",
|
||||
Digest: &types.Digest{UsersFile: "myUsersFile", Users: []string{"user:pwd", "user2:pwd2"}},
|
||||
Digest: &types.Digest{UsersFile: "myUsersFile", Users: []string{"user:pwd", "user2:pwd2"}, RemoveHeader: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -161,6 +161,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
appID("/app"),
|
||||
appPorts(80),
|
||||
withLabel(label.TraefikFrontendAuthHeaderField, "X-WebAuth-User"),
|
||||
withLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true"),
|
||||
withLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withLabel(label.TraefikFrontendAuthBasicUsersFile, ".htpasswd"),
|
||||
withTasks(localhostTask(taskPorts(80))),
|
||||
|
@ -176,6 +177,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -245,6 +247,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
appID("/app"),
|
||||
appPorts(80),
|
||||
withLabel(label.TraefikFrontendAuthHeaderField, "X-WebAuth-User"),
|
||||
withLabel(label.TraefikFrontendAuthDigestRemoveHeader, "true"),
|
||||
withLabel(label.TraefikFrontendAuthDigestUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withLabel(label.TraefikFrontendAuthDigestUsersFile, ".htpasswd"),
|
||||
withTasks(localhostTask(taskPorts(80))),
|
||||
|
@ -260,6 +263,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Digest: &types.Digest{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -371,8 +375,10 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
withLabel(label.TraefikBackendBufferingRetryExpression, "IsNetworkError() && Attempts() <= 2"),
|
||||
|
||||
withLabel(label.TraefikFrontendAuthBasic, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true"),
|
||||
withLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withLabel(label.TraefikFrontendAuthBasicUsersFile, ".htpasswd"),
|
||||
withLabel(label.TraefikFrontendAuthDigestRemoveHeader, "true"),
|
||||
withLabel(label.TraefikFrontendAuthDigestUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withLabel(label.TraefikFrontendAuthDigestUsersFile, ".htpasswd"),
|
||||
withLabel(label.TraefikFrontendAuthForwardAddress, "auth.server"),
|
||||
|
@ -452,6 +458,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -760,6 +767,21 @@ func TestBuildConfigurationSegments(t *testing.T) {
|
|||
withSegmentLabel(label.TraefikWeight, "12", "containous"),
|
||||
|
||||
withSegmentLabel(label.TraefikFrontendAuthBasic, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthBasicUsersFile, ".htpasswd", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthDigestRemoveHeader, "true", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthDigestUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthDigestUsersFile, ".htpasswd", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthForwardAddress, "auth.server", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthForwardTrustForwardHeader, "true", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthForwardTLSCa, "ca.crt", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthForwardTLSCaOptional, "true", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthForwardTLSCert, "server.crt", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthForwardTLSKey, "server.key", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthForwardTLSInsecureSkipVerify, "true", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthHeaderField, "X-WebAuth-User", "containous"),
|
||||
|
||||
withSegmentLabel(label.TraefikFrontendEntryPoints, "http,https", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendPassHostHeader, "true", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendPassTLSCert, "true", "containous"),
|
||||
|
@ -826,9 +848,12 @@ func TestBuildConfigurationSegments(t *testing.T) {
|
|||
PassTLSCert: true,
|
||||
Priority: 666,
|
||||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
},
|
||||
},
|
||||
WhiteList: &types.WhiteList{
|
||||
|
|
|
@ -121,6 +121,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
withStatus(withHealthy(true), withState("TASK_RUNNING")),
|
||||
withLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withLabel(label.TraefikFrontendAuthBasicUsersFile, ".htpasswd"),
|
||||
withLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true"),
|
||||
withLabel(label.TraefikFrontendAuthHeaderField, "X-WebAuth-User"),
|
||||
),
|
||||
},
|
||||
|
@ -137,6 +138,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -205,6 +207,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
withInfo("name1",
|
||||
withPorts(withPort("TCP", 80, "WEB"))),
|
||||
withStatus(withHealthy(true), withState("TASK_RUNNING")),
|
||||
withLabel(label.TraefikFrontendAuthDigestRemoveHeader, "true"),
|
||||
withLabel(label.TraefikFrontendAuthDigestUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withLabel(label.TraefikFrontendAuthDigestUsersFile, ".htpasswd"),
|
||||
withLabel(label.TraefikFrontendAuthHeaderField, "X-WebAuth-User"),
|
||||
|
@ -223,6 +226,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Digest: &types.Digest{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -327,8 +331,10 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
withLabel(label.TraefikBackendBufferingRetryExpression, "IsNetworkError() && Attempts() <= 2"),
|
||||
|
||||
withLabel(label.TraefikFrontendAuthBasic, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true"),
|
||||
withLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withLabel(label.TraefikFrontendAuthBasicUsersFile, ".htpasswd"),
|
||||
withLabel(label.TraefikFrontendAuthDigestRemoveHeader, "true"),
|
||||
withLabel(label.TraefikFrontendAuthDigestUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"),
|
||||
withLabel(label.TraefikFrontendAuthDigestUsersFile, ".htpasswd"),
|
||||
withLabel(label.TraefikFrontendAuthForwardAddress, "auth.server"),
|
||||
|
@ -414,6 +420,7 @@ func TestBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -678,8 +685,10 @@ func TestBuildConfigurationSegments(t *testing.T) {
|
|||
withSegmentLabel(label.TraefikWeight, "12", "containous"),
|
||||
|
||||
withSegmentLabel(label.TraefikFrontendAuthBasic, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthBasicRemoveHeader, "true", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthBasicUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthBasicUsersFile, ".htpasswd", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthDigestRemoveHeader, "true", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthDigestUsers, "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthDigestUsersFile, ".htpasswd", "containous"),
|
||||
withSegmentLabel(label.TraefikFrontendAuthForwardAddress, "auth.server", "containous"),
|
||||
|
@ -760,6 +769,7 @@ func TestBuildConfigurationSegments(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
|
|
@ -60,8 +60,10 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
label.TraefikBackendBufferingRetryExpression: "IsNetworkError() && Attempts() <= 2",
|
||||
|
||||
label.TraefikFrontendAuthBasic: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthBasicRemoveHeader: "true",
|
||||
label.TraefikFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthBasicUsersFile: ".htpasswd",
|
||||
label.TraefikFrontendAuthDigestRemoveHeader: "true",
|
||||
label.TraefikFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
label.TraefikFrontendAuthForwardAddress: "auth.server",
|
||||
|
@ -145,6 +147,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -289,8 +292,10 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
label.Prefix + "sauternes." + label.SuffixWeight: "12",
|
||||
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendRule: "Host:traefik.wtf",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicRemoveHeader: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthBasicUsersFile: ".htpasswd",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestRemoveHeader: "true",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
label.Prefix + "sauternes." + label.SuffixFrontendAuthForwardAddress: "auth.server",
|
||||
|
@ -370,6 +375,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
Auth: &types.Auth{
|
||||
HeaderField: "X-WebAuth-User",
|
||||
Basic: &types.Basic{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
@ -564,9 +570,10 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
{
|
||||
Name: "test/service",
|
||||
Labels: map[string]string{
|
||||
label.TraefikPort: "80",
|
||||
label.TraefikFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
label.TraefikPort: "80",
|
||||
label.TraefikFrontendAuthDigestUsers: "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/,test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
|
||||
label.TraefikFrontendAuthDigestUsersFile: ".htpasswd",
|
||||
label.TraefikFrontendAuthDigestRemoveHeader: "true",
|
||||
},
|
||||
Health: "healthy",
|
||||
Containers: []string{"127.0.0.1"},
|
||||
|
@ -579,6 +586,7 @@ func TestProviderBuildConfiguration(t *testing.T) {
|
|||
EntryPoints: []string{},
|
||||
Auth: &types.Auth{
|
||||
Digest: &types.Digest{
|
||||
RemoveHeader: true,
|
||||
Users: []string{"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
|
||||
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"},
|
||||
UsersFile: ".htpasswd",
|
||||
|
|
20
script/docs-verify-docker-image/Dockerfile
Normal file
20
script/docs-verify-docker-image/Dockerfile
Normal file
|
@ -0,0 +1,20 @@
|
|||
FROM alpine:3.7
|
||||
|
||||
RUN apk --no-cache --no-progress add \
|
||||
ca-certificates \
|
||||
curl \
|
||||
findutils \
|
||||
ruby-bigdecimal \
|
||||
ruby-ffi \
|
||||
ruby-json \
|
||||
ruby-nokogiri \
|
||||
tini \
|
||||
&& gem install --no-document html-proofer
|
||||
|
||||
COPY ./validate.sh /validate.sh
|
||||
|
||||
WORKDIR /app
|
||||
VOLUME ["/tmp","/app"]
|
||||
|
||||
ENTRYPOINT ["/sbin/tini","-g","sh"]
|
||||
CMD ["/validate.sh"]
|
26
script/docs-verify-docker-image/validate.sh
Normal file
26
script/docs-verify-docker-image/validate.sh
Normal file
|
@ -0,0 +1,26 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
PATH_TO_SITE="/app/site"
|
||||
[ -d "${PATH_TO_SITE}" ]
|
||||
|
||||
NUMBER_OF_CPUS="$(grep -c processor /proc/cpuinfo)"
|
||||
|
||||
|
||||
echo "=== Checking HTML content..."
|
||||
|
||||
# Search for all HTML files except the theme's partials
|
||||
# and pipe this to htmlproofer with parallel threads
|
||||
# (one htmlproofer per vCPU)
|
||||
find "${PATH_TO_SITE}" -type f -not -path "/app/site/theme/*" \
|
||||
-name "*.html" -print0 \
|
||||
| xargs -0 -r -P "${NUMBER_OF_CPUS}" -I '{}' \
|
||||
htmlproofer \
|
||||
--check-html \
|
||||
--alt_ignore="/traefik.logo.png/" \
|
||||
--url-ignore "/localhost:/,/127.0.0.1:/,/fonts.gstatic.com/,/.minikube/,/github.com\/containous\/traefik\/*edit*/,/github.com\/containous\/traefik\/$/" \
|
||||
'{}'
|
||||
## HTML-proofer options at https://github.com/gjtorikian/html-proofer#configuration
|
||||
|
||||
echo "= Documentation checked successfuly."
|
|
@ -274,11 +274,6 @@ func (s *Server) AddListener(listener func(types.Configuration)) {
|
|||
|
||||
// getCertificate allows to customize tlsConfig.GetCertificate behaviour to get the certificates inserted dynamically
|
||||
func (s *serverEntryPoint) getCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
bestCertificate := s.certs.GetBestCertificate(clientHello)
|
||||
if bestCertificate != nil {
|
||||
return bestCertificate, nil
|
||||
}
|
||||
|
||||
domainToCheck := types.CanonicalDomain(clientHello.ServerName)
|
||||
|
||||
if s.tlsALPNGetter != nil {
|
||||
|
@ -292,6 +287,11 @@ func (s *serverEntryPoint) getCertificate(clientHello *tls.ClientHelloInfo) (*tl
|
|||
}
|
||||
}
|
||||
|
||||
bestCertificate := s.certs.GetBestCertificate(clientHello)
|
||||
if bestCertificate != nil {
|
||||
return bestCertificate, nil
|
||||
}
|
||||
|
||||
if s.onDemandListener != nil && len(domainToCheck) > 0 {
|
||||
// Only check for an onDemandCert if there is a domain name
|
||||
return s.onDemandListener(domainToCheck)
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."frontend-{{ $service.ServiceName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader }}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -107,6 +108,7 @@
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."frontend-{{ $service.ServiceName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader }}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."frontend-{{ $frontendName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader }}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -107,6 +108,7 @@
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."frontend-{{ $frontendName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader }}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
|
|
@ -96,6 +96,7 @@
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."frontend-{{ $serviceName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader }}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -106,6 +107,7 @@
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."frontend-{{ $serviceName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader }}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
|
||||
{{if $frontend.Auth.Basic }}
|
||||
[frontends."{{ $frontendName }}".auth.basic]
|
||||
removeHeader = {{$frontend.Auth.Basic.RemoveHeader}}
|
||||
users = [{{range $frontend.Auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
@ -65,6 +66,7 @@
|
|||
|
||||
{{if $frontend.Auth.Digest }}
|
||||
[frontends."{{ $frontendName }}".auth.digest]
|
||||
removeHeader = {{$frontend.Auth.Digest.RemoveHeader}}
|
||||
users = [{{range $frontend.Auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
{{end}}]
|
||||
|
|
|
@ -96,6 +96,7 @@
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."{{ $frontendName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader }}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -106,6 +107,7 @@
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."{{ $frontendName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader }}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
|
|
@ -99,6 +99,7 @@
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."{{ $frontendName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader }}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -109,6 +110,7 @@
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."{{ $frontendName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader }}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
|
|
@ -99,6 +99,7 @@
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."frontend-{{ $frontendName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader}}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -109,6 +110,7 @@
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."frontend-{{ $frontendName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader}}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
|
||||
{{if $auth.Basic }}
|
||||
[frontends."frontend-{{ $frontendName }}".auth.basic]
|
||||
removeHeader = {{ $auth.Basic.RemoveHeader }}
|
||||
{{if $auth.Basic.Users }}
|
||||
users = [{{range $auth.Basic.Users }}
|
||||
"{{.}}",
|
||||
|
@ -107,6 +108,7 @@
|
|||
|
||||
{{if $auth.Digest }}
|
||||
[frontends."frontend-{{ $frontendName }}".auth.digest]
|
||||
removeHeader = {{ $auth.Digest.RemoveHeader }}
|
||||
{{if $auth.Digest.Users }}
|
||||
users = [{{range $auth.Digest.Users }}
|
||||
"{{.}}",
|
||||
|
|
|
@ -390,10 +390,10 @@ type Cluster struct {
|
|||
|
||||
// Auth holds authentication configuration (BASIC, DIGEST, users)
|
||||
type Auth struct {
|
||||
Basic *Basic `export:"true"`
|
||||
Digest *Digest `export:"true"`
|
||||
Forward *Forward `export:"true"`
|
||||
HeaderField string `export:"true"`
|
||||
Basic *Basic `json:"basic,omitempty" export:"true"`
|
||||
Digest *Digest `json:"digest,omitempty" export:"true"`
|
||||
Forward *Forward `json:"forward,omitempty" export:"true"`
|
||||
HeaderField string `json:"headerField,omitempty" export:"true"`
|
||||
}
|
||||
|
||||
// Users authentication users
|
||||
|
@ -401,22 +401,24 @@ type Users []string
|
|||
|
||||
// Basic HTTP basic authentication
|
||||
type Basic struct {
|
||||
Users `mapstructure:","`
|
||||
UsersFile string
|
||||
Users `json:"users,omitempty" mapstructure:","`
|
||||
UsersFile string `json:"usersFile,omitempty"`
|
||||
RemoveHeader bool `json:"removeHeader,omitempty"`
|
||||
}
|
||||
|
||||
// Digest HTTP authentication
|
||||
type Digest struct {
|
||||
Users `mapstructure:","`
|
||||
UsersFile string
|
||||
Users `json:"users,omitempty" mapstructure:","`
|
||||
UsersFile string `json:"usersFile,omitempty"`
|
||||
RemoveHeader bool `json:"removeHeader,omitempty"`
|
||||
}
|
||||
|
||||
// Forward authentication
|
||||
type Forward struct {
|
||||
Address string `description:"Authentication server address"`
|
||||
TLS *ClientTLS `description:"Enable TLS support" export:"true"`
|
||||
TrustForwardHeader bool `description:"Trust X-Forwarded-* headers" export:"true"`
|
||||
AuthResponseHeaders []string `description:"Headers to be forwarded from auth response"`
|
||||
Address string `description:"Authentication server address" json:"address,omitempty"`
|
||||
TLS *ClientTLS `description:"Enable TLS support" json:"tls,omitempty" export:"true"`
|
||||
TrustForwardHeader bool `description:"Trust X-Forwarded-* headers" json:"trustForwardHeader,omitempty" export:"true"`
|
||||
AuthResponseHeaders []string `description:"Headers to be forwarded from auth response" json:"authResponseHeaders,omitempty"`
|
||||
}
|
||||
|
||||
// CanonicalDomain returns a lower case domain with trim space
|
||||
|
@ -501,11 +503,11 @@ func (b *Buckets) SetValue(val interface{}) {
|
|||
// ClientTLS holds TLS specific configurations as client
|
||||
// CA, Cert and Key can be either path or file contents
|
||||
type ClientTLS struct {
|
||||
CA string `description:"TLS CA"`
|
||||
CAOptional bool `description:"TLS CA.Optional"`
|
||||
Cert string `description:"TLS cert"`
|
||||
Key string `description:"TLS key"`
|
||||
InsecureSkipVerify bool `description:"TLS insecure skip verify"`
|
||||
CA string `description:"TLS CA" json:"ca,omitempty"`
|
||||
CAOptional bool `description:"TLS CA.Optional" json:"caOptional,omitempty"`
|
||||
Cert string `description:"TLS cert" json:"cert,omitempty"`
|
||||
Key string `description:"TLS key" json:"key,omitempty"`
|
||||
InsecureSkipVerify bool `description:"TLS insecure skip verify" json:"insecureSkipVerify,omitempty"`
|
||||
}
|
||||
|
||||
// CreateTLSConfig creates a TLS config from ClientTLS structures
|
||||
|
|
30
vendor/github.com/containous/traefik-extra-service-fabric/servicefabric.go
generated
vendored
30
vendor/github.com/containous/traefik-extra-service-fabric/servicefabric.go
generated
vendored
|
@ -39,17 +39,16 @@ type Provider struct {
|
|||
AppInsightsKey string `description:"Application Insights Instrumentation Key"`
|
||||
AppInsightsBatchSize int `description:"Number of trace lines per batch, optional"`
|
||||
AppInsightsInterval flaeg.Duration `description:"The interval for sending data to Application Insights, optional"`
|
||||
sfClient sfClient
|
||||
}
|
||||
|
||||
// Init the provider
|
||||
func (p *Provider) Init(constraints types.Constraints) error {
|
||||
p.BaseProvider.Init(constraints)
|
||||
return nil
|
||||
}
|
||||
err := p.BaseProvider.Init(constraints)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Provide allows the ServiceFabric provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool) error {
|
||||
if p.APIVersion == "" {
|
||||
p.APIVersion = sf.DefaultAPIVersion
|
||||
}
|
||||
|
@ -59,7 +58,7 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
|||
return err
|
||||
}
|
||||
|
||||
sfClient, err := sf.NewClient(http.DefaultClient, p.ClusterManagementURL, p.APIVersion, tlsConfig)
|
||||
p.sfClient, err = sf.NewClient(http.DefaultClient, p.ClusterManagementURL, p.APIVersion, tlsConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -77,11 +76,16 @@ func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *s
|
|||
}
|
||||
createAppInsightsHook(p.AppInsightsClientName, p.AppInsightsKey, p.AppInsightsBatchSize, p.AppInsightsInterval)
|
||||
}
|
||||
|
||||
return p.updateConfig(configurationChan, pool, sfClient, time.Duration(p.RefreshSeconds))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Provider) updateConfig(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, sfClient sfClient, pollInterval time.Duration) error {
|
||||
// Provide allows the ServiceFabric provider to provide configurations to traefik
|
||||
// using the given configuration channel.
|
||||
func (p *Provider) Provide(configurationChan chan<- types.ConfigMessage, pool *safe.Pool) error {
|
||||
return p.updateConfig(configurationChan, pool, time.Duration(p.RefreshSeconds))
|
||||
}
|
||||
|
||||
func (p *Provider) updateConfig(configurationChan chan<- types.ConfigMessage, pool *safe.Pool, pollInterval time.Duration) error {
|
||||
pool.Go(func(stop chan bool) {
|
||||
operation := func() error {
|
||||
ticker := time.NewTicker(pollInterval)
|
||||
|
@ -96,7 +100,7 @@ func (p *Provider) updateConfig(configurationChan chan<- types.ConfigMessage, po
|
|||
log.Info("Checking service fabric config")
|
||||
}
|
||||
|
||||
configuration, err := p.getConfiguration(sfClient)
|
||||
configuration, err := p.getConfiguration()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -120,8 +124,8 @@ func (p *Provider) updateConfig(configurationChan chan<- types.ConfigMessage, po
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *Provider) getConfiguration(sfClient sfClient) (*types.Configuration, error) {
|
||||
services, err := getClusterServices(sfClient)
|
||||
func (p *Provider) getConfiguration() (*types.Configuration, error) {
|
||||
services, err := getClusterServices(p.sfClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -161,12 +161,85 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="p.basicAuth && p.basicAuth.length">
|
||||
<div *ngIf="p.auth">
|
||||
<hr/>
|
||||
<div class="section-line">
|
||||
<h2 class="section-line-header">Basic Authentication</h2>
|
||||
<div class="tags padding-5-10">
|
||||
<span class="tag is-info" *ngFor="let auth of p.basicAuth">{{ auth }}</span>
|
||||
<div *ngIf="p.auth.basic && (p.auth.basic.users || p.auth.basic.usersFile )">
|
||||
<h2 class="section-line-header">Basic Authentication</h2>
|
||||
<table class="table is-fullwidth is-hoverable">
|
||||
<tbody>
|
||||
<tr *ngIf="p.auth.basic.usersFile">
|
||||
<td><span class="has-text-grey-light">Users File</span></td>
|
||||
<td><span class="has-text-grey">{{ p.auth.basic.usersFile }}</span></td>
|
||||
</tr>
|
||||
<tr *ngIf="p.auth.headerField">
|
||||
<td><span class="has-text-grey-light">Header Field</span></td>
|
||||
<td><span class="has-text-grey">{{ p.auth.headerField }}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="has-text-grey-light">Remove Auth Header</span></td>
|
||||
<td><span class="has-text-grey">{{ !!p.auth.basic.removeHeader }}</span></td>
|
||||
</tr>
|
||||
<tr *ngIf="p.auth.basic.users?.length">
|
||||
<td><span class="has-text-grey-light">Users</span></td>
|
||||
<td>
|
||||
<div *ngFor="let user of p.auth.basic.users" class="padding-5-10">
|
||||
<code class="has-text-grey">{{ user }}</code>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div *ngIf="p.auth.digest && (p.auth.digest.users || p.auth.digest.usersFile )">
|
||||
<h2 class="section-line-header">Digest Authentication</h2>
|
||||
<table class="table is-fullwidth is-hoverable">
|
||||
<tbody>
|
||||
<tr *ngIf="p.auth.digest.usersFile">
|
||||
<td><span class="has-text-grey-light">Users File</span></td>
|
||||
<td><span class="has-text-grey">{{ p.auth.digest.usersFile }}</span></td>
|
||||
</tr>
|
||||
<tr *ngIf="p.auth.headerField">
|
||||
<td><span class="has-text-grey-light">Header Field</span></td>
|
||||
<td><span class="has-text-grey">{{ p.auth.headerField }}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="has-text-grey-light">Remove Auth Header</span></td>
|
||||
<td><span class="has-text-grey">{{ !!p.auth.digest.removeHeader }}</span></td>
|
||||
</tr>
|
||||
<tr *ngIf="p.auth.digest.users?.length">
|
||||
<td><span class="has-text-grey-light">Users</span></td>
|
||||
<td>
|
||||
<div *ngFor="let user of p.auth.digest.users" class="padding-5-10">
|
||||
<code class="has-text-grey">{{ user }}</code>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div *ngIf="p.auth.forward && p.auth.forward.address">
|
||||
<h2 class="section-line-header">Forward Authentication</h2>
|
||||
<table class="table is-fullwidth is-hoverable">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><span class="has-text-grey-light">Address</span></td>
|
||||
<td><span class="has-text-grey">{{ p.auth.forward.address }}</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class="has-text-grey-light">Trust Forward Header</span></td>
|
||||
<td><span class="has-text-grey">{{ p.auth.forward.trustForwardHeader }}</span></td>
|
||||
</tr>
|
||||
<tr *ngIf="p.auth.forward.authResponseHeaders?.length">
|
||||
<td><span class="has-text-grey-light">Response Headers</span></td>
|
||||
<td>
|
||||
<div *ngFor="let respHeader of p.auth.forward.authResponseHeaders">
|
||||
<span class="has-text-grey">{{ respHeader }}</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue