Configurable path for sticky cookies

This commit is contained in:
IIpragmaII 2024-11-06 16:04:04 +01:00 committed by GitHub
parent 552bd8f180
commit ec00c4aa42
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 530 additions and 26 deletions

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

@ -242,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.
@ -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

@ -242,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.

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

@ -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]

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

@ -242,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.
@ -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
}
@ -1515,7 +1520,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

@ -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

@ -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)
@ -4903,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

@ -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) {