Merge current v2.11 into v3.1
This commit is contained in:
commit
2ffa6c6feb
17 changed files with 266 additions and 74 deletions
4
.github/workflows/build.yaml
vendored
4
.github/workflows/build.yaml
vendored
|
@ -4,6 +4,10 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- '*'
|
- '*'
|
||||||
|
paths-ignore:
|
||||||
|
- 'docs/**'
|
||||||
|
- '**.md'
|
||||||
|
- 'script/gcg/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: '1.22'
|
GO_VERSION: '1.22'
|
||||||
|
|
2
.github/workflows/documentation.yml
vendored
2
.github/workflows/documentation.yml
vendored
|
@ -24,7 +24,7 @@ jobs:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Login to DockerHub
|
- name: Login to DockerHub
|
||||||
uses: docker/login-action@v1
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
4
.github/workflows/experimental.yaml
vendored
4
.github/workflows/experimental.yaml
vendored
|
@ -56,10 +56,10 @@ jobs:
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Build docker experimental image
|
- name: Build docker experimental image
|
||||||
env:
|
env:
|
||||||
|
|
6
.github/workflows/test-integration.yaml
vendored
6
.github/workflows/test-integration.yaml
vendored
|
@ -4,6 +4,10 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- '*'
|
- '*'
|
||||||
|
paths-ignore:
|
||||||
|
- 'docs/**'
|
||||||
|
- '**.md'
|
||||||
|
- 'script/gcg/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: '1.22'
|
GO_VERSION: '1.22'
|
||||||
|
@ -60,7 +64,7 @@ jobs:
|
||||||
|
|
||||||
- name: Generate go test Slice
|
- name: Generate go test Slice
|
||||||
id: test_split
|
id: test_split
|
||||||
uses: hashicorp-forge/go-test-split-action@v1
|
uses: hashicorp-forge/go-test-split-action@v2.0.0
|
||||||
with:
|
with:
|
||||||
packages: ./integration
|
packages: ./integration
|
||||||
total: ${{ matrix.parallel }}
|
total: ${{ matrix.parallel }}
|
||||||
|
|
4
.github/workflows/test-unit.yaml
vendored
4
.github/workflows/test-unit.yaml
vendored
|
@ -4,6 +4,10 @@ on:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- '*'
|
- '*'
|
||||||
|
paths-ignore:
|
||||||
|
- 'docs/**'
|
||||||
|
- '**.md'
|
||||||
|
- 'script/gcg/**'
|
||||||
|
|
||||||
env:
|
env:
|
||||||
GO_VERSION: '1.22'
|
GO_VERSION: '1.22'
|
||||||
|
|
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -1,3 +1,19 @@
|
||||||
|
## [v2.11.7](https://github.com/traefik/traefik/tree/v2.11.7) (2024-07-30)
|
||||||
|
[All Commits](https://github.com/traefik/traefik/compare/v2.11.6...v2.11.7)
|
||||||
|
|
||||||
|
**Bug fixes:**
|
||||||
|
- **[logs]** Make the log about new version more accurate ([#10903](https://github.com/traefik/traefik/pull/10903) by [jmcbri](https://github.com/jmcbri))
|
||||||
|
- **[tls,k8s/crd,k8s]** Enforce default cipher suites list ([#10907](https://github.com/traefik/traefik/pull/10907) by [rtribotte](https://github.com/rtribotte))
|
||||||
|
|
||||||
|
**Documentation:**
|
||||||
|
- **[acme]** Modify certificatesDuration documentation ([#10920](https://github.com/traefik/traefik/pull/10920) by [peacewalker122](https://github.com/peacewalker122))
|
||||||
|
- **[api]** Improve explanation on API exposition ([#10926](https://github.com/traefik/traefik/pull/10926) by [mloiseleur](https://github.com/mloiseleur))
|
||||||
|
- **[docker,consul,rancher,ecs]** Improve doc on sensitive data stored into labels/tags ([#10873](https://github.com/traefik/traefik/pull/10873) by [emilevauge](https://github.com/emilevauge))
|
||||||
|
- **[docker,logs]** Improve error and documentation on the needed link between router and service ([#10262](https://github.com/traefik/traefik/pull/10262) by [mloiseleur](https://github.com/mloiseleur))
|
||||||
|
- **[docker]** Document Docker port selection on multiple exposed ports ([#10935](https://github.com/traefik/traefik/pull/10935) by [mbrodala](https://github.com/mbrodala))
|
||||||
|
- Update the supported versions table for v3.1 release ([#10933](https://github.com/traefik/traefik/pull/10933) by [jnoordsij](https://github.com/jnoordsij))
|
||||||
|
- Update PR approval process ([#10887](https://github.com/traefik/traefik/pull/10887) by [emilevauge](https://github.com/emilevauge))
|
||||||
|
|
||||||
## [v3.1.0](https://github.com/traefik/traefik/tree/v3.1.0) (2024-07-15)
|
## [v3.1.0](https://github.com/traefik/traefik/tree/v3.1.0) (2024-07-15)
|
||||||
[All Commits](https://github.com/traefik/traefik/compare/v3.1.0-rc1...v3.1.0)
|
[All Commits](https://github.com/traefik/traefik/compare/v3.1.0-rc1...v3.1.0)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,8 @@ Below is a non-exhaustive list of versions and their maintenance status:
|
||||||
|
|
||||||
| Version | Release Date | Community Support |
|
| Version | Release Date | Community Support |
|
||||||
|---------|--------------|--------------------|
|
|---------|--------------|--------------------|
|
||||||
| 3.0 | Apr 29, 2024 | Yes |
|
| 3.1 | Jul 15, 2024 | Yes |
|
||||||
|
| 3.0 | Apr 29, 2024 | Ended Jul 15, 2024 |
|
||||||
| 2.11 | Feb 12, 2024 | Ends Apr 29, 2025 |
|
| 2.11 | Feb 12, 2024 | Ends Apr 29, 2025 |
|
||||||
| 2.10 | Apr 24, 2023 | Ended Feb 12, 2024 |
|
| 2.10 | Apr 24, 2023 | Ended Feb 12, 2024 |
|
||||||
| 2.9 | Oct 03, 2022 | Ended Apr 24, 2023 |
|
| 2.9 | Oct 03, 2022 | Ended Apr 24, 2023 |
|
||||||
|
|
|
@ -606,9 +606,21 @@ docker run -v "/my/host/acme:/etc/traefik/acme" traefik
|
||||||
|
|
||||||
_Optional, Default=2160_
|
_Optional, Default=2160_
|
||||||
|
|
||||||
The `certificatesDuration` option defines the certificates' duration in hours.
|
`certificatesDuration` is used to calculate two durations:
|
||||||
|
|
||||||
|
- `Renew Period`: the period before the end of the certificate duration, during which the certificate should be renewed.
|
||||||
|
- `Renew Interval`: the interval between renew attempts.
|
||||||
|
|
||||||
It defaults to `2160` (90 days) to follow Let's Encrypt certificates' duration.
|
It defaults to `2160` (90 days) to follow Let's Encrypt certificates' duration.
|
||||||
|
|
||||||
|
| Certificate Duration | Renew Period | Renew Interval |
|
||||||
|
|----------------------|-------------------|-------------------------|
|
||||||
|
| >= 1 year | 4 months | 1 week |
|
||||||
|
| >= 90 days | 30 days | 1 day |
|
||||||
|
| >= 7 days | 1 day | 1 hour |
|
||||||
|
| >= 24 hours | 6 hours | 10 min |
|
||||||
|
| < 24 hours | 20 min | 1 min |
|
||||||
|
|
||||||
!!! warning "Traefik cannot manage certificates with a duration lower than 1 hour."
|
!!! warning "Traefik cannot manage certificates with a duration lower than 1 hour."
|
||||||
|
|
||||||
```yaml tab="File (YAML)"
|
```yaml tab="File (YAML)"
|
||||||
|
@ -633,19 +645,6 @@ certificatesResolvers:
|
||||||
# ...
|
# ...
|
||||||
```
|
```
|
||||||
|
|
||||||
`certificatesDuration` is used to calculate two durations:
|
|
||||||
|
|
||||||
- `Renew Period`: the period before the end of the certificate duration, during which the certificate should be renewed.
|
|
||||||
- `Renew Interval`: the interval between renew attempts.
|
|
||||||
|
|
||||||
| Certificate Duration | Renew Period | Renew Interval |
|
|
||||||
|----------------------|-------------------|-------------------------|
|
|
||||||
| >= 1 year | 4 months | 1 week |
|
|
||||||
| >= 90 days | 30 days | 1 day |
|
|
||||||
| >= 7 days | 1 day | 1 hour |
|
|
||||||
| >= 24 hours | 6 hours | 10 min |
|
|
||||||
| < 24 hours | 20 min | 1 min |
|
|
||||||
|
|
||||||
### `preferredChain`
|
### `preferredChain`
|
||||||
|
|
||||||
_Optional, Default=""_
|
_Optional, Default=""_
|
||||||
|
|
|
@ -16,12 +16,8 @@ including sensitive data.
|
||||||
|
|
||||||
In production, it should be at least secured by authentication and authorizations.
|
In production, it should be at least secured by authentication and authorizations.
|
||||||
|
|
||||||
A good sane default (non exhaustive) set of recommendations
|
!!! info
|
||||||
would be to apply the following protection mechanisms:
|
It's recommended to NOT publicly exposing the API's port, keeping it restricted to internal networks
|
||||||
|
|
||||||
* At the transport level:
|
|
||||||
NOT publicly exposing the API's port,
|
|
||||||
keeping it restricted to internal networks
|
|
||||||
(as in the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege), applied to networks).
|
(as in the [principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege), applied to networks).
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
|
@ -20,7 +20,7 @@ This provider works with [Docker (standalone) Engine](https://docs.docker.com/en
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "Configuring Docker & Deploying / Exposing Services"
|
??? example "Configuring Docker & Deploying / Exposing one Service"
|
||||||
|
|
||||||
Enabling the docker provider
|
Enabling the docker provider
|
||||||
|
|
||||||
|
@ -73,12 +73,14 @@ When using Docker Compose, labels are specified by the directive
|
||||||
|
|
||||||
Traefik retrieves the private IP and port of containers from the Docker API.
|
Traefik retrieves the private IP and port of containers from the Docker API.
|
||||||
|
|
||||||
Port detection works as follows:
|
Port detection for private communication works as follows:
|
||||||
|
|
||||||
- If a container [exposes](https://docs.docker.com/engine/reference/builder/#expose) a single port,
|
- If a container [exposes](https://docs.docker.com/engine/reference/builder/#expose) a single port,
|
||||||
then Traefik uses this port for private communication.
|
then Traefik uses this port.
|
||||||
- If a container [exposes](https://docs.docker.com/engine/reference/builder/#expose) multiple ports,
|
- If a container [exposes](https://docs.docker.com/engine/reference/builder/#expose) multiple ports,
|
||||||
or does not expose any port, then you must manually specify which port Traefik should use for communication
|
then Traefik uses the lowest port. E.g. if `80` and `8080` are exposed, Traefik will use `80`.
|
||||||
|
- If a container does not expose any port, or the selection from multiple ports does not fit,
|
||||||
|
then you must manually specify which port Traefik should use for communication
|
||||||
by using the label `traefik.http.services.<service_name>.loadbalancer.server.port`
|
by using the label `traefik.http.services.<service_name>.loadbalancer.server.port`
|
||||||
(Read more on this label in the dedicated section in [routing](../routing/providers/docker.md#services)).
|
(Read more on this label in the dedicated section in [routing](../routing/providers/docker.md#services)).
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@ This provider works with [Docker Swarm Mode](https://docs.docker.com/engine/swar
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "Configuring Docker Swarm & Deploying / Exposing Services"
|
??? example "Configuring Docker Swarm & Deploying / Exposing one Service"
|
||||||
|
|
||||||
Enabling the Swarm provider
|
Enabling the Swarm provider
|
||||||
|
|
||||||
|
@ -48,7 +48,9 @@ This provider works with [Docker Swarm Mode](https://docs.docker.com/engine/swar
|
||||||
--providers.swarm.endpoint=tcp://127.0.0.1:2377
|
--providers.swarm.endpoint=tcp://127.0.0.1:2377
|
||||||
```
|
```
|
||||||
|
|
||||||
Attach labels to services (not to containers) while in Swarm mode (in your docker compose file)
|
Attach labels to a single service (not containers) while in Swarm mode (in your Docker compose file).
|
||||||
|
When there is only one service, and the router does not specify a service,
|
||||||
|
then that service is automatically assigned to the router.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: "3"
|
version: "3"
|
||||||
|
|
|
@ -22,7 +22,7 @@ With Docker, Traefik can leverage labels attached to a container to generate rou
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "Configuring Docker & Deploying / Exposing Services"
|
??? example "Configuring Docker & Deploying / Exposing one Service"
|
||||||
|
|
||||||
Enabling the docker provider
|
Enabling the docker provider
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ and the router automatically gets a rule defined by `defaultRule` (if no rule fo
|
||||||
|
|
||||||
--8<-- "content/routing/providers/service-by-label.md"
|
--8<-- "content/routing/providers/service-by-label.md"
|
||||||
|
|
||||||
??? example "Automatic service assignment with labels"
|
??? example "Automatic assignment with one Service"
|
||||||
|
|
||||||
With labels in a compose file
|
With labels in a compose file
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ and the router automatically gets a rule defined by `defaultRule` (if no rule fo
|
||||||
- "traefik.http.services.myservice.loadbalancer.server.port=80"
|
- "traefik.http.services.myservice.loadbalancer.server.port=80"
|
||||||
```
|
```
|
||||||
|
|
||||||
??? example "Automatic service creation and assignment with labels"
|
??? example "Automatic service creation with one Router"
|
||||||
|
|
||||||
With labels in a compose file
|
With labels in a compose file
|
||||||
|
|
||||||
|
@ -131,6 +131,18 @@ and the router automatically gets a rule defined by `defaultRule` (if no rule fo
|
||||||
- "traefik.http.routers.myproxy.rule=Host(`example.net`)"
|
- "traefik.http.routers.myproxy.rule=Host(`example.net`)"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
??? example "Explicit definition with one Service"
|
||||||
|
|
||||||
|
With labels in a compose file
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
labels:
|
||||||
|
- traefik.http.routers.www-router.rule=Host(`example-a.com`)
|
||||||
|
# Explicit link between the router and the service
|
||||||
|
- traefik.http.routers.www-router.service=www-service
|
||||||
|
- traefik.http.services.www-service.loadbalancer.server.port=8000
|
||||||
|
```
|
||||||
|
|
||||||
### Routers
|
### Routers
|
||||||
|
|
||||||
To update the configuration of the Router automatically attached to the container,
|
To update the configuration of the Router automatically attached to the container,
|
||||||
|
@ -433,7 +445,7 @@ More information about available middlewares in the dedicated [middlewares secti
|
||||||
|
|
||||||
You can declare TCP Routers and/or Services using labels.
|
You can declare TCP Routers and/or Services using labels.
|
||||||
|
|
||||||
??? example "Declaring TCP Routers and Services"
|
??? example "Declaring TCP Routers with one Service"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
|
@ -571,7 +583,7 @@ You can declare TCP Routers and/or Services using labels.
|
||||||
|
|
||||||
You can declare UDP Routers and/or Services using labels.
|
You can declare UDP Routers and/or Services using labels.
|
||||||
|
|
||||||
??? example "Declaring UDP Routers and Services"
|
??? example "Declaring UDP Routers with one Service"
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
|
|
|
@ -22,7 +22,7 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
|
||||||
|
|
||||||
## Configuration Examples
|
## Configuration Examples
|
||||||
|
|
||||||
??? example "Configuring Docker Swarm & Deploying / Exposing Services"
|
??? example "Configuring Docker Swarm & Deploying / Exposing one Service"
|
||||||
|
|
||||||
Enabling the docker provider (Swarm Mode)
|
Enabling the docker provider (Swarm Mode)
|
||||||
|
|
||||||
|
@ -50,7 +50,9 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
|
||||||
--providers.swarm.endpoint=tcp://127.0.0.1:2377
|
--providers.swarm.endpoint=tcp://127.0.0.1:2377
|
||||||
```
|
```
|
||||||
|
|
||||||
Attach labels to services (not to containers) while in Swarm mode (in your docker compose file)
|
Attach labels to services (not containers) while in Swarm mode (in your Docker compose file).
|
||||||
|
When there is only one service, and the router does not specify a service,
|
||||||
|
then that service is automatically assigned to the router.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
version: "3"
|
version: "3"
|
||||||
|
@ -67,6 +69,30 @@ With Docker Swarm, Traefik can leverage labels attached to a service to generate
|
||||||
Therefore, if you use a compose file with Swarm Mode, labels should be defined in the `deploy` part of your service.
|
Therefore, if you use a compose file with Swarm Mode, labels should be defined in the `deploy` part of your service.
|
||||||
This behavior is only enabled for docker-compose version 3+ ([Compose file reference](https://docs.docker.com/compose/compose-file/compose-file-v3/#labels-1)).
|
This behavior is only enabled for docker-compose version 3+ ([Compose file reference](https://docs.docker.com/compose/compose-file/compose-file-v3/#labels-1)).
|
||||||
|
|
||||||
|
??? example "Specify a Custom Port for the Container"
|
||||||
|
|
||||||
|
Forward requests for `http://example.com` to `http://<private IP of container>:12345`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "3"
|
||||||
|
services:
|
||||||
|
my-container:
|
||||||
|
# ...
|
||||||
|
deploy:
|
||||||
|
labels:
|
||||||
|
- traefik.http.routers.my-container.rule=Host(`example.com`)
|
||||||
|
- traefik.http.routers.my-container.service=my-service"
|
||||||
|
# Tell Traefik to use the port 12345 to connect to `my-container`
|
||||||
|
- traefik.http.services.my-service.loadbalancer.server.port=12345
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! important "Traefik Connecting to the Wrong Port: `HTTP/502 Gateway Error`"
|
||||||
|
By default, Traefik uses the lowest exposed port of a container as detailed in
|
||||||
|
[Port Detection](../providers/swarm.md#port-detection) of the Swarm provider.
|
||||||
|
|
||||||
|
Setting the label `traefik.http.services.xxx.loadbalancer.server.port`
|
||||||
|
overrides this behavior.
|
||||||
|
|
||||||
??? example "Specifying more than one router and service per container"
|
??? example "Specifying more than one router and service per container"
|
||||||
|
|
||||||
Forwarding requests to more than one port on a container requires referencing the service loadbalancer port definition using the service parameter on the router.
|
Forwarding requests to more than one port on a container requires referencing the service loadbalancer port definition using the service parameter on the router.
|
||||||
|
@ -232,7 +258,7 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
|
||||||
Registers a port.
|
Registers a port.
|
||||||
Useful when the container exposes multiples ports.
|
Useful when the container exposes multiples ports.
|
||||||
|
|
||||||
Mandatory for Docker Swarm (see the section ["Port Detection with Docker Swarm"](../../providers/docker.md#port-detection)).
|
Mandatory for Docker Swarm (see the section ["Port Detection with Docker Swarm"](../../providers/swarm.md#port-detection)).
|
||||||
{: #port }
|
{: #port }
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
"github.com/traefik/traefik/v3/pkg/config/dynamic"
|
||||||
"github.com/traefik/traefik/v3/pkg/logs"
|
"github.com/traefik/traefik/v3/pkg/logs"
|
||||||
"github.com/traefik/traefik/v3/pkg/tls"
|
"github.com/traefik/traefik/v3/pkg/tls"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Merge merges multiple configurations.
|
// Merge merges multiple configurations.
|
||||||
|
@ -422,7 +423,7 @@ func BuildTCPRouterConfiguration(ctx context.Context, configuration *dynamic.TCP
|
||||||
if len(configuration.Services) > 1 {
|
if len(configuration.Services) > 1 {
|
||||||
delete(configuration.Routers, routerName)
|
delete(configuration.Routers, routerName)
|
||||||
loggerRouter.Error().
|
loggerRouter.Error().
|
||||||
Msg("Could not define the service name for the router: too many services")
|
Msgf("Router %s cannot be linked automatically with multiple Services: %q", routerName, maps.Keys(configuration.Services))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -444,8 +445,8 @@ func BuildUDPRouterConfiguration(ctx context.Context, configuration *dynamic.UDP
|
||||||
|
|
||||||
if len(configuration.Services) > 1 {
|
if len(configuration.Services) > 1 {
|
||||||
delete(configuration.Routers, routerName)
|
delete(configuration.Routers, routerName)
|
||||||
loggerRouter.
|
loggerRouter.Error().
|
||||||
Error().Msg("Could not define the service name for the router: too many services")
|
Msgf("Router %s cannot be linked automatically with multiple Services: %q", routerName, maps.Keys(configuration.Services))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,7 +494,7 @@ func BuildRouterConfiguration(ctx context.Context, configuration *dynamic.HTTPCo
|
||||||
if len(configuration.Services) > 1 {
|
if len(configuration.Services) > 1 {
|
||||||
delete(configuration.Routers, routerName)
|
delete(configuration.Routers, routerName)
|
||||||
loggerRouter.Error().
|
loggerRouter.Error().
|
||||||
Msg("Could not define the service name for the router: too many services")
|
Msgf("Router %s cannot be linked automatically with multiple Services: %q", routerName, maps.Keys(configuration.Services))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -978,65 +978,69 @@ func createChainMiddleware(ctx context.Context, namespace string, chain *traefik
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options {
|
func buildTLSOptions(ctx context.Context, client Client) map[string]tls.Options {
|
||||||
tlsOptionsCRD := client.GetTLSOptions()
|
tlsOptionsCRDs := client.GetTLSOptions()
|
||||||
var tlsOptions map[string]tls.Options
|
var tlsOptions map[string]tls.Options
|
||||||
|
|
||||||
if len(tlsOptionsCRD) == 0 {
|
if len(tlsOptionsCRDs) == 0 {
|
||||||
return tlsOptions
|
return tlsOptions
|
||||||
}
|
}
|
||||||
tlsOptions = make(map[string]tls.Options)
|
tlsOptions = make(map[string]tls.Options)
|
||||||
var nsDefault []string
|
var nsDefault []string
|
||||||
|
|
||||||
for _, tlsOption := range tlsOptionsCRD {
|
for _, tlsOptionsCRD := range tlsOptionsCRDs {
|
||||||
logger := log.Ctx(ctx).With().Str("tlsOption", tlsOption.Name).Str("namespace", tlsOption.Namespace).Logger()
|
logger := log.Ctx(ctx).With().Str("tlsOption", tlsOptionsCRD.Name).Str("namespace", tlsOptionsCRD.Namespace).Logger()
|
||||||
var clientCAs []types.FileOrContent
|
var clientCAs []types.FileOrContent
|
||||||
|
|
||||||
for _, secretName := range tlsOption.Spec.ClientAuth.SecretNames {
|
for _, secretName := range tlsOptionsCRD.Spec.ClientAuth.SecretNames {
|
||||||
secret, exists, err := client.GetSecret(tlsOption.Namespace, secretName)
|
secret, exists, err := client.GetSecret(tlsOptionsCRD.Namespace, secretName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Err(err).Msgf("Failed to fetch secret %s/%s", tlsOption.Namespace, secretName)
|
logger.Error().Err(err).Msgf("Failed to fetch secret %s/%s", tlsOptionsCRD.Namespace, secretName)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
logger.Warn().Msgf("Secret %s/%s does not exist", tlsOption.Namespace, secretName)
|
logger.Warn().Msgf("Secret %s/%s does not exist", tlsOptionsCRD.Namespace, secretName)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
cert, err := getCABlocks(secret, tlsOption.Namespace, secretName)
|
cert, err := getCABlocks(secret, tlsOptionsCRD.Namespace, secretName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error().Err(err).Msgf("Failed to extract CA from secret %s/%s", tlsOption.Namespace, secretName)
|
logger.Error().Err(err).Msgf("Failed to extract CA from secret %s/%s", tlsOptionsCRD.Namespace, secretName)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
clientCAs = append(clientCAs, types.FileOrContent(cert))
|
clientCAs = append(clientCAs, types.FileOrContent(cert))
|
||||||
}
|
}
|
||||||
|
|
||||||
id := makeID(tlsOption.Namespace, tlsOption.Name)
|
id := makeID(tlsOptionsCRD.Namespace, tlsOptionsCRD.Name)
|
||||||
// If the name is default, we override the default config.
|
// If the name is default, we override the default config.
|
||||||
if tlsOption.Name == tls.DefaultTLSConfigName {
|
if tlsOptionsCRD.Name == tls.DefaultTLSConfigName {
|
||||||
id = tlsOption.Name
|
id = tlsOptionsCRD.Name
|
||||||
nsDefault = append(nsDefault, tlsOption.Namespace)
|
nsDefault = append(nsDefault, tlsOptionsCRD.Namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
alpnProtocols := tls.DefaultTLSOptions.ALPNProtocols
|
tlsOption := tls.Options{}
|
||||||
if len(tlsOption.Spec.ALPNProtocols) > 0 {
|
tlsOption.SetDefaults()
|
||||||
alpnProtocols = tlsOption.Spec.ALPNProtocols
|
|
||||||
|
tlsOption.MinVersion = tlsOptionsCRD.Spec.MinVersion
|
||||||
|
tlsOption.MaxVersion = tlsOptionsCRD.Spec.MaxVersion
|
||||||
|
|
||||||
|
if tlsOptionsCRD.Spec.CipherSuites != nil {
|
||||||
|
tlsOption.CipherSuites = tlsOptionsCRD.Spec.CipherSuites
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsOptions[id] = tls.Options{
|
tlsOption.CurvePreferences = tlsOptionsCRD.Spec.CurvePreferences
|
||||||
MinVersion: tlsOption.Spec.MinVersion,
|
tlsOption.ClientAuth = tls.ClientAuth{
|
||||||
MaxVersion: tlsOption.Spec.MaxVersion,
|
|
||||||
CipherSuites: tlsOption.Spec.CipherSuites,
|
|
||||||
CurvePreferences: tlsOption.Spec.CurvePreferences,
|
|
||||||
ClientAuth: tls.ClientAuth{
|
|
||||||
CAFiles: clientCAs,
|
CAFiles: clientCAs,
|
||||||
ClientAuthType: tlsOption.Spec.ClientAuth.ClientAuthType,
|
ClientAuthType: tlsOptionsCRD.Spec.ClientAuth.ClientAuthType,
|
||||||
},
|
|
||||||
SniStrict: tlsOption.Spec.SniStrict,
|
|
||||||
ALPNProtocols: alpnProtocols,
|
|
||||||
PreferServerCipherSuites: tlsOption.Spec.PreferServerCipherSuites,
|
|
||||||
}
|
}
|
||||||
|
tlsOption.SniStrict = tlsOptionsCRD.Spec.SniStrict
|
||||||
|
|
||||||
|
if tlsOptionsCRD.Spec.ALPNProtocols != nil {
|
||||||
|
tlsOption.ALPNProtocols = tlsOptionsCRD.Spec.ALPNProtocols
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsOptions[id] = tlsOption
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(nsDefault) > 1 {
|
if len(nsDefault) > 1 {
|
||||||
|
|
|
@ -886,6 +886,21 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||||
"http/1.1",
|
"http/1.1",
|
||||||
"acme-tls/1",
|
"acme-tls/1",
|
||||||
},
|
},
|
||||||
|
CipherSuites: []string{
|
||||||
|
"TLS_AES_128_GCM_SHA256",
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -942,6 +957,21 @@ func TestLoadIngressRouteTCPs(t *testing.T) {
|
||||||
"http/1.1",
|
"http/1.1",
|
||||||
"acme-tls/1",
|
"acme-tls/1",
|
||||||
},
|
},
|
||||||
|
CipherSuites: []string{
|
||||||
|
"TLS_AES_128_GCM_SHA256",
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -3549,6 +3579,21 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
"http/1.1",
|
"http/1.1",
|
||||||
"acme-tls/1",
|
"acme-tls/1",
|
||||||
},
|
},
|
||||||
|
CipherSuites: []string{
|
||||||
|
"TLS_AES_128_GCM_SHA256",
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -3611,6 +3656,21 @@ func TestLoadIngressRoutes(t *testing.T) {
|
||||||
"http/1.1",
|
"http/1.1",
|
||||||
"acme-tls/1",
|
"acme-tls/1",
|
||||||
},
|
},
|
||||||
|
CipherSuites: []string{
|
||||||
|
"TLS_AES_128_GCM_SHA256",
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -6334,6 +6394,21 @@ func TestCrossNamespace(t *testing.T) {
|
||||||
"cross-ns-tls-options-cn": {
|
"cross-ns-tls-options-cn": {
|
||||||
MinVersion: "VersionTLS12",
|
MinVersion: "VersionTLS12",
|
||||||
ALPNProtocols: []string{"h2", "http/1.1", "acme-tls/1"},
|
ALPNProtocols: []string{"h2", "http/1.1", "acme-tls/1"},
|
||||||
|
CipherSuites: []string{
|
||||||
|
"TLS_AES_128_GCM_SHA256",
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -6382,6 +6457,21 @@ func TestCrossNamespace(t *testing.T) {
|
||||||
"cross-ns-tls-options-cn": {
|
"cross-ns-tls-options-cn": {
|
||||||
MinVersion: "VersionTLS12",
|
MinVersion: "VersionTLS12",
|
||||||
ALPNProtocols: []string{"h2", "http/1.1", "acme-tls/1"},
|
ALPNProtocols: []string{"h2", "http/1.1", "acme-tls/1"},
|
||||||
|
CipherSuites: []string{
|
||||||
|
"TLS_AES_128_GCM_SHA256",
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -6723,6 +6813,21 @@ func TestCrossNamespace(t *testing.T) {
|
||||||
"cross-ns-tls-options-cn": {
|
"cross-ns-tls-options-cn": {
|
||||||
MinVersion: "VersionTLS12",
|
MinVersion: "VersionTLS12",
|
||||||
ALPNProtocols: []string{"h2", "http/1.1", "acme-tls/1"},
|
ALPNProtocols: []string{"h2", "http/1.1", "acme-tls/1"},
|
||||||
|
CipherSuites: []string{
|
||||||
|
"TLS_AES_128_GCM_SHA256",
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -6767,6 +6872,21 @@ func TestCrossNamespace(t *testing.T) {
|
||||||
"cross-ns-tls-options-cn": {
|
"cross-ns-tls-options-cn": {
|
||||||
MinVersion: "VersionTLS12",
|
MinVersion: "VersionTLS12",
|
||||||
ALPNProtocols: []string{"h2", "http/1.1", "acme-tls/1"},
|
ALPNProtocols: []string{"h2", "http/1.1", "acme-tls/1"},
|
||||||
|
CipherSuites: []string{
|
||||||
|
"TLS_AES_128_GCM_SHA256",
|
||||||
|
"TLS_AES_256_GCM_SHA384",
|
||||||
|
"TLS_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
|
||||||
|
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
|
||||||
|
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -34,6 +34,7 @@ type Options struct {
|
||||||
func (o *Options) SetDefaults() {
|
func (o *Options) SetDefaults() {
|
||||||
// ensure http2 enabled
|
// ensure http2 enabled
|
||||||
o.ALPNProtocols = DefaultTLSOptions.ALPNProtocols
|
o.ALPNProtocols = DefaultTLSOptions.ALPNProtocols
|
||||||
|
o.CipherSuites = DefaultTLSOptions.CipherSuites
|
||||||
}
|
}
|
||||||
|
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
|
|
Loading…
Reference in a new issue