New API security

This commit is contained in:
Julien Salleyron 2019-09-06 15:08:04 +02:00 committed by Traefiker Bot
parent 1959e1fd44
commit d044c0f4cc
90 changed files with 538 additions and 132 deletions

View file

@ -85,3 +85,34 @@ metrics:
```bash tab="CLI" ```bash tab="CLI"
--metrics.prometheus.addServicesLabels=true --metrics.prometheus.addServicesLabels=true
``` ```
#### `entryPoint`
_Optional, Default=traefik_
Entry point used to expose metrics.
```toml tab="File (TOML)"
[entryPoints]
[entryPoints.metrics]
address = ":8082"
[metrics]
[metrics.prometheus]
entryPoint = "metrics"
```
```yaml tab="File (YAML)"
entryPoints:
metrics:
address: ":8082"
metrics:
prometheus:
entryPoint: metrics
```
```bash tab="CLI"
--entryPoints.metrics.address=":8082"
--metrics.prometheus..entryPoint="metrics"
```

View file

@ -1,8 +1,5 @@
# API # API
!!! important
In the RC version, you can't configure middlewares (basic authentication or white listing) anymore, but as security is important, this will change before the GA version.
Traefik exposes a number of information through an API handler, such as the configuration of all routers, services, middlewares, etc. Traefik exposes a number of information through an API handler, such as the configuration of all routers, services, middlewares, etc.
As with all features of Traefik, this handler can be enabled with the [static configuration](../getting-started/configuration-overview.md#the-static-configuration). As with all features of Traefik, this handler can be enabled with the [static configuration](../getting-started/configuration-overview.md#the-static-configuration).
@ -22,11 +19,10 @@ would be to apply the following protection mechanisms:
keeping it restricted to internal networks keeping it restricted to internal networks
(as in the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege), applied to networks). (as in the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege), applied to networks).
!!! important
In the beta version, you can't configure middlewares (basic authentication or white listing) anymore, but as security is important, this will change before the RC version.
## Configuration ## Configuration
If you enable the API, a new special `service` named `api@internal` is created and then can be reference in a router.
To enable the API handler: To enable the API handler:
```toml tab="File (TOML)" ```toml tab="File (TOML)"
@ -41,6 +37,83 @@ api: {}
--api=true --api=true
``` ```
And then you will able to reference it like this.
```yaml tab="Docker"
- "traefik.http.routers.api.rule=PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
```
```json tab="Marathon"
"labels": {
"traefik.http.routers.api.rule": "PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
"traefik.http.routers.api.service": "api@internal"
"traefik.http.routers.api.middlewares": "auth"
"traefik.http.middlewares.auth.basicauth.users": "test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
}
```
```yaml tab="Rancher"
# Declaring the user list
labels:
- "traefik.http.routers.api.rule=PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
- "traefik.http.routers.api.service=api@internal"
- "traefik.http.routers.api.middlewares=auth"
- "traefik.http.middlewares.auth.basicauth.users=test:$$apr1$$H6uskkkW$$IgXLP6ewTrSuBkTrqE8wj/,test2:$$apr1$$d9hr9HBB$$4HxwgUir3HP4EsggP/QNo0"
```
```toml tab="File (TOML)"
[http.routers.my-api]
rule="PathPrefix(`/api`) || PathPrefix(`/dashboard`)"
service="api@internal"
middlewares=["auth"]
[http.middlewares.auth.basicAuth]
users = [
"test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/",
"test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0",
]
```
```yaml tab="File (YAML)"
http:
routers:
api:
rule: PathPrefix(`/api`) || PathPrefix(`/dashboard`)
service: api@internal
middlewares:
- auth
middlewares:
auth:
basicAuth:
users:
- "test:$apr1$H6uskkkW$IgXLP6ewTrSuBkTrqE8wj/"
- "test2:$apr1$d9hr9HBB$4HxwgUir3HP4EsggP/QNo0"
```
### `insecure`
Enable the API in `insecure` mode, which means that the API will be available directly on the entryPoint named `traefik`.
!!! Note
If the entryPoint named `traefik` is not configured, it will be automatically created on port 8080.
```toml tab="File (TOML)"
[api]
insecure = true
```
```yaml tab="File (YAML)"
api:
insecure: true
```
```bash tab="CLI"
--api.insecure=true
```
### `dashboard` ### `dashboard`
_Optional, Default=true_ _Optional, Default=true_

View file

@ -5,7 +5,7 @@ Checking the Health of Your Traefik Instances
## Configuration Examples ## Configuration Examples
??? example "Enabling /ping" !!! example "Enabling /ping"
```toml tab="File (TOML)" ```toml tab="File (TOML)"
[ping] [ping]
@ -19,10 +19,39 @@ ping: {}
--ping=true --ping=true
``` ```
## Configuration Options
The `/ping` health-check URL is enabled with the command-line `--ping` or config file option `[ping]`.
You can customize the `entryPoint` where the `/ping` is active with the `entryPoint` option (default value: `traefik`)
| Path | Method | Description | | Path | Method | Description |
|---------|---------------|-----------------------------------------------------------------------------------------------------| |---------|---------------|-----------------------------------------------------------------------------------------------------|
| `/ping` | `GET`, `HEAD` | A simple endpoint to check for Traefik process liveness. Return a code `200` with the content: `OK` | | `/ping` | `GET`, `HEAD` | A simple endpoint to check for Traefik process liveness. Return a code `200` with the content: `OK` |
## Configuration Options ### `entryPoint`
The `/ping` health-check URL is enabled with the command-line `--ping` or config file option `[ping]`. Enabling /ping on a dedicated EntryPoint.
```toml tab="File (TOML)"
[entryPoints]
[entryPoints.ping]
address = ":8082"
[ping]
entryPoint = "ping"
```
```yaml tab="File (YAML)"
entryPoints:
ping:
address: ":8082"
ping:
entryPoint: "ping"
```
```bash tab="CLI"
--entryPoints.ping.address=":8082"
--ping.entryPoint="ping"
```

View file

