Compare commits

...

17 Commits

Author SHA1 Message Date
Tom Moulard
84a0810546 Prepare release v2.6.1 2022-02-14 17:44:08 +01:00
Ludovic Fernandez
d9fbb5e25c Use CNAME for SNI check on host header
Co-authored-by: Julien Salleyron <julien.salleyron@gmail.com>
2022-02-14 17:18:08 +01:00
Ludovic Fernandez
e97aa6515b Update test certificates 2022-02-14 14:08:07 +01:00
luckielordie
6bcfba43c8 Rename Datadog span tags 2022-02-10 16:00:09 +01:00
Ludovic Fernandez
0c83ee736c Apply the same approach as the rules system on the TLS configuration choice
Co-authored-by: Julien Salleyron <julien.salleyron@gmail.com>
2022-02-10 10:42:07 +01:00
Tom Moulard
4da33c2bc2 Fix metrics bucket key high cardinality 2022-02-09 09:58:08 +01:00
Sylvain Rabot
2d56be0ebb Fix Kubernetes TCP examples 2022-02-07 15:22:07 +01:00
Tom Moulard
6742dd8454 Fix mixups in metrics documentation 2022-02-03 15:16:12 +01:00
Vladislav Shub
3ac755bd2f Add Hurricane Electric to acme documentation 2022-01-31 13:30:05 +01:00
Ludovic Fernandez
3ed72c4e46 Add domain to HTTP challenge errors 2022-01-27 10:58:04 +01:00
mpl
477fa15859 Clarify that ACME challenge is mandatory 2022-01-26 18:10:05 +01:00
Manuel Zapf
390eb9cb61 Explain a bit more around enabling HTTP3 2022-01-25 10:48:05 +01:00
Romain
5a1c936ede Prepare release v2.6.0 2022-01-24 17:58:04 +01:00
romain
47ad6538f1 Merge current v2.5 into v2.6 2022-01-24 15:42:27 +01:00
Kevin Pollet
9be44d8330 Configure Consul Catalog namespace at client level
Co-authored-by: Romain <rtribotte@users.noreply.github.com>
2022-01-24 15:30:05 +01:00
Ali
a4b354b33f Redact credentials before logging
Co-authored-by: Tom Moulard <tom.moulard@traefik.io>
Co-authored-by: Mathieu Lonjaret <mathieu.lonjaret@gmail.com>
2022-01-24 11:08:05 +01:00
Philippos Slicher
a70b864c55 Fix typo in metrics overview page 2022-01-21 09:54:07 +01:00
66 changed files with 1880 additions and 615 deletions

View File

@@ -3,11 +3,11 @@ PLEASE READ THIS MESSAGE.
Documentation fixes or enhancements:
- for Traefik v1: use branch v1.7
- for Traefik v2: use branch v2.5
- for Traefik v2: use branch v2.6
Bug fixes:
- for Traefik v1: use branch v1.7
- for Traefik v2: use branch v2.5
- for Traefik v2: use branch v2.6
Enhancements:
- for Traefik v1: we only accept bug fixes

View File

