Compare commits

..

4 commits

Author SHA1 Message Date
a3c1875eaa
Merge branch 'master' of github.com:traefik/traefik
All checks were successful
Build & Push / build-and-push (push) Successful in 21m43s
2024-11-10 22:41:40 +05:30
IIpragmaII
ec00c4aa42
Configurable path for sticky cookies 2024-11-06 16:04:04 +01:00
Bmagic
552bd8f180
Add AbortOnPluginFailure option to abort startup on plugin load failure 2024-11-06 11:58:04 +01:00
Shreyas Kirtane
97caf758ef
Make the IngressRoute kind optional 2024-11-04 16:26:04 +01:00
36 changed files with 579 additions and 38 deletions

View file

@ -238,6 +238,9 @@ func setupServer(staticConfiguration *static.Configuration) (*server.Server, err
}
pluginBuilder, err := createPluginBuilder(staticConfiguration)
if err != nil && staticConfiguration.Experimental != nil && staticConfiguration.Experimental.AbortOnPluginFailure {
return nil, fmt.Errorf("plugin: failed to create plugin builder: %w", err)
}
if err != nil {
pluginLogger.Err(err).Msg("Plugins are disabled because an error has occurred.")
} else if hasPlugins {

View file

@ -191,6 +191,7 @@
- "traefik.http.services.service02.loadbalancer.sticky.cookie.httponly=true"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.maxage=42"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.name=foobar"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.path=foobar"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.samesite=foobar"
- "traefik.http.services.service02.loadbalancer.sticky.cookie.secure=true"
- "traefik.http.services.service02.loadbalancer.server.port=foobar"

View file

@ -55,6 +55,7 @@
httpOnly = true
sameSite = "foobar"
maxAge = 42
path = "foobar"
[[http.services.Service02.loadBalancer.servers]]
url = "foobar"
@ -112,6 +113,7 @@
httpOnly = true
sameSite = "foobar"
maxAge = 42
path = "foobar"
[http.services.Service04.weighted.healthCheck]
[http.middlewares]
[http.middlewares.Middleware01]

View file

@ -63,6 +63,7 @@ http:
httpOnly: true
sameSite: foobar
maxAge: 42
path: foobar
servers:
- url: foobar
weight: 42
@ -113,6 +114,7 @@ http:
httpOnly: true
sameSite: foobar
maxAge: 42
path: foobar
healthCheck: {}
middlewares:
Middleware01:

View file

@ -57,6 +57,7 @@ spec:
description: |-
Kind defines the kind of the route.
Rule is the only supported kind.
If not defined, defaults to Rule.
enum:
- Rule
type: string
@ -241,13 +242,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -280,7 +287,6 @@ spec:
More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#rulesyntax
type: string
required:
- kind
- match
type: object
type: array
@ -1133,13 +1139,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -2686,13 +2698,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -2793,13 +2811,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -2976,13 +3000,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -3023,13 +3053,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.

View file

@ -266,6 +266,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/httpOnly` | `true` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/maxAge` | `42` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/name` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/path` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/sameSite` | `foobar` |
| `traefik/http/services/Service02/loadBalancer/sticky/cookie/secure` | `true` |
| `traefik/http/services/Service03/mirroring/healthCheck` | `` |
@ -284,6 +285,7 @@ THIS FILE MUST NOT BE EDITED BY HAND
| `traefik/http/services/Service04/weighted/sticky/cookie/httpOnly` | `true` |
| `traefik/http/services/Service04/weighted/sticky/cookie/maxAge` | `42` |
| `traefik/http/services/Service04/weighted/sticky/cookie/name` | `foobar` |
| `traefik/http/services/Service04/weighted/sticky/cookie/path` | `foobar` |
| `traefik/http/services/Service04/weighted/sticky/cookie/sameSite` | `foobar` |
| `traefik/http/services/Service04/weighted/sticky/cookie/secure` | `true` |
| `traefik/tcp/middlewares/TCPMiddleware01/ipAllowList/sourceRange/0` | `foobar` |

View file

@ -57,6 +57,7 @@ spec:
description: |-
Kind defines the kind of the route.
Rule is the only supported kind.
If not defined, defaults to Rule.
enum:
- Rule
type: string
@ -241,13 +242,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -280,7 +287,6 @@ spec:
More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#rulesyntax
type: string
required:
- kind
- match
type: object
type: array

View file

@ -409,13 +409,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.

View file

@ -279,13 +279,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -386,13 +392,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -569,13 +581,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -616,13 +634,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.

View file

@ -228,6 +228,9 @@ WriteTimeout is the maximum duration before timing out writes of the response. I
`--entrypoints.<name>.udp.timeout`:
Timeout defines how long to wait on an idle session before releasing the related resources. (Default: ```3```)
`--experimental.abortonpluginfailure`:
Defines whether all plugins must be loaded successfully for Traefik to start. (Default: ```false```)
`--experimental.fastproxy`:
Enable the FastProxy implementation. (Default: ```false```)

View file

@ -228,6 +228,9 @@ WriteTimeout is the maximum duration before timing out writes of the response. I
`TRAEFIK_ENTRYPOINTS_<NAME>_UDP_TIMEOUT`:
Timeout defines how long to wait on an idle session before releasing the related resources. (Default: ```3```)
`TRAEFIK_EXPERIMENTAL_ABORTONPLUGINFAILURE`:
Defines whether all plugins must be loaded successfully for Traefik to start. (Default: ```false```)
`TRAEFIK_EXPERIMENTAL_FASTPROXY`:
Enable the FastProxy implementation. (Default: ```false```)

View file

@ -488,6 +488,7 @@
[certificatesResolvers.CertificateResolver1.tailscale]
[experimental]
abortOnPluginFailure = true
kubernetesGateway = true
[experimental.plugins]
[experimental.plugins.Descriptor0]

View file

@ -576,6 +576,7 @@ experimental:
mounts:
- foobar
- foobar
abortOnPluginFailure: true
fastProxy:
debug: true
kubernetesGateway: true

View file

@ -265,6 +265,14 @@ you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.pass
traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.

View file

@ -380,6 +380,14 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.

View file

@ -267,6 +267,14 @@ you'd add the label `traefik.http.services.{name-of-your-choice}.loadbalancer.pa
traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.

View file

@ -352,6 +352,7 @@ Register the `IngressRoute` [kind](../../reference/dynamic-configuration/kuberne
secure: true
sameSite: none
maxAge: 42
path: /foo
strategy: RoundRobin
weight: 10
nativeLB: true # [12]
@ -377,11 +378,11 @@ Register the `IngressRoute` [kind](../../reference/dynamic-configuration/kuberne
| [4] | `routes[n].priority` | Defines the [priority](../routers/index.md#priority) to disambiguate rules of the same length, for route matching |
| [5] | `routes[n].middlewares` | List of reference to [Middleware](#kind-middleware) |
| [6] | `middlewares[n].name` | Defines the [Middleware](#kind-middleware) name |
| [7] | `middlewares[n].namespace` | Defines the [Middleware](#kind-middleware) namespace. It can be omitted when the Middleware is in the IngressRoute namespace. |
| [7] | `middlewares[n].namespace` | Defines the [Middleware](#kind-middleware) namespace. It can be omitted when the Middleware is in the IngressRoute namespace. |
| [8] | `routes[n].services` | List of any combination of [TraefikService](#kind-traefikservice) and reference to a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) (See below for `ExternalName Service` setup) |
| [9] | `services[n].port` | Defines the port of a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/). This can be a reference to a named port. |
| [10] | `services[n].serversTransport` | Defines the reference to a [ServersTransport](#kind-serverstransport). The ServersTransport namespace is assumed to be the [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) namespace (see [ServersTransport reference](#serverstransport-reference)). |
| [11] | `services[n].healthCheck` | Defines the HealthCheck when service references a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type ExternalName. |
| [11] | `services[n].healthCheck` | Defines the HealthCheck when service references a [Kubernetes service](https://kubernetes.io/docs/concepts/services-networking/service/) of type ExternalName. |
| [12] | `services[n].nativeLB` | Controls, when creating the load-balancer, whether the LB's children are directly the pods IPs or if the only child is the Kubernetes Service clusterIP. |
| [13] | `services[n].nodePortLB` | Controls, when creating the load-balancer, whether the LB's children are directly the nodes internal IPs using the nodePort when the service type is NodePort. |
| [14] | `tls` | Defines [TLS](../routers/index.md#tls) certificate configuration |

View file

@ -383,6 +383,14 @@ which in turn will create the resulting routers, services, handlers, etc.
traefik.ingress.kubernetes.io/service.sticky.cookie.maxage: 42
```
??? info "`traefik.ingress.kubernetes.io/service.sticky.cookie.path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
traefik.ingress.kubernetes.io/service.sticky.cookie.path: /foobar
```
## Path Types on Kubernetes 1.18+
If the Kubernetes cluster version is 1.18+,

View file

@ -228,6 +228,14 @@ A Story of key & values
|-------------------------------------------------------------------|----------|
| `traefik/http/services/myservice/loadbalancer/sticky/cookie/name` | `foobar` |
??? info "`traefik/http/services/<service_name>/loadbalancer/sticky/cookie/path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
| Key (Path) | Value |
|-------------------------------------------------------------------|-----------|
| `traefik/http/services/myservice/loadbalancer/sticky/cookie/path` | `/foobar` |
??? info "`traefik/http/services/<service_name>/loadbalancer/sticky/cookie/secure`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
@ -320,6 +328,12 @@ A Story of key & values
|----------------------------------------------------------------------|-------|
| `traefik/http/services/<service_name>/weighted/sticky/cookie/maxage` | `42` |
??? info "`traefik/http/services/<service_name>/weighted/sticky/cookie/path`"
| Key (Path) | Value |
|----------------------------------------------------------------------|-----------|
| `traefik/http/services/<service_name>/weighted/sticky/cookie/path` | `/foobar` |
### Middleware
More information about available middlewares in the dedicated [middlewares section](../../middlewares/overview.md).

View file

@ -281,6 +281,14 @@ you'd add the tag `traefik.http.services.{name-of-your-choice}.loadbalancer.pass
traefik.http.services.myservice.loadbalancer.sticky.cookie.maxage=42
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar
```
??? info "`traefik.http.services.<service_name>.loadbalancer.responseforwarding.flushinterval`"
See [response forwarding](../services/index.md#response-forwarding) for more information.

View file

@ -394,6 +394,14 @@ you'd add the label `traefik.http.services.<name-of-your-choice>.loadbalancer.pa
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.name=foobar"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.path`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.
```yaml
- "traefik.http.services.myservice.loadbalancer.sticky.cookie.path=/foobar"
```
??? info "`traefik.http.services.<service_name>.loadbalancer.sticky.cookie.secure`"
See [sticky sessions](../services/index.md#sticky-sessions) for more information.

View file

@ -57,6 +57,7 @@ spec:
description: |-
Kind defines the kind of the route.
Rule is the only supported kind.
If not defined, defaults to Rule.
enum:
- Rule
type: string
@ -241,13 +242,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -280,7 +287,6 @@ spec:
More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#rulesyntax
type: string
required:
- kind
- match
type: object
type: array
@ -1133,13 +1139,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -2686,13 +2698,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -2793,13 +2811,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -2976,13 +3000,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.
@ -3023,13 +3053,19 @@ spec:
type: boolean
maxAge:
description: |-
MaxAge indicates the number of seconds until the cookie expires.
MaxAge defines the number of seconds until the cookie expires.
When set to a negative number, the cookie expires immediately.
When set to zero, the cookie never expires.
type: integer
name:
description: Name defines the Cookie name.
type: string
path:
description: |-
Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
When not provided the cookie will be sent on every request to the domain.
More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
type: string
sameSite:
description: |-
SameSite defines the same site policy.

View file

@ -175,10 +175,20 @@ type Cookie struct {
// SameSite defines the same site policy.
// More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite
SameSite string `json:"sameSite,omitempty" toml:"sameSite,omitempty" yaml:"sameSite,omitempty" export:"true"`
// MaxAge indicates the number of seconds until the cookie expires.
// MaxAge defines the number of seconds until the cookie expires.
// When set to a negative number, the cookie expires immediately.
// When set to zero, the cookie never expires.
MaxAge int `json:"maxAge,omitempty" toml:"maxAge,omitempty" yaml:"maxAge,omitempty" export:"true"`
// Path defines the path that must exist in the requested URL for the browser to send the Cookie header.
// When not provided the cookie will be sent on every request to the domain.
// More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#pathpath-value
Path *string `json:"path,omitempty" toml:"path,omitempty" yaml:"path,omitempty" export:"true"`
}
// SetDefaults set the default values for a Cookie.
func (c *Cookie) SetDefaults() {
defaultPath := "/"
c.Path = &defaultPath
}
// +k8s:deepcopy-gen=true

View file

@ -266,6 +266,11 @@ func (in *ContentType) DeepCopy() *ContentType {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Cookie) DeepCopyInto(out *Cookie) {
*out = *in
if in.Path != nil {
in, out := &in.Path, &out.Path
*out = new(string)
**out = **in
}
return
}
@ -1517,7 +1522,7 @@ func (in *Sticky) DeepCopyInto(out *Sticky) {
if in.Cookie != nil {
in, out := &in.Cookie, &out.Cookie
*out = new(Cookie)
**out = **in
(*in).DeepCopyInto(*out)
}
return
}

View file

@ -174,6 +174,7 @@ func TestDecodeConfiguration(t *testing.T) {
"traefik.http.services.Service0.loadbalancer.server.port": "8080",
"traefik.http.services.Service0.loadbalancer.sticky.cookie.name": "foobar",
"traefik.http.services.Service0.loadbalancer.sticky.cookie.secure": "true",
"traefik.http.services.Service0.loadbalancer.sticky.cookie.path": "/foobar",
"traefik.http.services.Service0.loadbalancer.serversTransport": "foobar",
"traefik.http.services.Service1.loadbalancer.healthcheck.headers.name0": "foobar",
"traefik.http.services.Service1.loadbalancer.healthcheck.headers.name1": "foobar",
@ -674,6 +675,7 @@ func TestDecodeConfiguration(t *testing.T) {
Name: "foobar",
Secure: true,
HTTPOnly: false,
Path: func(v string) *string { return &v }("/foobar"),
},
},
Servers: []dynamic.Server{
@ -1196,6 +1198,7 @@ func TestEncodeConfiguration(t *testing.T) {
Cookie: &dynamic.Cookie{
Name: "foobar",
HTTPOnly: true,
Path: func(v string) *string { return &v }("/foobar"),
},
},
Servers: []dynamic.Server{
@ -1433,6 +1436,7 @@ func TestEncodeConfiguration(t *testing.T) {
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.HTTPOnly": "true",
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.Secure": "false",
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.MaxAge": "0",
"traefik.HTTP.Services.Service0.LoadBalancer.Sticky.Cookie.Path": "/foobar",
"traefik.HTTP.Services.Service0.LoadBalancer.ServersTransport": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name0": "foobar",
"traefik.HTTP.Services.Service1.LoadBalancer.HealthCheck.Headers.name1": "foobar",

View file

@ -4,8 +4,9 @@ import "github.com/traefik/traefik/v3/pkg/plugins"
// Experimental experimental Traefik features.
type Experimental struct {
Plugins map[string]plugins.Descriptor `description:"Plugins configuration." json:"plugins,omitempty" toml:"plugins,omitempty" yaml:"plugins,omitempty" export:"true"`
LocalPlugins map[string]plugins.LocalDescriptor `description:"Local plugins configuration." json:"localPlugins,omitempty" toml:"localPlugins,omitempty" yaml:"localPlugins,omitempty" export:"true"`
Plugins map[string]plugins.Descriptor `description:"Plugins configuration." json:"plugins,omitempty" toml:"plugins,omitempty" yaml:"plugins,omitempty" export:"true"`
LocalPlugins map[string]plugins.LocalDescriptor `description:"Local plugins configuration." json:"localPlugins,omitempty" toml:"localPlugins,omitempty" yaml:"localPlugins,omitempty" export:"true"`
AbortOnPluginFailure bool `description:"Defines whether all plugins must be loaded successfully for Traefik to start." json:"abortOnPluginFailure,omitempty" toml:"abortOnPluginFailure,omitempty" yaml:"abortOnPluginFailure,omitempty" export:"true"`
FastProxy *FastProxyConfig `description:"Enable the FastProxy implementation." json:"fastProxy,omitempty" toml:"fastProxy,omitempty" yaml:"fastProxy,omitempty" label:"allowEmpty" file:"allowEmpty" export:"true"`

View file

@ -0,0 +1,81 @@
---
apiVersion: traefik.io/v1alpha1
kind: TraefikService
metadata:
name: sticky-default
namespace: default
spec:
weighted:
sticky:
cookie:
httpOnly: true
name: cookie
secure: true
sameSite: none
maxAge: 42
services:
- name: whoami3
port: 8443
---
apiVersion: traefik.io/v1alpha1
kind: TraefikService
metadata:
name: sticky
namespace: default
spec:
weighted:
sticky:
cookie:
httpOnly: true
name: cookie
secure: true
sameSite: none
maxAge: 42
path: /foo
services:
- name: whoami3
port: 8443
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: test2.route
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`traefik-service`)
kind: Rule
services:
- name: sticky
kind: TraefikService
- name: sticky-default
kind: TraefikService
- match: Host(`k8s-service`)
kind: Rule
services:
- name: whoami
port: 80
sticky:
cookie:
httpOnly: true
name: cookie
secure: true
sameSite: none
maxAge: 42
path: /foo
- name: whoami2
port: 8080
sticky:
cookie:
httpOnly: true
name: cookie
secure: true
sameSite: none
maxAge: 42

View file

@ -60,7 +60,7 @@ func (p *Provider) loadIngressRouteConfiguration(ctx context.Context, client Cli
}
for _, route := range ingressRoute.Spec.Routes {
if route.Kind != "Rule" {
if len(route.Kind) > 0 && route.Kind != "Rule" {
logger.Error().Msgf("Unsupported match kind: %s. Only \"Rule\" is supported for now.", route.Kind)
continue
}
@ -248,10 +248,28 @@ func (c configBuilder) buildServicesLB(ctx context.Context, namespace string, tS
})
}
var sticky *dynamic.Sticky
if tService.Weighted.Sticky != nil && tService.Weighted.Sticky.Cookie != nil {
sticky = &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: tService.Weighted.Sticky.Cookie.Name,
Secure: tService.Weighted.Sticky.Cookie.Secure,
HTTPOnly: tService.Weighted.Sticky.Cookie.HTTPOnly,
SameSite: tService.Weighted.Sticky.Cookie.SameSite,
MaxAge: tService.Weighted.Sticky.Cookie.MaxAge,
},
}
sticky.Cookie.SetDefaults()
if tService.Weighted.Sticky.Cookie.Path != nil {
sticky.Cookie.Path = tService.Weighted.Sticky.Cookie.Path
}
}
conf[id] = &dynamic.Service{
Weighted: &dynamic.WeightedRoundRobin{
Services: wrrServices,
Sticky: tService.Weighted.Sticky,
Sticky: sticky,
},
}
return nil
@ -353,7 +371,22 @@ func (c configBuilder) buildServersLB(namespace string, svc traefikv1alpha1.Load
}
}
lb.Sticky = svc.Sticky
if svc.Sticky != nil && svc.Sticky.Cookie != nil {
lb.Sticky = &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: svc.Sticky.Cookie.Name,
Secure: svc.Sticky.Cookie.Secure,
HTTPOnly: svc.Sticky.Cookie.HTTPOnly,
SameSite: svc.Sticky.Cookie.SameSite,
MaxAge: svc.Sticky.Cookie.MaxAge,
},
}
lb.Sticky.Cookie.SetDefaults()
if svc.Sticky.Cookie.Path != nil {
lb.Sticky.Cookie.Path = svc.Sticky.Cookie.Path
}
}
lb.ServersTransport, err = c.makeServersTransportKey(namespace, svc.ServersTransport)
if err != nil {

View file

@ -25,6 +25,7 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
kubefake "k8s.io/client-go/kubernetes/fake"
kscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/utils/pointer"
)
var _ provider.Provider = (*Provider)(nil)
@ -3114,8 +3115,8 @@ func TestLoadIngressRoutes(t *testing.T) {
},
},
{
desc: "Route with kind not of a rule type (empty kind) is ignored",
paths: []string{"services.yml", "with_wrong_rule_kind.yml"},
desc: "Route with empty kind is allowed",
paths: []string{"services.yml", "with_empty_rule_kind.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
@ -3129,9 +3130,33 @@ func TestLoadIngressRoutes(t *testing.T) {
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{},
Routers: map[string]*dynamic.Router{
"default-test-route-02719a68b11e915a4b23": {
EntryPoints: []string{"web"},
Service: "default-test-route-02719a68b11e915a4b23",
Rule: "/prefix",
Priority: 12,
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test-route-02719a68b11e915a4b23": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: Bool(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
},
@ -4879,6 +4904,178 @@ func TestLoadIngressRoutes(t *testing.T) {
TLS: &dynamic.TLSConfiguration{},
},
},
{
desc: "Simple Ingress Route with sticky",
allowCrossNamespace: true,
paths: []string{"services.yml", "with_sticky.yml"},
expected: &dynamic.Configuration{
UDP: &dynamic.UDPConfiguration{
Routers: map[string]*dynamic.UDPRouter{},
Services: map[string]*dynamic.UDPService{},
},
TCP: &dynamic.TCPConfiguration{
Routers: map[string]*dynamic.TCPRouter{},
Middlewares: map[string]*dynamic.TCPMiddleware{},
Services: map[string]*dynamic.TCPService{},
ServersTransports: map[string]*dynamic.TCPServersTransport{},
},
HTTP: &dynamic.HTTPConfiguration{
Routers: map[string]*dynamic.Router{
"default-test2-route-840425136fbd5d85a4ad": {
EntryPoints: []string{"web"},
Service: "default-test2-route-840425136fbd5d85a4ad",
Rule: "Host(`k8s-service`)",
},
"default-test2-route-4f06607bbc69f34a4db5": {
EntryPoints: []string{"web"},
Service: "default-test2-route-4f06607bbc69f34a4db5",
Rule: "Host(`traefik-service`)",
},
},
Middlewares: map[string]*dynamic.Middleware{},
Services: map[string]*dynamic.Service{
"default-test2-route-840425136fbd5d85a4ad": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-whoami-80",
Weight: Int(1),
},
{
Name: "default-whoami2-8080",
Weight: Int(1),
},
},
},
},
"default-test2-route-4f06607bbc69f34a4db5": {
Weighted: &dynamic.WeightedRoundRobin{
Services: []dynamic.WRRService{
{
Name: "default-sticky",
Weight: Int(1),
},
{
Name: "default-sticky-default",
Weight: Int(1),
},
},
},
},
"default-sticky": {
Weighted: &dynamic.WeightedRoundRobin{
Sticky: &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: "cookie",
Secure: true,
HTTPOnly: true,
SameSite: "none",
MaxAge: 42,
Path: pointer.String("/foo"),
},
},
Services: []dynamic.WRRService{
{
Name: "default-whoami3-8443",
Weight: Int(1),
},
},
},
},
"default-sticky-default": {
Weighted: &dynamic.WeightedRoundRobin{
Sticky: &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: "cookie",
Secure: true,
HTTPOnly: true,
SameSite: "none",
MaxAge: 42,
Path: pointer.String("/"),
},
},
Services: []dynamic.WRRService{
{
Name: "default-whoami3-8443",
Weight: Int(1),
},
},
},
},
"default-whoami2-8080": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Sticky: &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: "cookie",
Secure: true,
HTTPOnly: true,
SameSite: "none",
MaxAge: 42,
Path: pointer.String("/"),
},
},
Servers: []dynamic.Server{
{
URL: "http://10.10.0.3:8080",
},
{
URL: "http://10.10.0.4:8080",
},
},
PassHostHeader: Bool(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
"default-whoami-80": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Sticky: &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Name: "cookie",
Secure: true,
HTTPOnly: true,
SameSite: "none",
MaxAge: 42,
Path: pointer.String("/foo"),
},
},
Servers: []dynamic.Server{
{
URL: "http://10.10.0.1:80",
},
{
URL: "http://10.10.0.2:80",
},
},
PassHostHeader: Bool(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
"default-whoami3-8443": {
LoadBalancer: &dynamic.ServersLoadBalancer{
Servers: []dynamic.Server{
{
URL: "http://10.10.0.7:8443",
},
{
URL: "http://10.10.0.8:8443",
},
},
PassHostHeader: Bool(true),
ResponseForwarding: &dynamic.ResponseForwarding{
FlushInterval: ptypes.Duration(100 * time.Millisecond),
},
},
},
},
ServersTransports: map[string]*dynamic.ServersTransport{},
},
TLS: &dynamic.TLSConfiguration{},
},
},
}
for _, test := range testCases {

View file

@ -28,8 +28,9 @@ type Route struct {
Match string `json:"match"`
// Kind defines the kind of the route.
// Rule is the only supported kind.
// If not defined, defaults to Rule.
// +kubebuilder:validation:Enum=Rule
Kind string `json:"kind"`
Kind string `json:"kind,omitempty"`
// Priority defines the router's priority.
// More info: https://doc.traefik.io/traefik/v3.2/routing/routers/#priority
Priority int `json:"priority,omitempty"`

View file

@ -113,6 +113,7 @@ func Test_parseServiceConfig(t *testing.T) {
"traefik.ingress.kubernetes.io/service.sticky.cookie.name": "foobar",
"traefik.ingress.kubernetes.io/service.sticky.cookie.secure": "true",
"traefik.ingress.kubernetes.io/service.sticky.cookie.samesite": "none",
"traefik.ingress.kubernetes.io/service.sticky.cookie.path": "foobar",
},
expected: &ServiceConfig{
Service: &ServiceIng{
@ -122,6 +123,7 @@ func Test_parseServiceConfig(t *testing.T) {
Secure: true,
HTTPOnly: true,
SameSite: "none",
Path: String("foobar"),
},
},
ServersScheme: "protocol",
@ -138,7 +140,11 @@ func Test_parseServiceConfig(t *testing.T) {
},
expected: &ServiceConfig{
Service: &ServiceIng{
Sticky: &dynamic.Sticky{Cookie: &dynamic.Cookie{}},
Sticky: &dynamic.Sticky{
Cookie: &dynamic.Cookie{
Path: String("/"),
},
},
PassHostHeader: Bool(true),
},
},

View file

@ -24,6 +24,8 @@ var _ provider.Provider = (*Provider)(nil)
func Bool(v bool) *bool { return &v }
func String(v string) *string { return &v }
func TestLoadConfigurationFromIngresses(t *testing.T) {
testCases := []struct {
desc string
@ -126,6 +128,7 @@ func TestLoadConfigurationFromIngresses(t *testing.T) {
Name: "foobar",
Secure: true,
HTTPOnly: true,
Path: String("/"),
},
},
Servers: []dynamic.Server{

View file

@ -58,6 +58,7 @@ func Test_buildConfiguration(t *testing.T) {
"traefik/http/services/Service01/loadBalancer/sticky/cookie/name": "foobar",
"traefik/http/services/Service01/loadBalancer/sticky/cookie/secure": "true",
"traefik/http/services/Service01/loadBalancer/sticky/cookie/httpOnly": "true",
"traefik/http/services/Service01/loadBalancer/sticky/cookie/path": "foobar",
"traefik/http/services/Service01/loadBalancer/servers/0/url": "foobar",
"traefik/http/services/Service01/loadBalancer/servers/1/url": "foobar",
"traefik/http/services/Service02/mirroring/service": "foobar",
@ -70,6 +71,7 @@ func Test_buildConfiguration(t *testing.T) {
"traefik/http/services/Service03/weighted/sticky/cookie/name": "foobar",
"traefik/http/services/Service03/weighted/sticky/cookie/secure": "true",
"traefik/http/services/Service03/weighted/sticky/cookie/httpOnly": "true",
"traefik/http/services/Service03/weighted/sticky/cookie/path": "foobar",
"traefik/http/services/Service03/weighted/services/0/name": "foobar",
"traefik/http/services/Service03/weighted/services/0/weight": "42",
"traefik/http/services/Service03/weighted/services/1/name": "foobar",
@ -642,6 +644,7 @@ func Test_buildConfiguration(t *testing.T) {
Name: "foobar",
Secure: true,
HTTPOnly: true,
Path: func(v string) *string { return &v }("foobar"),
},
},
Servers: []dynamic.Server{
@ -708,6 +711,7 @@ func Test_buildConfiguration(t *testing.T) {
Name: "foobar",
Secure: true,
HTTPOnly: true,
Path: func(v string) *string { return &v }("foobar"),
},
},
},

View file

@ -26,6 +26,7 @@ type stickyCookie struct {
httpOnly bool
sameSite string
maxAge int
path string
}
func convertSameSite(sameSite string) http.SameSite {
@ -79,6 +80,10 @@ func New(sticky *dynamic.Sticky, wantHealthCheck bool) *Balancer {
httpOnly: sticky.Cookie.HTTPOnly,
sameSite: sticky.Cookie.SameSite,
maxAge: sticky.Cookie.MaxAge,
path: "/",
}
if sticky.Cookie.Path != nil {
balancer.stickyCookie.path = *sticky.Cookie.Path
}
}
@ -236,7 +241,7 @@ func (b *Balancer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
cookie := &http.Cookie{
Name: b.stickyCookie.name,
Value: hash(server.name),
Path: "/",
Path: b.stickyCookie.path,
HttpOnly: b.stickyCookie.httpOnly,
Secure: b.stickyCookie.secure,
SameSite: convertSameSite(b.stickyCookie.sameSite),

View file

@ -226,6 +226,7 @@ func TestSticky(t *testing.T) {
HTTPOnly: true,
SameSite: "none",
MaxAge: 42,
Path: func(v string) *string { return &v }("/foo"),
},
}, false)
@ -263,6 +264,7 @@ func TestSticky(t *testing.T) {
assert.True(t, recorder.cookies["test"].Secure)
assert.Equal(t, http.SameSiteNoneMode, recorder.cookies["test"].SameSite)
assert.Equal(t, 42, recorder.cookies["test"].MaxAge)
assert.Equal(t, "/foo", recorder.cookies["test"].Path)
}
func TestSticky_FallBack(t *testing.T) {