@ -45,6 +45,9 @@ Activate dashboard. (Default: ```true```)
`--api.debug`: `--api.debug`:
Enable additional endpoints for debugging and profiling. (Default: ```false```) Enable additional endpoints for debugging and profiling. (Default: ```false```)
`--api.insecure`:
Activate API on an insecure entryPoints named traefik. (Default: ```false```)
`--certificatesresolvers.<name>`: `--certificatesresolvers.<name>`:
Certificates resolvers configuration. (Default: ```false```) Certificates resolvers configuration. (Default: ```false```)
@ -207,6 +210,9 @@ Enable metrics on services. (Default: ```true```)
`--metrics.prometheus.buckets`: `--metrics.prometheus.buckets`:
Buckets for latency metrics. (Default: ```0.100000, 0.300000, 1.200000, 5.000000```) Buckets for latency metrics. (Default: ```0.100000, 0.300000, 1.200000, 5.000000```)
`--metrics.prometheus.entrypoint`:
EntryPoint (Default: ```traefik```)
`--metrics.statsd`: `--metrics.statsd`:
StatsD metrics exporter type. (Default: ```false```) StatsD metrics exporter type. (Default: ```false```)
@ -223,7 +229,10 @@ Enable metrics on services. (Default: ```true```)
StatsD push interval. (Default: ```10```) StatsD push interval. (Default: ```10```)
`--ping`: `--ping`:
Enable ping. (Default: ```true```) Enable ping. (Default: ```false```)
`--ping.entrypoint`:
EntryPoint (Default: ```traefik```)
`--providers.docker`: `--providers.docker`:
Enable Docker backend with default settings. (Default: ```false```) Enable Docker backend with default settings. (Default: ```false```)
@ -433,7 +442,10 @@ Defines the polling interval in seconds. (Default: ```15```)
Watch provider. (Default: ```true```) Watch provider. (Default: ```true```)
`--providers.rest`: `--providers.rest`:
Enable Rest backend with default settings. (Default: ```true```) Enable Rest backend with default settings. (Default: ```false```)
`--providers.rest.insecure`:
Activate REST Provider on an insecure entryPoints named traefik. (Default: ```false```)
`--serverstransport.forwardingtimeouts.dialtimeout`: `--serverstransport.forwardingtimeouts.dialtimeout`:
The amount of time to wait until a connection to a backend server can be established. If zero, no timeout exists. (Default: ```30```) The amount of time to wait until a connection to a backend server can be established. If zero, no timeout exists. (Default: ```30```)

View file

@ -45,6 +45,9 @@ Activate dashboard. (Default: ```true```)
`TRAEFIK_API_DEBUG`: `TRAEFIK_API_DEBUG`:
Enable additional endpoints for debugging and profiling. (Default: ```false```) Enable additional endpoints for debugging and profiling. (Default: ```false```)
`TRAEFIK_API_INSECURE`:
Activate API on an insecure entryPoints named traefik. (Default: ```false```)
`TRAEFIK_CERTIFICATESRESOLVERS_<NAME>`: `TRAEFIK_CERTIFICATESRESOLVERS_<NAME>`:
Certificates resolvers configuration. (Default: ```false```) Certificates resolvers configuration. (Default: ```false```)
@ -207,6 +210,9 @@ Enable metrics on services. (Default: ```true```)
`TRAEFIK_METRICS_PROMETHEUS_BUCKETS`: `TRAEFIK_METRICS_PROMETHEUS_BUCKETS`:
Buckets for latency metrics. (Default: ```0.100000, 0.300000, 1.200000, 5.000000```) Buckets for latency metrics. (Default: ```0.100000, 0.300000, 1.200000, 5.000000```)
`TRAEFIK_METRICS_PROMETHEUS_ENTRYPOINT`:
EntryPoint (Default: ```traefik```)
`TRAEFIK_METRICS_STATSD`: `TRAEFIK_METRICS_STATSD`:
StatsD metrics exporter type. (Default: ```false```) StatsD metrics exporter type. (Default: ```false```)
@ -223,7 +229,10 @@ Enable metrics on services. (Default: ```true```)
StatsD push interval. (Default: ```10```) StatsD push interval. (Default: ```10```)
`TRAEFIK_PING`: `TRAEFIK_PING`:
Enable ping. (Default: ```true```) Enable ping. (Default: ```false```)
`TRAEFIK_PING_ENTRYPOINT`:
EntryPoint (Default: ```traefik```)
`TRAEFIK_PROVIDERS_DOCKER`: `TRAEFIK_PROVIDERS_DOCKER`:
Enable Docker backend with default settings. (Default: ```false```) Enable Docker backend with default settings. (Default: ```false```)
@ -433,7 +442,10 @@ Defines the polling interval in seconds. (Default: ```15```)
Watch provider. (Default: ```true```) Watch provider. (Default: ```true```)
`TRAEFIK_PROVIDERS_REST`: `TRAEFIK_PROVIDERS_REST`:
Enable Rest backend with default settings. (Default: ```true```) Enable Rest backend with default settings. (Default: ```false```)
`TRAEFIK_PROVIDERS_REST_INSECURE`:
Activate REST Provider on an insecure entryPoints named traefik. (Default: ```false```)
`TRAEFIK_SERVERSTRANSPORT_FORWARDINGTIMEOUTS_DIALTIMEOUT`: `TRAEFIK_SERVERSTRANSPORT_FORWARDINGTIMEOUTS_DIALTIMEOUT`:
The amount of time to wait until a connection to a backend server can be established. If zero, no timeout exists. (Default: ```30```) The amount of time to wait until a connection to a backend server can be established. If zero, no timeout exists. (Default: ```30```)

View file

@ -96,6 +96,7 @@
labelSelector = "foobar" labelSelector = "foobar"
ingressClass = "foobar" ingressClass = "foobar"
[providers.rest] [providers.rest]
insecure = true
[providers.rancher] [providers.rancher]
constraints = "foobar" constraints = "foobar"
watch = true watch = true
@ -107,6 +108,7 @@
prefix = "foobar" prefix = "foobar"
[api] [api]
insecure = true
dashboard = true dashboard = true
debug = true debug = true
@ -115,6 +117,7 @@
buckets = [42.0, 42.0] buckets = [42.0, 42.0]
addEntryPointsLabels = true addEntryPointsLabels = true
addServicesLabels = true addServicesLabels = true
entryPoint = "foobar"
[metrics.datadog] [metrics.datadog]
address = "foobar" address = "foobar"
pushInterval = "10s" pushInterval = "10s"
@ -137,6 +140,7 @@
addServicesLabels = true addServicesLabels = true
[ping] [ping]
entryPoint = "foobar"
[log] [log]
level = "foobar" level = "foobar"

View file

