forked from Ivasoft/traefik
Compare commits
17 Commits
v2.6.0-rc3
...
v2.6.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84a0810546 | ||
|
|
d9fbb5e25c | ||
|
|
e97aa6515b | ||
|
|
6bcfba43c8 | ||
|
|
0c83ee736c | ||
|
|
4da33c2bc2 | ||
|
|
2d56be0ebb | ||
|
|
6742dd8454 | ||
|
|
3ac755bd2f | ||
|
|
3ed72c4e46 | ||
|
|
477fa15859 | ||
|
|
390eb9cb61 | ||
|
|
5a1c936ede | ||
|
|
47ad6538f1 | ||
|
|
9be44d8330 | ||
|
|
a4b354b33f | ||
|
|
a70b864c55 |
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -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
|
||||
|
||||
64
CHANGELOG.md
64
CHANGELOG.md
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -14,7 +14,7 @@ labels:
|
||||
|
||||
```yaml tab="Kubernetes"
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: Middleware
|
||||
kind: MiddlewareTCP
|
||||
metadata:
|
||||
name: test-inflightconn
|
||||
spec:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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`.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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-----
|
||||
"""]
|
||||
|
||||
|
||||
@@ -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-----
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
107
pkg/middlewares/snicheck/snicheck.go
Normal file
107
pkg/middlewares/snicheck/snicheck.go
Normal 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 ""
|
||||
}
|
||||
60
pkg/middlewares/snicheck/snicheck_test.go
Normal file
60
pkg/middlewares/snicheck/snicheck_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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{}
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
@@ -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)
|
||||
})
|
||||
382
pkg/redactor/redactor_doOnStruct_test.go
Normal file
382
pkg/redactor/redactor_doOnStruct_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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": {
|
||||
487
pkg/redactor/testdata/secured-dynamic-config.json
vendored
Normal file
487
pkg/redactor/testdata/secured-dynamic-config.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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() {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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{}
|
||||
|
||||
@@ -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{}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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-----`)
|
||||
)
|
||||
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user