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"
--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
!!! 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.
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
(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
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:
```toml tab="File (TOML)"
@ -41,6 +37,83 @@ api: {}
--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`
_Optional, Default=true_

View file

@ -5,7 +5,7 @@ Checking the Health of Your Traefik Instances
## Configuration Examples
??? example "Enabling /ping"
!!! example "Enabling /ping"
```toml tab="File (TOML)"
[ping]
@ -19,10 +19,39 @@ ping: {}
--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 |
|---------|---------------|-----------------------------------------------------------------------------------------------------|
| `/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`:
Enable additional endpoints for debugging and profiling. (Default: ```false```)
`--api.insecure`:
Activate API on an insecure entryPoints named traefik. (Default: ```false```)
`--certificatesresolvers.<name>`:
Certificates resolvers configuration. (Default: ```false```)
@ -207,6 +210,9 @@ Enable metrics on services. (Default: ```true```)
`--metrics.prometheus.buckets`:
Buckets for latency metrics. (Default: ```0.100000, 0.300000, 1.200000, 5.000000```)
`--metrics.prometheus.entrypoint`:
EntryPoint (Default: ```traefik```)
`--metrics.statsd`:
StatsD metrics exporter type. (Default: ```false```)
@ -223,7 +229,10 @@ Enable metrics on services. (Default: ```true```)
StatsD push interval. (Default: ```10```)
`--ping`:
Enable ping. (Default: ```true```)
Enable ping. (Default: ```false```)
`--ping.entrypoint`:
EntryPoint (Default: ```traefik```)
`--providers.docker`:
Enable Docker backend with default settings. (Default: ```false```)
@ -433,7 +442,10 @@ Defines the polling interval in seconds. (Default: ```15```)
Watch provider. (Default: ```true```)
`--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`:
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`:
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>`:
Certificates resolvers configuration. (Default: ```false```)
@ -207,6 +210,9 @@ Enable metrics on services. (Default: ```true```)
`TRAEFIK_METRICS_PROMETHEUS_BUCKETS`:
Buckets for latency metrics. (Default: ```0.100000, 0.300000, 1.200000, 5.000000```)
`TRAEFIK_METRICS_PROMETHEUS_ENTRYPOINT`:
EntryPoint (Default: ```traefik```)
`TRAEFIK_METRICS_STATSD`:
StatsD metrics exporter type. (Default: ```false```)
@ -223,7 +229,10 @@ Enable metrics on services. (Default: ```true```)
StatsD push interval. (Default: ```10```)
`TRAEFIK_PING`:
Enable ping. (Default: ```true```)
Enable ping. (Default: ```false```)
`TRAEFIK_PING_ENTRYPOINT`:
EntryPoint (Default: ```traefik```)
`TRAEFIK_PROVIDERS_DOCKER`:
Enable Docker backend with default settings. (Default: ```false```)
@ -433,7 +442,10 @@ Defines the polling interval in seconds. (Default: ```15```)
Watch provider. (Default: ```true```)
`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`:
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"
ingressClass = "foobar"
[providers.rest]
insecure = true
[providers.rancher]
constraints = "foobar"
watch = true
@ -107,6 +108,7 @@
prefix = "foobar"
[api]
insecure = true
dashboard = true
debug = true
@ -115,6 +117,7 @@
buckets = [42.0, 42.0]
addEntryPointsLabels = true
addServicesLabels = true
entryPoint = "foobar"
[metrics.datadog]
address = "foobar"
pushInterval = "10s"
@ -137,6 +140,7 @@
addServicesLabels = true
[ping]
entryPoint = "foobar"
[log]
level = "foobar"

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -10,6 +10,8 @@
address = ":8000"
[api]
insecure = true
[providers]
[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"
[api]
insecure = true
[providers.file]
filename = "{{ .SelfFilename }}"

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,6 +4,8 @@ import (
"bytes"
"encoding/json"
"net/http"
"os"
"strings"
"time"
"github.com/containous/traefik/v2/integration/try"
@ -20,7 +22,7 @@ func (s *RestSuite) SetUpSuite(c *check.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"))
defer display(c)
@ -110,3 +112,107 @@ func (s *RestSuite) TestSimpleConfiguration(c *check.C) {
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) {
c.Skip("Stats is missing")
s.createComposeProject(c, "stats")
@ -250,7 +223,7 @@ func (s *SimpleSuite) TestDefaultEntryPointHTTP(c *check.C) {
s.createComposeProject(c, "base")
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)
err := cmd.Start()
@ -268,7 +241,7 @@ func (s *SimpleSuite) TestWithNonExistingEntryPoint(c *check.C) {
s.createComposeProject(c, "base")
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)
err := cmd.Start()
@ -286,7 +259,7 @@ func (s *SimpleSuite) TestMetricsPrometheusDefaultEntryPoint(c *check.C) {
s.createComposeProject(c, "base")
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)
err := cmd.Start()
@ -785,3 +758,27 @@ func (s *SimpleSuite) TestMirrorCanceled(c *check.C) {
c.Assert(val1, 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
}
// 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.
// It finishes populating the information provided in the runtimeConfig.
func New(staticConfig static.Configuration, runtimeConfig *runtime.Configuration) *Handler {

View file

@ -85,6 +85,7 @@ type ServersTransport struct {
// API holds the API configuration
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"`
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
@ -173,9 +174,9 @@ func (c *Configuration) SetEffectiveConfiguration() {
}
}
if (c.API != nil) ||
(c.Ping != nil) ||
(c.Metrics != nil && c.Metrics.Prometheus != nil) ||
if (c.API != nil && c.API.Insecure) ||
(c.Ping != nil && c.Ping.EntryPoint == DefaultInternalEntryPointName) ||
(c.Metrics != nil && c.Metrics.Prometheus != nil && c.Metrics.Prometheus.EntryPoint == DefaultInternalEntryPointName) ||
(c.Providers.Rest != nil) {
if _, ok := c.EntryPoints[DefaultInternalEntryPointName]; !ok {
ep := &EntryPoint{Address: ":8080"}

View file

@ -10,11 +10,13 @@ import (
// Handler expose ping routes.
type Handler struct {
EntryPoint string `description:"EntryPoint" export:"true" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"`
terminating bool
}
// SetDefaults sets the default values.
func (h *Handler) SetDefaults() {
h.EntryPoint = "traefik"
}
// 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.
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
}
@ -32,6 +33,13 @@ func (p *Provider) Init() error {
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.
func (p *Provider) Append(systemRouter *mux.Router) {
systemRouter.

View file

@ -19,30 +19,30 @@ type chainBuilder interface {
}
// 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 {
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" {
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)
}
if conf.API != nil {
if conf.API != nil && conf.API.Insecure {
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
}

View file

@ -6,72 +6,23 @@ import (
"net/http/httptest"
"testing"
"github.com/containous/alice"
"github.com/containous/traefik/v2/pkg/config/static"
"github.com/containous/traefik/v2/pkg/ping"
"github.com/gorilla/mux"
"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) {
t.Skip("Waiting for new api handler implementation")
testCases := []struct {
desc string
staticConf static.Configuration
middles map[string]alice.Constructor
expected map[string]int
}{
{
desc: "API with auth, ping without auth",
desc: "Secure API",
staticConf: static.Configuration{
Global: &static.Global{},
API: &static.API{
// EntryPoint: "traefik",
// 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",
API: &static.API{
Insecure: false,
},
EntryPoints: static.EntryPoints{
"traefik": {},
@ -81,6 +32,21 @@ func TestNewRouteAppenderAggregator(t *testing.T) {
"/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 {
@ -88,11 +54,9 @@ func TestNewRouteAppenderAggregator(t *testing.T) {
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
chainBuilder := &ChainBuilderMock{middles: test.middles}
ctx := context.Background()
router := NewRouteAppenderAggregator(ctx, chainBuilder, test.staticConf, "traefik", nil)
router := NewRouteAppenderAggregator(ctx, test.staticConf, "traefik", nil)
internalMuxRouter := mux.NewRouter()
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/static"
"github.com/containous/traefik/v2/pkg/provider/acme"
"github.com/containous/traefik/v2/pkg/server/middleware"
"github.com/containous/traefik/v2/pkg/types"
)
@ -27,8 +26,8 @@ type RouteAppenderFactory struct {
}
// NewAppender Creates a new RouteAppender
func (r *RouteAppenderFactory) NewAppender(ctx context.Context, middlewaresBuilder *middleware.Builder, runtimeConfiguration *runtime.Configuration) types.RouteAppender {
aggregator := NewRouteAppenderAggregator(ctx, middlewaresBuilder, r.staticConfiguration, r.entryPointName, runtimeConfiguration)
func (r *RouteAppenderFactory) NewAppender(ctx context.Context, runtimeConfiguration *runtime.Configuration) types.RouteAppender {
aggregator := NewRouteAppenderAggregator(ctx, r.staticConfiguration, r.entryPointName, runtimeConfiguration)
for _, p := range r.acmeProvider {
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,
},
})
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)
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
@ -407,7 +407,7 @@ func TestAccessLog(t *testing.T) {
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)
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
@ -693,7 +693,7 @@ func TestRuntimeConfiguration(t *testing.T) {
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)
responseModifierFactory := responsemodifiers.NewBuilder(map[string]*runtime.MiddlewareInfo{})
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
@ -767,7 +767,7 @@ func BenchmarkRouterServe(b *testing.B) {
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)
responseModifierFactory := responsemodifiers.NewBuilder(rtConf.Middlewares)
routerManager := NewManager(rtConf, serviceManager, middlewaresBuilder, responseModifierFactory)
@ -808,7 +808,7 @@ func BenchmarkService(b *testing.B) {
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()
req := testhelpers.MustNewRequest(http.MethodGet, "http://foo.bar/", nil)

View file

@ -9,6 +9,7 @@ import (
"sync"
"time"
"github.com/containous/traefik/v2/pkg/api"
"github.com/containous/traefik/v2/pkg/config/dynamic"
"github.com/containous/traefik/v2/pkg/config/runtime"
"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/provider"
"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/tracing"
"github.com/containous/traefik/v2/pkg/tracing/jaeger"
@ -44,11 +44,13 @@ type Server struct {
requestDecorator *requestdecorator.RequestDecorator
providersThrottleDuration time.Duration
tlsManager *tls.Manager
api func(configuration *runtime.Configuration) http.Handler
restHandler http.Handler
}
// RouteAppenderFactory the route appender factory 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 {
@ -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 {
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.entryPointsTCP = entryPoints
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.
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)
responseModifierFactory := responsemodifiers.NewBuilder(configuration.Middlewares)
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
if factory != nil {
// FIXME remove currentConfigurations
appender := factory.NewAppender(ctx, middlewaresBuilder, configuration)
appender := factory.NewAppender(ctx, configuration)
appender.Append(internalMuxRouter)
}

View file

@ -34,7 +34,7 @@ const (
)
// 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{
routinePool: routinePool,
metricsRegistry: metricsRegistry,
@ -42,6 +42,8 @@ func NewManager(configs map[string]*runtime.ServiceInfo, defaultRoundTripper htt
defaultRoundTripper: defaultRoundTripper,
balancers: make(map[string][]healthcheck.BalancerHandler),
configs: configs,
api: api,
rest: rest,
}
}
@ -53,10 +55,26 @@ type Manager struct {
defaultRoundTripper http.RoundTripper
balancers map[string][]healthcheck.BalancerHandler
configs map[string]*runtime.ServiceInfo
api http.Handler
rest http.Handler
}
// 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) {
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))
serviceName = internal.GetQualifiedName(ctx, serviceName)

View file

@ -80,7 +80,7 @@ func TestGetLoadBalancer(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) {
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.Parallel()
manager := NewManager(test.configs, http.DefaultTransport, nil, nil)
manager := NewManager(test.configs, http.DefaultTransport, nil, nil, nil, nil)
ctx := context.Background()
if len(test.providerName) > 0 {
@ -353,7 +353,7 @@ func TestMultipleTypeOnBuildHTTP(t *testing.T) {
Weighted: &dynamic.WeightedRoundRobin{},
},
},
}, http.DefaultTransport, nil, nil)
}, http.DefaultTransport, nil, nil, nil, 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")

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"`
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"`
EntryPoint string `description:"EntryPoint" export:"true" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"`
}
// SetDefaults sets the default values.
@ -24,6 +25,7 @@ func (p *Prometheus) SetDefaults() {
p.Buckets = []float64{0.1, 0.3, 1.2, 5}
p.AddEntryPointsLabels = true
p.AddServicesLabels = true
p.EntryPoint = "traefik"
}
// Datadog contains address and metrics pushing interval configuration.