@ -102,7 +102,8 @@ providers:
- foobar - foobar
labelSelector: foobar labelSelector: foobar
ingressClass: foobar ingressClass: foobar
rest: {} rest:
insecure: true
rancher: rancher:
constraints: foobar constraints: foobar
watch: true watch: true
@ -113,6 +114,7 @@ providers:
intervalPoll: true intervalPoll: true
prefix: foobar prefix: foobar
api: api:
insecure: true
dashboard: true dashboard: true
debug: true debug: true
metrics: metrics:
@ -122,6 +124,7 @@ metrics:
- 42 - 42
addEntryPointsLabels: true addEntryPointsLabels: true
addServicesLabels: true addServicesLabels: true
entryPoint: foobar
datadog: datadog:
address: foobar address: foobar
pushInterval: 42 pushInterval: 42
@ -142,7 +145,8 @@ metrics:
password: foobar password: foobar
addEntryPointsLabels: true addEntryPointsLabels: true
addServicesLabels: true addServicesLabels: true
ping: {} ping:
entryPoint: foobar
log: log:
level: foobar level: foobar
filePath: foobar filePath: foobar

View file

@ -22,6 +22,7 @@
address = ":8008" address = ":8008"
[api] [api]
insecure = true
[providers] [providers]
[providers.docker] [providers.docker]

View file

@ -31,6 +31,7 @@
{{end}} {{end}}
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -31,6 +31,7 @@
{{end}} {{end}}
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -31,6 +31,7 @@
{{end}} {{end}}
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -31,6 +31,7 @@
{{end}} {{end}}
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -31,6 +31,7 @@
{{end}} {{end}}
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -31,6 +31,7 @@
{{end}} {{end}}
[api] [api]
insecure = true
[providers] [providers]
[providers.file] [providers.file]

View file

@ -34,3 +34,4 @@
{{end}} {{end}}
[api] [api]
insecure = true

View file

@ -10,6 +10,7 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true
[providers] [providers]
[providers.docker] [providers.docker]

View file

@ -10,6 +10,7 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true
[providers] [providers]
[providers.docker] [providers.docker]

View file

@ -13,6 +13,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":8081" address = ":8081"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -13,6 +13,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -13,6 +13,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -12,6 +12,7 @@
address = ":9000" address = ":9000"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -13,6 +13,7 @@
address = ":8443" address = ":8443"
[api] [api]
insecure = true
[providers] [providers]
[providers.file] [providers.file]

View file

@ -10,6 +10,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -13,6 +13,7 @@
address = ":8443" address = ":8443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -29,6 +29,7 @@ fblo6RBxUQ==
address = ":8081" address = ":8081"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -14,6 +14,7 @@
address = ":8081" address = ":8081"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -6,6 +6,7 @@
level = "DEBUG" level = "DEBUG"
[api] [api]
insecure = true
[entryPoints] [entryPoints]
[entryPoints.footcp] [entryPoints.footcp]

View file

@ -3,6 +3,7 @@
sendAnonymousUsage = false sendAnonymousUsage = false
[api] [api]
insecure = true
[log] [log]
level = "DEBUG" level = "DEBUG"

View file

@ -12,6 +12,7 @@
address = ":9090" address = ":9090"
[api] [api]
insecure = true
[providers] [providers]
[providers.marathon] [providers.marathon]

View file

@ -3,6 +3,7 @@
sendAnonymousUsage = false sendAnonymousUsage = false
[api] [api]
insecure = true
[log] [log]
level = "DEBUG" level = "DEBUG"

View file

@ -10,6 +10,7 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true
[providers] [providers]
[providers.docker] [providers.docker]

View file

@ -6,6 +6,7 @@
level = "DEBUG" level = "DEBUG"
[api] [api]
insecure = true
[entryPoints] [entryPoints]
[entryPoints.web] [entryPoints.web]
@ -13,6 +14,7 @@
[providers] [providers]
[providers.rest] [providers.rest]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -12,6 +12,7 @@
trustedIPs = ["{{.HaproxyIP}}"] trustedIPs = ["{{.HaproxyIP}}"]
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -12,6 +12,7 @@
trustedIPs = ["1.2.3.4"] trustedIPs = ["1.2.3.4"]
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -3,6 +3,7 @@
sendAnonymousUsage = false sendAnonymousUsage = false
[api] [api]
insecure = true
[log] [log]
level = "DEBUG" level = "DEBUG"

View file

@ -10,6 +10,8 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true
[providers] [providers]
[providers.rest] [providers.rest]
insecure = true

View file

@ -0,0 +1,27 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "DEBUG"
[entryPoints]
[entryPoints.web]
address = ":8000"
[api]
insecure = true
[providers.rest]
[providers.file]
filename = "{{ .SelfFilename }}"
[http.routers.rest]
rule="PathPrefix(`/secure`)"
service="rest@internal"
middlewares=["strip"]
[http.middlewares.strip.stripPrefix]
prefixes = [ "/secure" ]

View file

@ -10,6 +10,7 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":4443" address = ":4443"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -13,6 +13,7 @@
address = ":8001" address = ":8001"
[api] [api]
insecure = true
middlewares = ["authentication@file"] middlewares = ["authentication@file"]
[ping] [ping]

View file

@ -10,6 +10,7 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true
[providers] [providers]
[providers.docker] [providers.docker]

View file

@ -0,0 +1,25 @@
[global]
checkNewVersion = false
sendAnonymousUsage = false
[entryPoints]
[entryPoints.web]
address = ":8000"
[entryPoints.traefik]
address = ":8080"
[api]
[providers.file]
filename = "{{ .SelfFilename }}"
[http.routers.api]
rule="PathPrefix(`/secure`)"
service="api@internal"
middlewares=["strip"]
[http.middlewares.strip.stripPrefix]
prefixes = [ "/secure" ]

View file

@ -10,6 +10,7 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,3 +10,4 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true

View file

@ -9,9 +9,10 @@
[entryPoints.web] [entryPoints.web]
address = ":8000" address = ":8000"
[entryPoints.web.ForwardedHeaders] [entryPoints.web.ForwardedHeaders]
insecure=true insecure = true
[api] [api]
insecure = true
[providers] [providers]
[providers.docker] [providers.docker]

View file

@ -10,6 +10,7 @@
address = ":8093" address = ":8093"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":8093" address = ":8093"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":8093" address = ":8093"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":8093" address = ":8093"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":8093" address = ":8093"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -10,6 +10,7 @@
address = ":8093" address = ":8093"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -17,6 +17,7 @@
format = "json" format = "json"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -13,6 +13,7 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -13,6 +13,7 @@
address = ":8443" address = ":8443"
[api] [api]
insecure = true
[providers] [providers]
[providers.docker] [providers.docker]

View file

@ -6,6 +6,7 @@
level = "DEBUG" level = "DEBUG"
[api] [api]
insecure = true
[entryPoints] [entryPoints]
[entryPoints.web] [entryPoints.web]