@@ -1,3 +1,67 @@
## [v2.6.1](https://github.com/traefik/traefik/tree/v2.6.1) (2022-02-14)
[All Commits](https://github.com/traefik/traefik/compare/v2.6.0...v2.6.1)
**Bug fixes:**
- **[acme]** Add domain to HTTP challenge errors ([#8740](https://github.com/traefik/traefik/pull/8740) by [ldez](https://github.com/ldez))
- **[metrics]** Fix metrics bucket key high cardinality ([#8761](https://github.com/traefik/traefik/pull/8761) by [tomMoulard](https://github.com/tomMoulard))
- **[middleware,tls]** Use CNAME for SNI check on host header ([#8773](https://github.com/traefik/traefik/pull/8773) by [ldez](https://github.com/ldez))
- **[middleware,tracing]** Rename Datadog span tags ([#8323](https://github.com/traefik/traefik/pull/8323) by [luckielordie](https://github.com/luckielordie))
- **[tls]** Apply the same approach as the rules system on the TLS configuration choice ([#8764](https://github.com/traefik/traefik/pull/8764) by [ldez](https://github.com/ldez))
**Documentation:**
- **[acme]** Add Hurricane Electric to acme documentation ([#8746](https://github.com/traefik/traefik/pull/8746) by [vladshub](https://github.com/vladshub))
- **[acme]** Clarify that ACME challenge is mandatory ([#8739](https://github.com/traefik/traefik/pull/8739) by [mpl](https://github.com/mpl))
- **[http3]** Explain a bit more around enabling HTTP3 ([#8731](https://github.com/traefik/traefik/pull/8731) by [SantoDE](https://github.com/SantoDE))
- **[metrics]** Fix mixups in metrics documentation ([#8752](https://github.com/traefik/traefik/pull/8752) by [tomMoulard](https://github.com/tomMoulard))
- **[middleware,k8s/crd]** Fix Kubernetes TCP examples ([#8759](https://github.com/traefik/traefik/pull/8759) by [sylr](https://github.com/sylr))
## [v2.6.0](https://github.com/traefik/traefik/tree/v2.6.0) (2022-01-24)
[All Commits](https://github.com/traefik/traefik/compare/v2.5.0-rc1...v2.6.0)
**Enhancements:**
- **[acme]** Allow configuration of ACME certificates duration ([#8046](https://github.com/traefik/traefik/pull/8046) by [pmontepagano](https://github.com/pmontepagano))
- **[consul,consulcatalog]** Support consul enterprise namespaces in consul catalog provider ([#8592](https://github.com/traefik/traefik/pull/8592) by [kevinpollet](https://github.com/kevinpollet))
- **[k8s,k8s/gatewayapi]** Update gateway api provider to v1alpha2 ([#8535](https://github.com/traefik/traefik/pull/8535) by [kevinpollet](https://github.com/kevinpollet))
- **[k8s,k8s/gatewayapi]** Support gateway api RouteNamespaces ([#8299](https://github.com/traefik/traefik/pull/8299) by [tomMoulard](https://github.com/tomMoulard))
- **[k8s/crd]** Support Kubernetes basic-auth secrets ([#8189](https://github.com/traefik/traefik/pull/8189) by [dtomcej](https://github.com/dtomcej))
- **[metrics]** Add configurable tags to influxdb metrics ([#8308](https://github.com/traefik/traefik/pull/8308) by [Tetha](https://github.com/Tetha))
- **[metrics]** Add prefix to datadog metrics ([#8234](https://github.com/traefik/traefik/pull/8234) by [fredwangwang](https://github.com/fredwangwang))
- **[middleware,tcp]** Add in flight connection middleware ([#8429](https://github.com/traefik/traefik/pull/8429) by [tomMoulard](https://github.com/tomMoulard))
- **[middleware]** Add Organizational Unit to passtlscert middleware ([#7958](https://github.com/traefik/traefik/pull/7958) by [FernFerret](https://github.com/FernFerret))
- **[middleware]** Allow configuration of minimum body size for compress middleware ([#8239](https://github.com/traefik/traefik/pull/8239) by [lus](https://github.com/lus))
- **[middleware]** Ceil Retry-After value in the rate-limit middleware ([#8581](https://github.com/traefik/traefik/pull/8581) by [pyaillet](https://github.com/pyaillet))
- **[middleware]** Refactor Exponential Backoff ([#7519](https://github.com/traefik/traefik/pull/7519) by [danieladams456](https://github.com/danieladams456))
- **[server,k8s/crd,k8s]** Allow configuration of HTTP/2 readIdleTimeout and pingTimeout ([#8539](https://github.com/traefik/traefik/pull/8539) by [tomMoulard](https://github.com/tomMoulard))
- **[server]** Allow configuration of advertised port for HTTP/3 ([#8131](https://github.com/traefik/traefik/pull/8131) by [valerauko](https://github.com/valerauko))
- **[tracing]** Upgrade Instana tracer and make process profiling configurable ([#8334](https://github.com/traefik/traefik/pull/8334) by [andriikushch](https://github.com/andriikushch))
**Bug fixes:**
- **[consul,kv]** Support Consul KV Enterprise namespaces ([#8692](https://github.com/traefik/traefik/pull/8692) by [kevinpollet](https://github.com/kevinpollet))
- **[consul]** Support token authentication for Consul KV ([#8712](https://github.com/traefik/traefik/pull/8712) by [kevinpollet](https://github.com/kevinpollet))
- **[consulcatalog]** Configure Consul Catalog namespace at client level ([#8725](https://github.com/traefik/traefik/pull/8725) by [kevinpollet](https://github.com/kevinpollet))
- **[tracing]** Upgrade Instana tracer dependency ([#8687](https://github.com/traefik/traefik/pull/8687) by [andriikushch](https://github.com/andriikushch))
- **[logs]** Redact credentials before logging ([#8699](https://github.com/traefik/traefik/pull/8699) by [ibrahimalihc](https://github.com/ibrahimalihc))
**Misc:**
- Merge current v2.5 into v2.6 ([#8720](https://github.com/traefik/traefik/pull/8720) by [tomMoulard](https://github.com/tomMoulard))
- Merge current v2.5 into v2.6 ([#8717](https://github.com/traefik/traefik/pull/8717) by [tomMoulard](https://github.com/tomMoulard))
- Merge current v2.5 into v2.6 ([#8714](https://github.com/traefik/traefik/pull/8714) by [rtribotte](https://github.com/rtribotte))
- Merge current v2.5 into v2.6 ([#8688](https://github.com/traefik/traefik/pull/8688) by [tomMoulard](https://github.com/tomMoulard))
- Merge current v2.5 into v2.6 ([#8664](https://github.com/traefik/traefik/pull/8664) by [tomMoulard](https://github.com/tomMoulard))
- Merge current v2.5 into v2.6 ([#8651](https://github.com/traefik/traefik/pull/8651) by [tomMoulard](https://github.com/tomMoulard))
- Merge current v2.5 into master ([#8645](https://github.com/traefik/traefik/pull/8645) by [tomMoulard](https://github.com/tomMoulard))
- Merge current v2.5 into master ([#8609](https://github.com/traefik/traefik/pull/8609) by [tomMoulard](https://github.com/tomMoulard))
- Merge current v2.5 into master ([#8563](https://github.com/traefik/traefik/pull/8563) by [kevinpollet](https://github.com/kevinpollet))
- Merge current v2.5 into master ([#8498](https://github.com/traefik/traefik/pull/8498) by [kevinpollet](https://github.com/kevinpollet))
- Merge current v2.5 into master ([#8461](https://github.com/traefik/traefik/pull/8461) by [tomMoulard](https://github.com/tomMoulard))
- Merge current v2.5 into master ([#8435](https://github.com/traefik/traefik/pull/8435) by [jbdoumenjou](https://github.com/jbdoumenjou))
- Merge current v2.5 into master ([#8419](https://github.com/traefik/traefik/pull/8419) by [rtribotte](https://github.com/rtribotte))
- Merge current v2.5 into master ([#8411](https://github.com/traefik/traefik/pull/8411) by [rtribotte](https://github.com/rtribotte))
- Merge current v2.5 into master ([#8316](https://github.com/traefik/traefik/pull/8316) by [rtribotte](https://github.com/rtribotte))
- Merge current v2.5 into master ([#8298](https://github.com/traefik/traefik/pull/8298) by [tomMoulard](https://github.com/tomMoulard))
- Merge current v2.5 into master ([#8289](https://github.com/traefik/traefik/pull/8289) by [rtribotte](https://github.com/rtribotte))
- Merge current v2.5 into master ([#8241](https://github.com/traefik/traefik/pull/8241) by [rtribotte](https://github.com/rtribotte))
## [v2.6.0-rc3](https://github.com/traefik/traefik/tree/v2.6.0-rc3) (2022-01-20)
[All Commits](https://github.com/traefik/traefik/compare/v2.6.0-rc2...v2.6.0-rc3)

View File

@@ -191,7 +191,7 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
// Entrypoints
serverEntryPointsTCP, err := server.NewTCPEntryPoints(staticConfiguration.EntryPoints)
serverEntryPointsTCP, err := server.NewTCPEntryPoints(staticConfiguration.EntryPoints, staticConfiguration.HostResolver)
if err != nil {
return nil, err
}

View File

@@ -11,8 +11,8 @@ You can install Traefik with the following flavors:
Choose one of the [official Docker images](https://hub.docker.com/_/traefik) and run it with one sample configuration file:
* [YAML](https://raw.githubusercontent.com/traefik/traefik/v2.5/traefik.sample.yml)
* [TOML](https://raw.githubusercontent.com/traefik/traefik/v2.5/traefik.sample.toml)
* [YAML](https://raw.githubusercontent.com/traefik/traefik/v2.6/traefik.sample.yml)
* [TOML](https://raw.githubusercontent.com/traefik/traefik/v2.6/traefik.sample.toml)
```bash
docker run -d -p 8080:8080 -p 80:80 \

View File

@@ -23,6 +23,8 @@ Certificates are requested for domain names retrieved from the router's [dynamic
You can read more about this retrieval mechanism in the following section: [ACME Domain Definition](#domain-definition).
!!! warning "Defining an [ACME challenge type](#the-different-acme-challenges) is a requirement for a certificate resolver to be functional."
!!! important "Defining a certificates resolver does not result in all routers automatically using it. Each router that is supposed to use the resolver must [reference](../routing/routers/index.md#certresolver) it."
??? note "Configuration Reference"
@@ -158,6 +160,8 @@ When using LetsEncrypt with kubernetes, there are some known caveats with both t
## The Different ACME Challenges
!!! warning "Defining one ACME challenge is a requirement for a certificate resolver to be functional."
!!! important "Defining a certificates resolver does not result in all routers automatically using it. Each router that is supposed to use the resolver must [reference](../routing/routers/index.md#certresolver) it."
### `tlsChallenge`
@@ -329,6 +333,7 @@ For complete details, refer to your provider's _Additional configuration_ link.
| [hosting.de](https://www.hosting.de) | `hostingde` | `HOSTINGDE_API_KEY`, `HOSTINGDE_ZONE_NAME` | [Additional configuration](https://go-acme.github.io/lego/dns/hostingde) |
| [Hosttech](https://www.hosttech.eu) | `hosttech` | `HOSTTECH_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/hosttech) |
| [HyperOne](https://www.hyperone.com) | `hyperone` | `HYPERONE_PASSPORT_LOCATION`, `HYPERONE_LOCATION_ID` | [Additional configuration](https://go-acme.github.io/lego/dns/hyperone) |
| [Hurricane Electric](https://dns.he.net) | `hurricane` | `HURRICANE_TOKENS` [^6] | [Additional configuration](https://go-acme.github.io/lego/dns/hurricane) |
| [IBM Cloud (SoftLayer)](https://www.ibm.com/cloud/) | `ibmcloud` | `SOFTLAYER_USERNAME`, `SOFTLAYER_API_KEY` | [Additional configuration](https://go-acme.github.io/lego/dns/ibmcloud) |
| [IIJ](https://www.iij.ad.jp/) | `iij` | `IIJ_API_ACCESS_KEY`, `IIJ_API_SECRET_KEY`, `IIJ_DO_SERVICE_CODE` | [Additional configuration](https://go-acme.github.io/lego/dns/iij) |
| [Infoblox](https://www.infoblox.com/) | `infoblox` | `INFOBLOX_USER`, `INFOBLOX_PASSWORD`, `INFOBLOX_HOST` | [Additional configuration](https://go-acme.github.io/lego/dns/infoblox) |
@@ -387,11 +392,12 @@ For complete details, refer to your provider's _Additional configuration_ link.
| HTTP request | `httpreq` | `HTTPREQ_ENDPOINT`, `HTTPREQ_MODE`, `HTTPREQ_USERNAME`, `HTTPREQ_PASSWORD` [^1] | [Additional configuration](https://go-acme.github.io/lego/dns/httpreq) |
| manual | `manual` | none, but you need to run Traefik interactively [^4], turn on debug log to see instructions and press <kbd>Enter</kbd>. | |
[^1]: more information about the HTTP message format can be found [here](https://go-acme.github.io/lego/dns/httpreq/)
[^2]: [providing_credentials_to_your_application](https://cloud.google.com/docs/authentication/production)
[^1]: More information about the HTTP message format can be found [here](https://go-acme.github.io/lego/dns/httpreq/).
[^2]: [Providing credentials to your application](https://cloud.google.com/docs/authentication/production).
[^3]: [google/default.go](https://github.com/golang/oauth2/blob/36a7019397c4c86cf59eeab3bc0d188bac444277/google/default.go#L61-L76)
[^4]: `docker stack` remark: there is no way to support terminal attached to container when deploying with `docker stack`, so you might need to run container with `docker run -it` to generate certificates using `manual` provider.
[^5]: The `Global API Key` needs to be used, not the `Origin CA Key`.
[^6]: As explained in the [LEGO hurricane configuration](https://go-acme.github.io/lego/dns/hurricane/#credentials), each domain or wildcard (record name) needs a token. So each update of record name must be followed by an update of the `HURRICANE_TOKENS` variable, and a restart of Traefik.
!!! info "`delayBeforeCheck`"
By default, the `provider` verifies the TXT record _before_ letting ACME verify.

View File

@@ -14,7 +14,7 @@ labels:
```yaml tab="Kubernetes"
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
kind: MiddlewareTCP
metadata:
name: test-inflightconn
spec:

View File

@@ -36,7 +36,7 @@ spec:
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
kind: MiddlewareTCP
metadata:
name: foo-ip-whitelist
spec:
@@ -47,7 +47,7 @@ spec:
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
kind: IngressRouteTCP
metadata:
name: ingressroute
spec:

View File

@@ -426,15 +426,29 @@ Check out the [Errors middleware](../middlewares/http/errorpages.md#service) doc
## v2.5 to v2.6
### HTTP3
### HTTP/3
Traefik v2.6 introduces the `AdvertisedPort` option,
which allows advertising, in the `Alt-Svc` header, a UDP port different from the one on which Traefik is actually listening (the EntryPoint's port).
By doing so, it introduces a new configuration structure `http3`, which replaces the `enableHTTP3` option (which therefore doesn't exist anymore).
To enable HTTP3 on an EntryPoint, please check out the [HTTP3 configuration](../routing/entrypoints.md#http3) documentation.
To enable HTTP/3 on an EntryPoint, please check out the [HTTP/3 configuration](../routing/entrypoints.md#http3) documentation.
### Kubernetes Gateway API Provider
In `v2.6`, the [Kubernetes Gateway API provider](../providers/kubernetes-gateway.md) now only supports the version [v1alpha2](https://gateway-api.sigs.k8s.io/v1alpha2/guides/getting-started/) of the specification and
[route namespaces](https://gateway-api.sigs.k8s.io/v1alpha2/references/spec/#gateway.networking.k8s.io/v1alpha2.RouteNamespaces) selectors, which requires Traefik to fetch and watch the cluster namespaces.
Therefore, the [RBAC](../reference/dynamic-configuration/kubernetes-gateway.md#rbac) and [CRD](../reference/dynamic-configuration/kubernetes-gateway.md#definitions) definitions must be updated.
## v2.6.0 to v2.6.1
### Metrics
In `v2.6.1`, the metrics system does not support any more custom HTTP method verbs to prevent potential metrics cardinality overhead.
In consequence, for metrics having the method label,
if the HTTP method verb of a request is not one defined in the set of common methods for [`HTTP/1.1`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)
or the [`PRI`](https://datatracker.ietf.org/doc/html/rfc7540#section-11.6) verb (for `HTTP/2`),
the value for the method label becomes `EXTENSION_METHOD`, instead of the request's one.
### Tracing
In `v2.6.1`, the Datadog tags added to a span changed from `service.name` to `traefik.service.name` and from `router.name` to `traefik.router.name`.

View File

@@ -118,7 +118,7 @@ metrics:
```toml tab="File (TOML)"
[metrics]
[metrics.datadog]
pushInterval = 10s
pushInterval = "10s"
```
```bash tab="CLI"
@@ -144,5 +144,5 @@ metrics:
```
```bash tab="CLI"
--metrics.datadog.prefix="traefik"
--metrics.datadog.prefix=traefik
```

View File

@@ -69,7 +69,7 @@ InfluxDB database used when protocol is http.
```yaml tab="File (YAML)"
metrics:
influxDB:
database: "db"
database: db
```
```toml tab="File (TOML)"
@@ -91,7 +91,7 @@ InfluxDB retention policy used when protocol is http.
```yaml tab="File (YAML)"
metrics:
influxDB:
retentionPolicy: "two_hours"
retentionPolicy: two_hours
```
```toml tab="File (TOML)"
@@ -113,7 +113,7 @@ InfluxDB username (only with http).
```yaml tab="File (YAML)"
metrics:
influxDB:
username: "john"
username: john
```
```toml tab="File (TOML)"
@@ -135,7 +135,7 @@ InfluxDB password (only with http).
```yaml tab="File (YAML)"
metrics:
influxDB:
password: "secret"
password: secret
```
```toml tab="File (TOML)"
@@ -176,18 +176,18 @@ _Optional, Default=false_
Enable metrics on routers.
```toml tab="File (TOML)"
[metrics]
[metrics.influxDB]
addRoutersLabels = true
```
```yaml tab="File (YAML)"
metrics:
influxDB:
addRoutersLabels: true
```
```toml tab="File (TOML)"
[metrics]
[metrics.influxDB]
addRoutersLabels = true
```
```bash tab="CLI"
--metrics.influxdb.addrouterslabels=true
```
@@ -229,7 +229,7 @@ metrics:
```toml tab="File (TOML)"
[metrics]
[metrics.influxDB]
pushInterval = 10s
pushInterval = "10s"
```
```bash tab="CLI"
@@ -242,14 +242,6 @@ _Optional, Default={}_
Additional labels (influxdb tags) on all metrics.
```toml tab="File (TOML)"
[metrics]
[metrics.influxDB]
[metrics.influxDB.additionalLabels]
host = "example.com"
environment = "production"
```
```yaml tab="File (YAML)"
metrics:
influxDB:
@@ -258,6 +250,14 @@ metrics:
environment: production
```
```toml tab="File (TOML)"
[metrics]
[metrics.influxDB]
[metrics.influxDB.additionalLabels]
host = "example.com"
environment = "production"
```
```bash tab="CLI"
--metrics.influxdb.additionallabels.host=example.com --metrics.influxdb.additionallabels.environment=production
```

View File

@@ -7,23 +7,23 @@ Traefik supports 4 metrics backends:
- [Prometheus](./prometheus.md)
- [StatsD](./statsd.md)
## Server Metrics
## Global Metrics
| Metric | DataDog | InfluxDB | Prometheus | StatsD |
|-------------------------------------------------------------------------|---------|----------|------------|--------|
| [Configuration reloads](#configuration-reloads) | ✓ | ✓ | ✓ | ✓ |
| [Configuration reload failures](#configuration-reload-failures) | ✓ | ✓ | ✓ | ✓ |
| [Last Configuration Reload Success](#last-configuration-reload-success) | ✓ | ✓ | ✓ | ✓ |
| [Last Configuration Reload Failure](#last-configuration-reload-failure) | ✓ | ✓ | ✓ | ✓ |
| [TLS certificates expiration](#tls-certificates-expiration) | ✓ | ✓ | ✓ | ✓ |
### Configuration Reloads
The total count of configuration reloads.
```dd tab="Datadog"
config.reload.total
```
```influxdb tab="InfluDB"
```influxdb tab="InfluxDB"
traefik.config.reload.total
```
@@ -36,34 +36,15 @@ traefik_config_reloads_total
{prefix}.config.reload.total
```
### Configuration Reload Failures
The total count of configuration reload failures.
```dd tab="Datadog"
config.reload.total (with tag "failure" to true)
```
```influxdb tab="InfluDB"
traefik.config.reload.total.failure
```
```prom tab="Prometheus"
traefik_config_reloads_failure_total
```
```statsd tab="StatsD"
# Default prefix: "traefik"
{prefix}.config.reload.total.failure
```
### Last Configuration Reload Success
The timestamp of the last configuration reload success.
```dd tab="Datadog"
config.reload.lastSuccessTimestamp
```
```influxdb tab="InfluDB"
```influxdb tab="InfluxDB"
traefik.config.reload.lastSuccessTimestamp
```
@@ -76,24 +57,27 @@ traefik_config_last_reload_success
{prefix}.config.reload.lastSuccessTimestamp
```
### Last Configuration Reload Failure
The timestamp of the last configuration reload failure.
### TLS certificates expiration
The expiration date of certificates.
[Labels](#labels): `cn`, `sans`, `serial`.
```dd tab="Datadog"
config.reload.lastFailureTimestamp
tls.certs.notAfterTimestamp
```
```influxdb tab="InfluDB"
traefik.config.reload.lastFailureTimestamp
```influxdb tab="InfluxDB"
traefik.tls.certs.notAfterTimestamp
```
```prom tab="Prometheus"
traefik_config_last_reload_failure
traefik_tls_certs_not_after
```
```statsd tab="StatsD"
# Default prefix: "traefik"
{prefix}.config.reload.lastFailureTimestamp
{prefix}.tls.certs.notAfterTimestamp
```
## EntryPoint Metrics
@@ -101,20 +85,21 @@ traefik_config_last_reload_failure
| Metric | DataDog | InfluxDB | Prometheus | StatsD |
|-----------------------------------------------------------|---------|----------|------------|--------|
| [HTTP Requests Count](#http-requests-count) | ✓ | ✓ | ✓ | ✓ |
| [HTTPS Requests Count](#https-requests-count) | | | ✓ | |
| [HTTPS Requests Count](#https-requests-count) | | | ✓ | |
| [Request Duration Histogram](#request-duration-histogram) | ✓ | ✓ | ✓ | ✓ |
| [Open Connections Count](#open-connections-count) | ✓ | ✓ | ✓ | ✓ |
### HTTP Requests Count
The total count of HTTP requests processed on an entrypoint.
Available labels: `code`, `method`, `protocol`, `entrypoint`.
The total count of HTTP requests received by an entrypoint.
[Labels](#labels): `code`, `method`, `protocol`, `entrypoint`.
```dd tab="Datadog"
entrypoint.request.total
```
```influxdb tab="InfluDB"
```influxdb tab="InfluxDB"
traefik.entrypoint.requests.total
```
@@ -128,24 +113,39 @@ traefik_entrypoint_requests_total
```
### HTTPS Requests Count
The total count of HTTPS requests processed on an entrypoint.
Available labels: `tls_version`, `tls_cipher`, `entrypoint`.
The total count of HTTPS requests received by an entrypoint.
[Labels](#labels): `tls_version`, `tls_cipher`, `entrypoint`.
```dd tab="Datadog"
entrypoint.request.tls.total
```
```influxdb tab="InfluxDB"
traefik.entrypoint.requests.tls.total
```
```prom tab="Prometheus"
traefik_entrypoint_requests_tls_total
```
### Request Duration Histogram
Request process time duration histogram on an entrypoint.
```statsd tab="StatsD"
# Default prefix: "traefik"
{prefix}.entrypoint.request.tls.total
```
Available labels: `code`, `method`, `protocol`, `entrypoint`.
### Request Duration Histogram
Request processing duration histogram on an entrypoint.
[Labels](#labels): `code`, `method`, `protocol`, `entrypoint`.
```dd tab="Datadog"
entrypoint.request.duration
```
```influxdb tab="InfluDB"
```influxdb tab="InfluxDB"
traefik.entrypoint.request.duration
```
@@ -159,15 +159,16 @@ traefik_entrypoint_request_duration_seconds
```
### Open Connections Count
The current count of open connections on an entrypoint.
Available labels: `method`, `protocol`, `entrypoint`.
[Labels](#labels): `method`, `protocol`, `entrypoint`.
```dd tab="Datadog"
entrypoint.connections.open
```
```influxdb tab="InfluDB"
```influxdb tab="InfluxDB"
traefik.entrypoint.connections.open
```
@@ -180,27 +181,129 @@ traefik_entrypoint_open_connections
{prefix}.entrypoint.connections.open
```
## Service Metrics
## Router Metrics
| Metric | DataDog | InfluxDB | Prometheus | StatsD |
|-------------------------------------------------------------|---------|----------|------------|--------|
| [HTTP Requests Count](#http-requests-count_1) | ✓ | ✓ | ✓ | ✓ |
| [HTTPS Requests Count](#https-requests-count_1) | | | ✓ | |
| [HTTPS Requests Count](#https-requests-count_1) | | | ✓ | |
| [Request Duration Histogram](#request-duration-histogram_1) | ✓ | ✓ | ✓ | ✓ |
| [Open Connections Count](#open-connections-count_1) | ✓ | ✓ | ✓ | ✓ |
### HTTP Requests Count
The total count of HTTP requests handled by a router.
[Labels](#labels): `code`, `method`, `protocol`, `router`, `service`.
```dd tab="Datadog"
router.request.total
```
```influxdb tab="InfluxDB"
traefik.router.requests.total
```
```prom tab="Prometheus"
traefik_router_requests_total
```
```statsd tab="StatsD"
# Default prefix: "traefik"
{prefix}.router.request.total
```
### HTTPS Requests Count
The total count of HTTPS requests handled by a router.
[Labels](#labels): `tls_version`, `tls_cipher`, `router`, `service`.
```dd tab="Datadog"
router.request.tls.total
```
```influxdb tab="InfluxDB"
traefik.router.requests.tls.total
```
```prom tab="Prometheus"
traefik_router_requests_tls_total
```
```statsd tab="StatsD"
# Default prefix: "traefik"
{prefix}.router.request.tls.total
```
### Request Duration Histogram
Request processing duration histogram on a router.
[Labels](#labels): `code`, `method`, `protocol`, `router`, `service`.
```dd tab="Datadog"
router.request.duration
```
```influxdb tab="InfluxDB"
traefik.router.request.duration
```
```prom tab="Prometheus"
traefik_router_request_duration_seconds
```
```statsd tab="StatsD"
# Default prefix: "traefik"
{prefix}.router.request.duration
```
### Open Connections Count
The current count of open connections on a router.
[Labels](#labels): `method`, `protocol`, `router`, `service`.
```dd tab="Datadog"
router.connections.open
```
```influxdb tab="InfluxDB"
traefik.router.connections.open
```
```prom tab="Prometheus"
traefik_router_open_connections
```
```statsd tab="StatsD"
# Default prefix: "traefik"
{prefix}.router.connections.open
```
## Service Metrics
| Metric | DataDog | InfluxDB | Prometheus | StatsD |
|-------------------------------------------------------------|---------|----------|------------|--------|
| [HTTP Requests Count](#http-requests-count_2) | ✓ | ✓ | ✓ | ✓ |
| [HTTPS Requests Count](#https-requests-count_2) | ✓ | ✓ | ✓ | ✓ |
| [Request Duration Histogram](#request-duration-histogram_2) | ✓ | ✓ | ✓ | ✓ |
| [Open Connections Count](#open-connections-count_2) | ✓ | ✓ | ✓ | ✓ |
| [Requests Retries Count](#requests-retries-count) | ✓ | ✓ | ✓ | ✓ |
| [Service Server UP](#service-server-up) | ✓ | ✓ | ✓ | ✓ |
### HTTP Requests Count
The total count of HTTP requests processed on a service.
Available labels: `code`, `method`, `protocol`, `service`.
[Labels](#labels): `code`, `method`, `protocol`, `service`.
```dd tab="Datadog"
service.request.total
```
```influxdb tab="InfluDB"
```influxdb tab="InfluxDB"
traefik.service.requests.total
```
@@ -214,24 +317,39 @@ traefik_service_requests_total
```
### HTTPS Requests Count
The total count of HTTPS requests processed on a service.
Available labels: `tls_version`, `tls_cipher`, `service`.
[Labels](#labels): `tls_version`, `tls_cipher`, `service`.
```dd tab="Datadog"
router.service.tls.total
```
```influxdb tab="InfluxDB"
traefik.service.requests.tls.total
```
```prom tab="Prometheus"
traefik_service_requests_tls_total
```
### Request Duration Histogram
Request process time duration histogram on a service.
```statsd tab="StatsD"
# Default prefix: "traefik"
{prefix}.service.request.tls.total
```
Available labels: `code`, `method`, `protocol`, `service`.
### Request Duration Histogram
Request processing duration histogram on a service.
[Labels](#labels): `code`, `method`, `protocol`, `service`.
```dd tab="Datadog"
service.request.duration
```
```influxdb tab="InfluDB"
```influxdb tab="InfluxDB"
traefik.service.request.duration
```
@@ -245,15 +363,16 @@ traefik_service_request_duration_seconds
```
### Open Connections Count
The current count of open connections on a service.
Available labels: `method`, `protocol`, `service`.
[Labels](#labels): `method`, `protocol`, `service`.
```dd tab="Datadog"
service.connections.open
```
```influxdb tab="InfluDB"
```influxdb tab="InfluxDB"
traefik.service.connections.open
```
@@ -267,15 +386,16 @@ traefik_service_open_connections
```
### Requests Retries Count
The count of requests retries on a service.
Available labels: `service`.
[Labels](#labels): `service`.
```dd tab="Datadog"
service.retries.total
```
```influxdb tab="InfluDB"
```influxdb tab="InfluxDB"
traefik.service.retries.total
```
@@ -289,15 +409,16 @@ traefik_service_retries_total
```
### Service Server UP
Current service's server status, described by a gauge with a value of 0 for a down server or a value of 1 for an up server.
Available labels: `service`, `url`.
[Labels](#labels): `service`, `url`.
```dd tab="Datadog"
service.server.up
```
```influxdb tab="InfluDB"
```influxdb tab="InfluxDB"
traefik.service.server.up
```
@@ -309,3 +430,28 @@ traefik_service_server_up
# Default prefix: "traefik"
{prefix}.service.server.up
```
## Labels
Here is a comprehensive list of labels that are provided by the metrics:
| Label | Description | example |
|---------------|---------------------------------------|----------------------------|
| `cn` | Certificate Common Name | "example.com" |
| `code` | Request code | "200" |
| `entrypoint` | Entrypoint that handled the request | "example_entrypoint" |
| `method` | Request Method | "GET" |
| `protocol` | Request protocol | "http" |
| `router` | Router that handled the request | "example_router" |
| `sans` | Certificate Subject Alternative NameS | "example.com" |
| `serial` | Certificate Serial Number | "123..." |
| `service` | Service that handled the request | "example_service@provider" |
| `tls_cipher` | TLS cipher used for the request | "TLS_FALLBACK_SCSV" |
| `tls_version` | TLS version used for the request | "1.0" |
| `url` | Service server url | "http://example.com" |
!!! info "`method` label value"
If the HTTP method verb on a request is not one defined in the set of common methods for [`HTTP/1.1`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)
or the [`PRI`](https://datatracker.ietf.org/doc/html/rfc7540#section-11.6) verb (for `HTTP/2`),
then the value for the method label becomes `EXTENSION_METHOD`.

View File

@@ -39,7 +39,7 @@ metrics:
```
```bash tab="CLI"
--metrics.prometheus.buckets=0.100000, 0.300000, 1.200000, 5.000000
--metrics.prometheus.buckets=0.1,0.3,1.2,5.0
```
#### `addEntryPointsLabels`
@@ -70,18 +70,18 @@ _Optional, Default=false_
Enable metrics on routers.
```toml tab="File (TOML)"
[metrics]
[metrics.prometheus]
addRoutersLabels = true
```
```yaml tab="File (YAML)"
metrics:
prometheus:
addRoutersLabels: true
```
```toml tab="File (TOML)"
[metrics]
[metrics.prometheus]
addRoutersLabels = true
```
```bash tab="CLI"
--metrics.prometheus.addrouterslabels=true
```
@@ -117,7 +117,7 @@ Entry point used to expose metrics.
```yaml tab="File (YAML)"
entryPoints:
metrics:
address: ":8082"
address: :8082
metrics:
prometheus:

View File

@@ -66,18 +66,18 @@ _Optional, Default=false_
Enable metrics on entry points.
```toml tab="File (TOML)"
[metrics]
[metrics.statsD]
addRoutersLabels = true
```
```yaml tab="File (YAML)"
metrics:
statsD:
addRoutersLabels: true
```
```toml tab="File (TOML)"
[metrics]
[metrics.statsD]
addRoutersLabels = true
```
```bash tab="CLI"
--metrics.statsd.addrouterslabels=true
```
@@ -119,7 +119,7 @@ metrics:
```toml tab="File (TOML)"
[metrics]
[metrics.statsD]
pushInterval = 10s
pushInterval = "10s"
```
```bash tab="CLI"
@@ -145,5 +145,5 @@ metrics:
```
```bash tab="CLI"
--metrics.statsd.prefix="traefik"
--metrics.statsd.prefix=traefik
```

View File

@@ -493,4 +493,4 @@ providers:
### Further
To learn more about the various aspects of the Ingress specification that Traefik supports,
many examples of Ingresses definitions are located in the test [examples](https://github.com/traefik/traefik/tree/v2.5/pkg/provider/kubernetes/ingress/fixtures) of the Traefik repository.
many examples of Ingresses definitions are located in the test [examples](https://github.com/traefik/traefik/tree/v2.6/pkg/provider/kubernetes/ingress/fixtures) of the Traefik repository.

View File

@@ -223,22 +223,22 @@ If both TCP and UDP are wanted for the same port, two entryPoints definitions ar
Full details for how to specify `address` can be found in [net.Listen](https://golang.org/pkg/net/#Listen) (and [net.Dial](https://golang.org/pkg/net/#Dial)) of the doc for go.
### HTTP3
### HTTP/3
#### `http3`
`http3` enables HTTP3 protocol on the entryPoint.
You can only enable HTTP3 on a TCP entrypoint.
Enabling HTTP3 will automatically add the correct headers for the connection upgrade to HTTP3.
`http3` enables HTTP/3 protocol on the entryPoint.
HTTP/3 requires a TCP entryPoint, as HTTP/3 always starts as a TCP connection that then gets upgraded to UDP.
In most scenarios, this entryPoint is the same as the one used for TLS traffic.
??? info "HTTP3 uses UDP+TLS"
??? info "HTTP/3 uses UDP+TLS"
As HTTP3 uses UDP, you can't have a TCP entrypoint with HTTP3 on the same port as a UDP entrypoint.
Since HTTP3 requires the use of TLS, only routers with TLS enabled will be usable with HTTP3.
As HTTP/3 uses UDP, you can't have a TCP entryPoint with HTTP/3 on the same port as a UDP entryPoint.
Since HTTP/3 requires the use of TLS, only routers with TLS enabled will be usable with HTTP/3.
!!! warning "Enabling Experimental HTTP3"
!!! warning "Enabling Experimental HTTP/3"
As the HTTP3 spec is still in draft, HTTP3 support in Traefik is an experimental feature and needs to be activated
As the HTTP/3 spec is still in draft, HTTP/3 support in Traefik is an experimental feature and needs to be activated
in the experimental section of the static configuration.
```yaml tab="File (YAML)"
@@ -263,8 +263,8 @@ Enabling HTTP3 will automatically add the correct headers for the connection upg
#### `advertisedPort`
`http3.advertisedPort` defines which UDP port to advertise as the HTTP3 authority.
It defaults to the entrypoint's address port.
`http3.advertisedPort` defines which UDP port to advertise as the HTTP/3 authority.
It defaults to the entryPoint's address port.
It can be used to override the authority in the `alt-svc` header, for example if the public facing port is different from where Traefik is listening.
!!! info "http3.advertisedPort"

View File

@@ -22,7 +22,7 @@ find "${PATH_TO_SITE}" -type f -not -path "/app/site/theme/*" \
--alt_ignore="/traefikproxy-vertical-logo-color.svg/" \
--http_status_ignore="0,500,501,503" \
--file_ignore="/404.html/" \
--url_ignore="/https://groups.google.com/a/traefik.io/forum/#!forum/security/,/localhost:/,/127.0.0.1:/,/fonts.gstatic.com/,/.minikube/,/github.com\/traefik\/traefik\/*edit*/,/github.com\/traefik\/traefik/,/doc.traefik.io/,/github\.com\/golang\/oauth2\/blob\/36a7019397c4c86cf59eeab3bc0d188bac444277\/.+/,/www.akamai.com/,/pilot.traefik.io\/profile/,/traefik.io/,/doc.traefik.io\/traefik-mesh/,/www.mkdocs.org/,/squidfunk.github.io/,/ietf.org/,/www.namesilo.com/,/www.youtube.com/,/www.linode.com/,/www.alibabacloud.com/,/www.cloudxns.net/" \
--url_ignore="/https://groups.google.com/a/traefik.io/forum/#!forum/security/,/localhost:/,/127.0.0.1:/,/fonts.gstatic.com/,/.minikube/,/github.com\/traefik\/traefik\/*edit*/,/github.com\/traefik\/traefik/,/doc.traefik.io/,/github\.com\/golang\/oauth2\/blob\/36a7019397c4c86cf59eeab3bc0d188bac444277\/.+/,/www.akamai.com/,/pilot.traefik.io\/profile/,/traefik.io/,/doc.traefik.io\/traefik-mesh/,/www.mkdocs.org/,/squidfunk.github.io/,/ietf.org/,/www.namesilo.com/,/www.youtube.com/,/www.linode.com/,/www.alibabacloud.com/,/www.cloudxns.net/,/www.vultr.com/,/vscale.io/" \
'{}' 1>/dev/null
## HTML-proofer options at https://github.com/gjtorikian/html-proofer#configuration

View File

@@ -9,18 +9,24 @@
# Use certificate in net/internal/testcert.go
rootCAs = [ """
-----BEGIN CERTIFICATE-----
MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS
MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4
iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul
rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO
BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw
AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA
AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9
tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs
h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM
fblo6RBxUQ==
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r
bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U
aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P
YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk
POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu
h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE
AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv
bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI
5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv
cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2
+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B
grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK
5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/
WkBKOclmOV2xlTVuPw==
-----END CERTIFICATE-----
"""]

View File

@@ -1,14 +1,20 @@
-----BEGIN CERTIFICATE-----
MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS
MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4
iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul
rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO
BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw
AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA
AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9
tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs
h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM
fblo6RBxUQ==
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r
bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U
aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P
YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk
POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu
h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE
AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv
bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI
5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv
cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2
+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B
grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK
5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/
WkBKOclmOV2xlTVuPw==
-----END CERTIFICATE-----

View File

@@ -1,177 +0,0 @@
package anonymize
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type Courgette struct {
Ji string
Ho string
}
type Tomate struct {
Ji string
Ho string
}
type Carotte struct {
Name string
Value int
List []string
EList []string `export:"true"`
Courgette Courgette
ECourgette Courgette `export:"true"`
Pourgette *Courgette
EPourgette *Courgette `export:"true"`
Aubergine map[string]string
EAubergine map[string]string `export:"true"`
SAubergine map[string]Tomate
ESAubergine map[string]Tomate `export:"true"`
PSAubergine map[string]*Tomate
EPAubergine map[string]*Tomate `export:"true"`
}
func Test_doOnStruct(t *testing.T) {
testCase := []struct {
name string
base *Carotte
expected *Carotte
}{
{
name: "primitive",
base: &Carotte{
Name: "koko",
Value: 666,
List: []string{"test"},
EList: []string{"test"},
},
expected: &Carotte{
Name: "xxxx",
List: []string{"xxxx"},
EList: []string{"test"},
},
},
{
name: "struct",
base: &Carotte{
Name: "koko",
Courgette: Courgette{
Ji: "huu",
},
},
expected: &Carotte{
Name: "xxxx",
},
},
{
name: "pointer",
base: &Carotte{
Name: "koko",
Pourgette: &Courgette{
Ji: "hoo",
},
},
expected: &Carotte{
Name: "xxxx",
Pourgette: nil,
},
},
{
name: "export struct",
base: &Carotte{
Name: "koko",
ECourgette: Courgette{
Ji: "huu",
},
},
expected: &Carotte{
Name: "xxxx",
ECourgette: Courgette{
Ji: "xxxx",
},
},
},
{
name: "export pointer struct",
base: &Carotte{
Name: "koko",
ECourgette: Courgette{
Ji: "huu",
},
},
expected: &Carotte{
Name: "xxxx",
ECourgette: Courgette{
Ji: "xxxx",
},
},
},
{
name: "export map string/string",
base: &Carotte{
Name: "koko",
EAubergine: map[string]string{
"foo": "bar",
},
},
expected: &Carotte{
Name: "xxxx",
EAubergine: map[string]string{
"foo": "bar",
},
},
},
{
name: "export map string/pointer",
base: &Carotte{
Name: "koko",
EPAubergine: map[string]*Tomate{
"foo": {
Ji: "fdskljf",
},
},
},
expected: &Carotte{
Name: "xxxx",
EPAubergine: map[string]*Tomate{
"foo": {
Ji: "xxxx",
},
},
},
},
{
name: "export map string/struct",
base: &Carotte{
Name: "koko",
ESAubergine: map[string]Tomate{
"foo": {
Ji: "JiJiJi",
},
},
},
expected: &Carotte{
Name: "xxxx",
ESAubergine: map[string]Tomate{
"foo": {
Ji: "xxxx",
},
},
},
},
}
for _, test := range testCase {
t.Run(test.name, func(t *testing.T) {
val := reflect.ValueOf(test.base).Elem()
err := doOnStruct(val)
require.NoError(t, err)
assert.EqualValues(t, test.expected, test.base)
})
}
}

View File

@@ -10,9 +10,9 @@ import (
"time"
"github.com/mitchellh/hashstructure"
"github.com/traefik/traefik/v2/pkg/anonymize"
"github.com/traefik/traefik/v2/pkg/config/static"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/redactor"
"github.com/traefik/traefik/v2/pkg/version"
)
@@ -30,7 +30,7 @@ type data struct {
// Collect anonymous data.
func Collect(staticConfiguration *static.Configuration) error {
anonConfig, err := anonymize.Do(staticConfiguration, false)
anonConfig, err := redactor.Anonymize(staticConfiguration)
if err != nil {
return err
}

View File

@@ -64,7 +64,7 @@ type AddPrefix struct {
// BasicAuth holds the HTTP basic authentication configuration.
type BasicAuth struct {
Users Users `json:"users,omitempty" toml:"users,omitempty" yaml:"users,omitempty"`
Users Users `json:"users,omitempty" toml:"users,omitempty" yaml:"users,omitempty" loggable:"false"`
UsersFile string `json:"usersFile,omitempty" toml:"usersFile,omitempty" yaml:"usersFile,omitempty"`
Realm string `json:"realm,omitempty" toml:"realm,omitempty" yaml:"realm,omitempty"`
RemoveHeader bool `json:"removeHeader,omitempty" toml:"removeHeader,omitempty" yaml:"removeHeader,omitempty" export:"true"`
@@ -108,7 +108,7 @@ type Compress struct {
// DigestAuth holds the Digest HTTP authentication configuration.
type DigestAuth struct {
Users Users `json:"users,omitempty" toml:"users,omitempty" yaml:"users,omitempty"`
Users Users `json:"users,omitempty" toml:"users,omitempty" yaml:"users,omitempty" loggable:"false"`
UsersFile string `json:"usersFile,omitempty" toml:"usersFile,omitempty" yaml:"usersFile,omitempty"`
RemoveHeader bool `json:"removeHeader,omitempty" toml:"removeHeader,omitempty" yaml:"removeHeader,omitempty" export:"true"`
Realm string `json:"realm,omitempty" toml:"realm,omitempty" yaml:"realm,omitempty"`

View File

@@ -2,7 +2,7 @@ package static
// Pilot Configuration related to Traefik Pilot.
type Pilot struct {
Token string `description:"Traefik Pilot token." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty"`
Token string `description:"Traefik Pilot token." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
Dashboard bool `description:"Enable Traefik Pilot in the dashboard." json:"dashboard,omitempty" toml:"dashboard,omitempty" yaml:"dashboard,omitempty"`
}

View File

@@ -106,7 +106,7 @@ type API struct {
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
// Statistics *types.Statistics `description:"Enable more detailed statistics." json:"statistics,omitempty" toml:"statistics,omitempty" yaml:"statistics,omitempty" export:"true" label:"allowEmpty" file:"allowEmpty"`
// Statistics *types.Statistics `description:"Enable more detailed statistics." json:"statistics,omitempty" toml:"statistics,omitempty" yaml:"statistics,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`
}
// SetDefaults sets the default values.

View File

@@ -159,12 +159,27 @@ func containsHeader(req *http.Request, name, value string) bool {
return false
}
// getMethod returns the request's method.
// It checks whether the method is a valid UTF-8 string.
// To restrict the (potentially infinite) number of accepted values for the method,
// and avoid unbounded memory issues,
// values that are not part of the set of HTTP verbs are replaced with EXTENSION_METHOD.
// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods
// https://datatracker.ietf.org/doc/html/rfc2616/#section-5.1.1.
func getMethod(r *http.Request) string {
if !utf8.ValidString(r.Method) {
log.Warnf("Invalid HTTP method encoding: %s", r.Method)
log.WithoutContext().Warnf("Invalid HTTP method encoding: %s", r.Method)
return "NON_UTF8_HTTP_METHOD"
}
return r.Method
switch r.Method {
case "HEAD", "GET", "POST", "PUT", "DELETE", "CONNECT", "OPTIONS", "TRACE", // https://datatracker.ietf.org/doc/html/rfc7231#section-4
"PATCH", // https://datatracker.ietf.org/doc/html/rfc5789#section-2
"PRI": // https://datatracker.ietf.org/doc/html/rfc7540#section-11.6
return r.Method
default:
return "EXTENSION_METHOD"
}
}
type retryMetrics interface {

View File

@@ -4,6 +4,7 @@ import (
"net/http"
"net/http/httptest"
"reflect"
"strings"
"testing"
"github.com/go-kit/kit/metrics"
@@ -98,3 +99,33 @@ func TestCloseNotifier(t *testing.T) {
})
}
}
func Test_getMethod(t *testing.T) {
testCases := []struct {
method string
expected string
}{
{
method: http.MethodGet,
expected: http.MethodGet,
},
{
method: strings.ToLower(http.MethodGet),
expected: "EXTENSION_METHOD",
},
{
method: "THIS_IS_NOT_A_VALID_METHOD",
expected: "EXTENSION_METHOD",
},
}
for _, test := range testCases {
test := test
t.Run(test.method, func(t *testing.T) {
t.Parallel()
request := httptest.NewRequest(test.method, "http://example.com", nil)
assert.Equal(t, test.expected, getMethod(request))
})
}
}

View File

@@ -0,0 +1,107 @@
package snicheck
import (
"net"
"net/http"
"strings"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/middlewares/requestdecorator"
traefiktls "github.com/traefik/traefik/v2/pkg/tls"
)
// SNICheck is an HTTP handler that checks whether the TLS configuration for the server name is the same as for the host header.
type SNICheck struct {
next http.Handler
tlsOptionsForHost map[string]string
}
// New creates a new SNICheck.
func New(tlsOptionsForHost map[string]string, next http.Handler) *SNICheck {
return &SNICheck{next: next, tlsOptionsForHost: tlsOptionsForHost}
}
func (s SNICheck) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
if req.TLS == nil {
s.next.ServeHTTP(rw, req)
return
}
host := getHost(req)
serverName := strings.TrimSpace(req.TLS.ServerName)
// Domain Fronting
if !strings.EqualFold(host, serverName) {
tlsOptionHeader := findTLSOptionName(s.tlsOptionsForHost, host, true)
tlsOptionSNI := findTLSOptionName(s.tlsOptionsForHost, serverName, false)
if tlsOptionHeader != tlsOptionSNI {
log.WithoutContext().
WithField("host", host).
WithField("req.Host", req.Host).
WithField("req.TLS.ServerName", req.TLS.ServerName).
Debugf("TLS options difference: SNI:%s, Header:%s", tlsOptionSNI, tlsOptionHeader)
http.Error(rw, http.StatusText(http.StatusMisdirectedRequest), http.StatusMisdirectedRequest)
return
}
}
s.next.ServeHTTP(rw, req)
}
func getHost(req *http.Request) string {
h := requestdecorator.GetCNAMEFlatten(req.Context())
if h != "" {
return h
}
h = requestdecorator.GetCanonizedHost(req.Context())
if h != "" {
return h
}
host, _, err := net.SplitHostPort(req.Host)
if err != nil {
host = req.Host
}
return strings.TrimSpace(host)
}
func findTLSOptionName(tlsOptionsForHost map[string]string, host string, fqdn bool) string {
name := findTLSOptName(tlsOptionsForHost, host, fqdn)
if name != "" {
return name
}
name = findTLSOptName(tlsOptionsForHost, strings.ToLower(host), fqdn)
if name != "" {
return name
}
return traefiktls.DefaultTLSConfigName
}
func findTLSOptName(tlsOptionsForHost map[string]string, host string, fqdn bool) string {
if tlsOptions, ok := tlsOptionsForHost[host]; ok {
return tlsOptions
}
if !fqdn {
return ""
}
if last := len(host) - 1; last >= 0 && host[last] == '.' {
if tlsOptions, ok := tlsOptionsForHost[host[:last]]; ok {
return tlsOptions
}
return ""
}
if tlsOptions, ok := tlsOptionsForHost[host+"."]; ok {
return tlsOptions
}
return ""
}

View File

@@ -0,0 +1,60 @@
package snicheck
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/stretchr/testify/assert"
)
func TestSNICheck_ServeHTTP(t *testing.T) {
testCases := []struct {
desc string
tlsOptionsForHost map[string]string
host string
expected int
}{
{
desc: "no TLS options",
expected: http.StatusOK,
},
{
desc: "with TLS options",
tlsOptionsForHost: map[string]string{
"example.com": "foo",
},
expected: http.StatusOK,
},
{
desc: "server name and host doesn't have the same TLS configuration",
tlsOptionsForHost: map[string]string{
"example.com": "foo",
},
host: "example.com",
expected: http.StatusMisdirectedRequest,
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
next := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {})
sniCheck := New(test.tlsOptionsForHost, next)
req := httptest.NewRequest(http.MethodGet, "https://localhost", nil)
if test.host != "" {
req.Host = test.host
}
recorder := httptest.NewRecorder()
sniCheck.ServeHTTP(recorder, req)
assert.Equal(t, test.expected, recorder.Code)
})
}
}

View File

@@ -43,8 +43,8 @@ func (f *forwarderMiddleware) ServeHTTP(rw http.ResponseWriter, req *http.Reques
span, req, finish := tr.StartSpanf(req, ext.SpanKindRPCClientEnum, "forward", opParts, "/")
defer finish()
span.SetTag("service.name", f.service)
span.SetTag("router.name", f.router)
span.SetTag("traefik.service.name", f.service)
span.SetTag("traefik.router.name", f.router)
ext.HTTPMethod.Set(span, req.Method)
ext.HTTPUrl.Set(span, req.URL.String())
span.SetTag("http.host", req.Host)

View File

@@ -36,12 +36,12 @@ func TestNewForwarder(t *testing.T) {
router: "some-service.domain.tld",
expected: expected{
Tags: map[string]interface{}{
"http.host": "www.test.com",
"http.method": "GET",
"http.url": "http://www.test.com/toto",
"service.name": "some-service.domain.tld",
"router.name": "some-service.domain.tld",
"span.kind": ext.SpanKindRPCClientEnum,
"http.host": "www.test.com",
"http.method": "GET",
"http.url": "http://www.test.com/toto",
"traefik.service.name": "some-service.domain.tld",
"traefik.router.name": "some-service.domain.tld",
"span.kind": ext.SpanKindRPCClientEnum,
},
OperationName: "forward some-service.domain.tld/some-service.domain.tld",
},
@@ -56,12 +56,12 @@ func TestNewForwarder(t *testing.T) {
router: "some-service-100.slug.namespace.environment.domain.tld",
expected: expected{
Tags: map[string]interface{}{
"http.host": "www.test.com",
"http.method": "GET",
"http.url": "http://www.test.com/toto",
"service.name": "some-service-100.slug.namespace.environment.domain.tld",
"router.name": "some-service-100.slug.namespace.environment.domain.tld",
"span.kind": ext.SpanKindRPCClientEnum,
"http.host": "www.test.com",
"http.method": "GET",
"http.url": "http://www.test.com/toto",
"traefik.service.name": "some-service-100.slug.namespace.environment.domain.tld",
"traefik.router.name": "some-service-100.slug.namespace.environment.domain.tld",
"span.kind": ext.SpanKindRPCClientEnum,
},
OperationName: "forward some-service-100.slug.namespace.enviro.../some-service-100.slug.namespace.enviro.../bc4a0d48",
},
@@ -76,12 +76,12 @@ func TestNewForwarder(t *testing.T) {
router: "some-service1.namespace.environment.domain.tld",
expected: expected{
Tags: map[string]interface{}{
"http.host": "www.test.com",
"http.method": "GET",
"http.url": "http://www.test.com/toto",
"service.name": "some-service1.namespace.environment.domain.tld",
"router.name": "some-service1.namespace.environment.domain.tld",
"span.kind": ext.SpanKindRPCClientEnum,
"http.host": "www.test.com",
"http.method": "GET",
"http.url": "http://www.test.com/toto",
"traefik.service.name": "some-service1.namespace.environment.domain.tld",
"traefik.router.name": "some-service1.namespace.environment.domain.tld",
"span.kind": ext.SpanKindRPCClientEnum,
},
OperationName: "forward some-service1.namespace.environment.domain.tld/some-service1.namespace.environment.domain.tld",
},
@@ -96,12 +96,12 @@ func TestNewForwarder(t *testing.T) {
router: "some-service1.backend.namespace.environment.domain.tld",
expected: expected{
Tags: map[string]interface{}{
"http.host": "www.test.com",
"http.method": "GET",
"http.url": "http://www.test.com/toto",
"service.name": "some-service1.frontend.namespace.environment.domain.tld",
"router.name": "some-service1.backend.namespace.environment.domain.tld",
"span.kind": ext.SpanKindRPCClientEnum,
"http.host": "www.test.com",
"http.method": "GET",
"http.url": "http://www.test.com/toto",
"traefik.service.name": "some-service1.frontend.namespace.environment.domain.tld",
"traefik.router.name": "some-service1.backend.namespace.environment.domain.tld",
"span.kind": ext.SpanKindRPCClientEnum,
},
OperationName: "forward some-service1.frontend.namespace.envir.../some-service1.backend.namespace.enviro.../fa49dd23",
},

View File

@@ -11,10 +11,10 @@ import (
"time"
"github.com/cenkalti/backoff/v4"
"github.com/traefik/traefik/v2/pkg/anonymize"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/metrics"
"github.com/traefik/traefik/v2/pkg/redactor"
"github.com/traefik/traefik/v2/pkg/safe"
"github.com/traefik/traefik/v2/pkg/version"
)
@@ -173,7 +173,7 @@ func (c *client) createUUID() (string, error) {
// SendAnonDynConf sends anonymized dynamic configuration to Pilot.
func (c *client) SendAnonDynConf(ctx context.Context, config dynamic.Configuration) error {
anonConfig, err := anonymize.Do(&config, false)
anonConfig, err := redactor.Anonymize(&config)
if err != nil {
return fmt.Errorf("unable to anonymize dynamic configuration: %w", err)
}

View File

@@ -8,7 +8,7 @@ import (
// Handler expose ping routes.
type Handler struct {
EntryPoint string `description:"EntryPoint" export:"true" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty"`
EntryPoint string `description:"EntryPoint" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty" export:"true"`
ManualRouting bool `description:"Manual routing" json:"manualRouting,omitempty" toml:"manualRouting,omitempty" yaml:"manualRouting,omitempty" export:"true"`
TerminatingStatusCode int `description:"Terminating status code" json:"terminatingStatusCode,omitempty" toml:"terminatingStatusCode,omitempty" yaml:"terminatingStatusCode,omitempty" export:"true"`
terminating bool

View File

@@ -103,7 +103,7 @@ func (c *ChallengeHTTP) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
func (c *ChallengeHTTP) getTokenValue(ctx context.Context, token, domain string) []byte {
logger := log.FromContext(ctx)
logger.Debugf("Retrieving the ACME challenge for token %s...", token)
logger.Debugf("Retrieving the ACME challenge for %s (token %q)...", domain, token)
var result []byte
@@ -112,13 +112,13 @@ func (c *ChallengeHTTP) getTokenValue(ctx context.Context, token, domain string)
defer c.lock.RUnlock()
if _, ok := c.httpChallenges[token]; !ok {
return fmt.Errorf("cannot find challenge for token %s", token)
return fmt.Errorf("cannot find challenge for token %q (%s)", token, domain)
}
var ok bool
result, ok = c.httpChallenges[token][domain]
if !ok {
return fmt.Errorf("cannot find challenge for domain %s", domain)
return fmt.Errorf("cannot find challenge for %s (token %q)", domain, token)
}
return nil
@@ -132,7 +132,7 @@ func (c *ChallengeHTTP) getTokenValue(ctx context.Context, token, domain string)
ebo.MaxElapsedTime = 60 * time.Second
err := backoff.RetryNotify(safe.OperationWithRecover(operation), ebo, notify)
if err != nil {
logger.Errorf("Cannot retrieve the ACME challenge for token %v: %v", token, err)
logger.Errorf("Cannot retrieve the ACME challenge for %s (token %q): %v", domain, token, err)
return []byte{}
}

View File

@@ -69,8 +69,8 @@ type Certificate struct {
// EAB contains External Account Binding configuration.
type EAB struct {
Kid string `description:"Key identifier from External CA." json:"kid,omitempty" toml:"kid,omitempty" yaml:"kid,omitempty"`
HmacEncoded string `description:"Base64 encoded HMAC key from External CA." json:"hmacEncoded,omitempty" toml:"hmacEncoded,omitempty" yaml:"hmacEncoded,omitempty"`
Kid string `description:"Key identifier from External CA." json:"kid,omitempty" toml:"kid,omitempty" yaml:"kid,omitempty" loggable:"false"`
HmacEncoded string `description:"Base64 encoded HMAC key from External CA." json:"hmacEncoded,omitempty" toml:"hmacEncoded,omitempty" yaml:"hmacEncoded,omitempty" loggable:"false"`
}
// DNSChallenge contains DNS challenge configuration.

View File

@@ -1,14 +1,13 @@
package aggregator
import (
"encoding/json"
"github.com/traefik/traefik/v2/pkg/config/dynamic"
"github.com/traefik/traefik/v2/pkg/config/static"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/provider"
"github.com/traefik/traefik/v2/pkg/provider/file"
"github.com/traefik/traefik/v2/pkg/provider/traefik"
"github.com/traefik/traefik/v2/pkg/redactor"
"github.com/traefik/traefik/v2/pkg/safe"
)
@@ -140,12 +139,13 @@ func (p ProviderAggregator) Provide(configurationChan chan<- dynamic.Message, po
}
func launchProvider(configurationChan chan<- dynamic.Message, pool *safe.Pool, prd provider.Provider) {
jsonConf, err := json.Marshal(prd)
jsonConf, err := redactor.RemoveCredentials(prd)
if err != nil {
log.WithoutContext().Debugf("Cannot marshal the provider configuration %T: %v", prd, err)
}
log.WithoutContext().Infof("Starting provider %T %s", prd, jsonConf)
log.WithoutContext().Infof("Starting provider %T", prd)
log.WithoutContext().Debugf("%T provider configuration: %s", prd, jsonConf)
currentProvider := prd
err = currentProvider.Provide(configurationChan, pool)

View File

@@ -67,7 +67,7 @@ type EndpointConfig struct {
Address string `description:"The address of the Consul server" json:"address,omitempty" toml:"address,omitempty" yaml:"address,omitempty"`
Scheme string `description:"The URI scheme for the Consul server" json:"scheme,omitempty" toml:"scheme,omitempty" yaml:"scheme,omitempty"`
DataCenter string `description:"Data center to use. If not provided, the default agent data center is used" json:"datacenter,omitempty" toml:"datacenter,omitempty" yaml:"datacenter,omitempty"`
Token string `description:"Token is used to provide a per-request ACL token which overrides the agent's default token" json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty"`
Token string `description:"Token is used to provide a per-request ACL token which overrides the agent's default token" json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
TLS *types.ClientTLS `description:"Enable TLS support." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
HTTPAuth *EndpointHTTPAuthConfig `description:"Auth info to use for http access" json:"httpAuth,omitempty" toml:"httpAuth,omitempty" yaml:"httpAuth,omitempty" export:"true"`
EndpointWaitTime ptypes.Duration `description:"WaitTime limits how long a Watch will block. If not provided, the agent default values will be used" json:"endpointWaitTime,omitempty" toml:"endpointWaitTime,omitempty" yaml:"endpointWaitTime,omitempty" export:"true"`
@@ -75,8 +75,8 @@ type EndpointConfig struct {
// EndpointHTTPAuthConfig holds configurations of the authentication.
type EndpointHTTPAuthConfig struct {
Username string `description:"Basic Auth username" json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty"`
Password string `description:"Basic Auth password" json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty"`
Username string `description:"Basic Auth username" json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty" loggable:"false"`
Password string `description:"Basic Auth password" json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty" loggable:"false"`
}
// SetDefaults sets the default values.
@@ -105,7 +105,7 @@ func (p *Provider) Init() error {
// Provide allows the consul catalog provider to provide configurations to traefik using the given configuration channel.
func (p *Provider) Provide(configurationChan chan<- dynamic.Message, pool *safe.Pool) error {
var err error
p.client, err = createClient(p.Endpoint)
p.client, err = createClient(p.Namespace, p.Endpoint)
if err != nil {
return fmt.Errorf("unable to create consul client: %w", err)
}
@@ -203,7 +203,7 @@ func (p *Provider) loadConfiguration(ctx context.Context, certInfo *connectCert,
func (p *Provider) getConsulServicesData(ctx context.Context) ([]itemData, error) {
// The query option "Filter" is not supported by /catalog/services.
// https://www.consul.io/api/catalog.html#list-services
opts := &api.QueryOptions{AllowStale: p.Stale, RequireConsistent: p.RequireConsistent, UseCache: p.Cache, Namespace: p.Namespace}
opts := &api.QueryOptions{AllowStale: p.Stale, RequireConsistent: p.RequireConsistent, UseCache: p.Cache}
opts = opts.WithContext(ctx)
serviceNames, _, err := p.client.Catalog().Services(opts)
@@ -296,7 +296,7 @@ func (p *Provider) fetchService(ctx context.Context, name string, connectEnabled
tagFilter = p.Prefix + ".enable=true"
}
opts := &api.QueryOptions{AllowStale: p.Stale, RequireConsistent: p.RequireConsistent, UseCache: p.Cache, Namespace: p.Namespace}
opts := &api.QueryOptions{AllowStale: p.Stale, RequireConsistent: p.RequireConsistent, UseCache: p.Cache}
opts = opts.WithContext(ctx)
catalogFunc := p.client.Catalog().Service
@@ -458,29 +458,30 @@ func (p *Provider) watchConnectTLS(ctx context.Context, leafWatcher *watch.Plan,
}
}
func createClient(cfg *EndpointConfig) (*api.Client, error) {
func createClient(namespace string, endpoint *EndpointConfig) (*api.Client, error) {
config := api.Config{
Address: cfg.Address,
Scheme: cfg.Scheme,
Datacenter: cfg.DataCenter,
WaitTime: time.Duration(cfg.EndpointWaitTime),
Token: cfg.Token,
Address: endpoint.Address,
Scheme: endpoint.Scheme,
Datacenter: endpoint.DataCenter,
WaitTime: time.Duration(endpoint.EndpointWaitTime),
Token: endpoint.Token,
Namespace: namespace,
}
if cfg.HTTPAuth != nil {
if endpoint.HTTPAuth != nil {
config.HttpAuth = &api.HttpBasicAuth{
Username: cfg.HTTPAuth.Username,
Password: cfg.HTTPAuth.Password,
Username: endpoint.HTTPAuth.Username,
Password: endpoint.HTTPAuth.Password,
}
}
if cfg.TLS != nil {
if endpoint.TLS != nil {
config.TLSConfig = api.TLSConfig{
Address: cfg.Address,
CAFile: cfg.TLS.CA,
CertFile: cfg.TLS.Cert,
KeyFile: cfg.TLS.Key,
InsecureSkipVerify: cfg.TLS.InsecureSkipVerify,
Address: endpoint.Address,
CAFile: endpoint.TLS.CA,
CertFile: endpoint.TLS.Cert,
KeyFile: endpoint.TLS.Key,
InsecureSkipVerify: endpoint.TLS.InsecureSkipVerify,
}
}

View File

@@ -34,8 +34,8 @@ type Provider struct {
Clusters []string `description:"ECS Clusters name" json:"clusters,omitempty" toml:"clusters,omitempty" yaml:"clusters,omitempty" export:"true"`
AutoDiscoverClusters bool `description:"Auto discover cluster" json:"autoDiscoverClusters,omitempty" toml:"autoDiscoverClusters,omitempty" yaml:"autoDiscoverClusters,omitempty" export:"true"`
Region string `description:"The AWS region to use for requests" json:"region,omitempty" toml:"region,omitempty" yaml:"region,omitempty" export:"true"`
AccessKeyID string `description:"The AWS credentials access key to use for making requests" json:"accessKeyID,omitempty" toml:"accessKeyID,omitempty" yaml:"accessKeyID,omitempty"`
SecretAccessKey string `description:"The AWS credentials access key to use for making requests" json:"secretAccessKey,omitempty" toml:"secretAccessKey,omitempty" yaml:"secretAccessKey,omitempty"`
AccessKeyID string `description:"The AWS credentials access key to use for making requests" json:"accessKeyID,omitempty" toml:"accessKeyID,omitempty" yaml:"accessKeyID,omitempty" loggable:"false"`
SecretAccessKey string `description:"The AWS credentials access key to use for making requests" json:"secretAccessKey,omitempty" toml:"secretAccessKey,omitempty" yaml:"secretAccessKey,omitempty" loggable:"false"`
defaultRuleTpl *template.Template
}

View File

@@ -45,7 +45,7 @@ const (
// Provider holds configurations of the provider.
type Provider struct {
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty"`
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)." json:"certAuthFilePath,omitempty" toml:"certAuthFilePath,omitempty" yaml:"certAuthFilePath,omitempty"`
Namespaces []string `description:"Kubernetes namespaces." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" export:"true"`
AllowCrossNamespace bool `description:"Allow cross namespace resource reference." json:"allowCrossNamespace,omitempty" toml:"allowCrossNamespace,omitempty" yaml:"allowCrossNamespace,omitempty" export:"true"`

View File

@@ -44,7 +44,7 @@ const (
// Provider holds configurations of the provider.
type Provider struct {
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty"`
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)." json:"certAuthFilePath,omitempty" toml:"certAuthFilePath,omitempty" yaml:"certAuthFilePath,omitempty"`
Namespaces []string `description:"Kubernetes namespaces." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" export:"true"`
LabelSelector string `description:"Kubernetes label selector to select specific GatewayClasses." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`

View File

@@ -37,7 +37,7 @@ const (
// Provider holds configurations of the provider.
type Provider struct {
Endpoint string `description:"Kubernetes server endpoint (required for external cluster client)." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty"`
Token string `description:"Kubernetes bearer token (not needed for in-cluster client)." json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
CertAuthFilePath string `description:"Kubernetes certificate authority file path (not needed for in-cluster client)." json:"certAuthFilePath,omitempty" toml:"certAuthFilePath,omitempty" yaml:"certAuthFilePath,omitempty"`
Namespaces []string `description:"Kubernetes namespaces." json:"namespaces,omitempty" toml:"namespaces,omitempty" yaml:"namespaces,omitempty" export:"true"`
LabelSelector string `description:"Kubernetes Ingress label selector to use." json:"labelSelector,omitempty" toml:"labelSelector,omitempty" yaml:"labelSelector,omitempty" export:"true"`

View File

@@ -24,14 +24,14 @@ import (
// Provider holds configurations of the provider.
type Provider struct {
RootKey string `description:"Root key used for KV store" export:"true" json:"rootKey,omitempty" toml:"rootKey,omitempty" yaml:"rootKey,omitempty"`
RootKey string `description:"Root key used for KV store" json:"rootKey,omitempty" toml:"rootKey,omitempty" yaml:"rootKey,omitempty"`
Endpoints []string `description:"KV store endpoints" json:"endpoints,omitempty" toml:"endpoints,omitempty" yaml:"endpoints,omitempty"`
Username string `description:"KV Username" json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty"`
Password string `description:"KV Password" json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty"`
Token string `description:"KV Token" json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty"`
Username string `description:"KV Username" json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty" loggable:"false"`
Password string `description:"KV Password" json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty" loggable:"false"`
Token string `description:"KV Token" json:"token,omitempty" toml:"token,omitempty" yaml:"token,omitempty" loggable:"false"`
Namespace string `description:"KV Namespace" json:"namespace,omitempty" toml:"namespace,omitempty" yaml:"namespace,omitempty"`
TLS *types.ClientTLS `description:"Enable TLS support" export:"true" json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty"`
TLS *types.ClientTLS `description:"Enable TLS support" json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true" `
storeType store.Backend
kvClient store.Store

View File

@@ -52,7 +52,7 @@ type Provider struct {
Endpoint string `description:"Marathon server endpoint. You can also specify multiple endpoint for Marathon." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
DefaultRule string `description:"Default rule." json:"defaultRule,omitempty" toml:"defaultRule,omitempty" yaml:"defaultRule,omitempty"`
ExposedByDefault bool `description:"Expose Marathon apps by default." json:"exposedByDefault,omitempty" toml:"exposedByDefault,omitempty" yaml:"exposedByDefault,omitempty" export:"true"`
DCOSToken string `description:"DCOSToken for DCOS environment, This will override the Authorization header." json:"dcosToken,omitempty" toml:"dcosToken,omitempty" yaml:"dcosToken,omitempty"`
DCOSToken string `description:"DCOSToken for DCOS environment, This will override the Authorization header." json:"dcosToken,omitempty" toml:"dcosToken,omitempty" yaml:"dcosToken,omitempty" loggable:"false"`
TLS *types.ClientTLS `description:"Enable TLS support." json:"tls,omitempty" toml:"tls,omitempty" yaml:"tls,omitempty" export:"true"`
DialerTimeout ptypes.Duration `description:"Set a dialer timeout for Marathon." json:"dialerTimeout,omitempty" toml:"dialerTimeout,omitempty" yaml:"dialerTimeout,omitempty" export:"true"`
ResponseHeaderTimeout ptypes.Duration `description:"Set a response header timeout for Marathon." json:"responseHeaderTimeout,omitempty" toml:"responseHeaderTimeout,omitempty" yaml:"responseHeaderTimeout,omitempty" export:"true"`
@@ -80,8 +80,8 @@ func (p *Provider) SetDefaults() {
// Basic holds basic authentication specific configurations.
type Basic struct {
HTTPBasicAuthUser string `description:"Basic authentication User." json:"httpBasicAuthUser,omitempty" toml:"httpBasicAuthUser,omitempty" yaml:"httpBasicAuthUser,omitempty"`
HTTPBasicPassword string `description:"Basic authentication Password." json:"httpBasicPassword,omitempty" toml:"httpBasicPassword,omitempty" yaml:"httpBasicPassword,omitempty"`
HTTPBasicAuthUser string `description:"Basic authentication User." json:"httpBasicAuthUser,omitempty" toml:"httpBasicAuthUser,omitempty" yaml:"httpBasicAuthUser,omitempty" loggable:"false"`
HTTPBasicPassword string `description:"Basic authentication Password." json:"httpBasicPassword,omitempty" toml:"httpBasicPassword,omitempty" yaml:"httpBasicPassword,omitempty" loggable:"false"`
}
// Init the provider.

View File

@@ -1,4 +1,4 @@
package anonymize
package redactor
import (
"encoding/json"
@@ -13,12 +13,39 @@ import (
)
const (
maskShort = "xxxx"
maskLarge = maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort
maskShort = "xxxx"
maskLarge = maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort + maskShort
tagLoggable = "loggable"
tagExport = "export"
)
// Do sends configuration.
func Do(baseConfig interface{}, indent bool) (string, error) {
// Anonymize redacts the configuration fields that do not have an export=true struct tag.
// It returns the resulting marshaled configuration.
func Anonymize(baseConfig interface{}) (string, error) {
return anonymize(baseConfig, false)
}
func anonymize(baseConfig interface{}, indent bool) (string, error) {
conf, err := do(baseConfig, tagExport, true, indent)
if err != nil {
return "", err
}
return doOnJSON(conf), nil
}
// RemoveCredentials redacts the configuration fields that have a loggable=false struct tag.
// It returns the resulting marshaled configuration.
func RemoveCredentials(baseConfig interface{}) (string, error) {
return removeCredentials(baseConfig, false)
}
func removeCredentials(baseConfig interface{}, indent bool) (string, error) {
return do(baseConfig, tagLoggable, false, indent)
}
// do marshals the given configuration, while redacting some of the fields
// respectively to the given tag.
func do(baseConfig interface{}, tag string, redactByDefault, indent bool) (string, error) {
anomConfig, err := copystructure.Copy(baseConfig)
if err != nil {
return "", err
@@ -26,7 +53,7 @@ func Do(baseConfig interface{}, indent bool) (string, error) {
val := reflect.ValueOf(anomConfig)
err = doOnStruct(val)
err = doOnStruct(val, tag, redactByDefault)
if err != nil {
return "", err
}
@@ -36,7 +63,7 @@ func Do(baseConfig interface{}, indent bool) (string, error) {
return "", err
}
return doOnJSON(string(configJSON)), nil
return string(configJSON), nil
}
func doOnJSON(input string) string {
@@ -44,7 +71,7 @@ func doOnJSON(input string) string {
return xurls.Relaxed().ReplaceAllString(mailExp.ReplaceAllString(input, maskLarge+"\""), maskLarge)
}
func doOnStruct(field reflect.Value) error {
func doOnStruct(field reflect.Value, tag string, redactByDefault bool) error {
if field.Type().AssignableTo(reflect.TypeOf(dynamic.PluginConf{})) {
resetPlugin(field)
return nil
@@ -53,7 +80,7 @@ func doOnStruct(field reflect.Value) error {
switch field.Kind() {
case reflect.Ptr:
if !field.IsNil() {
if err := doOnStruct(field.Elem()); err != nil {
if err := doOnStruct(field.Elem(), tag, redactByDefault); err != nil {
return err
}
}
@@ -65,25 +92,28 @@ func doOnStruct(field reflect.Value) error {
continue
}
if stField.Tag.Get("export") == "true" {
// A struct field cannot be set it must be filled as pointer.
if fld.Kind() == reflect.Struct {
fldPtr := reflect.New(fld.Type())
fldPtr.Elem().Set(fld)
if err := doOnStruct(fldPtr); err != nil {
return err
}
fld.Set(fldPtr.Elem())
continue
}
if err := doOnStruct(fld); err != nil {
if stField.Tag.Get(tag) == "false" || stField.Tag.Get(tag) != "true" && redactByDefault {
if err := reset(fld, stField.Name); err != nil {
return err
}
} else if err := reset(fld, stField.Name); err != nil {
continue
}
// A struct field cannot be set it must be filled as pointer.
if fld.Kind() == reflect.Struct {
fldPtr := reflect.New(fld.Type())
fldPtr.Elem().Set(fld)
if err := doOnStruct(fldPtr, tag, redactByDefault); err != nil {
return err
}
fld.Set(fldPtr.Elem())
continue
}
if err := doOnStruct(fld, tag, redactByDefault); err != nil {
return err
}
}
@@ -96,7 +126,7 @@ func doOnStruct(field reflect.Value) error {
valPtr := reflect.New(val.Type())
valPtr.Elem().Set(val)
if err := doOnStruct(valPtr); err != nil {
if err := doOnStruct(valPtr, tag, redactByDefault); err != nil {
return err
}
@@ -105,13 +135,13 @@ func doOnStruct(field reflect.Value) error {
continue
}
if err := doOnStruct(val); err != nil {
if err := doOnStruct(val, tag, redactByDefault); err != nil {
return err
}
}
case reflect.Slice:
for j := 0; j < field.Len(); j++ {
if err := doOnStruct(field.Index(j)); err != nil {
if err := doOnStruct(field.Index(j), tag, redactByDefault); err != nil {
return err
}
}

View File

@@ -1,4 +1,4 @@
package anonymize
package redactor
import (
"flag"
@@ -43,7 +43,9 @@ import (
var updateExpected = flag.Bool("update_expected", false, "Update expected files in fixtures")
func TestDo_dynamicConfiguration(t *testing.T) {
var fullDynConf *dynamic.Configuration
func init() {
config := &dynamic.Configuration{}
config.HTTP = &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
@@ -242,7 +244,7 @@ func TestDo_dynamicConfiguration(t *testing.T) {
SourceCriterion: &dynamic.SourceCriterion{
IPStrategy: &dynamic.IPStrategy{
Depth: 42,
ExcludedIPs: []string{"foo"},
ExcludedIPs: []string{"127.0.0.1"},
},
RequestHeaderName: "foo",
RequestHost: true,
@@ -291,7 +293,7 @@ func TestDo_dynamicConfiguration(t *testing.T) {
SourceCriterion: &dynamic.SourceCriterion{
IPStrategy: &dynamic.IPStrategy{
Depth: 42,
ExcludedIPs: []string{"foo"},
ExcludedIPs: []string{"127.0.0.1"},
},
RequestHeaderName: "foo",
RequestHost: true,
@@ -463,10 +465,16 @@ func TestDo_dynamicConfiguration(t *testing.T) {
},
}
fullDynConf = config
}
func TestAnonymize_dynamicConfiguration(t *testing.T) {
config := fullDynConf
expectedConfiguration, err := os.ReadFile("./testdata/anonymized-dynamic-config.json")
require.NoError(t, err)
cleanJSON, err := Do(config, true)
cleanJSON, err := anonymize(config, true)
require.NoError(t, err)
if *updateExpected {
@@ -477,6 +485,23 @@ func TestDo_dynamicConfiguration(t *testing.T) {
assert.Equal(t, expected, cleanJSON)
}
func TestSecure_dynamicConfiguration(t *testing.T) {
config := fullDynConf
expectedConfiguration, err := os.ReadFile("./testdata/secured-dynamic-config.json")
require.NoError(t, err)
cleanJSON, err := removeCredentials(config, true)
require.NoError(t, err)
if *updateExpected {
require.NoError(t, os.WriteFile("testdata/secured-dynamic-config.json", []byte(cleanJSON), 0o666))
}
expected := strings.TrimSuffix(string(expectedConfiguration), "\n")
assert.Equal(t, expected, cleanJSON)
}
func TestDo_staticConfiguration(t *testing.T) {
config := &static.Configuration{}
@@ -962,7 +987,7 @@ func TestDo_staticConfiguration(t *testing.T) {
expectedConfiguration, err := os.ReadFile("./testdata/anonymized-static-config.json")
require.NoError(t, err)
cleanJSON, err := Do(config, true)
cleanJSON, err := anonymize(config, true)
require.NoError(t, err)
if *updateExpected {

View File

@@ -1,4 +1,4 @@
package anonymize
package redactor
import (
"os"
@@ -57,7 +57,9 @@ func Test_doOnJSON_simple(t *testing.T) {
}
for _, test := range testCases {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
output := doOnJSON(test.input)
assert.Equal(t, test.expectedOutput, output)
})

View File

@@ -0,0 +1,382 @@
package redactor
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type Courgette struct {
Ji string
Ho string
}
type Tomate struct {
Ji string
Ho string
}
type Carotte struct {
Name string
EName string `export:"true"`
EFName string `export:"false"`
Value int
EValue int `export:"true"`
EFValue int `export:"false"`
List []string
EList []string `export:"true"`
EFList []string `export:"false"`
Courgette Courgette
ECourgette Courgette `export:"true"`
EFCourgette Courgette `export:"false"`
Pourgette *Courgette
EPourgette *Courgette `export:"true"`
EFPourgette *Courgette `export:"false"`
Aubergine map[string]string
EAubergine map[string]string `export:"true"`
EFAubergine map[string]string `export:"false"`
SAubergine map[string]Tomate
ESAubergine map[string]Tomate `export:"true"`
EFSAubergine map[string]Tomate `export:"false"`
PSAubergine map[string]*Tomate
EPAubergine map[string]*Tomate `export:"true"`
EFPAubergine map[string]*Tomate `export:"false"`
}
func Test_doOnStruct(t *testing.T) {
testCase := []struct {
name string
base *Carotte
expected *Carotte
redactByDefault bool
}{
{
name: "primitive",
base: &Carotte{
Name: "koko",
EName: "kiki",
Value: 666,
EValue: 666,
List: []string{"test"},
EList: []string{"test"},
},
expected: &Carotte{
Name: "xxxx",
EName: "kiki",
EValue: 666,
List: []string{"xxxx"},
EList: []string{"test"},
},
redactByDefault: true,
},
{
name: "primitive2",
base: &Carotte{
Name: "koko",
EFName: "keke",
Value: 666,
EFValue: 777,
List: []string{"test"},
EFList: []string{"test"},
},
expected: &Carotte{
Name: "koko",
EFName: "xxxx",
Value: 666,
List: []string{"test"},
EFList: []string{"xxxx"},
},
redactByDefault: false,
},
{
name: "struct",
base: &Carotte{
Name: "koko",
Courgette: Courgette{
Ji: "huu",
},
},
expected: &Carotte{
Name: "xxxx",
},
redactByDefault: true,
},
{
name: "struct2",
base: &Carotte{
Name: "koko",
EFName: "keke",
Courgette: Courgette{
Ji: "huu",
},
EFCourgette: Courgette{
Ji: "huu",
},
},
expected: &Carotte{
Name: "koko",
EFName: "xxxx",
Courgette: Courgette{
Ji: "huu",
Ho: "",
},
},
redactByDefault: false,
},
{
name: "pointer",
base: &Carotte{
Name: "koko",
Pourgette: &Courgette{
Ji: "hoo",
},
},
expected: &Carotte{
Name: "xxxx",
Pourgette: nil,
},
redactByDefault: true,
},
{
name: "pointer2",
base: &Carotte{
Name: "koko",
EFName: "keke",
Pourgette: &Courgette{
Ji: "hoo",
},
EFPourgette: &Courgette{
Ji: "hoo",
},
},
expected: &Carotte{
Name: "koko",
EFName: "xxxx",
Pourgette: &Courgette{
Ji: "hoo",
},
EFPourgette: nil,
},
redactByDefault: false,
},
{
name: "export struct",
base: &Carotte{
Name: "koko",
ECourgette: Courgette{
Ji: "huu",
},
},
expected: &Carotte{
Name: "xxxx",
ECourgette: Courgette{
Ji: "xxxx",
},
},
redactByDefault: true,
},
{
name: "export struct 2",
base: &Carotte{
Name: "koko",
EFName: "keke",
ECourgette: Courgette{
Ji: "huu",
},
EFCourgette: Courgette{
Ji: "huu",
},
},
expected: &Carotte{
Name: "koko",
EFName: "xxxx",
ECourgette: Courgette{
Ji: "huu",
},
},
redactByDefault: false,
},
{
name: "export pointer struct",
base: &Carotte{
Name: "koko",
EPourgette: &Courgette{
Ji: "huu",
},
},
expected: &Carotte{
Name: "xxxx",
EPourgette: &Courgette{
Ji: "xxxx",
},
},
redactByDefault: true,
},
{
name: "export pointer struct 2",
base: &Carotte{
Name: "koko",
EFName: "keke",
EPourgette: &Courgette{
Ji: "huu",
},
EFPourgette: &Courgette{
Ji: "huu",
},
},
expected: &Carotte{
Name: "koko",
EFName: "xxxx",
EPourgette: &Courgette{
Ji: "huu",
},
EFPourgette: nil,
},
redactByDefault: false,
},
{
name: "export map string/string",
base: &Carotte{
Name: "koko",
EAubergine: map[string]string{
"foo": "bar",
},
},
expected: &Carotte{
Name: "xxxx",
EAubergine: map[string]string{
"foo": "bar",
},
},
redactByDefault: true,
},
{
name: "export map string/string 2",
base: &Carotte{
Name: "koko",
EFName: "keke",
EAubergine: map[string]string{
"foo": "bar",
},
EFAubergine: map[string]string{
"foo": "bar",
},
},
expected: &Carotte{
Name: "koko",
EFName: "xxxx",
EAubergine: map[string]string{
"foo": "bar",
},
EFAubergine: map[string]string{},
},
redactByDefault: false,
},
{
name: "export map string/pointer",
base: &Carotte{
Name: "koko",
EPAubergine: map[string]*Tomate{
"foo": {
Ji: "fdskljf",
},
},
},
expected: &Carotte{
Name: "xxxx",
EPAubergine: map[string]*Tomate{
"foo": {
Ji: "xxxx",
},
},
},
redactByDefault: true,
},
{
name: "export map string/pointer 2",
base: &Carotte{
Name: "koko",
EPAubergine: map[string]*Tomate{
"foo": {
Ji: "fdskljf",
},
},
EFPAubergine: map[string]*Tomate{
"foo": {
Ji: "fdskljf",
},
},
},
expected: &Carotte{
Name: "koko",
EPAubergine: map[string]*Tomate{
"foo": {
Ji: "fdskljf",
},
},
EFPAubergine: map[string]*Tomate{},
},
redactByDefault: false,
},
{
name: "export map string/struct",
base: &Carotte{
Name: "koko",
ESAubergine: map[string]Tomate{
"foo": {
Ji: "JiJiJi",
},
},
},
expected: &Carotte{
Name: "xxxx",
ESAubergine: map[string]Tomate{
"foo": {
Ji: "xxxx",
},
},
},
redactByDefault: true,
},
{
name: "export map string/struct 2",
base: &Carotte{
Name: "koko",
ESAubergine: map[string]Tomate{
"foo": {
Ji: "JiJiJi",
},
},
EFSAubergine: map[string]Tomate{
"foo": {
Ji: "JiJiJi",
},
},
},
expected: &Carotte{
Name: "koko",
ESAubergine: map[string]Tomate{
"foo": {
Ji: "JiJiJi",
},
},
EFSAubergine: map[string]Tomate{},
},
redactByDefault: false,
},
}
for _, test := range testCase {
test := test
t.Run(test.name, func(t *testing.T) {
t.Parallel()
val := reflect.ValueOf(test.base).Elem()
err := doOnStruct(val, tagExport, test.redactByDefault)
require.NoError(t, err)
assert.EqualValues(t, test.expected, test.base)
})
}
}

View File

@@ -223,7 +223,7 @@
"secretAccessKey": "xxxx"
},
"consul": {
"rootKey": "RootKey",
"rootKey": "xxxx",
"username": "xxxx",
"password": "xxxx",
"tls": {
@@ -235,7 +235,7 @@
}
},
"etcd": {
"rootKey": "RootKey",
"rootKey": "xxxx",
"username": "xxxx",
"password": "xxxx",
"tls": {
@@ -247,7 +247,7 @@
}
},
"zooKeeper": {
"rootKey": "RootKey",
"rootKey": "xxxx",
"username": "xxxx",
"password": "xxxx",
"tls": {
@@ -259,7 +259,7 @@
}
},
"redis": {
"rootKey": "RootKey",
"rootKey": "xxxx",
"username": "xxxx",
"password": "xxxx",
"tls": {

View File

@@ -0,0 +1,487 @@
{
"http": {
"routers": {
"foo": {
"entryPoints": [
"foo"
],
"middlewares": [
"foo"
],
"service": "foo",
"rule": "foo",
"priority": 42,
"tls": {
"options": "foo",
"certResolver": "foo",
"domains": [
{
"main": "foo",
"sans": [
"foo"
]
}
]
}
}
},
"services": {
"bar": {
"weighted": {
"services": [
{
"name": "foo",
"weight": 42
}
],
"sticky": {
"cookie": {
"name": "foo",
"secure": true,
"httpOnly": true,
"sameSite": "foo"
}
}
}
},
"baz": {
"mirroring": {
"service": "foo",
"maxBodySize": 42,
"mirrors": [
{
"name": "foo",
"percent": 42
}
]
}
},
"foo": {
"loadBalancer": {
"sticky": {
"cookie": {
"name": "foo",
"secure": true,
"httpOnly": true,
"sameSite": "foo"
}
},
"servers": [
{
"url": "http://127.0.0.1:8080"
}
],
"healthCheck": {
"scheme": "foo",
"path": "foo",
"port": 42,
"interval": "foo",
"timeout": "foo",
"hostname": "foo",
"followRedirects": true,
"headers": {
"foo": "bar"
}
},
"passHostHeader": true,
"responseForwarding": {
"flushInterval": "foo"
},
"serversTransport": "foo"
}
}
},
"middlewares": {
"foo": {
"addPrefix": {
"prefix": "foo"
},
"stripPrefix": {
"prefixes": [
"foo"
],
"forceSlash": true
},
"stripPrefixRegex": {
"regex": [
"foo"
]
},
"replacePath": {
"path": "foo"
},
"replacePathRegex": {
"regex": "foo",
"replacement": "foo"
},
"chain": {
"middlewares": [
"foo"
]
},
"ipWhiteList": {
"sourceRange": [
"foo"
],
"ipStrategy": {
"depth": 42,
"excludedIPs": [
"127.0.0.1"
]
}
},
"headers": {
"customRequestHeaders": {
"foo": "bar"
},
"customResponseHeaders": {
"foo": "bar"
},
"accessControlAllowCredentials": true,
"accessControlAllowHeaders": [
"foo"
],
"accessControlAllowMethods": [
"foo"
],
"accessControlAllowOriginList": [
"foo"
],
"accessControlAllowOriginListRegex": [
"foo"
],
"accessControlExposeHeaders": [
"foo"
],
"accessControlMaxAge": 42,
"addVaryHeader": true,
"allowedHosts": [
"foo"
],
"hostsProxyHeaders": [
"foo"
],
"sslRedirect": true,
"sslTemporaryRedirect": true,
"sslHost": "foo",
"sslProxyHeaders": {
"foo": "bar"
},
"sslForceHost": true,
"stsSeconds": 42,
"stsIncludeSubdomains": true,
"stsPreload": true,
"forceSTSHeader": true,
"frameDeny": true,
"customFrameOptionsValue": "foo",
"contentTypeNosniff": true,
"browserXssFilter": true,
"customBrowserXSSValue": "foo",
"contentSecurityPolicy": "foo",
"publicKey": "foo",
"referrerPolicy": "foo",
"featurePolicy": "foo",
"permissionsPolicy": "foo",
"isDevelopment": true
},
"errors": {
"status": [
"foo"
],
"service": "foo",
"query": "foo"
},
"rateLimit": {
"average": 42,
"period": "42ns",
"burst": 42,
"sourceCriterion": {
"ipStrategy": {
"depth": 42,
"excludedIPs": [
"127.0.0.1"
]
},
"requestHeaderName": "foo",
"requestHost": true
}
},
"redirectRegex": {
"regex": "foo",
"replacement": "foo",
"permanent": true
},
"redirectScheme": {
"scheme": "foo",
"port": "foo",
"permanent": true
},
"basicAuth": {
"users": [
"xxxx"
],
"usersFile": "foo",
"realm": "foo",
"removeHeader": true,
"headerField": "foo"
},
"digestAuth": {
"users": [
"xxxx"
],
"usersFile": "foo",
"removeHeader": true,
"realm": "foo",
"headerField": "foo"
},
"forwardAuth": {
"address": "127.0.0.1",
"tls": {
"ca": "ca.pem",
"caOptional": true,
"cert": "cert.pem",
"key": "xxxx",
"insecureSkipVerify": true
},
"trustForwardHeader": true,
"authResponseHeaders": [
"foo"
],
"authResponseHeadersRegex": "foo",
"authRequestHeaders": [
"foo"
]
},
"inFlightReq": {
"amount": 42,
"sourceCriterion": {
"ipStrategy": {
"depth": 42,
"excludedIPs": [
"127.0.0.1"
]
},
"requestHeaderName": "foo",
"requestHost": true
}
},
"buffering": {
"maxRequestBodyBytes": 42,
"memRequestBodyBytes": 42,
"maxResponseBodyBytes": 42,
"memResponseBodyBytes": 42,
"retryExpression": "foo"
},
"circuitBreaker": {
"expression": "foo"
},
"compress": {
"excludedContentTypes": [
"foo"
]
},
"passTLSClientCert": {
"pem": true,
"info": {
"notAfter": true,
"notBefore": true,
"sans": true,
"subject": {
"country": true,
"province": true,
"locality": true,
"organization": true,
"organizationalUnit": true,
"commonName": true,
"serialNumber": true,
"domainComponent": true
},
"issuer": {
"country": true,
"province": true,
"locality": true,
"organization": true,
"commonName": true,
"serialNumber": true,
"domainComponent": true
},
"serialNumber": true
}
},
"retry": {
"attempts": 42,
"initialInterval": "42ns"
},
"contentType": {
"autoDetect": true
},
"plugin": {
"foo": {
"answer": {}
}
}
}
},
"models": {
"foo": {
"middlewares": [
"foo"
],
"tls": {
"options": "foo",
"certResolver": "foo",
"domains": [
{
"main": "foo",
"sans": [
"foo"
]
}
]
}
}
},
"serversTransports": {
"foo": {
"serverName": "foo",
"insecureSkipVerify": true,
"rootCAs": [
"rootca.pem"
],
"certificates": [
{
"certFile": "cert.pem",
"keyFile": "xxxx"
}
],
"maxIdleConnsPerHost": 42,
"forwardingTimeouts": {
"dialTimeout": "42ns",
"responseHeaderTimeout": "42ns",
"idleConnTimeout": "42ns",
"readIdleTimeout": "42ns",
"pingTimeout": "42ns"
}
}
}
},
"tcp": {
"routers": {
"foo": {
"entryPoints": [
"foo"
],
"service": "foo",
"rule": "foo",
"tls": {
"passthrough": true,
"options": "foo",
"certResolver": "foo",
"domains": [
{
"main": "foo",
"sans": [
"foo"
]
}
]
}
}
},
"services": {
"bar": {
"weighted": {
"services": [
{
"name": "foo",
"weight": 42
}
]
}
},
"foo": {
"loadBalancer": {
"terminationDelay": 42,
"proxyProtocol": {
"version": 42
},
"servers": [
{
"address": "127.0.0.1:8080"
}
]
}
}
}
},
"udp": {
"routers": {
"foo": {
"entryPoints": [
"foo"
],
"service": "foo"
}
},
"services": {
"bar": {
"weighted": {
"services": [
{
"name": "foo",
"weight": 42
}
]
}
},
"foo": {
"loadBalancer": {
"servers": [
{
"address": "127.0.0.1:8080"
}
]
}
}
}
},
"tls": {
"certificates": [
{
"certFile": "cert.pem",
"keyFile": "xxxx",
"stores": [
"foo"
]
}
],
"options": {
"foo": {
"minVersion": "foo",
"maxVersion": "foo",
"cipherSuites": [
"foo"
],
"curvePreferences": [
"foo"
],
"clientAuth": {
"caFiles": [
"ca.pem"
],
"clientAuthType": "RequireAndVerifyClientCert"
},
"sniStrict": true,
"preferServerCipherSuites": true
}
},
"stores": {
"foo": {
"defaultCertificate": {
"certFile": "cert.pem",
"keyFile": "xxxx"
}
}
}
}
}

View File

@@ -84,12 +84,8 @@ func (c *ConfigurationWatcher) AddListener(listener func(dynamic.Configuration))
func (c *ConfigurationWatcher) startProvider() {
logger := log.WithoutContext()
jsonConf, err := json.Marshal(c.provider)
if err != nil {
logger.Debugf("Unable to marshal provider configuration %T: %v", c.provider, err)
}
logger.Infof("Starting provider %T", c.provider)
logger.Infof("Starting provider %T %s", c.provider, jsonConf)
currentProvider := c.provider
safe.Go(func() {

View File

@@ -9,7 +9,6 @@ import (
"github.com/traefik/traefik/v2/pkg/metrics"
"github.com/traefik/traefik/v2/pkg/middlewares/accesslog"
metricsmiddleware "github.com/traefik/traefik/v2/pkg/middlewares/metrics"
"github.com/traefik/traefik/v2/pkg/middlewares/requestdecorator"
mTracing "github.com/traefik/traefik/v2/pkg/middlewares/tracing"
"github.com/traefik/traefik/v2/pkg/tracing"
"github.com/traefik/traefik/v2/pkg/tracing/jaeger"
@@ -20,7 +19,6 @@ type ChainBuilder struct {
metricsRegistry metrics.Registry
accessLoggerMiddleware *accesslog.Handler
tracer *tracing.Tracing
requestDecorator *requestdecorator.RequestDecorator
}
// NewChainBuilder Creates a new ChainBuilder.
@@ -29,7 +27,6 @@ func NewChainBuilder(staticConfiguration static.Configuration, metricsRegistry m
metricsRegistry: metricsRegistry,
accessLoggerMiddleware: accessLoggerMiddleware,
tracer: setupTracing(staticConfiguration.Tracing),
requestDecorator: requestdecorator.New(staticConfiguration.HostResolver),
}
}
@@ -49,7 +46,7 @@ func (c *ChainBuilder) Build(ctx context.Context, entryPointName string) alice.C
chain = chain.Append(metricsmiddleware.WrapEntryPointHandler(ctx, c.metricsRegistry, entryPointName))
}
return chain.Append(requestdecorator.WrapHandler(c.requestDecorator))
return chain
}
// Close accessLogger and tracer.

View File

@@ -5,12 +5,11 @@ import (
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
"strings"
"github.com/traefik/traefik/v2/pkg/config/runtime"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/middlewares/snicheck"
"github.com/traefik/traefik/v2/pkg/rules"
"github.com/traefik/traefik/v2/pkg/server/provider"
tcpservice "github.com/traefik/traefik/v2/pkg/server/service/tcp"
@@ -161,38 +160,7 @@ func (m *Manager) buildEntryPointHandler(ctx context.Context, configs map[string
}
}
sniCheck := http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
if req.TLS == nil {
handlerHTTPS.ServeHTTP(rw, req)
return
}
host, _, err := net.SplitHostPort(req.Host)
if err != nil {
host = req.Host
}
host = strings.TrimSpace(host)
serverName := strings.TrimSpace(req.TLS.ServerName)
// Domain Fronting
if !strings.EqualFold(host, serverName) {
tlsOptionSNI := findTLSOptionName(tlsOptionsForHost, serverName)
tlsOptionHeader := findTLSOptionName(tlsOptionsForHost, host)
if tlsOptionHeader != tlsOptionSNI {
log.WithoutContext().
WithField("host", host).
WithField("req.Host", req.Host).
WithField("req.TLS.ServerName", req.TLS.ServerName).
Debugf("TLS options difference: SNI=%s, Header:%s", tlsOptionSNI, tlsOptionHeader)
http.Error(rw, http.StatusText(http.StatusMisdirectedRequest), http.StatusMisdirectedRequest)
return
}
}
handlerHTTPS.ServeHTTP(rw, req)
})
sniCheck := snicheck.New(tlsOptionsForHost, handlerHTTPS)
router.HTTPSHandler(sniCheck, defaultTLSConf)
@@ -321,17 +289,3 @@ func (m *Manager) buildTCPHandler(ctx context.Context, router *runtime.TCPRouter
return tcp.NewChain().Extend(*mHandler).Then(sHandler)
}
func findTLSOptionName(tlsOptionsForHost map[string]string, host string) string {
tlsOptions, ok := tlsOptionsForHost[host]
if ok {
return tlsOptions
}
tlsOptions, ok = tlsOptionsForHost[strings.ToLower(host)]
if ok {
return tlsOptions
}
return traefiktls.DefaultTLSConfigName
}

View File

@@ -59,7 +59,6 @@ func TestRuntimeConfiguration(t *testing.T) {
},
"bar": {
TCPRouter: &dynamic.TCPRouter{
EntryPoints: []string{"web"},
Service: "foo-service",
Rule: "HostSNI(`foo.bar`)",
@@ -136,7 +135,6 @@ func TestRuntimeConfiguration(t *testing.T) {
},
"bar": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
Service: "foo-service",
Rule: "Host(`bar.foo`) && PathPrefix(`/path`)",
@@ -240,7 +238,6 @@ func TestRuntimeConfiguration(t *testing.T) {
},
"bar": {
TCPRouter: &dynamic.TCPRouter{
EntryPoints: []string{"web"},
Service: "foo-service",
Rule: "HostSNI(`foo.bar`)",
@@ -340,9 +337,26 @@ func TestRuntimeConfiguration(t *testing.T) {
}
func TestDomainFronting(t *testing.T) {
tlsOptionsBase := map[string]traefiktls.Options{
"default": {
MinVersion: "VersionTLS10",
},
"host1@file": {
MinVersion: "VersionTLS12",
},
"host1@crd": {
MinVersion: "VersionTLS12",
},
}
entryPoints := []string{"web"}
tests := []struct {
desc string
routers map[string]*runtime.RouterInfo
tlsOptions map[string]traefiktls.Options
host string
ServerName string
expectedStatus int
}{
{
@@ -350,7 +364,7 @@ func TestDomainFronting(t *testing.T) {
routers: map[string]*runtime.RouterInfo{
"router-1@file": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host1.local`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1",
@@ -359,12 +373,15 @@ func TestDomainFronting(t *testing.T) {
},
"router-2@file": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host2.local`)",
TLS: &dynamic.RouterTLSConfig{},
},
},
},
tlsOptions: tlsOptionsBase,
host: "host1.local",
ServerName: "host2.local",
expectedStatus: http.StatusMisdirectedRequest,
},
{
@@ -372,7 +389,7 @@ func TestDomainFronting(t *testing.T) {
routers: map[string]*runtime.RouterInfo{
"router-1@file": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host1.local`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1",
@@ -381,7 +398,7 @@ func TestDomainFronting(t *testing.T) {
},
"router-2@file": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host2.local`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1",
@@ -389,6 +406,9 @@ func TestDomainFronting(t *testing.T) {
},
},
},
tlsOptions: tlsOptionsBase,
host: "host1.local",
ServerName: "host2.local",
expectedStatus: http.StatusOK,
},
{
@@ -396,7 +416,7 @@ func TestDomainFronting(t *testing.T) {
routers: map[string]*runtime.RouterInfo{
"router-1@file": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host1.local`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1",
@@ -405,7 +425,7 @@ func TestDomainFronting(t *testing.T) {
},
"router-2@file": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host1.local`) && PathPrefix(`/foo`)",
TLS: &dynamic.RouterTLSConfig{
Options: "default",
@@ -414,7 +434,7 @@ func TestDomainFronting(t *testing.T) {
},
"router-3@file": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host2.local`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1",
@@ -422,6 +442,9 @@ func TestDomainFronting(t *testing.T) {
},
},
},
tlsOptions: tlsOptionsBase,
host: "host1.local",
ServerName: "host2.local",
expectedStatus: http.StatusMisdirectedRequest,
},
{
@@ -429,7 +452,7 @@ func TestDomainFronting(t *testing.T) {
routers: map[string]*runtime.RouterInfo{
"router-1@file": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host1.local`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1",
@@ -438,7 +461,7 @@ func TestDomainFronting(t *testing.T) {
},
"router-2@file": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host1.local`) && PathPrefix(`/bar`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1",
@@ -447,7 +470,7 @@ func TestDomainFronting(t *testing.T) {
},
"router-3@file": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host2.local`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1",
@@ -455,6 +478,9 @@ func TestDomainFronting(t *testing.T) {
},
},
},
tlsOptions: tlsOptionsBase,
host: "host1.local",
ServerName: "host2.local",
expectedStatus: http.StatusOK,
},
{
@@ -462,7 +488,7 @@ func TestDomainFronting(t *testing.T) {
routers: map[string]*runtime.RouterInfo{
"router-1@file": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host1.local`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1",
@@ -471,7 +497,7 @@ func TestDomainFronting(t *testing.T) {
},
"router-2@crd": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host2.local`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1",
@@ -479,6 +505,9 @@ func TestDomainFronting(t *testing.T) {
},
},
},
tlsOptions: tlsOptionsBase,
host: "host1.local",
ServerName: "host2.local",
expectedStatus: http.StatusMisdirectedRequest,
},
{
@@ -486,7 +515,7 @@ func TestDomainFronting(t *testing.T) {
routers: map[string]*runtime.RouterInfo{
"router-1@file": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host1.local`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1@crd",
@@ -495,7 +524,7 @@ func TestDomainFronting(t *testing.T) {
},
"router-2@crd": {
Router: &dynamic.Router{
EntryPoints: []string{"web"},
EntryPoints: entryPoints,
Rule: "Host(`host2.local`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1@crd",
@@ -503,25 +532,63 @@ func TestDomainFronting(t *testing.T) {
},
},
},
tlsOptions: tlsOptionsBase,
host: "host1.local",
ServerName: "host2.local",
expectedStatus: http.StatusOK,
},
{
desc: "Request is misdirected when server name is empty and the host name is an FQDN, but router's rule is not",
routers: map[string]*runtime.RouterInfo{
"router-1@file": {
Router: &dynamic.Router{
EntryPoints: entryPoints,
Rule: "Host(`host1.local`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1@file",
},
},
},
},
tlsOptions: map[string]traefiktls.Options{
"default": {
MinVersion: "VersionTLS13",
},
"host1@file": {
MinVersion: "VersionTLS12",
},
},
host: "host1.local.",
expectedStatus: http.StatusMisdirectedRequest,
},
{
desc: "Request is misdirected when server name is empty and the host name is not FQDN, but router's rule is",
routers: map[string]*runtime.RouterInfo{
"router-1@file": {
Router: &dynamic.Router{
EntryPoints: entryPoints,
Rule: "Host(`host1.local.`)",
TLS: &dynamic.RouterTLSConfig{
Options: "host1@file",
},
},
},
},
tlsOptions: map[string]traefiktls.Options{
"default": {
MinVersion: "VersionTLS13",
},
"host1@file": {
MinVersion: "VersionTLS12",
},
},
host: "host1.local",
expectedStatus: http.StatusMisdirectedRequest,
},
}
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
entryPoints := []string{"web"}
tlsOptions := map[string]traefiktls.Options{
"default": {
MinVersion: "VersionTLS10",
},
"host1@file": {
MinVersion: "VersionTLS12",
},
"host1@crd": {
MinVersion: "VersionTLS12",
},
}
conf := &runtime.Configuration{
Routers: test.routers,
}
@@ -529,7 +596,7 @@ func TestDomainFronting(t *testing.T) {
serviceManager := tcp.NewManager(conf)
tlsManager := traefiktls.NewManager()
tlsManager.UpdateConfigs(context.Background(), map[string]traefiktls.Store{}, tlsOptions, []*traefiktls.CertAndStores{})
tlsManager.UpdateConfigs(context.Background(), map[string]traefiktls.Store{}, test.tlsOptions, []*traefiktls.CertAndStores{})
httpsHandler := map[string]http.Handler{
"web": http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {}),
@@ -545,9 +612,9 @@ func TestDomainFronting(t *testing.T) {
require.True(t, ok)
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Host = "host1.local"
req.Host = test.host
req.TLS = &tls.ConnectionState{
ServerName: "host2.local",
ServerName: test.ServerName,
}
rw := httptest.NewRecorder()

View File

@@ -11,6 +11,7 @@ import (
"syscall"
"time"
"github.com/containous/alice"
"github.com/pires/go-proxyproto"
"github.com/sirupsen/logrus"
"github.com/traefik/traefik/v2/pkg/config/static"
@@ -18,9 +19,11 @@ import (
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/middlewares"
"github.com/traefik/traefik/v2/pkg/middlewares/forwardedheaders"
"github.com/traefik/traefik/v2/pkg/middlewares/requestdecorator"
"github.com/traefik/traefik/v2/pkg/safe"
"github.com/traefik/traefik/v2/pkg/server/router"
"github.com/traefik/traefik/v2/pkg/tcp"
"github.com/traefik/traefik/v2/pkg/types"
"golang.org/x/net/http2"
"golang.org/x/net/http2/h2c"
)
@@ -60,7 +63,7 @@ func (h *httpForwarder) Accept() (net.Conn, error) {
type TCPEntryPoints map[string]*TCPEntryPoint
// NewTCPEntryPoints creates a new TCPEntryPoints.
func NewTCPEntryPoints(entryPointsConfig static.EntryPoints) (TCPEntryPoints, error) {
func NewTCPEntryPoints(entryPointsConfig static.EntryPoints, hostResolverConfig *types.HostResolverConfig) (TCPEntryPoints, error) {
serverEntryPointsTCP := make(TCPEntryPoints)
for entryPointName, config := range entryPointsConfig {
protocol, err := config.GetProtocol()
@@ -74,7 +77,7 @@ func NewTCPEntryPoints(entryPointsConfig static.EntryPoints) (TCPEntryPoints, er
ctx := log.With(context.Background(), log.Str(log.EntryPointName, entryPointName))
serverEntryPointsTCP[entryPointName], err = NewTCPEntryPoint(ctx, config)
serverEntryPointsTCP[entryPointName], err = NewTCPEntryPoint(ctx, config, hostResolverConfig)
if err != nil {
return nil, fmt.Errorf("error while building entryPoint %s: %w", entryPointName, err)
}
@@ -130,7 +133,7 @@ type TCPEntryPoint struct {
}
// NewTCPEntryPoint creates a new TCPEntryPoint.
func NewTCPEntryPoint(ctx context.Context, configuration *static.EntryPoint) (*TCPEntryPoint, error) {
func NewTCPEntryPoint(ctx context.Context, configuration *static.EntryPoint, hostResolverConfig *types.HostResolverConfig) (*TCPEntryPoint, error) {
tracker := newConnectionTracker()
listener, err := buildListener(ctx, configuration)
@@ -140,14 +143,16 @@ func NewTCPEntryPoint(ctx context.Context, configuration *static.EntryPoint) (*T
rt := &tcp.Router{}
httpServer, err := createHTTPServer(ctx, listener, configuration, true)
reqDecorator := requestdecorator.New(hostResolverConfig)
httpServer, err := createHTTPServer(ctx, listener, configuration, true, reqDecorator)
if err != nil {
return nil, fmt.Errorf("error preparing httpServer: %w", err)
}
rt.HTTPForwarder(httpServer.Forwarder)
httpsServer, err := createHTTPServer(ctx, listener, configuration, false)
httpsServer, err := createHTTPServer(ctx, listener, configuration, false, reqDecorator)
if err != nil {
return nil, fmt.Errorf("error preparing httpsServer: %w", err)
}
@@ -500,16 +505,19 @@ type httpServer struct {
Switcher *middlewares.HTTPHandlerSwitcher
}
func createHTTPServer(ctx context.Context, ln net.Listener, configuration *static.EntryPoint, withH2c bool) (*httpServer, error) {
func createHTTPServer(ctx context.Context, ln net.Listener, configuration *static.EntryPoint, withH2c bool, reqDecorator *requestdecorator.RequestDecorator) (*httpServer, error) {
httpSwitcher := middlewares.NewHandlerSwitcher(router.BuildDefaultHTTPRouter())
next, err := alice.New(requestdecorator.WrapHandler(reqDecorator)).Then(httpSwitcher)
if err != nil {
return nil, err
}
var handler http.Handler
var err error
handler, err = forwardedheaders.NewXForwarded(
configuration.ForwardedHeaders.Insecure,
configuration.ForwardedHeaders.TrustedIPs,
httpSwitcher)
next)
if err != nil {
return nil, err
}

View File

@@ -17,38 +17,57 @@ import (
// LocalhostCert is a PEM-encoded TLS cert with SAN IPs
// "127.0.0.1" and "[::1]", expiring at Jan 29 16:00:00 2084 GMT.
// generated from src/crypto/tls:
// go run generate_cert.go --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
// go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
var (
localhostCert = traefiktls.FileOrContent(`-----BEGIN CERTIFICATE-----
MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS
MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4
iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul
rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO
BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw
AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA
AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9
tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs
h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM
fblo6RBxUQ==
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r
bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U
aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P
YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk
POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu
h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE
AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv
bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI
5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv
cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2
+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B
grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK
5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/
WkBKOclmOV2xlTVuPw==
-----END CERTIFICATE-----`)
// LocalhostKey is the private key for localhostCert.
localhostKey = traefiktls.FileOrContent(`-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9
SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZB
l2+XsDulrKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQAB
AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xlp/DoCzjA0CQQDU
y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj013sovGKUFfYAqVXVlxtIX
qyUBnu3X9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JEMhNRcVFMO8dJDaFeo
f9Oeos0UUothgiDktdQHxdNEwLjQf7lJJBzV+5OtwswCWA==
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi
4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS
gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW
URnoU85w+W6aLI2bNSq3AaE771p3VbkGolpEjo9h+i42TBHo1rhPNKPkGupR8/QX
AOLMpInRdeaHyDwb2a3DE5I3dG7VAVzrVfJ6W6Q84YoFX+rpEE2SVM17SAjy6xQy
VjKgLvK2mk0xbtfa+h0B6VK7bmODHZqeP18NVm6HsBcXn7iclLgAC3SfWU1jucZK
x1lqzw9tAgMBAAECggEABWzxS1Y2wckblnXY57Z+sl6YdmLV+gxj2r8Qib7g4ZIk
lIlWR1OJNfw7kU4eryib4fc6nOh6O4AWZyYqAK6tqNQSS/eVG0LQTLTTEldHyVJL
dvBe+MsUQOj4nTndZW+QvFzbcm2D8lY5n2nBSxU5ypVoKZ1EqQzytFcLZpTN7d89
EPj0qDyrV4NZlWAwL1AygCwnlwhMQjXEalVF1ylXwU3QzyZ/6MgvF6d3SSUlh+sq
XefuyigXw484cQQgbzopv6niMOmGP3of+yV4JQqUSb3IDmmT68XjGd2Dkxl4iPki
6ZwXf3CCi+c+i/zVEcufgZ3SLf8D99kUGE7v7fZ6AQKBgQD1ZX3RAla9hIhxCf+O
3D+I1j2LMrdjAh0ZKKqwMR4JnHX3mjQI6LwqIctPWTU8wYFECSh9klEclSdCa64s
uI/GNpcqPXejd0cAAdqHEEeG5sHMDt0oFSurL4lyud0GtZvwlzLuwEweuDtvT9cJ
Wfvl86uyO36IW8JdvUprYDctrQKBgQDycZ697qutBieZlGkHpnYWUAeImVA878sJ
w44NuXHvMxBPz+lbJGAg8Cn8fcxNAPqHIraK+kx3po8cZGQywKHUWsxi23ozHoxo
+bGqeQb9U661TnfdDspIXia+xilZt3mm5BPzOUuRqlh4Y9SOBpSWRmEhyw76w4ZP
OPxjWYAgwQKBgA/FehSYxeJgRjSdo+MWnK66tjHgDJE8bYpUZsP0JC4R9DL5oiaA
brd2fI6Y+SbyeNBallObt8LSgzdtnEAbjIH8uDJqyOmknNePRvAvR6mP4xyuR+Bv
m+Lgp0DMWTw5J9CKpydZDItc49T/mJ5tPhdFVd+am0NAQnmr1MCZ6nHxAoGABS3Y
LkaC9FdFUUqSU8+Chkd/YbOkuyiENdkvl6t2e52jo5DVc1T7mLiIrRQi4SI8N9bN
/3oJWCT+uaSLX2ouCtNFunblzWHBrhxnZzTeqVq4SLc8aESAnbslKL4i8/+vYZlN
s8xtiNcSvL+lMsOBORSXzpj/4Ot8WwTkn1qyGgECgYBKNTypzAHeLE6yVadFp3nQ
Ckq9yzvP/ib05rvgbvrne00YeOxqJ9gtTrzgh7koqJyX1L4NwdkEza4ilDWpucn0
xiUZS4SoaJq6ZvcBYS62Yr1t8n09iG47YL8ibgtmH3L+svaotvpVxVK+d7BLevA/
ZboOWVe3icTy64BT3OQhmg==
-----END RSA PRIVATE KEY-----`)
)
@@ -72,7 +91,7 @@ func TestHTTP3AdvertisedPort(t *testing.T) {
HTTP3: &static.HTTP3Config{
AdvertisedPort: 8080,
},
})
}, nil)
require.NoError(t, err)
router := &tcp.Router{}

View File

@@ -79,7 +79,7 @@ func testShutdown(t *testing.T, router *tcp.Router) {
Address: "127.0.0.1:0",
Transport: epConfig,
ForwardedHeaders: &static.ForwardedHeaders{},
})
}, nil)
require.NoError(t, err)
conn, err := startEntrypoint(entryPoint, router)
@@ -162,7 +162,7 @@ func TestReadTimeoutWithoutFirstByte(t *testing.T) {
Address: ":0",
Transport: epConfig,
ForwardedHeaders: &static.ForwardedHeaders{},
})
}, nil)
require.NoError(t, err)
router := &tcp.Router{}
@@ -198,7 +198,7 @@ func TestReadTimeoutWithFirstByte(t *testing.T) {
Address: ":0",
Transport: epConfig,
ForwardedHeaders: &static.ForwardedHeaders{},
})
}, nil)
require.NoError(t, err)
router := &tcp.Router{}

View File

@@ -50,7 +50,7 @@ var (
// Certs and Key could be either a file path, or the file content itself.
type Certificate struct {
CertFile FileOrContent `json:"certFile,omitempty" toml:"certFile,omitempty" yaml:"certFile,omitempty"`
KeyFile FileOrContent `json:"keyFile,omitempty" toml:"keyFile,omitempty" yaml:"keyFile,omitempty"`
KeyFile FileOrContent `json:"keyFile,omitempty" toml:"keyFile,omitempty" yaml:"keyFile,omitempty" loggable:"false"`
}
// Certificates defines traefik certificates type

View File

@@ -17,35 +17,54 @@ import (
// go run generate_cert.go --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
var (
localhostCert = FileOrContent(`-----BEGIN CERTIFICATE-----
MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS
MIIDOTCCAiGgAwIBAgIQSRJrEpBGFc7tNb1fb5pKFzANBgkqhkiG9w0BAQsFADAS
MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4
iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul
rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO
BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw
AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA
AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9
tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs
h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM
fblo6RBxUQ==
MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEA6Gba5tHV1dAKouAaXO3/ebDUU4rvwCUg/CNaJ2PT5xLD4N1Vcb8r
bFSW2HXKq+MPfVdwIKR/1DczEoAGf/JWQTW7EgzlXrCd3rlajEX2D73faWJekD0U
aUgz5vtrTXZ90BQL7WvRICd7FlEZ6FPOcPlumiyNmzUqtwGhO+9ad1W5BqJaRI6P
YfouNkwR6Na4TzSj5BrqUfP0FwDizKSJ0XXmh8g8G9mtwxOSN3Ru1QFc61Xyeluk
POGKBV/q6RBNklTNe0gI8usUMlYyoC7ytppNMW7X2vodAelSu25jgx2anj9fDVZu
h7AXF5+4nJS4AAt0n1lNY7nGSsdZas8PbQIDAQABo4GIMIGFMA4GA1UdDwEB/wQE
AwICpDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
DgQWBBStsdjh3/JCXXYlQryOrL4Sh7BW5TAuBgNVHREEJzAlggtleGFtcGxlLmNv
bYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQsFAAOCAQEAxWGI
5NhpF3nwwy/4yB4i/CwwSpLrWUa70NyhvprUBC50PxiXav1TeDzwzLx/o5HyNwsv
cxv3HdkLW59i/0SlJSrNnWdfZ19oTcS+6PtLoVyISgtyN6DpkKpdG1cOkW3Cy2P2
+tK/tKHRP1Y/Ra0RiDpOAmqn0gCOFGz8+lqDIor/T7MTpibL3IxqWfPrvfVRHL3B
grw/ZQTTIVjjh4JBSW3WyWgNo/ikC1lrVxzl4iPUGptxT36Cr7Zk2Bsg0XqwbOvK
5d+NTDREkSnUbie4GeutujmX3Dsx88UiV6UY/4lHJa6I5leHUNOHahRbpbWeOfs/
WkBKOclmOV2xlTVuPw==
-----END CERTIFICATE-----`)
// LocalhostKey is the private key for localhostCert.
localhostKey = FileOrContent(`-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9
SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZB
l2+XsDulrKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQAB
AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xlp/DoCzjA0CQQDU
y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj013sovGKUFfYAqVXVlxtIX
qyUBnu3X9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JEMhNRcVFMO8dJDaFeo
f9Oeos0UUothgiDktdQHxdNEwLjQf7lJJBzV+5OtwswCWA==
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDoZtrm0dXV0Aqi
4Bpc7f95sNRTiu/AJSD8I1onY9PnEsPg3VVxvytsVJbYdcqr4w99V3AgpH/UNzMS
gAZ/8lZBNbsSDOVesJ3euVqMRfYPvd9pYl6QPRRpSDPm+2tNdn3QFAvta9EgJ3sW
URnoU85w+W6aLI2bNSq3AaE771p3VbkGolpEjo9h+i42TBHo1rhPNKPkGupR8/QX
AOLMpInRdeaHyDwb2a3DE5I3dG7VAVzrVfJ6W6Q84YoFX+rpEE2SVM17SAjy6xQy
VjKgLvK2mk0xbtfa+h0B6VK7bmODHZqeP18NVm6HsBcXn7iclLgAC3SfWU1jucZK
x1lqzw9tAgMBAAECggEABWzxS1Y2wckblnXY57Z+sl6YdmLV+gxj2r8Qib7g4ZIk
lIlWR1OJNfw7kU4eryib4fc6nOh6O4AWZyYqAK6tqNQSS/eVG0LQTLTTEldHyVJL
dvBe+MsUQOj4nTndZW+QvFzbcm2D8lY5n2nBSxU5ypVoKZ1EqQzytFcLZpTN7d89
EPj0qDyrV4NZlWAwL1AygCwnlwhMQjXEalVF1ylXwU3QzyZ/6MgvF6d3SSUlh+sq
XefuyigXw484cQQgbzopv6niMOmGP3of+yV4JQqUSb3IDmmT68XjGd2Dkxl4iPki
6ZwXf3CCi+c+i/zVEcufgZ3SLf8D99kUGE7v7fZ6AQKBgQD1ZX3RAla9hIhxCf+O
3D+I1j2LMrdjAh0ZKKqwMR4JnHX3mjQI6LwqIctPWTU8wYFECSh9klEclSdCa64s
uI/GNpcqPXejd0cAAdqHEEeG5sHMDt0oFSurL4lyud0GtZvwlzLuwEweuDtvT9cJ
Wfvl86uyO36IW8JdvUprYDctrQKBgQDycZ697qutBieZlGkHpnYWUAeImVA878sJ
w44NuXHvMxBPz+lbJGAg8Cn8fcxNAPqHIraK+kx3po8cZGQywKHUWsxi23ozHoxo
+bGqeQb9U661TnfdDspIXia+xilZt3mm5BPzOUuRqlh4Y9SOBpSWRmEhyw76w4ZP
OPxjWYAgwQKBgA/FehSYxeJgRjSdo+MWnK66tjHgDJE8bYpUZsP0JC4R9DL5oiaA
brd2fI6Y+SbyeNBallObt8LSgzdtnEAbjIH8uDJqyOmknNePRvAvR6mP4xyuR+Bv
m+Lgp0DMWTw5J9CKpydZDItc49T/mJ5tPhdFVd+am0NAQnmr1MCZ6nHxAoGABS3Y
LkaC9FdFUUqSU8+Chkd/YbOkuyiENdkvl6t2e52jo5DVc1T7mLiIrRQi4SI8N9bN
/3oJWCT+uaSLX2ouCtNFunblzWHBrhxnZzTeqVq4SLc8aESAnbslKL4i8/+vYZlN
s8xtiNcSvL+lMsOBORSXzpj/4Ot8WwTkn1qyGgECgYBKNTypzAHeLE6yVadFp3nQ
Ckq9yzvP/ib05rvgbvrne00YeOxqJ9gtTrzgh7koqJyX1L4NwdkEza4ilDWpucn0
xiUZS4SoaJq6ZvcBYS62Yr1t8n09iG47YL8ibgtmH3L+svaotvpVxVK+d7BLevA/
ZboOWVe3icTy64BT3OQhmg==
-----END RSA PRIVATE KEY-----`)
)

View File

@@ -25,7 +25,7 @@ func init() {
// Config provides configuration settings for a elastic.co tracer.
type Config struct {
ServerURL string `description:"Sets the URL of the Elastic APM server." json:"serverURL,omitempty" toml:"serverURL,omitempty" yaml:"serverURL,omitempty"`
SecretToken string `description:"Sets the token used to connect to Elastic APM Server." json:"secretToken,omitempty" toml:"secretToken,omitempty" yaml:"secretToken,omitempty"`
SecretToken string `description:"Sets the token used to connect to Elastic APM Server." json:"secretToken,omitempty" toml:"secretToken,omitempty" yaml:"secretToken,omitempty" loggable:"false"`
ServiceEnvironment string `description:"Sets the name of the environment Traefik is deployed in, e.g. 'production' or 'staging'." json:"serviceEnvironment,omitempty" toml:"serviceEnvironment,omitempty" yaml:"serviceEnvironment,omitempty" export:"true"`
}

View File

@@ -43,8 +43,8 @@ func (c *Config) SetDefaults() {
// Collector provides configuration settings for jaeger collector.
type Collector struct {
Endpoint string `description:"Instructs reporter to send spans to jaeger-collector at this URL." json:"endpoint,omitempty" toml:"endpoint,omitempty" yaml:"endpoint,omitempty"`
User string `description:"User for basic http authentication when sending spans to jaeger-collector." json:"user,omitempty" toml:"user,omitempty" yaml:"user,omitempty"`
Password string `description:"Password for basic http authentication when sending spans to jaeger-collector." json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty"`
User string `description:"User for basic http authentication when sending spans to jaeger-collector." json:"user,omitempty" toml:"user,omitempty" yaml:"user,omitempty" loggable:"false"`
Password string `description:"Password for basic http authentication when sending spans to jaeger-collector." json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty" loggable:"false"`
}
// SetDefaults sets the default values.

View File

@@ -22,7 +22,7 @@ type Prometheus struct {
AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"`
AddRoutersLabels bool `description:"Enable metrics on routers." json:"addRoutersLabels,omitempty" toml:"addRoutersLabels,omitempty" yaml:"addRoutersLabels,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"`
EntryPoint string `description:"EntryPoint" json:"entryPoint,omitempty" toml:"entryPoint,omitempty" yaml:"entryPoint,omitempty" export:"true"`
ManualRouting bool `description:"Manual routing" json:"manualRouting,omitempty" toml:"manualRouting,omitempty" yaml:"manualRouting,omitempty" export:"true"`
}
@@ -88,8 +88,8 @@ type InfluxDB struct {
PushInterval types.Duration `description:"InfluxDB push interval." json:"pushInterval,omitempty" toml:"pushInterval,omitempty" yaml:"pushInterval,omitempty" export:"true"`
Database string `description:"InfluxDB database used when protocol is http." json:"database,omitempty" toml:"database,omitempty" yaml:"database,omitempty" export:"true"`
RetentionPolicy string `description:"InfluxDB retention policy used when protocol is http." json:"retentionPolicy,omitempty" toml:"retentionPolicy,omitempty" yaml:"retentionPolicy,omitempty" export:"true"`
Username string `description:"InfluxDB username (only with http)." json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty"`
Password string `description:"InfluxDB password (only with http)." json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty"`
Username string `description:"InfluxDB username (only with http)." json:"username,omitempty" toml:"username,omitempty" yaml:"username,omitempty" loggable:"false"`
Password string `description:"InfluxDB password (only with http)." json:"password,omitempty" toml:"password,omitempty" yaml:"password,omitempty" loggable:"false"`
AddEntryPointsLabels bool `description:"Enable metrics on entry points." json:"addEntryPointsLabels,omitempty" toml:"addEntryPointsLabels,omitempty" yaml:"addEntryPointsLabels,omitempty" export:"true"`
AddRoutersLabels bool `description:"Enable metrics on routers." json:"addRoutersLabels,omitempty" toml:"addRoutersLabels,omitempty" yaml:"addRoutersLabels,omitempty" export:"true"`
AddServicesLabels bool `description:"Enable metrics on services." json:"addServicesLabels,omitempty" toml:"addServicesLabels,omitempty" yaml:"addServicesLabels,omitempty" export:"true"`

View File

@@ -19,7 +19,7 @@ type ClientTLS struct {
CA string `description:"TLS CA" json:"ca,omitempty" toml:"ca,omitempty" yaml:"ca,omitempty"`
CAOptional bool `description:"TLS CA.Optional" json:"caOptional,omitempty" toml:"caOptional,omitempty" yaml:"caOptional,omitempty" export:"true"`
Cert string `description:"TLS cert" json:"cert,omitempty" toml:"cert,omitempty" yaml:"cert,omitempty"`
Key string `description:"TLS key" json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty"`
Key string `description:"TLS key" json:"key,omitempty" toml:"key,omitempty" yaml:"key,omitempty" loggable:"false"`
InsecureSkipVerify bool `description:"TLS insecure skip verify" json:"insecureSkipVerify,omitempty" toml:"insecureSkipVerify,omitempty" yaml:"insecureSkipVerify,omitempty" export:"true"`
}

View File

@@ -4,11 +4,11 @@ RepositoryName = "traefik"
OutputType = "file"
FileName = "traefik_changelog.md"
# example new bugfix v2.5.7
CurrentRef = "v2.5"
PreviousRef = "v2.5.6"
BaseBranch = "v2.5"
FutureCurrentRefName = "v2.5.7"
# example new bugfix v2.6.1
CurrentRef = "v2.6"
PreviousRef = "v2.6.0"
BaseBranch = "v2.6"
FutureCurrentRefName = "v2.6.1"
ThresholdPreviousRef = 10
ThresholdCurrentRef = 10

View File

@@ -4,11 +4,11 @@ RepositoryName = "traefik"
OutputType = "file"
FileName = "traefik_changelog.md"
# example final release of v2.5.0
CurrentRef = "v2.5"
PreviousRef = "v2.5.0-rc1"
BaseBranch = "v2.5"
FutureCurrentRefName = "v2.5.0"
# example final release of v2.6.0
CurrentRef = "v2.6"
PreviousRef = "v2.6.0-rc1"
BaseBranch = "v2.6"
FutureCurrentRefName = "v2.6.0"
ThresholdPreviousRef = 10
ThresholdCurrentRef = 10

View File

@@ -4,11 +4,11 @@ RepositoryName = "traefik"
OutputType = "file"
FileName = "traefik_changelog.md"
# example final release of v2.5.0
CurrentRef = "v2.5.0-rc1"
PreviousRef = "v2.4.0-rc1"
# example final release of v2.6.0
CurrentRef = "v2.6.0-rc1"
PreviousRef = "v2.5.0-rc1"
BaseBranch = "master"
FutureCurrentRefName = "v2.5.0-rc1"
FutureCurrentRefName = "v2.6.0-rc1"
ThresholdPreviousRef = 10
ThresholdCurrentRef = 10