Add support for session-cookie-expires nginx annotation

This commit is contained in:
LBF38
2026-01-20 15:26:05 +01:00
committed by GitHub
parent 08b1336af0
commit 82c756006b
8 changed files with 21 additions and 3 deletions
@@ -288,6 +288,7 @@ The following annotations are organized by category for easier navigation.
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-domain" href="#opt-nginx-ingress-kubernetes-iosession-cookie-domain" title="#opt-nginx-ingress-kubernetes-iosession-cookie-domain">`nginx.ingress.kubernetes.io/session-cookie-domain`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-samesite" href="#opt-nginx-ingress-kubernetes-iosession-cookie-samesite" title="#opt-nginx-ingress-kubernetes-iosession-cookie-samesite">`nginx.ingress.kubernetes.io/session-cookie-samesite`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-max-age" href="#opt-nginx-ingress-kubernetes-iosession-cookie-max-age" title="#opt-nginx-ingress-kubernetes-iosession-cookie-max-age">`nginx.ingress.kubernetes.io/session-cookie-max-age`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-expires" href="#opt-nginx-ingress-kubernetes-iosession-cookie-expires" title="#opt-nginx-ingress-kubernetes-iosession-cookie-expires">`nginx.ingress.kubernetes.io/session-cookie-expires`</a> | |
### Load Balancing & Backend
@@ -416,7 +417,6 @@ The following annotations are organized by category for easier navigation.
| <a id="opt-nginx-ingress-kubernetes-ioserver-alias" href="#opt-nginx-ingress-kubernetes-ioserver-alias" title="#opt-nginx-ingress-kubernetes-ioserver-alias">`nginx.ingress.kubernetes.io/server-alias`</a> | |
| <a id="opt-nginx-ingress-kubernetes-ioserver-snippet" href="#opt-nginx-ingress-kubernetes-ioserver-snippet" title="#opt-nginx-ingress-kubernetes-ioserver-snippet">`nginx.ingress.kubernetes.io/server-snippet`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-conditional-samesite-none" href="#opt-nginx-ingress-kubernetes-iosession-cookie-conditional-samesite-none" title="#opt-nginx-ingress-kubernetes-iosession-cookie-conditional-samesite-none">`nginx.ingress.kubernetes.io/session-cookie-conditional-samesite-none`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-expires" href="#opt-nginx-ingress-kubernetes-iosession-cookie-expires" title="#opt-nginx-ingress-kubernetes-iosession-cookie-expires">`nginx.ingress.kubernetes.io/session-cookie-expires`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iosession-cookie-change-on-failure" href="#opt-nginx-ingress-kubernetes-iosession-cookie-change-on-failure" title="#opt-nginx-ingress-kubernetes-iosession-cookie-change-on-failure">`nginx.ingress.kubernetes.io/session-cookie-change-on-failure`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iossl-ciphers" href="#opt-nginx-ingress-kubernetes-iossl-ciphers" title="#opt-nginx-ingress-kubernetes-iossl-ciphers">`nginx.ingress.kubernetes.io/ssl-ciphers`</a> | |
| <a id="opt-nginx-ingress-kubernetes-iossl-prefer-server-ciphers" href="#opt-nginx-ingress-kubernetes-iossl-prefer-server-ciphers" title="#opt-nginx-ingress-kubernetes-iossl-prefer-server-ciphers">`nginx.ingress.kubernetes.io/ssl-prefer-server-ciphers`</a> | |
+4
View File
@@ -298,6 +298,10 @@ type Cookie struct {
// Domain defines the host to which the cookie will be sent.
// More info: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#domaindomain-value
Domain string `json:"domain,omitempty" toml:"domain,omitempty" yaml:"domain,omitempty"`
// Expires defines the number of seconds to add to the current time to calculate the expiration date of the cookie.
// This option is exposed only for the Ingress NGINX provider.
Expires int `json:"-" toml:"-" yaml:"-" label:"-" file:"-" kv:"-" export:"true"`
}
// SetDefaults set the default values for a Cookie.
@@ -33,6 +33,7 @@ type ingressConfig struct {
SessionCookieDomain *string `annotation:"nginx.ingress.kubernetes.io/session-cookie-domain"`
SessionCookieSameSite *string `annotation:"nginx.ingress.kubernetes.io/session-cookie-samesite"`
SessionCookieMaxAge *int `annotation:"nginx.ingress.kubernetes.io/session-cookie-max-age"`
SessionCookieExpires *int `annotation:"nginx.ingress.kubernetes.io/session-cookie-expires"`
ServiceUpstream *bool `annotation:"nginx.ingress.kubernetes.io/service-upstream"`
@@ -12,6 +12,7 @@ metadata:
nginx.ingress.kubernetes.io/session-cookie-domain: "foo.localhost"
nginx.ingress.kubernetes.io/session-cookie-samesite: "None"
nginx.ingress.kubernetes.io/session-cookie-max-age: "42"
nginx.ingress.kubernetes.io/session-cookie-expires: "42"
spec:
ingressClassName: nginx
@@ -555,6 +555,7 @@ func (p *Provider) buildService(namespace string, backend netv1.IngressBackend,
HTTPOnly: true, // Default value in Nginx.
SameSite: strings.ToLower(ptr.Deref(cfg.SessionCookieSameSite, "")),
MaxAge: ptr.Deref(cfg.SessionCookieMaxAge, 0),
Expires: ptr.Deref(cfg.SessionCookieExpires, 0),
Path: ptr.To(ptr.Deref(cfg.SessionCookiePath, "/")),
Domain: ptr.Deref(cfg.SessionCookieDomain, ""),
},
@@ -492,6 +492,7 @@ func TestLoadIngresses(t *testing.T) {
Domain: "foo.localhost",
HTTPOnly: true,
MaxAge: 42,
Expires: 42,
Path: ptr.To("/foobar"),
SameSite: "none",
Secure: true,
@@ -9,6 +9,7 @@ import (
"net/http"
"strconv"
"sync"
"time"
"github.com/traefik/traefik/v3/pkg/config/dynamic"
)
@@ -27,6 +28,7 @@ type stickyCookie struct {
httpOnly bool
sameSite http.SameSite
maxAge int
expires time.Time
path string
domain string
}
@@ -59,6 +61,9 @@ func NewSticky(cookieConfig dynamic.Cookie) *Sticky {
if cookieConfig.Path != nil {
cookie.path = *cookieConfig.Path
}
if cookieConfig.Expires > 0 {
cookie.expires = time.Now().Add(time.Duration(cookieConfig.Expires) * time.Second)
}
return &Sticky{
cookie: cookie,
@@ -137,6 +142,7 @@ func (s *Sticky) WriteStickyCookie(rw http.ResponseWriter, name string) error {
Secure: s.cookie.secure,
SameSite: s.cookie.sameSite,
MaxAge: s.cookie.maxAge,
Expires: s.cookie.expires,
}
http.SetCookie(rw, cookie)
@@ -4,6 +4,7 @@ import (
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -103,15 +104,17 @@ func TestSticky_StickyHandler(t *testing.T) {
}
func TestSticky_WriteStickyCookie(t *testing.T) {
sticky := NewSticky(dynamic.Cookie{
cookieConfig := dynamic.Cookie{
Name: "test",
Secure: true,
HTTPOnly: true,
SameSite: "none",
MaxAge: 42,
Expires: 10,
Path: pointer("/foo"),
Domain: "foo.com",
})
}
sticky := NewSticky(cookieConfig)
// Should return an error if the handler does not exist.
res := httptest.NewRecorder()
@@ -133,6 +136,7 @@ func TestSticky_WriteStickyCookie(t *testing.T) {
assert.True(t, cookie.HttpOnly)
assert.Equal(t, http.SameSiteNoneMode, cookie.SameSite)
assert.Equal(t, 42, cookie.MaxAge)
assert.WithinDuration(t, time.Now(), cookie.Expires, time.Duration(cookieConfig.Expires)*time.Second)
assert.Equal(t, "/foo", cookie.Path)
assert.Equal(t, "foo.com", cookie.Domain)
}