View file

@ -6,6 +6,7 @@
level = "DEBUG" level = "DEBUG"
[api] [api]
insecure = true
[entryPoints] [entryPoints]
[entryPoints.web] [entryPoints.web]

View file

@ -6,6 +6,7 @@
level = "DEBUG" level = "DEBUG"
[api] [api]
insecure = true
[entryPoints] [entryPoints]
[entryPoints.web] [entryPoints.web]

View file

@ -14,6 +14,7 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true
dashboard = false dashboard = false
[providers] [providers]

View file

@ -10,6 +10,7 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -13,6 +13,7 @@
address = ":8000" address = ":8000"
[api] [api]
insecure = true
[providers.file] [providers.file]
filename = "{{ .SelfFilename }}" filename = "{{ .SelfFilename }}"

View file

@ -3,6 +3,7 @@
sendAnonymousUsage = false sendAnonymousUsage = false
[api] [api]
insecure = true
[log] [log]
level = "DEBUG" level = "DEBUG"

View file

@ -3,6 +3,7 @@
sendAnonymousUsage = false sendAnonymousUsage = false
[api] [api]
insecure = true
[log] [log]
level = "DEBUG" level = "DEBUG"

View file

@ -4,6 +4,8 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"net/http" "net/http"
"os"
"strings"
"time" "time"
"github.com/containous/traefik/v2/integration/try" "github.com/containous/traefik/v2/integration/try"
@ -20,7 +22,7 @@ func (s *RestSuite) SetUpSuite(c *check.C) {
s.composeProject.Start(c) s.composeProject.Start(c)
} }
func (s *RestSuite) TestSimpleConfiguration(c *check.C) { func (s *RestSuite) TestSimpleConfigurationInsecure(c *check.C) {
cmd, display := s.traefikCmd(withConfigFile("fixtures/rest/simple.toml")) cmd, display := s.traefikCmd(withConfigFile("fixtures/rest/simple.toml"))
defer display(c) defer display(c)
@ -110,3 +112,107 @@ func (s *RestSuite) TestSimpleConfiguration(c *check.C) {
c.Assert(err, checker.IsNil) c.Assert(err, checker.IsNil)
} }
} }
func (s *RestSuite) TestSimpleConfiguration(c *check.C) {
file := s.adaptFile(c, "fixtures/rest/simple_secure.toml", struct{}{})
defer os.Remove(file)
cmd, display := s.traefikCmd(withConfigFile(file))
defer display(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
// Expected a 404 as we did not configure anything.
err = try.GetRequest("http://127.0.0.1:8000/", 1000*time.Millisecond, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 2000*time.Millisecond, try.BodyContains("PathPrefix(`/secure`)"))
c.Assert(err, checker.IsNil)
request, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:8080/api/providers/rest", strings.NewReader("{}"))
c.Assert(err, checker.IsNil)
response, err := http.DefaultClient.Do(request)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusNotFound)
testCase := []struct {
desc string
config *dynamic.Configuration
ruleMatch string
}{
{
desc: "deploy http configuration",
config: &dynamic.Configuration{
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"router1": {
EntryPoints: []string{"web"},
Middlewares: []string{},
Service: "service1",
Rule: "PathPrefix(`/`)",
},
},
Services: map[string]*dynamic.Service{
"service1": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://" + s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80",
},
},
},
},
},
},
},
ruleMatch: "PathPrefix(`/`)",
},
{
desc: "deploy tcp configuration",
config: &dynamic.Configuration{
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{
"router1": {
EntryPoints: []string{"web"},
Service: "service1",
Rule: "HostSNI(`*`)",
},
},
Services: map[string]*dynamic.TCPService{
"service1": {
LoadBalancer: &dynamic.TCPLoadBalancerService{
Servers: []dynamic.TCPServer{
{
Address: s.composeProject.Container(c, "whoami1").NetworkSettings.IPAddress + ":80",
},
},
},
},
},
},
},
ruleMatch: "HostSNI(`*`)",
},
}
for _, test := range testCase {
json, err := json.Marshal(test.config)
c.Assert(err, checker.IsNil)
request, err := http.NewRequest(http.MethodPut, "http://127.0.0.1:8000/secure/api/providers/rest", bytes.NewReader(json))
c.Assert(err, checker.IsNil)
response, err := http.DefaultClient.Do(request)
c.Assert(err, checker.IsNil)
c.Assert(response.StatusCode, checker.Equals, http.StatusOK)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1000*time.Millisecond, try.BodyContains(test.ruleMatch))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/", 1000*time.Millisecond, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
}
}

View file

