mirror of
https://github.com/containous/traefik.git
synced 2026-01-18 00:34:10 +03:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51343bc15f | ||
|
|
9e5d4ba5a1 | ||
|
|
adf47fba31 | ||
|
|
ee265a8509 | ||
|
|
fc67185987 | ||
|
|
e8067f4e01 | ||
|
|
e9f3089e90 | ||
|
|
47d7094dfb |
63
.github/workflows/check_doc.yaml
vendored
Normal file
63
.github/workflows/check_doc.yaml
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
name: Check Documentation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
paths:
|
||||
- '.github/workflows/check_doc.yaml'
|
||||
- 'docs/**'
|
||||
|
||||
jobs:
|
||||
|
||||
docs:
|
||||
name: lint, build and verify
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install markdownlint
|
||||
run: |
|
||||
npm install --global markdownlint@0.29.0 markdownlint-cli@0.35.0
|
||||
|
||||
- name: Lint
|
||||
run: ./docs/scripts/lint.sh docs
|
||||
|
||||
- name: Setup python
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: '3.12'
|
||||
cache: 'pip'
|
||||
cache-dependency-path: "./docs/requirements.txt"
|
||||
|
||||
- name: Build documentation
|
||||
working-directory: ./docs
|
||||
run: |
|
||||
pip install -r requirements.txt
|
||||
mkdocs build --strict
|
||||
|
||||
- name: Setup ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
ruby-version: '3.4'
|
||||
|
||||
- name: Install html-proofer
|
||||
run: |
|
||||
gem install nokogiri --version 1.18.6 --no-document -- --use-system-libraries
|
||||
gem install html-proofer --version 5.0.10 --no-document -- --use-system-libraries
|
||||
env:
|
||||
NOKOGIRI_USE_SYSTEM_LIBRARIES: "true"
|
||||
|
||||
# Comes from https://github.com/gjtorikian/html-proofer?tab=readme-ov-file#caching-with-continuous-integration
|
||||
- name: Cache HTMLProofer
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: tmp/.htmlproofer
|
||||
key: ${{ runner.os }}-htmlproofer
|
||||
|
||||
- name: Verify
|
||||
run: ./docs/scripts/verify.sh docs/site
|
||||
25
.github/workflows/check_doc.yml
vendored
25
.github/workflows/check_doc.yml
vendored
@@ -1,25 +0,0 @@
|
||||
name: Check Documentation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
|
||||
docs:
|
||||
name: Check, verify and build documentation
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check documentation
|
||||
run: make docs-pull-images docs
|
||||
env:
|
||||
# These variables are not passed to workflows that are triggered by a pull request from a fork.
|
||||
DOCS_VERIFY_SKIP: ${{ vars.DOCS_VERIFY_SKIP }}
|
||||
DOCS_LINT_SKIP: ${{ vars.DOCS_LINT_SKIP }}
|
||||
4
.github/workflows/validate.yaml
vendored
4
.github/workflows/validate.yaml
vendored
@@ -7,8 +7,8 @@ on:
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.24'
|
||||
GOLANGCI_LINT_VERSION: v2.0.2
|
||||
MISSPELL_VERSION: v0.6.0
|
||||
GOLANGCI_LINT_VERSION: v2.7.2
|
||||
MISSPELL_VERSION: v0.7.0
|
||||
|
||||
jobs:
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ linters:
|
||||
- nilnil # Not relevant
|
||||
- nlreturn # Not relevant
|
||||
- noctx # Too strict
|
||||
- noinlineerr # Too strict
|
||||
- nonamedreturns # Too strict
|
||||
- paralleltest # Not relevant
|
||||
- prealloc # Too many false-positive.
|
||||
@@ -47,6 +48,7 @@ linters:
|
||||
- varnamelen # Not relevant
|
||||
- wrapcheck # Too strict
|
||||
- wsl # Too strict
|
||||
- wsl_v5 # Too strict
|
||||
|
||||
settings:
|
||||
depguard:
|
||||
@@ -292,15 +294,31 @@ linters:
|
||||
source: 'errors.New\("Nomad provider'
|
||||
text: 'ST1005: error strings should not be capitalized'
|
||||
- path: (.+)\.go
|
||||
text: 'struct-tag: unknown option ''inline'' in JSON tag'
|
||||
text: 'omitzero: Omitempty has no effect on nested struct field'
|
||||
linters:
|
||||
- modernize
|
||||
- path: (.+)\.go
|
||||
text: 'struct-tag: unknown option "inline" in json tag'
|
||||
linters:
|
||||
- revive
|
||||
- path: (.+)\.go
|
||||
text: 'struct-tag: unknown option ''omitzero'' in TOML tag'
|
||||
text: 'struct-tag: unknown option "omitzero" in toml tag'
|
||||
linters:
|
||||
- revive
|
||||
- path: (pkg/types/.+|pkg/api/.+)\.go
|
||||
text: 'var-naming: avoid meaningless package names'
|
||||
linters:
|
||||
- revive
|
||||
- path: (pkg/muxer/http/.+|pkg/provider/http/.+)\.go
|
||||
text: 'var-naming: avoid package names that conflict with Go standard library package names'
|
||||
linters:
|
||||
- revive
|
||||
- path: (.+)\.go$
|
||||
text: 'SA1019: http.CloseNotifier has been deprecated' # FIXME must be fixed
|
||||
- path: (.+)\.go$
|
||||
text: 'SA1019: dynamic.(TCPIPWhiteList|IPWhiteList) is deprecated: please use IPAllowList instead.'
|
||||
- path: (.+)\.go$
|
||||
text: 'SA1019: middlewareTCP.Spec.IPWhiteList is deprecated: please use IPAllowList instead.'
|
||||
- path: (.+)\.go$
|
||||
text: 'SA1019: cfg.(SSLRedirect|SSLTemporaryRedirect|SSLHost|SSLForceHost|FeaturePolicy) is deprecated'
|
||||
- path: (.+)\.go$
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
## [v2.11.35](https://github.com/traefik/traefik/tree/v2.11.35) (2026-01-14)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v2.11.34...v2.11.35)
|
||||
|
||||
**Bug fixes:**
|
||||
- **[acme]** Add timeout to ACME-TLS/1 challenge handshake ([#12516](https://github.com/traefik/traefik/pull/12516) by [LBF38](https://github.com/LBF38))
|
||||
- **[server]** Make encoded character options opt-in ([#12540](https://github.com/traefik/traefik/pull/12540) by [gndz07](https://github.com/gndz07))
|
||||
|
||||
## [v2.11.34](https://github.com/traefik/traefik/tree/v2.11.34) (2025-12-23)
|
||||
[All Commits](https://github.com/traefik/traefik/compare/v2.11.33...v2.11.34)
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
// TraefikCmdConfiguration wraps the static configuration and extra parameters.
|
||||
type TraefikCmdConfiguration struct {
|
||||
static.Configuration `export:"true"`
|
||||
|
||||
// ConfigFile is the path to the configuration file.
|
||||
ConfigFile string `description:"Configuration file to use. If specified all other flags are ignored." export:"true"`
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ func run(dest string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(filepath.Join(dest, "marshaler.go"), []byte(fmt.Sprintf(marsh, destPkg)), 0o666)
|
||||
return os.WriteFile(filepath.Join(dest, "marshaler.go"), fmt.Appendf(nil, marsh, destPkg), 0o666)
|
||||
}
|
||||
|
||||
func cleanType(typ types.Type, base string) string {
|
||||
|
||||
@@ -87,10 +87,10 @@ Complete documentation is available at https://traefik.io`,
|
||||
func runCmd(staticConfiguration *static.Configuration) error {
|
||||
configureLogging(staticConfiguration)
|
||||
|
||||
// Display warning to advertise for new behavior of rejecting encoded characters in the request path.
|
||||
// Deprecated: this has to be removed in the next minor/major version.
|
||||
log.WithoutContext().Warnf("Starting with v2.11.32, Traefik now rejects some encoded characters in the request path by default. " +
|
||||
"Refer to the documentation for more details: https://doc.traefik.io/traefik/v2.11/migration/v2/#encoded-characters-in-request-path")
|
||||
log.WithoutContext().Warn("Traefik can reject some encoded characters in the request path." +
|
||||
"When your backend is not fully compliant with [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986)," +
|
||||
"it is recommended to set these options to `false` to avoid split-view situation." +
|
||||
"Refer to the documentation for more details: https://doc.traefik.io/traefik/v2.11/migration/v2/#encoded-characters-configuration-default-values")
|
||||
|
||||
http.DefaultTransport.(*http.Transport).Proxy = http.ProxyFromEnvironment
|
||||
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
/* Highlight */
|
||||
(function(hljs) {
|
||||
hljs.initHighlightingOnLoad();
|
||||
})(hljs);
|
||||
})(hljs);
|
||||
|
||||
/* Scarf Analytics - cookieless, anonymous company-level intelligence */
|
||||
(function() {
|
||||
var img = document.createElement('img');
|
||||
img.src = 'https://static.scarf.sh/a.png?x-pxid=1a49232a-b165-4015-8ed2-a1092f1f0d83';
|
||||
img.referrerPolicy = 'no-referrer-when-downgrade';
|
||||
img.loading = 'eager';
|
||||
img.style.cssText = 'visibility:hidden;position:absolute;width:1px;height:1px;';
|
||||
document.body.appendChild(img);
|
||||
})();
|
||||
@@ -34,7 +34,7 @@ Below is a non-exhaustive list of versions and their maintenance status:
|
||||
|
||||
This page is maintained and updated periodically to reflect our roadmap and any decisions affecting the end of support for Traefik Proxy.
|
||||
|
||||
Please refer to our migration guides for specific instructions on upgrading between versions, an example is the [v2 to v3 migration guide](../migration/v2-to-v3.md).
|
||||
Please refer to our migration guides for specific instructions on upgrading between versions.
|
||||
|
||||
!!! important "All target dates for end of support or feature removal announcements may be subject to change."
|
||||
|
||||
|
||||
@@ -57,4 +57,4 @@ You no longer need to create and synchronize configuration files cluttered with
|
||||
Traefik is able to use your cluster API to discover the services and read the attached information.
|
||||
In Traefik, these connectors are called [providers](../providers/overview.md "Link to overview about Traefik providers") because they *provide* the configuration to Traefik.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -94,4 +94,4 @@ All the configuration options are documented in their related section.
|
||||
|
||||
You can browse the available features in the menu, the [providers](../providers/overview.md), or the [routing section](../routing/overview.md) to see them in action.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -252,4 +252,4 @@ In which case, you should make sure your infrastructure is properly set up for a
|
||||
LEGO_DISABLE_CNAME_SUPPORT=true
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -144,4 +144,4 @@ And run it:
|
||||
|
||||
All the details are available in the [Contributing Guide](../contributing/building-testing.md)
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -334,4 +334,4 @@ curl -v http://localhost/
|
||||
- Use [IngressRoute CRD](../providers/kubernetes-crd.md)
|
||||
- Protect [ingresses with TLS](../routing/providers/kubernetes-ingress.md#enabling-tls-via-annotations)
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -121,4 +121,4 @@ IP: 172.27.0.4
|
||||
|
||||
Now that you have a basic understanding of how Traefik can automatically create the routes to your services and load balance them, it is time to dive into [the user guides](../../user-guides/docker-compose/basic-example/ "Link to the user guides") and [the documentation](/ "Link to the docs landing page") and let Traefik work for you!
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -797,4 +797,4 @@ If Let's Encrypt is not reachable, the following certificates will apply:
|
||||
!!! important
|
||||
For new (sub)domains which need Let's Encrypt authentication, the default Traefik certificate will be used until Traefik is restarted.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -20,4 +20,4 @@ That is to say, how to obtain [TLS certificates](./tls.md#certificates-definitio
|
||||
either through a definition in the dynamic configuration, or through [Let's Encrypt](./acme.md) (ACME).
|
||||
And how to configure [TLS options](./tls.md#tls-options), and [certificates stores](./tls.md#certificates-stores).
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -561,4 +561,4 @@ spec:
|
||||
clientAuthType: RequireAndVerifyClientCert
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -404,4 +404,4 @@ http:
|
||||
[http.middlewares.test-auth.basicAuth]
|
||||
removeHeader = true
|
||||
```
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -637,4 +637,4 @@ http:
|
||||
[http.middlewares.test-auth.forwardAuth.tls]
|
||||
insecureSkipVerify: true
|
||||
```
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -480,4 +480,4 @@ Set `isDevelopment` to `true` when developing to mitigate the unwanted effects o
|
||||
Usually testing takes place using HTTP, not HTTPS, and on `localhost`, not your production domain.
|
||||
If you would like your development environment to mimic production with complete Host blocking, SSL redirects, and STS headers, leave this as `false`.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -158,4 +158,4 @@ http:
|
||||
|
||||
Please take a look at the community-contributed plugins in the [plugin catalog](https://plugins.traefik.io/plugins).
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -100,4 +100,4 @@ The `replacement` option defines how to modify the URL to have the new target UR
|
||||
|
||||
Care should be taken when defining replacement expand variables: `$1x` is equivalent to `${1x}`, not `${1}x` (see [Regexp.Expand](https://golang.org/pkg/regexp/#Regexp.Expand)), so use `${1}` syntax.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -171,4 +171,4 @@ http:
|
||||
forceSlash = false
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -130,4 +130,4 @@ A list of HTTP middlewares can be found [here](http/overview.md).
|
||||
|
||||
A list of TCP middlewares can be found [here](tcp/overview.md).
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -737,3 +737,30 @@ Note: This check is not done against query parameters,
|
||||
but only against the request path as defined in [RFC3986 section-3](https://datatracker.ietf.org/doc/html/rfc3986#section-3).
|
||||
|
||||
Please check out the entrypoint [encodedCharacters option](../routing/entrypoints.md#encoded-characters) documentation for more details.
|
||||
|
||||
## v2.11.35
|
||||
|
||||
### Encoded Characters Configuration Default Values
|
||||
|
||||
Since `v2.11.35`, the options for encoded characters now have a `true` default value.
|
||||
This means that Traefik will not reject requests with a path containing a specific set of encoded characters by default.
|
||||
It is now up to the users to configure the security hardening of encoded characters.
|
||||
|
||||
Here is the list of the encoded characters that can be configured to `false` to disallow them:
|
||||
|
||||
| Encoded Character | Character | Config options | Default value |
|
||||
|-------------------|-------------------------|--------------------------------------------------------------------------------------|---------------|
|
||||
| `%2f` or `%2F` | `/` (slash) | `entryPoints.<name>`<br/>`.http.encodedCharacters`<br/>`.allowEncodedSlash` | `true` |
|
||||
| `%5c` or `%5C` | `\` (backslash) | `entryPoints.<name>.`<br/>`.http.encodedCharacters`<br/>`.allowEncodedBackSlash` | `true` |
|
||||
| `%00` | `NULL` (null character) | `entryPoints.<name>.`<br/>`.http.encodedCharacters`<br/>`.allowEncodedNullCharacter` | `true` |
|
||||
| `%3b` or `%3B` | `;` (semicolon) | `entryPoints.<name>.`<br/>`.http.encodedCharacters`<br/>`.allowEncodedSemicolon` | `true` |
|
||||
| `%25` | `%` (percent) | `entryPoints.<name>.`<br/>`.http.encodedCharacters`<br/>`.allowEncodedPercent` | `true` |
|
||||
| `%3f` or `%3F` | `?` (question mark) | `entryPoints.<name>.`<br/>`.http.encodedCharacters`<br/>`.allowEncodedQuestionMark` | `true` |
|
||||
| `%23` | `#` (hash) | `entryPoints.<name>.`<br/>`.http.encodedCharacters`<br/>`.allowEncodedHash` | `true` |
|
||||
|
||||
Note: This check is not done against query parameters,
|
||||
but only against the request path as defined
|
||||
in [RFC3986 section-3](https://datatracker.ietf.org/doc/html/rfc3986#section-3).
|
||||
|
||||
Please check out the entrypoint [encodedCharacters option](../routing/entrypoints.md#encoded-characters) documentation
|
||||
for more details.
|
||||
|
||||
@@ -281,4 +281,4 @@ services:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -90,4 +90,4 @@ This allows the logs to be rotated and processed by an external program, such as
|
||||
!!! warning
|
||||
This does not work on Windows due to the lack of USR signals.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -175,4 +175,4 @@ All the following endpoints must be accessed with a `GET` HTTP request.
|
||||
| `/debug/pprof/symbol` | See the [pprof Symbol](https://golang.org/pkg/net/http/pprof/#Symbol) Go documentation. |
|
||||
| `/debug/pprof/trace` | See the [pprof Trace](https://golang.org/pkg/net/http/pprof/#Trace) Go documentation. |
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -132,4 +132,4 @@ api:
|
||||
--api.dashboard=false
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -31,4 +31,4 @@ The experience of implementing a Traefik plugin is comparable to writing a web b
|
||||
|
||||
To learn more about Traefik plugin creation, please refer to the [developer documentation](https://plugins.traefik.io/create).
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -764,4 +764,4 @@ providers:
|
||||
--providers.docker.allowEmptyServices=true
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -292,4 +292,4 @@ To illustrate, it is possible to easily define multiple routers, services, and T
|
||||
{{ end }}
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -345,4 +345,4 @@ providers:
|
||||
|
||||
For additional information, refer to the [full example](../user-guides/crd-acme/index.md) with Let's Encrypt.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -269,4 +269,4 @@ providers:
|
||||
--providers.kubernetesgateway.throttleDuration=10s
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -504,4 +504,4 @@ providers:
|
||||
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.11/pkg/provider/kubernetes/ingress/fixtures) of the Traefik repository.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -233,4 +233,4 @@ List of providers that support constraints:
|
||||
- [Kubernetes Ingress](./kubernetes-ingress.md#labelselector)
|
||||
- [Kubernetes Gateway](./kubernetes-gateway.md#labelselector)
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -1273,6 +1273,7 @@ spec:
|
||||
IPWhiteList holds the IP whitelist middleware configuration.
|
||||
This middleware limits allowed requests based on the client IP.
|
||||
More info: https://doc.traefik.io/traefik/v2.11/middlewares/http/ipwhitelist/
|
||||
|
||||
Deprecated: please use IPAllowList instead.
|
||||
properties:
|
||||
ipStrategy:
|
||||
@@ -1663,8 +1664,9 @@ spec:
|
||||
description: |-
|
||||
IPWhiteList defines the IPWhiteList middleware configuration.
|
||||
This middleware accepts/refuses connections based on the client IP.
|
||||
Deprecated: please use IPAllowList instead.
|
||||
More info: https://doc.traefik.io/traefik/v2.11/middlewares/tcp/ipwhitelist/
|
||||
|
||||
Deprecated: please use IPAllowList instead.
|
||||
properties:
|
||||
sourceRange:
|
||||
description: SourceRange defines the allowed IPs (or ranges of
|
||||
@@ -1907,6 +1909,7 @@ spec:
|
||||
description: |-
|
||||
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
||||
It is enabled automatically when minVersion or maxVersion is set.
|
||||
|
||||
Deprecated: https://github.com/golang/go/issues/45430
|
||||
type: boolean
|
||||
sniStrict:
|
||||
@@ -3703,6 +3706,7 @@ spec:
|
||||
IPWhiteList holds the IP whitelist middleware configuration.
|
||||
This middleware limits allowed requests based on the client IP.
|
||||
More info: https://doc.traefik.io/traefik/v2.11/middlewares/http/ipwhitelist/
|
||||
|
||||
Deprecated: please use IPAllowList instead.
|
||||
properties:
|
||||
ipStrategy:
|
||||
@@ -4093,8 +4097,9 @@ spec:
|
||||
description: |-
|
||||
IPWhiteList defines the IPWhiteList middleware configuration.
|
||||
This middleware accepts/refuses connections based on the client IP.
|
||||
Deprecated: please use IPAllowList instead.
|
||||
More info: https://doc.traefik.io/traefik/v2.11/middlewares/tcp/ipwhitelist/
|
||||
|
||||
Deprecated: please use IPAllowList instead.
|
||||
properties:
|
||||
sourceRange:
|
||||
description: SourceRange defines the allowed IPs (or ranges of
|
||||
@@ -4337,6 +4342,7 @@ spec:
|
||||
description: |-
|
||||
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
||||
It is enabled automatically when minVersion or maxVersion is set.
|
||||
|
||||
Deprecated: https://github.com/golang/go/issues/45430
|
||||
type: boolean
|
||||
sniStrict:
|
||||
|
||||
@@ -36,4 +36,4 @@ Dynamic configuration with Kubernetes Custom Resource
|
||||
--8<-- "content/reference/dynamic-configuration/kubernetes-crd-rbac.yml"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -30,4 +30,4 @@ Dynamic configuration with Kubernetes Gateway provider.
|
||||
--8<-- "content/reference/dynamic-configuration/kubernetes-gateway-rbac.yml"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -658,6 +658,7 @@ spec:
|
||||
IPWhiteList holds the IP whitelist middleware configuration.
|
||||
This middleware limits allowed requests based on the client IP.
|
||||
More info: https://doc.traefik.io/traefik/v2.11/middlewares/http/ipwhitelist/
|
||||
|
||||
Deprecated: please use IPAllowList instead.
|
||||
properties:
|
||||
ipStrategy:
|
||||
|
||||
@@ -68,8 +68,9 @@ spec:
|
||||
description: |-
|
||||
IPWhiteList defines the IPWhiteList middleware configuration.
|
||||
This middleware accepts/refuses connections based on the client IP.
|
||||
Deprecated: please use IPAllowList instead.
|
||||
More info: https://doc.traefik.io/traefik/v2.11/middlewares/tcp/ipwhitelist/
|
||||
|
||||
Deprecated: please use IPAllowList instead.
|
||||
properties:
|
||||
sourceRange:
|
||||
description: SourceRange defines the allowed IPs (or ranges of
|
||||
|
||||
@@ -99,6 +99,7 @@ spec:
|
||||
description: |-
|
||||
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
||||
It is enabled automatically when minVersion or maxVersion is set.
|
||||
|
||||
Deprecated: https://github.com/golang/go/issues/45430
|
||||
type: boolean
|
||||
sniStrict:
|
||||
|
||||
@@ -658,6 +658,7 @@ spec:
|
||||
IPWhiteList holds the IP whitelist middleware configuration.
|
||||
This middleware limits allowed requests based on the client IP.
|
||||
More info: https://doc.traefik.io/traefik/v2.11/middlewares/http/ipwhitelist/
|
||||
|
||||
Deprecated: please use IPAllowList instead.
|
||||
properties:
|
||||
ipStrategy:
|
||||
|
||||
@@ -68,8 +68,9 @@ spec:
|
||||
description: |-
|
||||
IPWhiteList defines the IPWhiteList middleware configuration.
|
||||
This middleware accepts/refuses connections based on the client IP.
|
||||
Deprecated: please use IPAllowList instead.
|
||||
More info: https://doc.traefik.io/traefik/v2.11/middlewares/tcp/ipwhitelist/
|
||||
|
||||
Deprecated: please use IPAllowList instead.
|
||||
properties:
|
||||
sourceRange:
|
||||
description: SourceRange defines the allowed IPs (or ranges of
|
||||
|
||||
@@ -99,6 +99,7 @@ spec:
|
||||
description: |-
|
||||
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
||||
It is enabled automatically when minVersion or maxVersion is set.
|
||||
|
||||
Deprecated: https://github.com/golang/go/issues/45430
|
||||
type: boolean
|
||||
sniStrict:
|
||||
|
||||
@@ -124,25 +124,25 @@ Trust only forwarded headers from selected IPs.
|
||||
HTTP configuration.
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodedbackslash`:
|
||||
Defines whether requests with encoded back slash characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded back slash characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodedhash`:
|
||||
Defines whether requests with encoded hash characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded hash characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodednullcharacter`:
|
||||
Defines whether requests with encoded null characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded null characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodedpercent`:
|
||||
Defines whether requests with encoded percent characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded percent characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodedquestionmark`:
|
||||
Defines whether requests with encoded question mark characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded question mark characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodedsemicolon`:
|
||||
Defines whether requests with encoded semicolon characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded semicolon characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodedcharacters.allowencodedslash`:
|
||||
Defines whether requests with encoded slash characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded slash characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`--entrypoints.<name>.http.encodequerysemicolons`:
|
||||
Defines whether request query semicolons should be URLEncoded. (Default: ```false```)
|
||||
|
||||
@@ -133,25 +133,25 @@ HTTP/3 configuration. (Default: ```false```)
|
||||
UDP port to advertise, on which HTTP/3 is available. (Default: ```0```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDBACKSLASH`:
|
||||
Defines whether requests with encoded back slash characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded back slash characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDHASH`:
|
||||
Defines whether requests with encoded hash characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded hash characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDNULLCHARACTER`:
|
||||
Defines whether requests with encoded null characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded null characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDPERCENT`:
|
||||
Defines whether requests with encoded percent characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded percent characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDQUESTIONMARK`:
|
||||
Defines whether requests with encoded question mark characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded question mark characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDSEMICOLON`:
|
||||
Defines whether requests with encoded semicolon characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded semicolon characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEDCHARACTERS_ALLOWENCODEDSLASH`:
|
||||
Defines whether requests with encoded slash characters in the path are allowed. (Default: ```false```)
|
||||
Defines whether requests with encoded slash characters in the path are allowed. (Default: ```true```)
|
||||
|
||||
`TRAEFIK_ENTRYPOINTS_<NAME>_HTTP_ENCODEQUERYSEMICOLONS`:
|
||||
Defines whether request query semicolons should be URLEncoded. (Default: ```false```)
|
||||
|
||||
@@ -129,13 +129,13 @@ They can be defined by using a file (YAML or TOML) or CLI arguments.
|
||||
- "192.168.0.1"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedSlash: true
|
||||
allowEncodedBackSlash: true
|
||||
allowEncodedNullCharacter: true
|
||||
allowEncodedSemicolon: true
|
||||
allowEncodedPercent: true
|
||||
allowEncodedQuestionMark: true
|
||||
allowEncodedHash: true
|
||||
allowEncodedSlash: false
|
||||
allowEncodedBackSlash: false
|
||||
allowEncodedNullCharacter: false
|
||||
allowEncodedSemicolon: false
|
||||
allowEncodedPercent: false
|
||||
allowEncodedQuestionMark: false
|
||||
allowEncodedHash: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -162,13 +162,13 @@ They can be defined by using a file (YAML or TOML) or CLI arguments.
|
||||
insecure = true
|
||||
trustedIPs = ["127.0.0.1", "192.168.0.1"]
|
||||
[entryPoints.name.http.encodedCharacters]
|
||||
allowEncodedSlash = true
|
||||
allowEncodedBackSlash = true
|
||||
allowEncodedNullCharacter = true
|
||||
allowEncodedSemicolon = true
|
||||
allowEncodedPercent = true
|
||||
allowEncodedQuestionMark = true
|
||||
allowEncodedHash = true
|
||||
allowEncodedSlash = false
|
||||
allowEncodedBackSlash = false
|
||||
allowEncodedNullCharacter = false
|
||||
allowEncodedSemicolon = false
|
||||
allowEncodedPercent = false
|
||||
allowEncodedQuestionMark = false
|
||||
allowEncodedHash = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
@@ -185,13 +185,13 @@ They can be defined by using a file (YAML or TOML) or CLI arguments.
|
||||
--entryPoints.name.proxyProtocol.trustedIPs=127.0.0.1,192.168.0.1
|
||||
--entryPoints.name.forwardedHeaders.insecure=true
|
||||
--entryPoints.name.forwardedHeaders.trustedIPs=127.0.0.1,192.168.0.1
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedSlash=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedBackSlash=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedNullCharacter=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedSemicolon=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedPercent=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedQuestionMark=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedHash=true
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedSlash=false
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedBackSlash=false
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedNullCharacter=false
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedSemicolon=false
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedPercent=false
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedQuestionMark=false
|
||||
--entryPoints.name.http.encodedCharacters.allowEncodedHash=false
|
||||
```
|
||||
|
||||
### Address
|
||||
@@ -1021,20 +1021,21 @@ entryPoints:
|
||||
### Encoded Characters
|
||||
|
||||
You can configure Traefik to control the handling of encoded characters in request paths for security purposes.
|
||||
By default, Traefik rejects requests with path containing certain encoded characters that could be used in path traversal or other security attacks.
|
||||
By default, Traefik do not reject requests with path containing certain encoded characters that could be used in path traversal or other security attacks.
|
||||
|
||||
!!! info
|
||||
|
||||
This check is not done against the request query parameters,
|
||||
but only against the request path as defined in [RFC3986 section-3](https://datatracker.ietf.org/doc/html/rfc3986#section-3).
|
||||
|
||||
!!! warning "Security Considerations"
|
||||
!!! info "Security Considerations"
|
||||
|
||||
Allowing certain encoded characters may expose your application to security vulnerabilities.
|
||||
When your backend is not fully compliant with [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) and notably decode encoded reserved characters in the requets path,
|
||||
it is recommended to set these options to `false` to avoid split-view situation and helps prevent path traversal attacks or other malicious attempts to bypass security controls.
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedSlash`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded slash characters (`%2F` or `%2f`) in the path are allowed.
|
||||
|
||||
@@ -1045,7 +1046,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedSlash: true
|
||||
allowEncodedSlash: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1055,18 +1056,18 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedSlash = true
|
||||
allowEncodedSlash = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedSlash=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedSlash=false
|
||||
```
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedBackSlash`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded back slash characters (`%5C` or `%5c`) in the path are allowed.
|
||||
|
||||
@@ -1077,7 +1078,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedBackSlash: true
|
||||
allowEncodedBackSlash: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1087,18 +1088,18 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedBackSlash = true
|
||||
allowEncodedBackSlash = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedBackSlash=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedBackSlash=false
|
||||
```
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedNullCharacter`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded null characters (`%00`) in the path are allowed.
|
||||
|
||||
@@ -1109,7 +1110,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedNullCharacter: true
|
||||
allowEncodedNullCharacter: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1119,18 +1120,18 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedNullCharacter = true
|
||||
allowEncodedNullCharacter = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedNullCharacter=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedNullCharacter=false
|
||||
```
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedSemicolon`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded semicolon characters (`%3B` or `%3b`) in the path are allowed.
|
||||
|
||||
@@ -1141,7 +1142,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedSemicolon: true
|
||||
allowEncodedSemicolon: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1151,18 +1152,18 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedSemicolon = true
|
||||
allowEncodedSemicolon = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedSemicolon=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedSemicolon=false
|
||||
```
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedPercent`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded percent characters (`%25`) in the path are allowed.
|
||||
|
||||
@@ -1173,7 +1174,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedPercent: true
|
||||
allowEncodedPercent: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1183,18 +1184,18 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedPercent = true
|
||||
allowEncodedPercent = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedPercent=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedPercent=false
|
||||
```
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedQuestionMark`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded question mark characters (`%3F` or `%3f`) in the path are allowed.
|
||||
|
||||
@@ -1205,7 +1206,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedQuestionMark: true
|
||||
allowEncodedQuestionMark: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1215,18 +1216,18 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedQuestionMark = true
|
||||
allowEncodedQuestionMark = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedQuestionMark=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedQuestionMark=false
|
||||
```
|
||||
|
||||
??? info "`encodedCharacters.allowEncodedHash`"
|
||||
|
||||
_Optional, Default=false_
|
||||
_Optional, Default=true_
|
||||
|
||||
Controls whether requests with encoded hash characters (`%23`) in the path are allowed.
|
||||
|
||||
@@ -1237,7 +1238,7 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address: ":80"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedHash: true
|
||||
allowEncodedHash: false
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
@@ -1247,13 +1248,13 @@ By default, Traefik rejects requests with path containing certain encoded charac
|
||||
address = ":80"
|
||||
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedHash = true
|
||||
allowEncodedHash = false
|
||||
```
|
||||
|
||||
```bash tab="CLI"
|
||||
## Static configuration
|
||||
--entryPoints.web.address=:80
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedHash=true
|
||||
--entryPoints.web.http.encodedCharacters.allowEncodedHash=false
|
||||
```
|
||||
|
||||
### SanitizePath
|
||||
@@ -1441,4 +1442,4 @@ entryPoints:
|
||||
--entryPoints.foo.udp.timeout=10s
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -412,4 +412,4 @@ serversTransport:
|
||||
--serversTransport.forwardingTimeouts.idleConnTimeout=1s
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -1904,4 +1904,4 @@ If the ServersTransport CRD is defined in another provider the cross-provider fo
|
||||
|
||||
Also see the [full example](../../user-guides/crd-acme/index.md) with Let's Encrypt.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -355,4 +355,4 @@ Kubernetes cluster before creating `TLSRoute` objects.
|
||||
| [11] | `group` | Group is the group of the referent. Only `traefik.io`, `traefik.containo.us` and `gateway.networking.k8s.io` values are supported. |
|
||||
| [12] | `kind` | Kind is kind of the referent. Only `TraefikService` and `Service` values are supported. |
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -969,4 +969,4 @@ This will allow users to create a "default router" that will match all unmatched
|
||||
|
||||
To do this, use the `traefik.ingress.kubernetes.io/router.priority` annotation (as seen in [Annotations on Ingress](#on-ingress)) on your ingresses accordingly.
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -1349,4 +1349,4 @@ Services are the target for the router.
|
||||
|
||||
!!! important "UDP routers can only target UDP services (and not HTTP or TCP services)."
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -1646,4 +1646,4 @@ udp:
|
||||
address = "private-ip-server-2:8080/"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -20,7 +20,7 @@ When Traefik receives an HTTP request, it processes the request path through sev
|
||||
|
||||
Traefik inspects the path for potentially dangerous encoded characters and rejects requests containing them unless explicitly allowed.
|
||||
|
||||
Here is the list of the encoded characters that are rejected by default:
|
||||
Here is the list of the encoded characters that are allowed by default:
|
||||
|
||||
| Encoded Character | Character |
|
||||
|-------------------|-------------------------|
|
||||
@@ -87,7 +87,12 @@ Configure it in the [EntryPoints](../routing/entrypoints.md#encoded-characters)
|
||||
|
||||
This filtering occurs before path sanitization and catches attack attempts that use encoding to bypass other security controls.
|
||||
|
||||
All encoded character filtering is enabled by default (`false` means encoded characters are rejected), providing maximum security:
|
||||
All encoded character filtering is disabled by default (`true` means encoded characters are allowed).
|
||||
|
||||
!!! info "Security Considerations"
|
||||
|
||||
When your backend is not fully compliant with [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986) and notably decode encoded reserved characters in the requets path,
|
||||
it is recommended to set these options to `false` to avoid split-view situation and helps prevent path traversal attacks or other malicious attempts to bypass security controls.
|
||||
|
||||
```yaml tab="File (YAML)"
|
||||
entryPoints:
|
||||
@@ -95,13 +100,13 @@ entryPoints:
|
||||
address: ":443"
|
||||
http:
|
||||
encodedCharacters:
|
||||
allowEncodedSlash: false # %2F - Default: false (RECOMMENDED)
|
||||
allowEncodedBackSlash: false # %5C - Default: false (RECOMMENDED)
|
||||
allowEncodedNullCharacter: false # %00 - Default: false (RECOMMENDED)
|
||||
allowEncodedSemicolon: false # %3B - Default: false (RECOMMENDED)
|
||||
allowEncodedPercent: false # %25 - Default: false (RECOMMENDED)
|
||||
allowEncodedQuestionMark: false # %3F - Default: false (RECOMMENDED)
|
||||
allowEncodedHash: false # %23 - Default: false (RECOMMENDED)
|
||||
allowEncodedSlash: false # %2F - Default: true
|
||||
allowEncodedBackSlash: false # %5C - Default: true
|
||||
allowEncodedNullCharacter: false # %00 - Default: true
|
||||
allowEncodedSemicolon: false # %3B - Default: true
|
||||
allowEncodedPercent: false # %25 - Default: true
|
||||
allowEncodedQuestionMark: false # %3F - Default: true
|
||||
allowEncodedHash: false # %23 - Default: true
|
||||
```
|
||||
|
||||
```toml tab="File (TOML)"
|
||||
|
||||
@@ -187,4 +187,4 @@ environment:
|
||||
- "OVH_CONSUMER_KEY_FILE=/run/secrets/ovh_consumer_key"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -83,4 +83,4 @@ labels:
|
||||
- "traefik.http.routers.whoami.tls.certresolver=myresolver"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -133,4 +133,4 @@ whoami:
|
||||
- "traefik.http.routers.whoami.entrypoints=web"
|
||||
```
|
||||
|
||||
{!traefik-for-business-applications.md!}
|
||||
{% include-markdown "includes/traefik-for-business-applications.md" %}
|
||||
|
||||
@@ -2,18 +2,19 @@ site_name: Traefik
|
||||
site_description: Traefik Documentation
|
||||
site_author: traefik.io
|
||||
site_url: https://doc.traefik.io/traefik
|
||||
dev_addr: 0.0.0.0:8000
|
||||
dev_addr: localhost:8000
|
||||
|
||||
repo_name: 'GitHub'
|
||||
repo_url: 'https://github.com/traefik/traefik'
|
||||
|
||||
docs_dir: 'content'
|
||||
|
||||
product: proxy
|
||||
|
||||
# https://squidfunk.github.io/mkdocs-material/
|
||||
# Use custom version of mkdocs-material
|
||||
# See https://github.com/traefik/mkdocs-material
|
||||
theme:
|
||||
name: 'traefik-labs'
|
||||
product: proxy
|
||||
language: en
|
||||
include_sidebar: true
|
||||
favicon: assets/img/traefikproxy-icon-color.png
|
||||
@@ -27,7 +28,7 @@ theme:
|
||||
prev: 'Previous'
|
||||
next: 'Next'
|
||||
|
||||
copyright: 'Traefik Labs • Copyright © 2016-2025'
|
||||
copyright: 'Traefik Labs • Copyright © 2016-2026'
|
||||
|
||||
extra_javascript:
|
||||
- assets/js/hljs/highlight.pack.js # Download from https://highlightjs.org/download/ and enable YAML, TOML and Dockerfile
|
||||
@@ -38,6 +39,8 @@ plugins:
|
||||
- exclude:
|
||||
glob:
|
||||
- "**/include-*.md"
|
||||
- include-markdown:
|
||||
encoding: utf-8
|
||||
|
||||
# https://squidfunk.github.io/mkdocs-material/extensions/admonition/
|
||||
# https://facelessuser.github.io/pymdown-extensions/
|
||||
@@ -55,9 +58,6 @@ markdown_extensions:
|
||||
- pymdownx.tasklist
|
||||
- pymdownx.snippets:
|
||||
check_paths: true
|
||||
- markdown_include.include:
|
||||
base_path: content/includes/
|
||||
encoding: utf-8
|
||||
- toc:
|
||||
permalink: true
|
||||
|
||||
@@ -165,7 +165,6 @@ nav:
|
||||
- 'Instana': 'observability/tracing/instana.md'
|
||||
- 'Haystack': 'observability/tracing/haystack.md'
|
||||
- 'Elastic': 'observability/tracing/elastic.md'
|
||||
- 'OpenTelemetry': 'observability/tracing/opentelemetry.md'
|
||||
- 'Security':
|
||||
- 'Request Path': 'security/request-path.md'
|
||||
- 'Content-Length': 'security/content-length.md'
|
||||
|
||||
@@ -16,3 +16,15 @@
|
||||
|
||||
[pymdown-extensions]: https://facelessuser.github.io/pymdown-extensions "PyMdown Extensions"
|
||||
[pymdown-extensions-src]: https://github.com/facelessuser/pymdown-extensions "PyMdown Extensions - Sources"
|
||||
|
||||
## Build locally without docker
|
||||
|
||||
```sh
|
||||
# Pre-requisite: python3, pip and virtualenv
|
||||
DOCS="/tmp/traefik-docs"
|
||||
mkdir "$DOCS"
|
||||
virtualenv "$DOCS"
|
||||
source "$DOCS/bin/activate"
|
||||
pip install -r requirements.txt
|
||||
mkdocs serve # or mkdocs build
|
||||
```
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
markdown-include==0.5.1
|
||||
mkdocs==1.2.4
|
||||
mkdocs==1.4.3
|
||||
mkdocs-include-markdown-plugin==7.2.0
|
||||
mkdocs-exclude==1.0.2
|
||||
mkdocs-traefiklabs>=100.0.7
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
# This script will run a couple of linter on the documentation
|
||||
|
||||
set -eu
|
||||
@@ -6,14 +6,14 @@ set -eu
|
||||
# We want to run all linters before returning success (exit 0) or failure (exit 1)
|
||||
# So this variable holds the global exit code
|
||||
EXIT_CODE=0
|
||||
readonly BASE_DIR=/app
|
||||
readonly BASE_DIR="${1:-/app}"
|
||||
|
||||
echo "== Linting Markdown"
|
||||
# Uses the file ".markdownlint.json" for setup
|
||||
cd "${BASE_DIR}" || exit 1
|
||||
|
||||
LINTER_EXCLUSIONS="$(find "${BASE_DIR}/content" -type f -name '.markdownlint.json')"
|
||||
GLOBAL_LINT_OPTIONS="--config ${BASE_DIR}/.markdownlint.json"
|
||||
LINTER_EXCLUSIONS="$(find "content" -type f -name '.markdownlint.json')"
|
||||
GLOBAL_LINT_OPTIONS="--config .markdownlint.json"
|
||||
|
||||
# Lint the specific folders (containing linter specific rulesets)
|
||||
for LINTER_EXCLUSION in ${LINTER_EXCLUSIONS}
|
||||
@@ -24,6 +24,6 @@ do
|
||||
done
|
||||
|
||||
# Lint all the content, excluding the previously done`
|
||||
eval markdownlint "${GLOBAL_LINT_OPTIONS}" "${BASE_DIR}/content/**/*.md" || EXIT_CODE=1
|
||||
eval markdownlint "${GLOBAL_LINT_OPTIONS}" "content/**/*.md" || EXIT_CODE=1
|
||||
|
||||
exit "${EXIT_CODE}"
|
||||
|
||||
@@ -245,8 +245,7 @@ func digestParts(resp *http.Response) map[string]string {
|
||||
result := map[string]string{}
|
||||
if len(resp.Header["Www-Authenticate"]) > 0 {
|
||||
wantedHeaders := []string{"nonce", "realm", "qop", "opaque"}
|
||||
responseHeaders := strings.Split(resp.Header["Www-Authenticate"][0], ",")
|
||||
for _, r := range responseHeaders {
|
||||
for r := range strings.SplitSeq(resp.Header["Www-Authenticate"][0], ",") {
|
||||
for _, w := range wantedHeaders {
|
||||
if strings.Contains(r, w) {
|
||||
result[w] = strings.Split(r, `"`)[1]
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
// ACME test suites.
|
||||
type AcmeSuite struct {
|
||||
BaseSuite
|
||||
|
||||
pebbleIP string
|
||||
fakeDNSServer *dns.Server
|
||||
}
|
||||
@@ -63,11 +64,6 @@ const (
|
||||
wildcardDomain = "*.acme.wtf"
|
||||
)
|
||||
|
||||
func (s *AcmeSuite) getAcmeURL() string {
|
||||
return fmt.Sprintf("https://%s/dir",
|
||||
net.JoinHostPort(s.pebbleIP, "14000"))
|
||||
}
|
||||
|
||||
func setupPebbleRootCA() (*http.Transport, error) {
|
||||
path, err := filepath.Abs("fixtures/acme/ssl/pebble.minica.pem")
|
||||
if err != nil {
|
||||
@@ -540,3 +536,8 @@ func (s *AcmeSuite) retrieveAcmeCertificate(testCase acmeTestCase) {
|
||||
assert.Equal(s.T(), sub.expectedAlgorithm, gotPublicKeyAlgorithm)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *AcmeSuite) getAcmeURL() string {
|
||||
return fmt.Sprintf("https://%s/dir",
|
||||
net.JoinHostPort(s.pebbleIP, "14000"))
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
type ConsulCatalogSuite struct {
|
||||
BaseSuite
|
||||
|
||||
consulClient *api.Client
|
||||
consulAgentClient *api.Client
|
||||
consulURL string
|
||||
@@ -53,47 +54,6 @@ func (s *ConsulCatalogSuite) TearDownSuite() {
|
||||
s.BaseSuite.TearDownSuite()
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) waitToElectConsulLeader() error {
|
||||
return try.Do(15*time.Second, func() error {
|
||||
leader, err := s.consulClient.Status().Leader()
|
||||
|
||||
if err != nil || len(leader) == 0 {
|
||||
return fmt.Errorf("leader not found. %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) waitForConnectCA() error {
|
||||
return try.Do(15*time.Second, func() error {
|
||||
caroots, _, err := s.consulClient.Connect().CARoots(nil)
|
||||
|
||||
if err != nil || len(caroots.Roots) == 0 {
|
||||
return fmt.Errorf("connect CA not fully initialized. %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) registerService(reg *api.AgentServiceRegistration, onAgent bool) error {
|
||||
client := s.consulClient
|
||||
if onAgent {
|
||||
client = s.consulAgentClient
|
||||
}
|
||||
|
||||
return client.Agent().ServiceRegister(reg)
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) deregisterService(id string, onAgent bool) error {
|
||||
client := s.consulClient
|
||||
if onAgent {
|
||||
client = s.consulAgentClient
|
||||
}
|
||||
return client.Agent().ServiceDeregister(id)
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) TestWithNotExposedByDefaultAndDefaultsSettings() {
|
||||
reg1 := &api.AgentServiceRegistration{
|
||||
ID: "whoami1",
|
||||
@@ -847,3 +807,44 @@ func (s *ConsulCatalogSuite) TestConsulConnect_NotAware() {
|
||||
err = s.deregisterService("whoami1", false)
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) waitToElectConsulLeader() error {
|
||||
return try.Do(15*time.Second, func() error {
|
||||
leader, err := s.consulClient.Status().Leader()
|
||||
|
||||
if err != nil || len(leader) == 0 {
|
||||
return fmt.Errorf("leader not found. %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) waitForConnectCA() error {
|
||||
return try.Do(15*time.Second, func() error {
|
||||
caroots, _, err := s.consulClient.Connect().CARoots(nil)
|
||||
|
||||
if err != nil || len(caroots.Roots) == 0 {
|
||||
return fmt.Errorf("connect CA not fully initialized. %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) registerService(reg *api.AgentServiceRegistration, onAgent bool) error {
|
||||
client := s.consulClient
|
||||
if onAgent {
|
||||
client = s.consulAgentClient
|
||||
}
|
||||
|
||||
return client.Agent().ServiceRegister(reg)
|
||||
}
|
||||
|
||||
func (s *ConsulCatalogSuite) deregisterService(id string, onAgent bool) error {
|
||||
client := s.consulClient
|
||||
if onAgent {
|
||||
client = s.consulAgentClient
|
||||
}
|
||||
return client.Agent().ServiceDeregister(id)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
// Consul test suites.
|
||||
type ConsulSuite struct {
|
||||
BaseSuite
|
||||
|
||||
kvClient store.Store
|
||||
consulURL string
|
||||
}
|
||||
@@ -164,16 +165,6 @@ func (s *ConsulSuite) TestSimpleConfiguration() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ConsulSuite) assertWhoami(host string, expectedStatusCode int) {
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000", nil)
|
||||
require.NoError(s.T(), err)
|
||||
req.Host = host
|
||||
|
||||
resp, err := try.ResponseUntilStatusCode(req, 15*time.Second, expectedStatusCode)
|
||||
require.NoError(s.T(), err)
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
func (s *ConsulSuite) TestDeleteRootKey() {
|
||||
// This test case reproduce the issue: https://github.com/traefik/traefik/issues/8092
|
||||
|
||||
@@ -222,3 +213,13 @@ func (s *ConsulSuite) TestDeleteRootKey() {
|
||||
s.assertWhoami("kv1.localhost", http.StatusNotFound)
|
||||
s.assertWhoami("kv2.localhost", http.StatusNotFound)
|
||||
}
|
||||
|
||||
func (s *ConsulSuite) assertWhoami(host string, expectedStatusCode int) {
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8000", nil)
|
||||
require.NoError(s.T(), err)
|
||||
req.Host = host
|
||||
|
||||
resp, err := try.ResponseUntilStatusCode(req, 15*time.Second, expectedStatusCode)
|
||||
require.NoError(s.T(), err)
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func (s *DockerSuite) TestDefaultDockerContainers() {
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
var version map[string]interface{}
|
||||
var version map[string]any
|
||||
|
||||
assert.NoError(s.T(), json.Unmarshal(body, &version))
|
||||
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
|
||||
@@ -145,7 +145,7 @@ func (s *DockerSuite) TestDockerContainersWithLabels() {
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
var version map[string]interface{}
|
||||
var version map[string]any
|
||||
|
||||
assert.NoError(s.T(), json.Unmarshal(body, &version))
|
||||
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
|
||||
@@ -203,7 +203,7 @@ func (s *DockerSuite) TestRestartDockerContainers() {
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
var version map[string]interface{}
|
||||
var version map[string]any
|
||||
|
||||
assert.NoError(s.T(), json.Unmarshal(body, &version))
|
||||
assert.Equal(s.T(), "swarm/1.0.0", version["Version"])
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
// ErrorPagesSuite test suites.
|
||||
type ErrorPagesSuite struct {
|
||||
BaseSuite
|
||||
|
||||
ErrorPageIP string
|
||||
BackendIP string
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
// etcd test suites.
|
||||
type EtcdSuite struct {
|
||||
BaseSuite
|
||||
|
||||
kvClient store.Store
|
||||
etcdAddr string
|
||||
}
|
||||
|
||||
@@ -1273,6 +1273,7 @@ spec:
|
||||
IPWhiteList holds the IP whitelist middleware configuration.
|
||||
This middleware limits allowed requests based on the client IP.
|
||||
More info: https://doc.traefik.io/traefik/v2.11/middlewares/http/ipwhitelist/
|
||||
|
||||
Deprecated: please use IPAllowList instead.
|
||||
properties:
|
||||
ipStrategy:
|
||||
@@ -1663,8 +1664,9 @@ spec:
|
||||
description: |-
|
||||
IPWhiteList defines the IPWhiteList middleware configuration.
|
||||
This middleware accepts/refuses connections based on the client IP.
|
||||
Deprecated: please use IPAllowList instead.
|
||||
More info: https://doc.traefik.io/traefik/v2.11/middlewares/tcp/ipwhitelist/
|
||||
|
||||
Deprecated: please use IPAllowList instead.
|
||||
properties:
|
||||
sourceRange:
|
||||
description: SourceRange defines the allowed IPs (or ranges of
|
||||
@@ -1907,6 +1909,7 @@ spec:
|
||||
description: |-
|
||||
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
||||
It is enabled automatically when minVersion or maxVersion is set.
|
||||
|
||||
Deprecated: https://github.com/golang/go/issues/45430
|
||||
type: boolean
|
||||
sniStrict:
|
||||
@@ -3703,6 +3706,7 @@ spec:
|
||||
IPWhiteList holds the IP whitelist middleware configuration.
|
||||
This middleware limits allowed requests based on the client IP.
|
||||
More info: https://doc.traefik.io/traefik/v2.11/middlewares/http/ipwhitelist/
|
||||
|
||||
Deprecated: please use IPAllowList instead.
|
||||
properties:
|
||||
ipStrategy:
|
||||
@@ -4093,8 +4097,9 @@ spec:
|
||||
description: |-
|
||||
IPWhiteList defines the IPWhiteList middleware configuration.
|
||||
This middleware accepts/refuses connections based on the client IP.
|
||||
Deprecated: please use IPAllowList instead.
|
||||
More info: https://doc.traefik.io/traefik/v2.11/middlewares/tcp/ipwhitelist/
|
||||
|
||||
Deprecated: please use IPAllowList instead.
|
||||
properties:
|
||||
sourceRange:
|
||||
description: SourceRange defines the allowed IPs (or ranges of
|
||||
@@ -4337,6 +4342,7 @@ spec:
|
||||
description: |-
|
||||
PreferServerCipherSuites defines whether the server chooses a cipher suite among his own instead of among the client's.
|
||||
It is enabled automatically when minVersion or maxVersion is set.
|
||||
|
||||
Deprecated: https://github.com/golang/go/issues/45430
|
||||
type: boolean
|
||||
sniStrict:
|
||||
|
||||
@@ -8,12 +8,18 @@
|
||||
[entryPoints]
|
||||
[entryPoints.strict]
|
||||
address = ":8000"
|
||||
# Default: no encoded characters allowed
|
||||
[entryPoints.strict.http.encodedCharacters]
|
||||
allowEncodedSlash = false
|
||||
|
||||
[entryPoints.permissive]
|
||||
address = ":8001"
|
||||
# No config, default values should apply
|
||||
|
||||
[entryPoints.permissive2]
|
||||
address = ":8002"
|
||||
# No config for allowEncodedSlash, default value is effectively true
|
||||
[entryPoints.permissive.http.encodedCharacters]
|
||||
allowEncodedSlash = true
|
||||
allowEncodedBackSlash = false
|
||||
|
||||
[api]
|
||||
insecure = true
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
[entryPoints]
|
||||
[entryPoints.web]
|
||||
address = ":8000"
|
||||
[entryPoints.web.http.encodedCharacters]
|
||||
allowEncodedSlash = true
|
||||
|
||||
[api]
|
||||
insecure = true
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
// HealthCheck test suites.
|
||||
type HealthCheckSuite struct {
|
||||
BaseSuite
|
||||
|
||||
whoami1IP string
|
||||
whoami2IP string
|
||||
whoami3IP string
|
||||
@@ -305,7 +306,7 @@ func (s *HealthCheckSuite) TestPropagate() {
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
try.Sleep(time.Second)
|
||||
try.Sleep(time.Second) //nolint:staticcheck // Intentional use for integration test timing.
|
||||
|
||||
want2 := `IP: ` + s.whoami2IP
|
||||
want4 := `IP: ` + s.whoami4IP
|
||||
@@ -387,7 +388,7 @@ func (s *HealthCheckSuite) TestPropagate() {
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
try.Sleep(time.Second)
|
||||
try.Sleep(time.Second) //nolint:staticcheck // Intentional use for integration test timing.
|
||||
|
||||
// Verify that everything is down, and that we get 503s everywhere.
|
||||
for range 2 {
|
||||
@@ -413,7 +414,7 @@ func (s *HealthCheckSuite) TestPropagate() {
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
try.Sleep(time.Second)
|
||||
try.Sleep(time.Second) //nolint:staticcheck // Intentional use for integration test timing.
|
||||
|
||||
// Verify everything is up on root router.
|
||||
reachedServers = make(map[string]int)
|
||||
|
||||
@@ -187,7 +187,7 @@ func RegisterGreeterServer(s *grpc.Server, srv GreeterServer) {
|
||||
s.RegisterService(&_Greeter_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
func _Greeter_SayHello_Handler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) {
|
||||
in := new(HelloRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
@@ -199,13 +199,13 @@ func _Greeter_SayHello_Handler(srv interface{}, ctx context.Context, dec func(in
|
||||
Server: srv,
|
||||
FullMethod: "/helloworld.Greeter/SayHello",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
handler := func(ctx context.Context, req any) (any, error) {
|
||||
return srv.(GreeterServer).SayHello(ctx, req.(*HelloRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Greeter_StreamExample_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
func _Greeter_StreamExample_Handler(srv any, stream grpc.ServerStream) error {
|
||||
m := new(StreamExampleRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
|
||||
@@ -876,40 +876,6 @@ func (s *HTTPSSuite) TestWithSNIDynamicConfigRouteWithTlsConfigurationDeletion()
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
// modifyCertificateConfFileContent replaces the content of a HTTPS configuration file.
|
||||
func (s *HTTPSSuite) modifyCertificateConfFileContent(certFileName, confFileName string) {
|
||||
file, err := os.OpenFile("./"+confFileName, os.O_WRONLY, os.ModeExclusive)
|
||||
require.NoError(s.T(), err)
|
||||
defer func() {
|
||||
file.Close()
|
||||
}()
|
||||
err = file.Truncate(0)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
// If certificate file is not provided, just truncate the configuration file
|
||||
if len(certFileName) > 0 {
|
||||
tlsConf := dynamic.Configuration{
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Certificates: []*traefiktls.CertAndStores{
|
||||
{
|
||||
Certificate: traefiktls.Certificate{
|
||||
CertFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".cert"),
|
||||
KeyFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".key"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var confBuffer bytes.Buffer
|
||||
err := toml.NewEncoder(&confBuffer).Encode(tlsConf)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
_, err = file.Write(confBuffer.Bytes())
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *HTTPSSuite) TestEntryPointHttpsRedirectAndPathModification() {
|
||||
file := s.adaptFile("fixtures/https/https_redirect.toml", struct{}{})
|
||||
s.traefikCmd(withConfigFile(file))
|
||||
@@ -1176,6 +1142,40 @@ func (s *HTTPSSuite) TestWithInvalidTLSOption() {
|
||||
}
|
||||
}
|
||||
|
||||
// modifyCertificateConfFileContent replaces the content of a HTTPS configuration file.
|
||||
func (s *HTTPSSuite) modifyCertificateConfFileContent(certFileName, confFileName string) {
|
||||
file, err := os.OpenFile("./"+confFileName, os.O_WRONLY, os.ModeExclusive)
|
||||
require.NoError(s.T(), err)
|
||||
defer func() {
|
||||
file.Close()
|
||||
}()
|
||||
err = file.Truncate(0)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
// If certificate file is not provided, just truncate the configuration file
|
||||
if len(certFileName) > 0 {
|
||||
tlsConf := dynamic.Configuration{
|
||||
TLS: &dynamic.TLSConfiguration{
|
||||
Certificates: []*traefiktls.CertAndStores{
|
||||
{
|
||||
Certificate: traefiktls.Certificate{
|
||||
CertFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".cert"),
|
||||
KeyFile: traefiktls.FileOrContent("fixtures/https/" + certFileName + ".key"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var confBuffer bytes.Buffer
|
||||
err := toml.NewEncoder(&confBuffer).Encode(tlsConf)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
_, err = file.Write(confBuffer.Bytes())
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SimpleSuite) TestMaxConcurrentStream() {
|
||||
file := s.adaptFile("fixtures/https/max_concurrent_stream.toml", struct{}{})
|
||||
|
||||
|
||||
@@ -61,45 +61,12 @@ type composeDeploy struct {
|
||||
|
||||
type BaseSuite struct {
|
||||
suite.Suite
|
||||
|
||||
containers map[string]testcontainers.Container
|
||||
network *testcontainers.DockerNetwork
|
||||
hostIP string
|
||||
}
|
||||
|
||||
func (s *BaseSuite) waitForTraefik(containerName string) {
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Wait for Traefik to turn ready.
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8080/api/rawdata", nil)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
err = try.Request(req, 2*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains(containerName))
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *BaseSuite) displayTraefikLogFile(path string) {
|
||||
if s.T().Failed() {
|
||||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||
content, errRead := os.ReadFile(path)
|
||||
// TODO TestName
|
||||
// fmt.Printf("%s: Traefik logs: \n", c.TestName())
|
||||
fmt.Print("Traefik logs: \n")
|
||||
if errRead == nil {
|
||||
fmt.Println(string(content))
|
||||
} else {
|
||||
fmt.Println(errRead)
|
||||
}
|
||||
} else {
|
||||
// fmt.Printf("%s: No Traefik logs.\n", c.TestName())
|
||||
fmt.Print("No Traefik logs.\n")
|
||||
}
|
||||
errRemove := os.Remove(path)
|
||||
if errRemove != nil {
|
||||
fmt.Println(errRemove)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BaseSuite) SetupSuite() {
|
||||
if isDockerDesktop(context.Background(), s.T()) {
|
||||
_, err := os.Stat(tailscaleSecretFilePath)
|
||||
@@ -400,7 +367,7 @@ func (s *BaseSuite) displayTraefikLog(output *bytes.Buffer) {
|
||||
if output == nil || output.Len() == 0 {
|
||||
log.WithoutContext().Info("No Traefik logs.")
|
||||
} else {
|
||||
for _, line := range strings.Split(output.String(), "\n") {
|
||||
for line := range strings.SplitSeq(output.String(), "\n") {
|
||||
log.WithoutContext().Info(line)
|
||||
}
|
||||
}
|
||||
@@ -416,7 +383,7 @@ func (s *BaseSuite) getDockerHost() string {
|
||||
return dockerHost
|
||||
}
|
||||
|
||||
func (s *BaseSuite) adaptFile(path string, tempObjects interface{}) string {
|
||||
func (s *BaseSuite) adaptFile(path string, tempObjects any) string {
|
||||
// Load file
|
||||
tmpl, err := template.ParseFiles(path)
|
||||
require.NoError(s.T(), err)
|
||||
@@ -504,3 +471,37 @@ func (s *BaseSuite) composeExec(service string, args ...string) string {
|
||||
|
||||
return string(content)
|
||||
}
|
||||
|
||||
func (s *BaseSuite) waitForTraefik(containerName string) {
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// Wait for Traefik to turn ready.
|
||||
req, err := http.NewRequest(http.MethodGet, "http://127.0.0.1:8080/api/rawdata", nil)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
err = try.Request(req, 2*time.Second, try.StatusCodeIs(http.StatusOK), try.BodyContains(containerName))
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *BaseSuite) displayTraefikLogFile(path string) {
|
||||
if s.T().Failed() {
|
||||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||
content, errRead := os.ReadFile(path)
|
||||
// TODO TestName
|
||||
// fmt.Printf("%s: Traefik logs: \n", c.TestName())
|
||||
fmt.Print("Traefik logs: \n")
|
||||
if errRead == nil {
|
||||
fmt.Println(string(content))
|
||||
} else {
|
||||
fmt.Println(errRead)
|
||||
}
|
||||
} else {
|
||||
// fmt.Printf("%s: No Traefik logs.\n", c.TestName())
|
||||
fmt.Print("No Traefik logs.\n")
|
||||
}
|
||||
errRemove := os.Remove(path)
|
||||
if errRemove != nil {
|
||||
fmt.Println(errRemove)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package integration
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
// Marathon test suites.
|
||||
type MarathonSuite15 struct {
|
||||
BaseSuite
|
||||
|
||||
marathonURL string
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ const containerNameMarathon = "marathon"
|
||||
// Marathon test suites.
|
||||
type MarathonSuite struct {
|
||||
BaseSuite
|
||||
|
||||
marathonURL string
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package integration
|
||||
import (
|
||||
"bufio"
|
||||
"net"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -15,6 +16,7 @@ import (
|
||||
|
||||
type ProxyProtocolSuite struct {
|
||||
BaseSuite
|
||||
|
||||
whoamiIP string
|
||||
}
|
||||
|
||||
@@ -124,15 +126,16 @@ func proxyProtoRequest(address string, version byte) (string, error) {
|
||||
}
|
||||
|
||||
// Read the response from the server
|
||||
var content string
|
||||
var content strings.Builder
|
||||
scanner := bufio.NewScanner(conn)
|
||||
for scanner.Scan() {
|
||||
content += scanner.Text() + "\n"
|
||||
content.WriteString(scanner.Text())
|
||||
content.WriteString("\n")
|
||||
}
|
||||
|
||||
if scanner.Err() != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return content, nil
|
||||
return content.String(), nil
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
type RateLimitSuite struct {
|
||||
BaseSuite
|
||||
|
||||
ServerIP string
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
// Redis test suites.
|
||||
type RedisSentinelSuite struct {
|
||||
BaseSuite
|
||||
|
||||
kvClient store.Store
|
||||
redisEndpoints []string
|
||||
}
|
||||
@@ -76,36 +77,6 @@ func (s *RedisSentinelSuite) TearDownSuite() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RedisSentinelSuite) setupSentinelConfiguration(ports []string) {
|
||||
for i, port := range ports {
|
||||
templateValue := struct{ SentinelPort string }{SentinelPort: port}
|
||||
|
||||
// Load file
|
||||
templateFile := "resources/compose/config/sentinel_template.conf"
|
||||
tmpl, err := template.ParseFiles(templateFile)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
folder, prefix := filepath.Split(templateFile)
|
||||
|
||||
fileName := fmt.Sprintf("%s/sentinel%d.conf", folder, i+1)
|
||||
tmpFile, err := os.Create(fileName)
|
||||
require.NoError(s.T(), err)
|
||||
defer tmpFile.Close()
|
||||
|
||||
err = tmpFile.Chmod(0o666)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
model := structs.Map(templateValue)
|
||||
model["SelfFilename"] = tmpFile.Name()
|
||||
|
||||
err = tmpl.ExecuteTemplate(tmpFile, prefix, model)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
err = tmpFile.Sync()
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RedisSentinelSuite) TestSentinelConfiguration() {
|
||||
file := s.adaptFile("fixtures/redis/sentinel.toml", struct{ RedisAddress string }{
|
||||
RedisAddress: strings.Join(s.redisEndpoints, `","`),
|
||||
@@ -202,3 +173,33 @@ func (s *RedisSentinelSuite) TestSentinelConfiguration() {
|
||||
log.WithoutContext().Info(text)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RedisSentinelSuite) setupSentinelConfiguration(ports []string) {
|
||||
for i, port := range ports {
|
||||
templateValue := struct{ SentinelPort string }{SentinelPort: port}
|
||||
|
||||
// Load file
|
||||
templateFile := "resources/compose/config/sentinel_template.conf"
|
||||
tmpl, err := template.ParseFiles(templateFile)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
folder, prefix := filepath.Split(templateFile)
|
||||
|
||||
fileName := fmt.Sprintf("%s/sentinel%d.conf", folder, i+1)
|
||||
tmpFile, err := os.Create(fileName)
|
||||
require.NoError(s.T(), err)
|
||||
defer tmpFile.Close()
|
||||
|
||||
err = tmpFile.Chmod(0o666)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
model := structs.Map(templateValue)
|
||||
model["SelfFilename"] = tmpFile.Name()
|
||||
|
||||
err = tmpl.ExecuteTemplate(tmpFile, prefix, model)
|
||||
require.NoError(s.T(), err)
|
||||
|
||||
err = tmpFile.Sync()
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
// Redis test suites.
|
||||
type RedisSuite struct {
|
||||
BaseSuite
|
||||
|
||||
kvClient store.Store
|
||||
redisEndpoints []string
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
|
||||
type RestSuite struct {
|
||||
BaseSuite
|
||||
|
||||
whoamiAddr string
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
type RetrySuite struct {
|
||||
BaseSuite
|
||||
|
||||
whoamiIP string
|
||||
}
|
||||
|
||||
|
||||
@@ -1520,6 +1520,12 @@ func (s *SimpleSuite) TestEncodedCharactersDifferentEntryPoints() {
|
||||
target: "127.0.0.1:8001", // permissive entry point
|
||||
expected: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Encoded slash should be ALLOWED on permissive2 entry point",
|
||||
request: "GET /path%2Fwith%2Fslash HTTP/1.1\r\nHost: test.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8002", // permissive2 entry point
|
||||
expected: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Regular path should work on strict entry point",
|
||||
request: "GET /regular/path HTTP/1.1\r\nHost: test.localhost\r\n\r\n",
|
||||
@@ -1532,6 +1538,12 @@ func (s *SimpleSuite) TestEncodedCharactersDifferentEntryPoints() {
|
||||
target: "127.0.0.1:8001",
|
||||
expected: http.StatusOK,
|
||||
},
|
||||
{
|
||||
desc: "Regular path should work on permissive2 entry point",
|
||||
request: "GET /regular/path HTTP/1.1\r\nHost: test.localhost\r\n\r\n",
|
||||
target: "127.0.0.1:8002",
|
||||
expected: http.StatusOK,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range testCases {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
type TracingSuite struct {
|
||||
BaseSuite
|
||||
|
||||
whoamiIP string
|
||||
whoamiPort int
|
||||
tracerZipkinIP string
|
||||
@@ -43,15 +44,6 @@ func (s *TracingSuite) TearDownSuite() {
|
||||
s.BaseSuite.TearDownSuite()
|
||||
}
|
||||
|
||||
func (s *TracingSuite) startZipkin() {
|
||||
s.composeUp("zipkin")
|
||||
s.tracerZipkinIP = s.getComposeServiceIP("zipkin")
|
||||
|
||||
// Wait for Zipkin to turn ready.
|
||||
err := try.GetRequest("http://"+s.tracerZipkinIP+":9411/api/v2/services", 20*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestZipkinRateLimit() {
|
||||
s.startZipkin()
|
||||
|
||||
@@ -141,15 +133,6 @@ func (s *TracingSuite) TestZipkinAuth() {
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) startJaeger() {
|
||||
s.composeUp("jaeger", "whoami")
|
||||
s.tracerJaegerIP = s.getComposeServiceIP("jaeger")
|
||||
|
||||
// Wait for Jaeger to turn ready.
|
||||
err := try.GetRequest("http://"+s.tracerJaegerIP+":16686/api/services", 20*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) TestJaegerRateLimit() {
|
||||
s.startJaeger()
|
||||
// defer s.composeStop(c, "jaeger")
|
||||
@@ -290,3 +273,21 @@ func (s *TracingSuite) TestJaegerAuthCollector() {
|
||||
err = try.GetRequest("http://"+s.tracerJaegerIP+":16686/api/traces?service=tracing", 20*time.Second, try.BodyContains("EntryPoint web", "basic-auth@file"))
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) startZipkin() {
|
||||
s.composeUp("zipkin")
|
||||
s.tracerZipkinIP = s.getComposeServiceIP("zipkin")
|
||||
|
||||
// Wait for Zipkin to turn ready.
|
||||
err := try.GetRequest("http://"+s.tracerZipkinIP+":9411/api/v2/services", 20*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
func (s *TracingSuite) startJaeger() {
|
||||
s.composeUp("jaeger", "whoami")
|
||||
s.tracerJaegerIP = s.getComposeServiceIP("jaeger")
|
||||
|
||||
// Wait for Jaeger to turn ready.
|
||||
err := try.GetRequest("http://"+s.tracerJaegerIP+":16686/api/services", 20*time.Second, try.StatusCodeIs(http.StatusOK))
|
||||
require.NoError(s.T(), err)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ const (
|
||||
type timedAction func(timeout time.Duration, operation DoCondition) error
|
||||
|
||||
// Sleep pauses the current goroutine for at least the duration d.
|
||||
//
|
||||
// Deprecated: Use only when use another Try[...] functions is not possible.
|
||||
func Sleep(d time.Duration) {
|
||||
d = applyCIMultiplier(d)
|
||||
@@ -92,10 +93,7 @@ func Do(timeout time.Duration, operation DoCondition) error {
|
||||
panic("timeout must be larger than zero")
|
||||
}
|
||||
|
||||
interval := time.Duration(math.Ceil(float64(timeout) / 15.0))
|
||||
if interval > maxInterval {
|
||||
interval = maxInterval
|
||||
}
|
||||
interval := min(time.Duration(math.Ceil(float64(timeout)/15.0)), maxInterval)
|
||||
|
||||
timeout = applyCIMultiplier(timeout)
|
||||
|
||||
@@ -166,7 +164,7 @@ func doRequest(action timedAction, timeout time.Duration, request *http.Request,
|
||||
func applyCIMultiplier(timeout time.Duration) time.Duration {
|
||||
ci := os.Getenv("CI")
|
||||
if len(ci) > 0 {
|
||||
log.Debug("Apply CI multiplier:", CITimeoutMultiplier)
|
||||
log.WithoutContext().Debug("Apply CI multiplier:", CITimeoutMultiplier)
|
||||
return time.Duration(float64(timeout) * CITimeoutMultiplier)
|
||||
}
|
||||
return timeout
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
// Zk test suites.
|
||||
type ZookeeperSuite struct {
|
||||
BaseSuite
|
||||
|
||||
kvClient store.Store
|
||||
zookeeperAddr string
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ func main() {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
genStaticConfDoc("./docs/content/reference/static-configuration/env-ref.md", "", func(i interface{}) ([]parser.Flat, error) {
|
||||
genStaticConfDoc("./docs/content/reference/static-configuration/env-ref.md", "", func(i any) ([]parser.Flat, error) {
|
||||
return env.Encode(env.DefaultNamePrefix, i)
|
||||
})
|
||||
genStaticConfDoc("./docs/content/reference/static-configuration/cli-ref.md", "--", flag.Encode)
|
||||
@@ -240,7 +240,7 @@ func clean(element any) {
|
||||
valSvcs.SetMapIndex(reflect.ValueOf(fmt.Sprintf("%s1", valueSvcRoot.Type().Name())), reflect.Value{})
|
||||
}
|
||||
|
||||
func genStaticConfDoc(outputFile, prefix string, encodeFn func(interface{}) ([]parser.Flat, error)) {
|
||||
func genStaticConfDoc(outputFile, prefix string, encodeFn func(any) ([]parser.Flat, error)) {
|
||||
logger := log.WithoutContext().WithField("file", outputFile)
|
||||
|
||||
element := &cmd.NewTraefikConfiguration().Configuration
|
||||
@@ -309,7 +309,7 @@ type errWriter struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (ew *errWriter) writeln(a ...interface{}) {
|
||||
func (ew *errWriter) writeln(a ...any) {
|
||||
if ew.err != nil {
|
||||
return
|
||||
}
|
||||
@@ -319,15 +319,15 @@ func (ew *errWriter) writeln(a ...interface{}) {
|
||||
|
||||
func genKVDynConfDoc(outputFile string) {
|
||||
dynConfPath := "./docs/content/reference/dynamic-configuration/file.toml"
|
||||
conf := map[string]interface{}{}
|
||||
conf := map[string]any{}
|
||||
_, err := toml.DecodeFile(dynConfPath, &conf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.WithoutContext().Fatal(err)
|
||||
}
|
||||
|
||||
file, err := os.Create(outputFile)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.WithoutContext().Fatal(err)
|
||||
}
|
||||
|
||||
store := storeWriter{data: map[string]string{}}
|
||||
@@ -335,7 +335,7 @@ func genKVDynConfDoc(outputFile string) {
|
||||
c := client{store: store}
|
||||
err = c.load("traefik", conf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
log.WithoutContext().Fatal(err)
|
||||
}
|
||||
|
||||
var keys []string
|
||||
@@ -374,10 +374,10 @@ type client struct {
|
||||
store storeWriter
|
||||
}
|
||||
|
||||
func (c client) load(parentKey string, conf map[string]interface{}) error {
|
||||
func (c client) load(parentKey string, conf map[string]any) error {
|
||||
for k, v := range conf {
|
||||
switch entry := v.(type) {
|
||||
case map[string]interface{}:
|
||||
case map[string]any:
|
||||
key := path.Join(parentKey, k)
|
||||
|
||||
if len(entry) == 0 {
|
||||
@@ -391,7 +391,7 @@ func (c client) load(parentKey string, conf map[string]interface{}) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case []map[string]interface{}:
|
||||
case []map[string]any:
|
||||
for i, o := range entry {
|
||||
key := path.Join(parentKey, k, strconv.Itoa(i))
|
||||
|
||||
@@ -399,11 +399,11 @@ func (c client) load(parentKey string, conf map[string]interface{}) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case []interface{}:
|
||||
case []any:
|
||||
for i, o := range entry {
|
||||
key := path.Join(parentKey, k, strconv.Itoa(i))
|
||||
|
||||
err := c.store.Put(key, []byte(fmt.Sprintf("%v", o)), nil)
|
||||
err := c.store.Put(key, fmt.Appendf(nil, "%v", o), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -411,7 +411,7 @@ func (c client) load(parentKey string, conf map[string]interface{}) error {
|
||||
default:
|
||||
key := path.Join(parentKey, k)
|
||||
|
||||
err := c.store.Put(key, []byte(fmt.Sprintf("%v", v)), nil)
|
||||
err := c.store.Put(key, fmt.Appendf(nil, "%v", v), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ func encodeNode(labels map[string]string, root string, node *parser.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
func encodeRawValue(labels map[string]string, root string, rawValue interface{}) {
|
||||
func encodeRawValue(labels map[string]string, root string, rawValue any) {
|
||||
if rawValue == nil {
|
||||
return
|
||||
}
|
||||
@@ -47,14 +47,14 @@ func encodeRawValue(labels map[string]string, root string, rawValue interface{})
|
||||
|
||||
if tValue.Kind() == reflect.Map && tValue.Elem().Kind() == reflect.Interface {
|
||||
r := reflect.ValueOf(rawValue).
|
||||
Convert(reflect.TypeOf((map[string]interface{})(nil))).
|
||||
Interface().(map[string]interface{})
|
||||
Convert(reflect.TypeFor[map[string]any]()).
|
||||
Interface().(map[string]any)
|
||||
|
||||
for k, v := range r {
|
||||
switch tv := v.(type) {
|
||||
case string:
|
||||
labels[root+"."+k] = tv
|
||||
case []interface{}:
|
||||
case []any:
|
||||
for i, e := range tv {
|
||||
encodeRawValue(labels, fmt.Sprintf("%s.%s[%d]", root, k, i), e)
|
||||
}
|
||||
|
||||
@@ -72,10 +72,7 @@ func pagination(request *http.Request, maximum int) (pageInfo, error) {
|
||||
return pageInfo{}, fmt.Errorf("invalid request: page: %d, per_page: %d", page, perPage)
|
||||
}
|
||||
|
||||
endIndex := startIndex + perPage
|
||||
if endIndex >= maximum {
|
||||
endIndex = maximum
|
||||
}
|
||||
endIndex := min(startIndex+perPage, maximum)
|
||||
|
||||
nextPage := 1
|
||||
if page*perPage < maximum {
|
||||
|
||||
@@ -15,7 +15,7 @@ func init() {
|
||||
expvar.Publish("Goroutines2", expvar.Func(goroutines))
|
||||
}
|
||||
|
||||
func goroutines() interface{} {
|
||||
func goroutines() any {
|
||||
return runtime.NumGoroutine()
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ func writeError(rw http.ResponseWriter, msg string, code int) {
|
||||
|
||||
type serviceInfoRepresentation struct {
|
||||
*runtime.ServiceInfo
|
||||
|
||||
ServerStatus map[string]string `json:"serverStatus,omitempty"`
|
||||
}
|
||||
|
||||
@@ -147,12 +148,12 @@ func getProviderName(id string) string {
|
||||
return strings.SplitN(id, "@", 2)[1]
|
||||
}
|
||||
|
||||
func extractType(element interface{}) string {
|
||||
func extractType(element any) string {
|
||||
v := reflect.ValueOf(element).Elem()
|
||||
for i := range v.NumField() {
|
||||
field := v.Field(i)
|
||||
|
||||
if field.Kind() == reflect.Map && field.Type().Elem() == reflect.TypeOf(dynamic.PluginConf{}) {
|
||||
if field.Kind() == reflect.Map && field.Type().Elem() == reflect.TypeFor[dynamic.PluginConf]() {
|
||||
if keys := field.MapKeys(); len(keys) == 1 {
|
||||
return keys[0].String()
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
type entryPointRepresentation struct {
|
||||
*static.EntryPoint
|
||||
|
||||
Name string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
|
||||
@@ -235,7 +235,7 @@ func TestHandler_EntryPoints(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
if *updateExpected {
|
||||
var results interface{}
|
||||
var results any
|
||||
err := json.Unmarshal(contents, &results)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
|
||||
type routerRepresentation struct {
|
||||
*runtime.RouterInfo
|
||||
|
||||
Name string `json:"name,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
}
|
||||
@@ -35,6 +36,7 @@ func newRouterRepresentation(name string, rt *runtime.RouterInfo) routerRepresen
|
||||
|
||||
type serviceRepresentation struct {
|
||||
*runtime.ServiceInfo
|
||||
|
||||
ServerStatus map[string]string `json:"serverStatus,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
@@ -53,6 +55,7 @@ func newServiceRepresentation(name string, si *runtime.ServiceInfo) serviceRepre
|
||||
|
||||
type middlewareRepresentation struct {
|
||||
*runtime.MiddlewareInfo
|
||||
|
||||
Name string `json:"name,omitempty"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user