@ -161,33 +161,6 @@ func (s *SimpleSuite) TestRequestAcceptGraceTimeout(c *check.C) {
} }
} }
func (s *SimpleSuite) TestApiOnSameEntryPoint(c *check.C) {
c.Skip("Waiting for new api handler implementation")
s.createComposeProject(c, "base")
s.composeProject.Start(c)
cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--api.entryPoint=http", "--log.level=DEBUG", "--providers.docker")
defer output(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
// TODO validate : run on 80
// Expected a 404 as we did not configure anything
err = try.GetRequest("http://127.0.0.1:8000/test", 1*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/api/rawdata", 1*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/api/rawdata", 1*time.Second, try.BodyContains("PathPrefix"))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/whoami", 1*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
}
func (s *SimpleSuite) TestStatsWithMultipleEntryPoint(c *check.C) { func (s *SimpleSuite) TestStatsWithMultipleEntryPoint(c *check.C) {
c.Skip("Stats is missing") c.Skip("Stats is missing")
s.createComposeProject(c, "stats") s.createComposeProject(c, "stats")
@ -250,7 +223,7 @@ func (s *SimpleSuite) TestDefaultEntryPointHTTP(c *check.C) {
s.createComposeProject(c, "base") s.createComposeProject(c, "base")
s.composeProject.Start(c) s.composeProject.Start(c)
cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--log.level=DEBUG", "--providers.docker", "--api") cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--log.level=DEBUG", "--providers.docker", "--api.insecure")
defer output(c) defer output(c)
err := cmd.Start() err := cmd.Start()
@ -268,7 +241,7 @@ func (s *SimpleSuite) TestWithNonExistingEntryPoint(c *check.C) {
s.createComposeProject(c, "base") s.createComposeProject(c, "base")
s.composeProject.Start(c) s.composeProject.Start(c)
cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--log.level=DEBUG", "--providers.docker", "--api") cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--log.level=DEBUG", "--providers.docker", "--api.insecure")
defer output(c) defer output(c)
err := cmd.Start() err := cmd.Start()
@ -286,7 +259,7 @@ func (s *SimpleSuite) TestMetricsPrometheusDefaultEntryPoint(c *check.C) {
s.createComposeProject(c, "base") s.createComposeProject(c, "base")
s.composeProject.Start(c) s.composeProject.Start(c)
cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--api", "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0", "--providers.docker", "--log.level=DEBUG") cmd, output := s.traefikCmd("--entryPoints.http.Address=:8000", "--api.insecure", "--metrics.prometheus.buckets=0.1,0.3,1.2,5.0", "--providers.docker", "--log.level=DEBUG")
defer output(c) defer output(c)
err := cmd.Start() err := cmd.Start()
@ -785,3 +758,27 @@ func (s *SimpleSuite) TestMirrorCanceled(c *check.C) {
c.Assert(val1, checker.Equals, int32(0)) c.Assert(val1, checker.Equals, int32(0))
c.Assert(val2, checker.Equals, int32(0)) c.Assert(val2, checker.Equals, int32(0))
} }
func (s *SimpleSuite) TestSecureAPI(c *check.C) {
s.createComposeProject(c, "base")
s.composeProject.Start(c)
file := s.adaptFile(c, "./fixtures/simple_secure_api.toml", struct{}{})
defer os.Remove(file)
cmd, output := s.traefikCmd(withConfigFile(file))
defer output(c)
err := cmd.Start()
c.Assert(err, checker.IsNil)
defer cmd.Process.Kill()
err = try.GetRequest("http://127.0.0.1:8000/secure/api/rawdata", 1*time.Second, try.StatusCodeIs(http.StatusOK))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8000/api/rawdata", 1*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
err = try.GetRequest("http://127.0.0.1:8080/api/rawdata", 1*time.Second, try.StatusCodeIs(http.StatusNotFound))
c.Assert(err, checker.IsNil)
}

View file

@ -55,6 +55,15 @@ type Handler struct {
dashboardAssets *assetfs.AssetFS dashboardAssets *assetfs.AssetFS
} }
// NewBuilder returns a http.Handler builder based on runtime.Configuration
func NewBuilder(staticConfig static.Configuration) func(*runtime.Configuration) http.Handler {
return func(configuration *runtime.Configuration) http.Handler {
router := mux.NewRouter()
New(staticConfig, configuration).Append(router)
return router
}
}
// New returns a Handler defined by staticConfig, and if provided, by runtimeConfig. // New returns a Handler defined by staticConfig, and if provided, by runtimeConfig.
// It finishes populating the information provided in the runtimeConfig. // It finishes populating the information provided in the runtimeConfig.
func New(staticConfig static.Configuration, runtimeConfig *runtime.Configuration) *Handler { func New(staticConfig static.Configuration, runtimeConfig *runtime.Configuration) *Handler {

View file

@ -85,6 +85,7 @@ type ServersTransport struct {
// API holds the API configuration // API holds the API configuration
type API struct { type API struct {
Insecure bool `description:"Activate API directly on the entryPoint named traefik." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"`
Dashboard bool `description:"Activate dashboard." json:"dashboard,omitempty" toml:"dashboard,omitempty" yaml:"dashboard,omitempty" export:"true"` Dashboard bool `description:"Activate dashboard." json:"dashboard,omitempty" toml:"dashboard,omitempty" yaml:"dashboard,omitempty" export:"true"`
Debug bool `description:"Enable additional endpoints for debugging and profiling." json:"debug,omitempty" toml:"debug,omitempty" yaml:"debug,omitempty" export:"true"` Debug bool `description:"Enable additional endpoints for debugging and profiling." json:"debug,omitempty" toml:"debug,omitempty" yaml:"debug,omitempty" export:"true"`
// TODO: Re-enable statistics // TODO: Re-enable statistics
@ -173,9 +174,9 @@ func (c *Configuration) SetEffectiveConfiguration() {
} }
} }
if (c.API != nil) || if (c.API != nil && c.API.Insecure) ||
(c.Ping != nil) || (c.Ping != nil && c.Ping.EntryPoint == DefaultInternalEntryPointName) ||
(c.Metrics != nil && c.Metrics.Prometheus != nil) || (c.Metrics != nil && c.Metrics.Prometheus != nil && c.Metrics.Prometheus.EntryPoint == DefaultInternalEntryPointName) ||
(c.Providers.Rest != nil) { (c.Providers.Rest != nil) {
if _, ok := c.EntryPoints[DefaultInternalEntryPointName]; !ok { if _, ok := c.EntryPoints[DefaultInternalEntryPointName]; !ok {
ep := &EntryPoint{Address: ":8080"} ep := &EntryPoint{Address: ":8080"}

View file

@ -10,11 +10,13 @@ import (
// Handler expose ping routes. // Handler expose ping routes.
type Handler struct { type Handler struct {
EntryPoint string `description:"EntryPoint" export:"true" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"`
terminating bool terminating bool
} }
// SetDefaults sets the default values. // SetDefaults sets the default values.
func (h *Handler) SetDefaults() { func (h *Handler) SetDefaults() {
h.EntryPoint = "traefik"
} }
// WithContext causes the ping endpoint to serve non 200 responses. // WithContext causes the ping endpoint to serve non 200 responses.

View file

@ -18,6 +18,7 @@ var _ provider.Provider = (*Provider)(nil)
// Provider is a provider.Provider implementation that provides a Rest API. // Provider is a provider.Provider implementation that provides a Rest API.
type Provider struct { type Provider struct {
Insecure bool `description:"Activate REST Provider directly on the entryPoint named traefik." json:"insecure,omitempty" toml:"insecure,omitempty" yaml:"insecure,omitempty" export:"true"`
configurationChan chan<- dynamic.Message configurationChan chan<- dynamic.Message
} }
@ -32,6 +33,13 @@ func (p *Provider) Init() error {
return nil return nil
} }
// Handler creates an http.Handler for the Rest API
func (p *Provider) Handler() http.Handler {
router := mux.NewRouter()
p.Append(router)
return router
}
// Append add rest provider routes on a router. // Append add rest provider routes on a router.
func (p *Provider) Append(systemRouter *mux.Router) { func (p *Provider) Append(systemRouter *mux.Router) {
systemRouter. systemRouter.

View file

@ -19,30 +19,30 @@ type chainBuilder interface {
} }
// NewRouteAppenderAggregator Creates a new RouteAppenderAggregator // NewRouteAppenderAggregator Creates a new RouteAppenderAggregator
func NewRouteAppenderAggregator(ctx context.Context, chainBuilder chainBuilder, conf static.Configuration, func NewRouteAppenderAggregator(ctx context.Context, conf static.Configuration,
entryPointName string, runtimeConfiguration *runtime.Configuration) *RouteAppenderAggregator { entryPointName string, runtimeConfiguration *runtime.Configuration) *RouteAppenderAggregator {
aggregator := &RouteAppenderAggregator{} aggregator := &RouteAppenderAggregator{}
if conf.Ping != nil && conf.Ping.EntryPoint == entryPointName {
aggregator.AddAppender(conf.Ping)
}
if conf.Metrics != nil && conf.Metrics.Prometheus != nil && conf.Metrics.Prometheus.EntryPoint == entryPointName {
aggregator.AddAppender(metrics.PrometheusHandler{})
}
if entryPointName != "traefik" { if entryPointName != "traefik" {
return aggregator return aggregator
} }
if conf.Providers != nil && conf.Providers.Rest != nil { if conf.Providers != nil && conf.Providers.Rest != nil && conf.Providers.Rest.Insecure {
aggregator.AddAppender(conf.Providers.Rest) aggregator.AddAppender(conf.Providers.Rest)
} }
if conf.API != nil { if conf.API != nil && conf.API.Insecure {
aggregator.AddAppender(api.New(conf, runtimeConfiguration)) aggregator.AddAppender(api.New(conf, runtimeConfiguration))
} }
if conf.Ping != nil {
aggregator.AddAppender(conf.Ping)
}
if conf.Metrics != nil && conf.Metrics.Prometheus != nil {
aggregator.AddAppender(metrics.PrometheusHandler{})
}
return aggregator return aggregator
} }

View file

@ -6,72 +6,23 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/containous/alice"
"github.com/containous/traefik/v2/pkg/config/static" "github.com/containous/traefik/v2/pkg/config/static"
"github.com/containous/traefik/v2/pkg/ping"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
type ChainBuilderMock struct {
middles map[string]alice.Constructor
}
func (c *ChainBuilderMock) BuildChain(ctx context.Context, middles []string) *alice.Chain {
chain := alice.New()
for _, mName := range middles {
if constructor, ok := c.middles[mName]; ok {
chain = chain.Append(constructor)
}
}
return &chain
}
func TestNewRouteAppenderAggregator(t *testing.T) { func TestNewRouteAppenderAggregator(t *testing.T) {
t.Skip("Waiting for new api handler implementation")
testCases := []struct { testCases := []struct {
desc string desc string
staticConf static.Configuration staticConf static.Configuration
middles map[string]alice.Constructor
expected map[string]int expected map[string]int
}{ }{
{ {
desc: "API with auth, ping without auth", desc: "Secure API",
staticConf: static.Configuration{ staticConf: static.Configuration{
Global: &static.Global{}, Global: &static.Global{},
API: &static.API{ API: &static.API{
// EntryPoint: "traefik", Insecure: false,
// Middlewares: []string{"dumb"},
},
Ping: &ping.Handler{
// EntryPoint: "traefik",
},
EntryPoints: static.EntryPoints{
"traefik": {},
},
},
middles: map[string]alice.Constructor{
"dumb": func(_ http.Handler) (http.Handler, error) {
return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
}), nil
},
},
expected: map[string]int{
"/wrong": http.StatusBadGateway,
"/ping": http.StatusOK,
// "/.well-known/acme-challenge/token": http.StatusNotFound, // FIXME
"/api/rawdata": http.StatusUnauthorized,
},
},
{
desc: "Wrong entrypoint name",
staticConf: static.Configuration{
Global: &static.Global{},
API: &static.API{
// EntryPoint: "no",
}, },
EntryPoints: static.EntryPoints{ EntryPoints: static.EntryPoints{
"traefik": {}, "traefik": {},
@ -81,6 +32,21 @@ func TestNewRouteAppenderAggregator(t *testing.T) {
"/api/providers": http.StatusBadGateway, "/api/providers": http.StatusBadGateway,
}, },
}, },
{
desc: "Insecure API",
staticConf: static.Configuration{
Global: &static.Global{},
API: &static.API{
Insecure: true,
},
EntryPoints: static.EntryPoints{
"traefik": {},
},
},
expected: map[string]int{
"/api/rawdata": http.StatusOK,
},
},
} }
for _, test := range testCases { for _, test := range testCases {
@ -88,11 +54,9 @@ func TestNewRouteAppenderAggregator(t *testing.T) {
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
t.Parallel() t.Parallel()
chainBuilder := &ChainBuilderMock{middles: test.middles}
ctx := context.Background() ctx := context.Background()
router := NewRouteAppenderAggregator(ctx, chainBuilder, test.staticConf, "traefik", nil) router := NewRouteAppenderAggregator(ctx, test.staticConf, "traefik", nil)
internalMuxRouter := mux.NewRouter() internalMuxRouter := mux.NewRouter()
router.Append(internalMuxRouter) router.Append(internalMuxRouter)

View file

@ -6,7 +6,6 @@ import (
"github.com/containous/traefik/v2/pkg/config/runtime" "github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/config/static" "github.com/containous/traefik/v2/pkg/config/static"
"github.com/containous/traefik/v2/pkg/provider/acme" "github.com/containous/traefik/v2/pkg/provider/acme"
"github.com/containous/traefik/v2/pkg/server/middleware"
"github.com/containous/traefik/v2/pkg/types" "github.com/containous/traefik/v2/pkg/types"
) )
@ -27,8 +26,8 @@ type RouteAppenderFactory struct {
} }
// NewAppender Creates a new RouteAppender // NewAppender Creates a new RouteAppender
func (r *RouteAppenderFactory) NewAppender(ctx context.Context, middlewaresBuilder *middleware.Builder, runtimeConfiguration *runtime.Configuration) types.RouteAppender { func (r *RouteAppenderFactory) NewAppender(ctx context.Context, runtimeConfiguration *runtime.Configuration) types.RouteAppender {
aggregator := NewRouteAppenderAggregator(ctx, middlewaresBuilder, r.staticConfiguration, r.entryPointName, runtimeConfiguration) aggregator := NewRouteAppenderAggregator(ctx, r.staticConfiguration, r.entryPointName, runtimeConfiguration)
for _, p := range r.acmeProvider { for _, p := range r.acmeProvider {
if p != nil && p.HTTPChallenge != nil && p.HTTPChallenge.EntryPoint == r.entryPointName { if p != nil && p.HTTPChallenge != nil && p.HTTPChallenge.EntryPoint == r.entryPointName {

View file

@ -306,7 +306,7 @@ func TestRouterManager_Get(t *testing.T) {
Middlewares: test.middlewaresConfig, Middlewares: test.middlewaresConfig,
}, },
}) })
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil) serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil, nil, nil)
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager) middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares) responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory) routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
@ -407,7 +407,7 @@ func TestAccessLog(t *testing.T) {
Middlewares: test.middlewaresConfig, Middlewares: test.middlewaresConfig,
}, },
}) })
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil) serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil, nil, nil)
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager) middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares) responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory) routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
@ -693,7 +693,7 @@ func TestRuntimeConfiguration(t *testing.T) {
Middlewares: test.middlewareConfig, Middlewares: test.middlewareConfig,
}, },
}) })
serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil) serviceManager := service.NewManager(rtConf.Services, http.DefaultTransport, nil, nil, nil, nil)
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager) middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
responseModifierFactory := responsemodifiers.NewBuilder(map[string]*runtime.MiddlewareInfo{}) responseModifierFactory := responsemodifiers.NewBuilder(map[string]*runtime.MiddlewareInfo{})
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory) routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
@ -767,7 +767,7 @@ func BenchmarkRouterServe(b *testing.B) {
Middlewares: map[string]*dynamic.Middleware{}, Middlewares: map[string]*dynamic.Middleware{},
}, },
}) })
serviceManager := service.NewManager(rtConf.Services, &staticTransport{res}, nil, nil) serviceManager := service.NewManager(rtConf.Services, &staticTransport{res}, nil, nil, nil, nil)
middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager) middlewaresBuilder := middleware.NewBuilder(rtConf.Middlewares, serviceManager)
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares) responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory) routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
@ -808,7 +808,7 @@ func BenchmarkService(b *testing.B) {
Services: serviceConfig, Services: serviceConfig,
}, },
}) })
serviceManager := service.NewManager(rtConf.Services, &staticTransport{res}, nil, nil) serviceManager := service.NewManager(rtConf.Services, &staticTransport{res}, nil, nil, nil, nil)
w := httptest.NewRecorder() w := httptest.NewRecorder()
req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/", nil) req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/", nil)

View file

@ -9,6 +9,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/containous/traefik/v2/pkg/api"
"github.com/containous/traefik/v2/pkg/config/dynamic" "github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/config/runtime" "github.com/containous/traefik/v2/pkg/config/runtime"
"github.com/containous/traefik/v2/pkg/config/static" "github.com/containous/traefik/v2/pkg/config/static"
@ -18,7 +19,6 @@ import (
"github.com/containous/traefik/v2/pkg/middlewares/requestdecorator" "github.com/containous/traefik/v2/pkg/middlewares/requestdecorator"
"github.com/containous/traefik/v2/pkg/provider" "github.com/containous/traefik/v2/pkg/provider"
"github.com/containous/traefik/v2/pkg/safe" "github.com/containous/traefik/v2/pkg/safe"
"github.com/containous/traefik/v2/pkg/server/middleware"
"github.com/containous/traefik/v2/pkg/tls" "github.com/containous/traefik/v2/pkg/tls"
"github.com/containous/traefik/v2/pkg/tracing" "github.com/containous/traefik/v2/pkg/tracing"
"github.com/containous/traefik/v2/pkg/tracing/jaeger" "github.com/containous/traefik/v2/pkg/tracing/jaeger"
@ -44,11 +44,13 @@ type Server struct {
requestDecorator *requestdecorator.RequestDecorator requestDecorator *requestdecorator.RequestDecorator
providersThrottleDuration time.Duration providersThrottleDuration time.Duration
tlsManager *tls.Manager tlsManager *tls.Manager
api func(configuration *runtime.Configuration) http.Handler
restHandler http.Handler
} }
// RouteAppenderFactory the route appender factory interface // RouteAppenderFactory the route appender factory interface
type RouteAppenderFactory interface { type RouteAppenderFactory interface {
NewAppender(ctx context.Context, middlewaresBuilder *middleware.Builder, runtimeConfiguration *runtime.Configuration) types.RouteAppender NewAppender(ctx context.Context, runtimeConfiguration *runtime.Configuration) types.RouteAppender
} }
func setupTracing(conf *static.Tracing) tracing.Backend { func setupTracing(conf *static.Tracing) tracing.Backend {
@ -103,6 +105,14 @@ func setupTracing(conf *static.Tracing) tracing.Backend {
func NewServer(staticConfiguration static.Configuration, provider provider.Provider, entryPoints TCPEntryPoints, tlsManager *tls.Manager) *Server { func NewServer(staticConfiguration static.Configuration, provider provider.Provider, entryPoints TCPEntryPoints, tlsManager *tls.Manager) *Server {
server := &Server{} server := &Server{}
if staticConfiguration.API != nil {
server.api = api.NewBuilder(staticConfiguration)
}
if staticConfiguration.Providers != nil && staticConfiguration.Providers.Rest != nil {
server.restHandler = staticConfiguration.Providers.Rest.Handler()
}
server.provider = provider server.provider = provider
server.entryPointsTCP = entryPoints server.entryPointsTCP = entryPoints
server.configurationChan = make(chan dynamic.Message, 100) server.configurationChan = make(chan dynamic.Message, 100)

View file

@ -97,7 +97,12 @@ func (s *Server) createTCPRouters(ctx context.Context, configuration *runtime.Co
// createHTTPHandlers returns, for the given configuration and entryPoints, the HTTP handlers for non-TLS connections, and for the TLS ones. the given configuration must not be nil. its fields will get mutated. // createHTTPHandlers returns, for the given configuration and entryPoints, the HTTP handlers for non-TLS connections, and for the TLS ones. the given configuration must not be nil. its fields will get mutated.
func (s *Server) createHTTPHandlers(ctx context.Context, configuration *runtime.Configuration, entryPoints []string) (map[string]http.Handler, map[string]http.Handler) { func (s *Server) createHTTPHandlers(ctx context.Context, configuration *runtime.Configuration, entryPoints []string) (map[string]http.Handler, map[string]http.Handler) {
serviceManager := service.NewManager(configuration.Services, s.defaultRoundTripper, s.metricsRegistry, s.routinesPool) var apiHandler http.Handler
if s.api != nil {
apiHandler = s.api(configuration)
}
serviceManager := service.NewManager(configuration.Services, s.defaultRoundTripper, s.metricsRegistry, s.routinesPool, apiHandler, s.restHandler)
middlewaresBuilder := middleware.NewBuilder(configuration.Middlewares, serviceManager) middlewaresBuilder := middleware.NewBuilder(configuration.Middlewares, serviceManager)
responseModifierFactory := responsemodifiers.NewBuilder(configuration.Middlewares) responseModifierFactory := responsemodifiers.NewBuilder(configuration.Middlewares)
routerManager := router.NewManager(configuration, serviceManager, middlewaresBuilder, responseModifierFactory) routerManager := router.NewManager(configuration, serviceManager, middlewaresBuilder, responseModifierFactory)
@ -114,7 +119,7 @@ func (s *Server) createHTTPHandlers(ctx context.Context, configuration *runtime.
factory := s.entryPointsTCP[entryPointName].RouteAppenderFactory factory := s.entryPointsTCP[entryPointName].RouteAppenderFactory
if factory != nil { if factory != nil {
// FIXME remove currentConfigurations // FIXME remove currentConfigurations
appender := factory.NewAppender(ctx, middlewaresBuilder, configuration) appender := factory.NewAppender(ctx, configuration)
appender.Append(internalMuxRouter) appender.Append(internalMuxRouter)
} }

View file

@ -34,7 +34,7 @@ const (
) )
// NewManager creates a new Manager // NewManager creates a new Manager
func NewManager(configs map[string]*runtime.ServiceInfo, defaultRoundTripper http.RoundTripper, metricsRegistry metrics.Registry, routinePool *safe.Pool) *Manager { func NewManager(configs map[string]*runtime.ServiceInfo, defaultRoundTripper http.RoundTripper, metricsRegistry metrics.Registry, routinePool *safe.Pool, api http.Handler, rest http.Handler) *Manager {
return &Manager{ return &Manager{
routinePool: routinePool, routinePool: routinePool,
metricsRegistry: metricsRegistry, metricsRegistry: metricsRegistry,
@ -42,6 +42,8 @@ func NewManager(configs map[string]*runtime.ServiceInfo, defaultRoundTripper htt
defaultRoundTripper: defaultRoundTripper, defaultRoundTripper: defaultRoundTripper,
balancers: make(map[string][]healthcheck.BalancerHandler), balancers: make(map[string][]healthcheck.BalancerHandler),
configs: configs, configs: configs,
api: api,
rest: rest,
} }
} }
@ -53,10 +55,26 @@ type Manager struct {
defaultRoundTripper http.RoundTripper defaultRoundTripper http.RoundTripper
balancers map[string][]healthcheck.BalancerHandler balancers map[string][]healthcheck.BalancerHandler
configs map[string]*runtime.ServiceInfo configs map[string]*runtime.ServiceInfo
api http.Handler
rest http.Handler
} }
// BuildHTTP Creates a http.Handler for a service configuration. // BuildHTTP Creates a http.Handler for a service configuration.
func (m *Manager) BuildHTTP(rootCtx context.Context, serviceName string, responseModifier func(*http.Response) error) (http.Handler, error) { func (m *Manager) BuildHTTP(rootCtx context.Context, serviceName string, responseModifier func(*http.Response) error) (http.Handler, error) {
if serviceName == "api@internal" {
if m.api == nil {
return nil, errors.New("api is not enabled")
}
return m.api, nil
}
if serviceName == "rest@internal" {
if m.rest == nil {
return nil, errors.New("rest is not enabled")
}
return m.rest, nil
}
ctx := log.With(rootCtx, log.Str(log.ServiceName, serviceName)) ctx := log.With(rootCtx, log.Str(log.ServiceName, serviceName))
serviceName = internal.GetQualifiedName(ctx, serviceName) serviceName = internal.GetQualifiedName(ctx, serviceName)

View file

@ -80,7 +80,7 @@ func TestGetLoadBalancer(t *testing.T) {
} }
func TestGetLoadBalancerServiceHandler(t *testing.T) { func TestGetLoadBalancerServiceHandler(t *testing.T) {
sm := NewManager(nil, http.DefaultTransport, nil, nil) sm := NewManager(nil, http.DefaultTransport, nil, nil, nil, nil)
server1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { server1 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-From", "first") w.Header().Set("X-From", "first")
@ -332,7 +332,7 @@ func TestManager_Build(t *testing.T) {
t.Run(test.desc, func(t *testing.T) { t.Run(test.desc, func(t *testing.T) {
t.Parallel() t.Parallel()
manager := NewManager(test.configs, http.DefaultTransport, nil, nil) manager := NewManager(test.configs, http.DefaultTransport, nil, nil, nil, nil)
ctx := context.Background() ctx := context.Background()
if len(test.providerName) > 0 { if len(test.providerName) > 0 {
@ -353,7 +353,7 @@ func TestMultipleTypeOnBuildHTTP(t *testing.T) {
Weighted: &dynamic.WeightedRoundRobin{}, Weighted: &dynamic.WeightedRoundRobin{},
}, },
}, },
}, http.DefaultTransport, nil, nil) }, http.DefaultTransport, nil, nil, nil, nil)
_, err := manager.BuildHTTP(context.Background(), "test@file", nil) _, err := manager.BuildHTTP(context.Background(), "test@file", nil)
assert.Error(t, err, "cannot create service: multi-types service not supported, consider declaring two different pieces of service instead") assert.Error(t, err, "cannot create service: multi-types service not supported, consider declaring two different pieces of service instead")

View file

@ -17,6 +17,7 @@ type Prometheus struct {
Buckets []float64 `description:"Buckets for latency metrics." json:"buckets,omitempty" toml:"buckets,omitempty" yaml:"buckets,omitempty" export:"true"` Buckets []float64 `description:"Buckets for latency metrics." json:"buckets,omitempty" toml:"buckets,omitempty" yaml:"buckets,omitempty" export:"true"`
AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"` AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"`
AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"` AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"`
EntryPoint string `description:"EntryPoint" export:"true" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"`
} }
// SetDefaults sets the default values. // SetDefaults sets the default values.
@ -24,6 +25,7 @@ func (p *Prometheus) SetDefaults() {
p.Buckets = []float64{0.1, 0.3, 1.2, 5} p.Buckets = []float64{0.1, 0.3, 1.2, 5}
p.AddEntryPointsLabels = true p.AddEntryPointsLabels = true
p.AddServicesLabels = true p.AddServicesLabels = true
p.EntryPoint = "traefik"
} }
// Datadog contains address and metrics pushing interval configuration. // Datadog contains address and metrics pushing interval configuration.