sigs.k8s.io/gateway-api@v1.0.0/geps/gep-1619.md (about) 1 # GEP-1619: Session Persistence 2 3 * Issue: [#1619](https://github.com/kubernetes-sigs/gateway-api/issues/1619) 4 * Status: Provisional 5 6 (See definitions in [GEP Status][/contributing/gep#status].) 7 8 ## Graduation Criteria for Implementable Status 9 10 This GEP was accidentally merged as Provisional before the required approval 11 from 2 maintainers had been received. Before this graduates to implementable, 12 we need to get at least one of @robscott or @youngnick to also approve this GEP. 13 14 There are some open questions that will need to be answered before this can 15 graduate: 16 17 1. Should we leave room in this policy to add additional concepts in the future 18 such as Session Affinity? If so, how would we adjust the naming and overall 19 scope of this policy? 20 2. Should we leave room for configuring different forms of Session Persistence? 21 If so, what would that look like? 22 23 ## TLDR 24 25 This GEP initially proposes a definitions for session persistence, followed by the definition of an API spec for 26 configuring it. Additionally, it explores example scenarios of session persistence and examines the approaches that 27 implementations have taken to design APIs for session persistence. It intentionally refrains from defining an API for 28 session affinity, as this design is expected to be addressed within a separate GEP. 29 30 ## Goals 31 32 - Define session persistence and session affinity to establish a common language 33 - Identify differences in session persistence functionality between implementations 34 - Define an API for session persistence 35 - Establish anticipated outcomes for specific API configurations or scenarios 36 37 ## Non-Goals 38 39 - Define an API for session affinity 40 - Mandate a default session persistence or session affinity functionality for implementations 41 - Prescribe the precise manner (the "how") in which implementations should achieve session persistence or handle 42 specific scenarios 43 - Add API configuration for supporting backend initiated sessions 44 45 ## Introduction 46 47 ### Defining Session Persistence 48 49 Session persistence is when a client request is directed to the same backend server for the duration of a "session". It is achieved when a client directly provides information, such as a header, that a proxy uses as a reference to direct traffic to a specific server. Persistence is an exception to load balancing: a persistent client request bypasses the proxy's load balancing algorithm, going directly to a backend server it has previously established a session with. 50 51 Session persistence enables more efficient application workflows: 52 1. Better performance: Maintaining a single session allows a server to cache information about a client locally reducing the need for servers to exchange session data and overall storage needs. 53 2. Seamless client experience: Clients can reconnect to the same server without re-authenticating or re-entering their information. 54 55 Some of the concerns of session persistence are the duration and expiration of the session, security of the transaction stream, and storage of the context or state. 56 57 Session affinity, not to be confused with session persistence, uses an existing attribute of the request to consistently send to the same backend. Session affinity can be considered a weaker form of session persistence: it is not guaranteed to persist a connection to the same backend server if certain attributes of the request or the backends are changed. 58 59 ### Security and Privacy Implications 60 61 Session persistence can introduce security and privacy vulnerabilities if not properly implemented. These vulnerabilities can include: 62 63 1. Session hijacking: Attackers intercepting or predicting a valid session token to gain unauthorized access. 64 2. Session fixation: Attackers setting a client's session ID to a known value, which they can then use to hijack the session. 65 3. Session replay attacks: Attackers capturing and resending a client's message with a valid session ID. 66 4. Data leakage: Attackers can exploit sensitive session information cached on servers if not properly secured. 67 5. Denial of service attacks: Attackers can use up server resources by creating and maintaining large numbers of sessions. 68 69 To mitigate these security concerns, it is important to implement session persistence using secure practices, such as using strong session ID generation algorithms, implementing session timeouts, encrypting sensitive data, and monitoring server resources for unusual activity. 70 71 IP address reuse may also be a security or privacy concern when using session persistence or session affinity. If Kubernetes reuses an IP address of previously shutdown pod, the new pod may receive session persistent traffic meant for the old pod. 72 73 Session affinity introduces fewer security and privacy vulnerabilities since there are no session tokens to protect or exploit. 74 75 ### Achieving Session Persistence 76 77 Session persistence is achieved using attributes residing in the application layer. The following are mechanisms for achieving session persistence: 78 79 **1. Cookie-Based Session Persistence** 80 81 The most common mechanism is by using cookies (described by [RFC6265](https://www.rfc-editor.org/rfc/rfc6265)) with the set-cookie HTTP response header. A client will use the provided value in the set-cookie response header in a cookie request header in subsequent requests. Proxies can use this cookie header to maintain a persistent connection to a single backend server on behalf of the client. 82 83 **2. Header-Based Session Persistence** 84 85 Header-based stateful sessions are achieved by a backend or gateway providing an HTTP response header and the client using the same header in subsequent HTTP requests. Proxies can use this header to maintain a persistent connection to a single backend server on behalf of the client. 86 87 **3. URL-Encoded Session Persistence** 88 89 Session information can be also encoded into the request URL to establish a persistent session. The server rewrites the client's URL to encode the new session information automatically. The server or the gateway then decodes the session information from the URL to identify the session. 90 91 ### Session Persistence Initiation 92 93 For all implementations of session persistence, the initiation of the persistent session is possible from various 94 sources, including the gateway, intermediary gateway, backend, a sidecar in a backend, or any other infrastructure 95 component. 96 97 Let's consider a simple implementation comprised of gateways and backends. The following rules apply based on who initiates the session: 98 - If the gateway initiates the session, the backend will be presented with session attributes regardless if it enabled them. 99 - If the backend initiates the session, the gateway should allow this and not force persistent connections, unless 100 specifically configured to[^1]. The gateway may decode and alter the cookie established by the backend to achieve 101 session persistence. 102 103 It's important to note that we can have more complex implementations which involve traversing global load balancers, 104 regional load balancers, intermediary internal gateways, sidecars, or waypoints before reaching the backend. At any 105 point within this architecture, a persistent session can be initiated. See [Global Load Balancer Initiated Session Example](#global-load-balancer-initiated-session-example) 106 for an example of one of these alternative implementations. 107 108 In the next sections, we will take a closer look at the initiation of sessions in both the gateway and the backend. 109 Please note that in the next sections, we are examining the various scenarios in which a session can be initiated. We 110 are not prescribing specific implementations for session persistence. The intention is to understand the possibilities 111 and behaviors related to session initiation while the [API](#api) section will provide more details on specific 112 implementation details. 113 114 #### Gateway Initiated Session Example 115 116 To illustrate how a gateway can initiate a session, let's examine an implementation that uses cookies for persistence. 117 This represents the most straightforward scenario for utilizing cookies. When a request is made, the gateway includes 118 the `set-cookie` header in the final response, prompting the client to store the cookie. This cookie is subsequently 119 used in future requests, allowing the gateway to consistently choose the same upstream, establishing a persistent 120 session. 121 122 Here an example implementation of a gateway initiating a session through cookies: 123 ```mermaid 124 sequenceDiagram 125 actor C as Client 126 participant G as Gateway 127 participant B as Backend 128 C->>+G: Request Web Page 129 activate G 130 G->>+B: Request 131 B-->>-G: Response 132 G->>G: Add set-cookie header 133 G-->>-C: Response<br>[set-cookie] 134 Note right of G: [set-cookie] indicates a response<br> with a set-cookie header.<br>May include other set-cookie<br>headers from backend. 135 C->>C: Create Cookie(s)<br>from set-cookie header(s) 136 Note right of C: [cookie] indicates a request<br> with one or more cookies 137 C->>+G: Request Web Page<br>[cookie] 138 G->>G: Consistent lookup of<br>server using cookie value 139 G->>+B: Request<br>[cookie] 140 B-->>-G: Response 141 G-->>-C: Response 142 ``` 143 144 #### Backend Initiated Session Example 145 146 **Important**: While we took it into consideration, this GEP does not support configuring backend-initiated sessions. 147 This could potentially affect frameworks that initiate sessions in the backend. Implementing this feature is complicated 148 and requires careful design, making it suitable for exploration in a separate GEP. 149 150 Continuing with the cookie example, when dealing with backend-initiated sessions, the process becomes somewhat more 151 complex. For cookie-based session persistence, the gateway needs to store a value within a cookie containing a backend 152 identifier. This identifier can be then used as a reference to maintain a persistent session to a specific backend. 153 There are several approaches a gateway could use in this situation to achieve session persistence: 154 155 1. Insert an additional cookie 156 2. Modify the existing cookie's value 157 3. Prefix the existing cookie 158 159 Additionally, there are variations to each of these approaches, such as making new or updated cookies transparent to the 160 backend, either by remove an inserted cookie or reversing modifications of the cookie's value. 161 162 Alternatively, if the backend is not configured for session persistence, the gateway should refrain from modifying or 163 inserting a cookie. In this situation, the gateway should remain passive and simply forward the `set-cookie` header as 164 it is. 165 166 Refer to the [Session Initiation Guidelines](#session-initiation-guidelines) section of the API for implementation 167 guidance. 168 169 Here's an example implementation of a backend initiating a session and the gateway modifies the cookie's value: 170 ```mermaid 171 sequenceDiagram 172 actor C as Client 173 participant G as Gateway 174 participant B as Backend 175 C->>+G: Request Web Page 176 activate G 177 G->>+B: Request 178 B->>B: Add set-cookie<br>header 179 B-->>-G: Response<br>[set-cookie] 180 G->>G: Modify set-cookie<br>header per configuration 181 G-->>-C: Response<br>[set-cookie*] 182 Note right of G: [set-cookie] indicates a response<br> with a set-cookie header<br>[set-cookie*] indicates a response<br>with a MODIFIED set-cookie header 183 C->>C: Create Cookie<br>from set-cookie header 184 Note right of C: [cookie] indicates a request<br>or response with a cookie 185 C->>+G: Request Web Page<br>[cookie] 186 G->>G: Consistent lookup<br>of server using cookie value 187 G->>+B: Request<br>[cookie] 188 B-->>-G: Response 189 G-->>-C: Response 190 ``` 191 192 #### Global Load Balancer Initiated Session Example 193 194 In a more complex architecture example, a global load balancer may need to use cookies in order to maintain persistent 195 connections to a regional load balancer. The regional cluster load balancer initiates the session by issuing the 196 `set-cookie` header and subsequently uses the cookie to maintain persistent connections to a specific backend. The 197 global load balancer then adds or modifies a cookie in order to establish persistent connection to a regional cluster 198 load balancer. 199 200 Here an example implementation of a global load balancer and a regional load balancer creating sessions through cookies: 201 ```mermaid 202 sequenceDiagram 203 actor C as Client 204 participant G as Global<br>Load Balancer 205 participant R as Regional Cluster<br>Load Balancer 206 participant B as Backend 207 C->>+G: Request Web Page 208 G->>+R: Request 209 R->>+B: Request 210 B-->>-R: Response 211 R->>R: Initiates session by<br>adding set-cookie header 212 R-->>-G: Response<br>[set-cookie] 213 G->>G: Add or modify<br>set-cookie header 214 G-->>-C: Response<br>[set-cookie] 215 Note right of G: [set-cookie] indicates a response<br> with a set-cookie header.<br>May include other set-cookie<br>headers from backend or GLB. 216 C->>C: Create Cookie<br>from set-cookie header 217 Note right of C: [cookie] indicates a request<br> with one or more cookies 218 C->>+G: Request Web Page<br>[cookie] 219 G->>G: Consistent lookup of<br>regional cluster load balancer<br>using cookie value 220 G->>+R: Request<br>[cookie] 221 R->>R: Consistent lookup of backend<br>using cookie value 222 R->>+B: Request<br>[cookie] 223 B-->>-G: Response 224 G-->>-C: Response 225 ``` 226 227 ### When does an application require session persistence? 228 229 Enabling session persistence is a required configuration for applications intentionally designed by the application 230 developer to use it, as they will encounter failures or malfunctions when it's not enabled. However, it's worth noting 231 that certain applications may be designed to function both with and without session persistence. Regardless, the 232 importance of Gateway API supporting session persistence remains emphasized because it is frequently seen as a necessary 233 feature. 234 235 Conversely, apps that have not been designed or tested with session persistence in mind may misbehave when it is 236 enabled, primarily because of the impacts of load distribution on the app. Apps using session persistence must account 237 for aspects like load shedding, draining, and session migration as a part of their application design. 238 239 ### The Relationship of Session Persistence and Session Affinity 240 241 Though this GEP's intention is not to define a spec for session affinity, it is important to recognize and understand 242 its distinction with session persistence. While session persistence uses attributes in the application layer, session 243 affinity often uses, but is not limited to, attributes below the application layer. Session affinity doesn't require a 244 session identifier like session persistence (e.g. a cookie), but instead uses existing connection attributes to 245 establish a consistent hashing load balancing algorithm. It is important to note the session affinity doesn't guarantee 246 persistent connections to the same backend server. 247 248 Session affinity can be achieved by deterministic load balancing algorithms or a proxy feature that tracks IP-to-backend associations such as [HAProxy's stick tables](https://www.haproxy.com/blog/introduction-to-haproxy-stick-tables/) or [Cilium's session affinity](https://docs.cilium.io/en/v1.12/gettingstarted/kubeproxy-free/#id2). 249 250 We can also examine how session persistence and session affinity functionally work together, by framing the relationship into a two tiered logical decision made by the data plane: 251 1. If the request contains a session persistence identity (e.g. a cookie or header), then route it directly to the backend it has previously established a session with. 252 2. If no session persistence identity is present, load balance as per load balancing configuration, taking into account the session affinity configuration (e.g. by utilizing a hashing algorithm that is deterministic). 253 254 This tiered decision-based logic is consistent with the idea that session persistence is an exception to load balancing. Though there are different ways to frame this relationship, this design will influence the separation between persistence and affinity API design. 255 256 ### Implementations 257 In this section, we will describe how implementations achieve session persistence, along with a breakdown of related configuration options. Input from implementations is appreciated to complete this information. 258 259 In the following tables, we will example two types of APIs: 260 1. Dataplane APIs 261 2. Implementation APIs 262 263 Generally, the implementation API programs the dataplane API; however these two are not always clearly separated. The two types of APIs can use different API structures for configuring the same feature. Examining the dataplane APIs helps to remove the layer of API abstraction that implementations provide. Removing this layer avoids situations where implementations don’t fully implement all capabilities of a dataplane API or obfuscate certain configuration around session persistence. On the other hand, examining implementation APIs provides valuable data points in what implementations are interested in configuring. 264 265 | **Technology** | **Technology Type** | **Session Persistence Type** | **Configuration Options** | **Configuration Association (Global, Gateway, Route, or Backends)** | **Notes** | 266 |--- |--- |--- |--- |--- |--- | 267 | Acnodal EPIC | Implementation (Envoy) | N/A | Supports Gateway API Only* | N/A | *Acnodal Epic solely uses Gateway API; therefore, it doesn’t yet have a way to configure session persistence. [Acnodal EPIC Docs](https://www.epick8sgw.io/docs/) | 268 | Apache APISIX | Implementation (Nginx) | [Cookie-Based](https://apisix.apache.org/docs/apisix/admin-api/#upstream) | hash_on=[vars \| header \| cookie \| consumer]<br>key=cookie_name | [Upstream](https://apisix.apache.org/docs/apisix/admin-api/#upstream) (Route or Backends) | N/A | 269 | | Implementation (Nginx) | [Header-Based](https://apisix.apache.org/docs/apisix/terminology/upstream/#header) | hash_on=[vars \| header \| cookie \| consumer]<br>key=header_name | [Upstream](https://apisix.apache.org/docs/apisix/admin-api/#upstream) (Route or Backends) | N/A | 270 | Apache httpd | Web Server | [Cookie-Based / URL-Encoded](https://httpd.apache.org/docs/2.4/mod/mod_proxy_balancer.html) | Cookie Attributes | N/A | N/A | 271 | Cilium | Implementation / Dataplane | None | None | None | Cilium has no documented way of doing session persistence. [Cilium Docs](https://cilium.io/) | 272 | Contour | Implementation (Envoy) | [Cookie-Based](https://projectcontour.io/docs/1.24/config/api/#projectcontour.io/v1.CookieRewritePolicy) | Name=name<br>pathRewrite=path<br>domainRewrite=domain<br>secure<br>sameSite | [Route](https://projectcontour.io/docs/1.24/config/api/#projectcontour.io/v1.Route) and [Service](https://projectcontour.io/docs/1.24/config/api/#projectcontour.io/v1.Service) (Backends) | Envoy does not natively support cookie attribute rewriting nor adding attributes other than path and TTL, but rewriting and adding additional attributes is possible via Lua ([Contour design reference](https://github.com/projectcontour/contour/blob/main/design/cookie-rewrite-design.md), [Envoy Issue](https://github.com/envoyproxy/envoy/issues/15612)). | 273 | Emissary-Ingress | Implementation (Envoy) | [Cookie-Based](https://www.getambassador.io/docs/emissary/latest/topics/running/load-balancer#cookie) | Name=name<br>Path=path<br>TTL=duration | [Module or Mapping](https://www.getambassador.io/docs/emissary/latest/topics/running/load-balancer#cookie) (Global or Route) | N/A | 274 | | | [Header-Based](https://www.getambassador.io/docs/emissary/latest/topics/running/load-balancer#header) | Name=name | [Module or Mapping](https://www.getambassador.io/docs/emissary/latest/topics/running/load-balancer#cookie) (Global or Route) | N/A | 275 | Envoy | Dataplane | [Cookie-Based](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/http/stateful_session/cookie/v3/cookie.proto) | Name=name<br>Path=path<br>TTL=duration | [HttpConnectionManager](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto) (Route) | Envoy does not natively support cookie attribute rewriting nor adding attributes other than path and TTL, but rewriting and adding additional attributes is possible via Lua ([Contour design reference](https://github.com/projectcontour/contour/blob/main/design/cookie-rewrite-design.md), [Envoy Issue](https://github.com/envoyproxy/envoy/issues/15612)). | 276 | | | [Header-Based](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/http/stateful_session/header/v3/header.proto) | Name=name | [HttpConnectionManager](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto) (Route) | N/A | 277 | Envoy Gateway | Implementation (Envoy) | N/A | Supports Gateway API Only* | N/A | *Envoy Gateway solely uses Gateway API; therefore, it doesn’t yet have a way to configure session persistence. [Envoy Gateway Docs](https://gateway.envoyproxy.io/v0.3.0/index.html) | 278 | Flomesh Service Mesh | Implementation / Dataplane (Pipy) | ? | ? | ? | ? | 279 | Gloo Edge 2.0 | Implementation (Envoy) | [Cookie-Based](https://docs.solo.io/gloo-edge/latest/reference/api/envoy/api/v2/route/route.proto.sk/#cookie) | Name=name<br>Path=path<br>TTL=duration | [Route](https://docs.solo.io/gloo-edge/latest/reference/api/envoy/api/v2/route/route.proto.sk/#route) (Route) | N/A | 280 | | | [Header-Based](https://docs.solo.io/gloo-edge/latest/reference/api/envoy/api/v2/route/route.proto.sk/#hashpolicy) | Name=name | [Route](https://docs.solo.io/gloo-edge/latest/reference/api/envoy/api/v2/route/route.proto.sk/#route) (Route) | N/A | 281 | Google CloudRun | Implementation / Dataplane | [Cookie-Based](https://cloud.google.com/run/docs/configuring/session-affinity) | Enabled / Disabled | [Service](https://cloud.google.com/run/docs/configuring/session-affinity) (Backends) | Only allowed to turn off or on, no other configuration items | 282 | Google Kubernetes Engine | Implementation / Dataplane | [Cookie-Based](https://cloud.google.com/load-balancing/docs/backend-service#session_affinity) | GENERATED_COOKIE or HTTP_COOKIE=name<br>cookieTtlSec | [Backend Policy](https://cloud.google.com/kubernetes-engine/docs/how-to/configure-gateway-resources#session_affinity) (Backends) | Google Kubernetes Engine [lists](https://cloud.google.com/load-balancing/docs/backend-service#bs-session-affinity) the products that can do persistence/affinity mode. All persistence/affinity options are exclusive and can’t be used at the same time.<br>Note: Google Kubernetes Engine defines everything (persistence and affinity) as session affinity. | 283 | | | [Header-Based](https://cloud.google.com/load-balancing/docs/backend-service#header_field_affinity) | httpHeaderName=name | [Backend Policy](https://cloud.google.com/kubernetes-engine/docs/how-to/configure-gateway-resources#session_affinity) (Backends) | N/A | 284 | HAProxy | Dataplane | [Cookie-Based](https://docs.haproxy.org/2.6/configuration.html#4.2-cookie) | name=name<br>[rewrite \| insert \| prefix ]<br>indirect<br>nocache<br>postonly<br>preserve<br>httponly<br>secure<br>domain=domain<br>maxidle=idle<br>maxlife=life<br>dynamic<br>attr=value | [Default or Backends](https://docs.haproxy.org/2.6/configuration.html#4.2-cookie) (Global or Backends) | HAProxy allows for operational cookie strategy configuration (i.e. when/how HAProxy should inject cookies) | 285 | HAProxy Ingress | Implementation (HAProxy) | [Cookie-Based](https://haproxy-ingress.github.io/docs/configuration/keys/#affinity) | affinity (enable/disable)<br>cookie-key=key<br>session-cookie-domain=domain<br>session-cookie-dynamic=[true \| false]<br>session-cookie-keywords=keywords<br>session-cookie-name=name<br>session-cookie-preserve=[true \| false]<br>session-cookie-same-site=[true \| false]<br>session-cookie-shared=[true \| false]<br>session-cookie-strategy=strategy<br>session-cookie-value-strategy=value_strategy | [Backend](https://haproxy-ingress.github.io/docs/configuration/keys/#affinity) (Backends) | N/A | 286 | Hashicorp Consul | Implementation (Envoy) | N/A | Supports Gateway API Only* | N/A | *Hashicorp Consul solely uses Gateway API; therefore, it doesn’t yet have a way to configure session persistence. [Hashicorp Consul API Gateway Docs](https://developer.hashicorp.com/consul/docs/api-gateway) | 287 | Istio | Implementation (Envoy) | [Cookie-Based](https://istio.io/latest/docs/reference/config/networking/destination-rule/#LoadBalancerSettings-ConsistentHashLB-HTTPCookie) | Name=name<br>Path=path<br>TTL=duration | [ConsistentHashLB](https://istio.io/latest/docs/reference/config/networking/destination-rule/#LoadBalancerSettings-ConsistentHashLB) (Backends) | Istio also supports turning on cookie-based session persistence via the Pilot ENV variable [PILOT_PERSISTENT_SESSION_LABEL](https://istio.io/latest/docs/reference/commands/pilot-discovery/#envvars). | 288 | | Implementation (Envoy) | [Header-Based](https://istio.io/latest/docs/reference/config/networking/destination-rule/#LoadBalancerSettings-ConsistentHashLB) | Name=name | [ConsistentHashLB](https://istio.io/latest/docs/reference/config/networking/destination-rule/#LoadBalancerSettings-ConsistentHashLB) (Backends) | N/A | 289 | Java Servlet | Web Server | [Cookie-Based / URL-Encoded](https://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpSession.html) | invalidate()<br>setAttribute(String name, Object value)<br>setMaxInactiveInterval(int interval) | N/A | Java Servlets do not natively support proxy functions. | 290 | Kong | Implementation / Dataplane | [Cookie-Based](https://docs.konghq.com/hub/kong-inc/session/) | cookie_name=name<br>rolling_timeout=timeout<br>absolute_timeout=timeout<br>idling_timeout=timeout<br>cookie_path=path<br>cookie_domain=domain<br>cookie_same_site=[Strict \| Lax \| None \| off]<br>cookie_http_only<br>cookie_secure=[true \| false]<br>stale_ttl=duration<br>cookie_persistent=[true \| false]<br>storage=storage_type | [Route, Service, Global](https://docs.konghq.com/hub/kong-inc/session/) (Route or Backends or Global) | N/A | 291 | | | [Header-Based](https://docs.konghq.com/gateway/latest/how-kong-works/load-balancing/#balancing-algorithms) | name | [Upstreams](https://docs.konghq.com/gateway/3.2.x/admin-api/#add-upstream) (Backends) | N/A | 292 | Kuma | Implementation (Envoy) | None | None | None | Kuma has no documentation on how it supports session persistence or cookies. [Kuma Docs](https://kuma.io/docs/2.1.x/) | 293 | Nginx | Dataplane | [Cookie-Based (Nginx Plus Only)](https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/#enabling-session-persistence) | Name=name<br>Expires=time<br>Domain=domain<br>HttpOnly<br>SameSite = [strict \| lax \| none \| $variable]<br>Secure<br>path=path | [Upstream](https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/#enabling-session-persistence) (Backends) | See also [Sticky Cookie](https://nginx.org/en/docs/http/ngx_http_upstream_module.html?&_ga=2.184452070.1306763907.1680031702-1761609832.1671225057#sticky_cookie) | 294 | NGINX Gateway Fabric | Implementation (Nginx) | N/A | Supports Gateway API Only* | N/A | *NGINX Gateway Fabric solely uses Gateway API; therefore, it doesn’t yet have a way to configure session persistence. [NGINX Gateway Fabric Docs](https://github.com/nginxinc/nginx-gateway-fabric) | 295 | Traefik | Implementation / Dataplane | [Cookie-Based](https://doc.traefik.io/traefik/routing/services/#sticky-sessions) | name=name<br>secure<br>httpOnly<br>sameSite=[none \| lax \| strict ] | [Services](https://doc.traefik.io/traefik/routing/services/#sticky-sessions) (Backends) | N/A | 296 297 ### Sessions in Java 298 299 Java application servers such as Tomcat and Jetty, were the first to standardize the API around cookies and sessions. 300 These Java applications introduced the “jsessionid” cookie and session IDs encoded in URL parameters as well as more 301 advanced features such as session migration, replication, and on demand session activation. It’s important for Gateway 302 API to examine cookie use cases and history from Java APIs to ensure the API is designed appropriately. 303 304 ### Session Affinity in K8S Services 305 306 Kubernetes provides an API that allows you to enable [session affinity](https://kubernetes.io/docs/reference/networking/virtual-ips/#session-affinity) 307 on service objects. It ensures consistent sessions by utilizing the client's IP address and also offers the option to 308 set a timeout for the maximum session duration. Implementations of Gateway API, such as service mesh use cases, may use 309 the service IP directly. In these cases where both Kubernetes service session affinity and Gateway API session 310 persistence are both enabled, the route must be rejected, and a status should be set describing the incompatibility of 311 these two configurations. 312 313 ## API 314 315 In this section, we will explore the questions and design elements associated with a session persistence API. 316 317 ### GO 318 319 ```go 320 // SessionPersistencePolicy provides a way to define session persistence rules 321 // for a service or route. 322 // 323 // Support: Core 324 type SessionPersistencePolicy struct { 325 metav1.TypeMeta `json:",inline"` 326 metav1.ObjectMeta `json:"metadata,omitempty"` 327 328 // Spec defines the desired state of SessionPersistencePolicy. 329 Spec SessionPersistencePolicySpec `json:"spec"` 330 331 // Status defines the current state of SessionPersistencePolicy. 332 Status SessionPersistencePolicyStatus `json:"status,omitempty"` 333 } 334 335 // SessionPersistencePolicySpec defines the desired state of 336 // SessionPersistencePolicy. 337 // Note: there is no Override or Default policy configuration. 338 type SessionPersistencePolicySpec struct { 339 // TargetRef identifies an API object to apply policy to. 340 // The TargetRef may be a Service, HTTPRoute, GRPCRoute, 341 // or a HTTPRouteRule or GRPCRouteRule section. 342 // At least one of these targets must be supported for 343 // core-level compliance. 344 // 345 TargetRef gatewayv1a2.PolicyTargetReference `json:"targetRef"` 346 347 // AbsoluteTimeoutSeconds defines the absolute timeout of the 348 // persistent session measured in seconds. Once 349 // AbsoluteTimeoutSeconds has elapsed, the session becomes invalid. 350 // 351 // Support: Core 352 // 353 // +optional 354 AbsoluteTimeoutSeconds int64 `json:"absoluteTimeoutSeconds,omitempty"` 355 356 // IdleTimeoutSeconds defines the idle timeout of the 357 // persistent session measured in seconds. Once the session 358 // has been idle for more than specified IdleTimeoutSeconds 359 // duration, the session becomes invalid. 360 // 361 // Support: Core 362 // 363 // +optional 364 IdleTimeoutSeconds int64 `json:"idleTimeoutSeconds,omitempty"` 365 366 // SessionName defines the name of the persistent session token 367 // (e.g. a cookie name). 368 // 369 // Support: Extended 370 // 371 // +optional 372 // +kubebuilder:validation:MaxLength=4096 373 SessionName String `json:"sessionName,omitempty"` 374 } 375 376 // SessionPersistencePolicyStatus defines the observed state of SessionPersistencePolicy. 377 type SessionPersistencePolicyStatus struct { 378 // Conditions describe the current conditions of the SessionPersistencePolicy. 379 // 380 // Implementations should prefer to express SessionPersistencePolicy 381 // conditions using the `SessionPersistencePolicyConditionType` and 382 // `SessionPersistencePolicyConditionReason` constants so that 383 // operators and tools can converge on a common vocabulary to 384 // describe SessionPersistencePolicy state. 385 // Known condition types are: 386 // 387 // * “Accepted” 388 // 389 // +optional 390 // +listType=map 391 // +listMapKey=type 392 // +kubebuilder:validation:MaxItems=8 393 // +kubebuilder:default={type: "Accepted", status: "Unknown", reason:"Pending", message:"Waiting for validation", lastTransitionTime: "1970-01-01T00:00:00Z"} 394 Conditions []metav1.Condition `json:"conditions,omitempty"` 395 } 396 397 // SessionPersistencePolicyConditionType is the type of condition used 398 // as a signal by SessionPersistencePolicy. This type should be used with 399 // the SessionPersistencePolicy.Conditions field. 400 type SessionPersistencePolicyConditionType string 401 402 // SessionPersistencePolicyConditionReason is a reason that explains why a 403 // particular SessionPersistencePolicyConditionType was generated. This reason 404 // should be used with the SessionPersistencePolicy.Conditions field. 405 type SessionPersistencePolicyConditionReason string 406 407 const ( 408 // This condition indicates that the SessionPersistencePolicyStatus has been 409 // accepted as valid. 410 // Possible reason for this condition to be True is: 411 // 412 // * “Accepted” 413 // 414 // Possible reasons for this condition to be False are: 415 // 416 // * “Invalid” 417 // * “Pending” 418 SessionPersistencePolicyConditionAccepted SessionPersistencePolicyConditionType = “Accepted” 419 420 // This reason is used with the “Accepted” condition when the condition is true. 421 SessionPersistencePolicyReasonAccepted SessionPersistencePolicyConditionReason = “Valid” 422 423 // This reason is used with the “Accepted” condition when the SessionPersistencePolicy is invalid, e.g. crossing namespace boundaries. 424 SessionPersistencePolicyReasonInvalid SessionPersistencePolicyConditionReason = “Invalid” 425 426 // This reason is used with the “Accepted” condition when the SessionPersistencePolicy is pending validation. 427 SessionPersistencePolicyReasonPending SessionPersistencePolicyConditionReason = “Pending” 428 ) 429 ``` 430 431 ### API Granularity 432 433 The purpose of this session persistence API spec is to enable developers to specify that a specific backend expects a 434 persistent session. However, it intentionally avoids specifying low-level details or configurations related to the 435 session persistence implementation, such as cookie attributes. This decision is because the Gateway API supports various 436 infrastructure types, and some implementations that already provide session persistence may not be able to adhere to a 437 low-level API. 438 439 For instance, platforms using global load balancers to maintain persistent sessions between regional load balancers, or 440 Tomcat servlets generating distinct cookies per server. In such scenarios, it is important that this GEP does not 441 obstruct the existing use of cookies while enabling session persistence. Enabling particular low-level API 442 configurations, like allowing customization of the cookie name, could prevent certain implementations from conforming to 443 the spec. In other words, opting for a higher-level API provides better interoperability among our implementations. 444 445 ### Target Persona 446 447 Referring to the [Gateway API Security Model](https://gateway-api.sigs.k8s.io/concepts/security-model/#roles-and-personas), 448 the target kubernetes role/persona for session persistence are application developers, as mentioned in the [When does an application require session persistence?](#when-does-an-application-require-session-persistence) 449 section. It is the responsibility of the application developers to adjust the persistence configuration to ensure the 450 functionality of their applications. 451 452 ### Prior Art 453 454 Referring to our [Implementations](#Implementations) table on session persistence, the majority of Gateway API 455 implementations designed session persistence in their APIs to be attached to a service or backends. This should be 456 considered cautiously, as making associations to Gateway API's notion of Gateway, Route, and Service to other 457 implementation's objects is hard to directly translate. The idea of a route in Gateway API is often not the same as a 458 route in any given implementation. 459 460 ### Metaresource Policy Design 461 462 In order to apply session persistence configuration to both a service and a route, we will implement it as a 463 metaresource policy, as outlined in [Policy Attachment](https://gateway-api.sigs.k8s.io/reference/policy-attachment/#direct-policy-attachment). 464 The metaresource is named `SessionPersistencePolicy` and is only responsible for configuring session persistence for 465 services or routes. It is defined as a [Direct Policy Attachment](https://gateway-api.sigs.k8s.io/v1alpha2/reference/policy-attachment/#direct-policy-attachment) 466 without defaults or overrides, applied to the targeted service, HTTPRoute, or GRPCRoute. 467 468 Attaching the `SessionPersistencePolicy` metaresource to a service will be a core support level feature, while attaching 469 it to a route will be considered extended. Implementations must support services for conformance, while routes are 470 considered optional. This distinction arises because most existing implementations primarily support attaching to a 471 service, while attaching to a route is less common and involves greater complexities (see [API Attachment Points](#api-attachment-points) 472 for more details). 473 474 ### API Attachment Points 475 476 The `SessionPersistencePolicy` metaresource can target a service, route, and a route rule section (e.g. [HTTPRouteRule](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io%2fv1beta1.HTTPRouteRule)). 477 The core functionality of attaching it to any of these is generally identical. The distinction lies in where the 478 configuration gets propagated: when attached to a route or a route rule, it can define session persistence for multiple 479 services, whereas attaching it to a service defines it for a single service. Enabling session persistence doesn't 480 require configuration on the route, route rule, and service; configuring it on any one is sufficient. 481 482 Given that certain implementations will only support attaching to services, and considering that some implementations 483 might want to solely support attachment to routes, implementations must provide support for at least one of the options 484 (route, route rule, or service) to be compliant with this GEP. 485 486 Attaching `SessionPersistencePolicy` to a route ensures session persistence for all possible paths the route can take. 487 Conversely, attaching to a route rule section provides session persistence exclusively for that route rule. Without the 488 capability to target a specific rule section within a route, users might be required to decompose their route into 489 multiple routes to satisfy different session persistence requirements for each individual route path. 490 491 Edge cases will arise when providing supporting services, routes, and the route rule section. For guidance on addressing 492 conflicting attachments, please consult the [Expected API Behavior](#expected-api-behavior) section, which outlines API 493 use cases. 494 495 To learn more about the process of attaching to services, routes, and the route rule section, please refer to 496 [GEP-713](/geps/gep-713). 497 498 ### Traffic Splitting 499 500 In scenarios involving traffic splitting, session persistence impacts load balancing done after routing, regardless if 501 it is attached to a service or a route. When a persistent session is established and traffic splitting is configured 502 across services, the persistence to a single backend should be maintained across services. Consequently, a persistent 503 session takes precedence over traffic split weights when selecting a backend after route matching. It's important to 504 note that session persistence does not impact the process of route matching. 505 506 When using multiple backends in traffic splitting, all backend services should have session persistence enabled. 507 Nonetheless, implementations should also support traffic splitting scenarios in which one service has persistence 508 enabled while the other does not. This support is necessary, particularly in scenarios where users are transitioning 509 to or from an implementation version designed with or without persistence. 510 511 See [Expected API Behavior](#expected-api-behavior) for more use cases on traffic splitting. 512 513 ### Cookie Attributes 514 515 While the API is intended to be generic, as described in [API Granularity](#api-granularity), a majority of 516 implementations will employ session persistence through cookies. Therefore, let's explore the possibilities of cookie 517 configuration for these APIs. 518 519 A cookie is composed of various attributes, each represented as key=value pairs. While some attributes may have optional 520 values, the cookie name attribute is the only mandatory one, and the rest are considered optional. 521 522 The cookie attributes defined by [RFC6265](https://www.rfc-editor.org/rfc/rfc6265#section-5.2) are: 523 - Name=_value_ 524 - Expires=_date_ 525 - Max-Age=_number_ 526 - Domain=_domain_ 527 - Path=_path-value_ 528 - Secure 529 - HttpOnly 530 531 Other cookie attributes not defined by RFC6265, but are captured in draft RFCs and could be considered de facto 532 standards due to wide acceptance are: 533 - SameSite=[Strict|Lax|None] 534 - Partitioned 535 536 Unless a `SessionPersistencePolicy` API field can be satisfied through a manipulating a cookie attribute, the attributes 537 of the cookies are considered as opaque values in this spec and are to be determined by the individual implementations. 538 Let's discuss some of these cookie attributes in more detail. 539 540 #### Name 541 542 The `Name` cookie attribute can be configured via the `SessionName` field on `SessionPersistencePolicy`. However, this 543 field is considered extended support level. This is because some implementations, such as ones supporting global load 544 balancers, don't have the capability to configure the cookie name. 545 546 #### TTL 547 548 The `TTL` cookie attribute may be influenced by the `AbsoluteTimeoutSeconds` field on `SessionPersistencePolicy`. 549 However, it's important to understand that `AbsoluteTimeoutSeconds` represents the duration of the entire session, not 550 just the cookie duration. Conversely, the cookie's `TTL` attribute does not have to be configured in order to implement 551 `AbsoluteTimeoutSeconds`. 552 553 #### Path 554 555 The cookie's `Path` attribute defines the URL path that must exist in order for the client to send the `cookie` header. 556 Whether attaching session persistence to an xRoute or a service, it's important to consider the relationship the cookie 557 `Path` attribute has with the route path. 558 559 When the `SessionPersistencePolicy` policy is attached to an xRoute, the implementor should interpret the path as 560 configured on the xRoute. To interpret the `Path` attribute from an xRoute, implementors should take note of the 561 following: 562 563 1. For an xRoute that matches all paths, the `Path` should be set to `/`. 564 2. For an xRoute that has multiple paths, the `Path` should be interpreted based on the route path that was matched. 565 3. For an xRoute using a path that is a regex, the `Path` should be set to the longest non-regex prefix (.e.g. if the 566 path is /p1/p2/*/p3 and the request path was /p1/p2/foo/p3, then the cookie path would be /p1/p2). 567 568 It is also important to note that this design makes persistent session unique per route path. For instance, if two 569 distinct routes, one with path prefix `/foo` and the other with `/bar`, both target the same service, the persistent 570 session won't be shared between these two paths. 571 572 Conversely, if the `SessionPersistencePolicy` policy is attached to a service, the `Path` attribute should be left 573 unset. This is because multiple routes can target a single service. If the `Path` cookie attribute is configured in this 574 scenario, it could result in problems due to the possibility of different paths being taken for the same cookie. 575 Implementations should also handle the case where client is a browser making requests to multiple persistent services 576 from the same page. 577 578 #### Secure, HttpOnly, SameSite 579 580 The `Secure`, `HttpOnly`, and `SameSite` cookie attributes are security-related. The API implementers should follow the 581 security-by-default principle and configure these attributes accordingly. This means enabling `Secure` and `HttpOnly`, 582 and setting `SameSite` to `Strict`. However, in certain implementation use cases such as service mesh, secure values 583 might not function as expected. In such cases, it's acceptable to make appropriate adjustments. 584 585 ### Session Persistence API with GAMMA 586 587 The object of the [GAMMA (Gateway API for Mesh Management and Administration)](https://gateway-api.sigs.k8s.io/contributing/gamma/) 588 initiative is to provide support for service mesh and mesh-adjacent use-cases with Gateway API. GAMMA is focused on 589 defining how Gateway API could also be used for inter-service or [east/west](https://gateway-api.sigs.k8s.io/concepts/glossary/#eastwest-traffic) 590 traffic within the same cluster. 591 592 Given that service meshes commonly have session persistence requirements, this API design should take into consideration 593 session persistence needs in GAMMA and service mesh scenarios. 594 595 ### Session Initiation Guidelines 596 597 As illustrated in the examples provided in [Session Persistence Initiation](#session-persistence-initiation), 598 implementations must consider how to manage sessions initiated by other components. As mentioned in [Backend Initiated Session Example](#backend-initiated-session-example), 599 this GEP does not support configuring backend-initiated persistent sessions. We leave the decision of handling existing 600 sessions with each specific implementation. In the case of cookie-based session persistence, an implementation has the 601 freedom to either rewrite the cookie or insert an additional cookie, or to do nothing (resulting in the lack of a 602 persistent session). In general, inserting an additional cookie is a generally safe option, but it's important for 603 implementations to exercise their own discretion. However, regardless of the implementation's design choice, the 604 implementation must be able to handle multiple cookies. 605 606 ### Expected API Behavior 607 608 Implementing session persistence is complex and involves many edge cases. In this section, we will outline API 609 configuration scenarios (use cases) and how implementations should handle them. 610 611 #### Attaching Session Persistence to both Service And Route 612 613 In a situation which: 614 - `ServiceA` with `SessionPersistencePolicy` attached 615 - `RouteX` with `SessionPersistencePolicy` attached and backend `ServiceA` 616 617 The `SessionPersistencePolicy` policy attached to `RouteX` should take precedence. Since routes effectively group 618 services, the policy attached to xRoutes operates at a higher-level and should override policies applied to individual 619 services. 620 621 ```mermaid 622 graph TB 623 RouteX ----> ServiceA((ServiceA)) 624 SessionPersistencePolicyServiceA[SessionPersistence] -.-> ServiceA 625 SessionPersistencePolicyRouteA[SessionPersistence] -.Precedence.-> RouteX 626 linkStyle 2 stroke:red; 627 ``` 628 629 #### Two Routes Share Backends with Session Persistence Applied only on one Route 630 631 In the situation in which: 632 - `ServiceA` with`SessionPersistencePolicy` attached 633 - `ServiceB` with no session persistence 634 - `RouteX` with no session persistence backends `ServiceA` and `ServiceB` 635 636 At this point, traffic through `RouteX` to `ServiceB` doesn't use session persistence. 637 638 A new route is added: 639 - `RouteY` with `SessionPersistencePolicy` attached 640 641 Even though it's not explicitly configured, traffic flowing through `RouteX` to `ServiceB` should utilize session 642 persistence. This behavior occurs because `ServiceB` has session persistence configured via `RouteY`. 643 644 ```mermaid 645 graph TB 646 RouteX ----> ServiceA((ServiceA)) 647 RouteX --Persistence--> ServiceB 648 RouteY ----> ServiceA 649 RouteY ----> ServiceB((ServiceB)) 650 SessionPersistencePolicyServiceA[SessionPersistence] -.-> ServiceA 651 SessionPersistencePolicyRouteB[SessionPersistence] -.-> RouteY 652 linkStyle 1 stroke:red; 653 ``` 654 655 #### Traffic Splitting 656 657 Consider the scenario where a route is traffic splitting between two backends, and additionally, a 658 `SessionPersistencePolicy` is attached to the route: 659 ```yaml 660 kind: HTTPRoute 661 metadata: 662 name: split-route 663 spec: 664 rules: 665 - backendRefs: 666 - name: servicev1 667 weight: 50 668 - name: servicev2 669 weight: 50 670 --- 671 kind: SessionPersistencePolicy 672 metadata: 673 name: spp-split-route 674 spec: 675 targetRef: 676 kind: HTTPRoute 677 name: split-route 678 type: HTTPCookie 679 ``` 680 681 When persistent sessions are established, the persistence to a single backend should override the traffic splitting 682 configuration. 683 684 #### Traffic Splitting with two Backends and one with Weight 0 685 686 Consider the scenario where a route has two path matches, but one of those paths involves traffic splitting with a 687 backendRef that has a weight of 0, and additionally, a `SessionPersistencePolicy` is attached to the route: 688 ```yaml 689 kind: HTTPRoute 690 metadata: 691 name: split-route 692 spec: 693 rules: 694 - matches: 695 - path: 696 value: /a 697 backendRefs: 698 - name: servicev1 699 - matches: 700 - path: 701 value: /b 702 backendRefs: 703 - name: servicev1 704 weight: 0 705 - name: servicev2 706 weight: 100 707 --- 708 kind: SessionPersistencePolicy 709 metadata: 710 name: spp-split-route 711 spec: 712 targetRef: 713 kind: HTTPRoute 714 name: split-route 715 type: HTTPCookie 716 ``` 717 718 A potentially unexpected situation occurs when: 719 1. Curl to `/a` which establishes a persistent session with `servicev1` 720 2. Curl to `/b` routes to `servicev1` due to route persistence despite `weight: 0` configuration 721 722 In this scenario, implementations should give precedence to session persistence, regardless of the `weight` 723 configuration. 724 725 #### A Service's Selector is Dynamically Updated 726 727 In Kubernetes, it's possible to modify the [selector](https://kubernetes.io/docs/concepts/services-networking/service/#services-in-kubernetes) 728 of a service after the gateway has established persistent sessions with it. 729 730 ```yaml 731 kind: Service 732 metadata: 733 name: my-service 734 spec: 735 selector: 736 app.kubernetes.io/name: MyApp # Service selector can change 737 ``` 738 739 The expected behavior is that the gateway will retain existing persistent sessions, even if the pod is no longer 740 selected, and establish new persistent sessions after a selector update. This use case is uncommon and may not be 741 supported by some implementations due to their current designs. 742 743 ### Open Questions 744 745 - What happens when session persistence is broken because the backend is not up or healthy? If that's an error case, how should that be handled? Should the API dictate the http error code? Or should the API dictate fall back behavior? 746 - What happens when session persistence causes traffic splitting scenarios to overload a backend? 747 - Should we add status somewhere when a user gets in to a "risky" configuration with session persistence? 748 - Should there be an API configuration field that specifies how already established sessions are handled? 749 750 ## TODO 751 The following are items that we intend to resolve before we consider this GEP implementable: 752 753 - We need to identify and document requirements regarding session draining and migration. How do implementations drain established sessions during backend upgrades without disruption? 754 - Do we need a "session draining timeout" as documented by [A55: xDS-Based Stateful Session Affinity for Proxyless gRPC](https://github.com/grpc/proposal/blob/master/A55-xds-stateful-session-affinity.md#background) 755 defined in this API? 756 - We need to document sessions with Java in greater detail. Java standardized the API and behavior of session persistence long ago and would be worth examining. 757 - We need to add a small section on compliance regarding the browser and client relationship. 758 - We need to finish enumerating all the edge cases in [Expected API Behavior](#expected-api-behavior) and identify 759 potential scenarios where session persistence could break so an implementation can implement session persistence in a 760 predicable way. 761 762 ## Alternatives 763 764 ### Alternate Session Persistence API 765 766 Alternatively, the API for Session Persistence could define a loosely-typed list of attributes instead of strongly-typed 767 attribute fields. This approach offers a more flexible specification, particularly when new attributes need to be 768 introduced. However, loosely-typed lists may not be as user-friendly due to the lack of validation. 769 770 ```go 771 // HttpCookie defines a cookie to achieve session persistence. 772 // 773 // Support: Core 774 type HttpCookie struct { 775 // Name defines the cookie's name. 776 // 777 // Support: Core 778 // 779 // +kubebuilder:validation:MaxLength=4096 780 Name String `json:"name,omitempty"` 781 782 // CookieAttributes defines the cookie's attributes. 783 // 784 // Support: Core 785 // +optional 786 CookieAttributes []CookieAttribute `json:cookieAttributes` 787 } 788 789 // CookieAttribute defines the cookie's attributes. 790 type CookieAttribute map[string][]string 791 ) 792 ``` 793 794 The API could also be a mix of individual fields and listed attributes. More specifically, we could separate the key 795 attributes with no value into a list. This approach is taken by [Haproxy Ingress](https://haproxy-ingress.github.io/docs/configuration/keys/#affinity) 796 with their `session-cookie-keywords` field. This provides flexibility for simple boolean-typed attributes, while 797 validating attributes that have values. However, this approach may be confusing to users as uses two different API 798 patterns for cookie attributes. 799 800 ```go 801 // HttpCookie defines a cookie to achieve session persistence. 802 // 803 // Support: Core 804 type HttpCookie struct { 805 // Name defines the cookie's name. 806 // 807 // Support: Core 808 // 809 // +kubebuilder:validation:MaxLength=4096 810 Name String `json:"name,omitempty"` 811 812 // SameSite defines the cookie's SameSite attribute. 813 // 814 // Support: Extended 815 // 816 // +optional 817 // +kubebuilder:validation:Enum=Strict;Lax;None 818 SameSite SameSiteType `json:"sameSite,omitempty"` 819 820 // Domain defines the cookie's Domain attribute. 821 // 822 // Support: Extended 823 // 824 // +optional 825 // +kubebuilder:validation:MaxLength=4096 826 Domain String `json:"domain,omitempty"` 827 828 // CookieKeywords defines the cookie's attributes that have no value. 829 // 830 // Support: Extended 831 // +optional 832 CookieKeywords []CookieKeyword `json:cookieKeywords` 833 } 834 835 // CookieKeyword defines the cookie's attributes that have no value. 836 type CookieKeyword string 837 838 const ( 839 // CookieKeywordsHttpOnly specifies the HttpOnly cookie attribute. 840 CookieKeywordsHttpOnly HttpOnlyMode = "HttpOnly" 841 // CookieKeywordsSecure specifies the Secure cookie attribute. 842 CookieKeywordsSecure HttpOnlyMode = "Secure" 843 ) 844 ``` 845 846 Taking a different approach, this GEP could design a generic approach to configuring load balancing policy. Instead of 847 only having a metaresource specifically for session persistence, a metaresource called `LoadBalancerPolicy` of which 848 includes a field for session persistence along with other load balancer related configuration. It's important to note 849 that persistent session takes priority over balance algorithm. 850 851 The `LoadBalancerPolicy` design provides tighter coupling with other load balancing configuration which help reduce CRD 852 proliferation, but may limit API flexibility as it forces coupling between concepts that may not be appropriate for 853 current and future implementations. 854 855 ```go 856 // LoadBalancerPolicy provides a way to define load balancing rules 857 // for a service. 858 // 859 // Support: Core 860 type LoadBalancerPolicy struct { 861 metav1.TypeMeta `json:",inline"` 862 metav1.ObjectMeta `json:"metadata,omitempty"` 863 864 // Spec defines the desired state of LoadBalancerPolicy. 865 Spec LoadBalancerPolicySpec `json:"spec"` 866 867 // Status defines the current state of LoadBalancerPolicy. 868 Status LoadBalancerPolicyStatus `json:"status,omitempty"` 869 } 870 871 // LoadBalancerPolicySpec defines the desired state of 872 // LoadBalancerPolicy. 873 // Note: there is no Override or Default policy configuration. 874 type LoadBalancerPolicySpec struct { 875 // TargetRef identifies an API object to apply policy to. 876 // Services are the only valid API target references. 877 TargetRef gatewayv1a2.PolicyTargetReference `json:"targetRef"` 878 879 // SessionPersistence defines and configures session persistence. 880 SessionPersistence *SessionPersistence `json:"sessionPersistence"` 881 882 // BalanceAlgorithm defines and configures the load balancer 883 // balancing algorithm. 884 BalanceAlgorithm *BalanceAlgorithm `json:"balanceAlgorithm"` 885 } 886 887 // SessionPersistence defines and configures session persistence. 888 // 889 // Support: Core 890 type SessionPersistence struct { 891 // HttpCookie defines and configures a cookie to achieve 892 // session persistence. 893 // 894 // Support: Core 895 HttpCookie *HttpCookie `json:"httpCookie"` 896 } 897 ``` 898 899 ### Alternate Naming 900 901 This GEP describes session persistence and session affinity as the idea of strong and weak connection persistence respectively. Other technologies use different names or define persistence and affinity differently: 902 903 - Envoy defines [stateful sessions](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/http/stateful_session/cookie/v3/cookie.proto) as what we've defined as session persistence 904 - Google Cloud defines [session affinity](https://cloud.google.com/run/docs/configuring/session-affinity) as what we've defined as session persistence 905 - Nginx defines [session persistence](https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/#enabling-session-persistence) as what we've defined as both session persistence and affinity 906 - Traefik defines [sticky sessions](https://doc.traefik.io/traefik/routing/services/#sticky-sessions) as what we've defined as session persistence 907 - Apache httpd defines [sticky sessions or stickiness](https://httpd.apache.org/docs/2.4/mod/mod_proxy_balancer.html) as what we've defined as session persistence 908 - Kubernetes defines [session affinity](https://kubernetes.io/docs/reference/networking/virtual-ips/#session-affinity) based on client IP hashing (same as our session affinity) 909 910 Though session persistence is a ubiquitous name, session affinity is more inconsistently used. An alternate decision could be made to use a different name for session affinity based on the prevalence of other naming conventions. 911 912 ## References 913 914 - [LBPolicy](https://static.sched.com/hosted_files/kccnceu2023/c4/Autoscaling%20Elastic%20Kubernetes%20Infrastructure%20for%20Stateful%20Applications%20using%20Proxyless%20gRPC%20and%20Istio.pdf#page=25) (proposed extension for session persistence API) 915 - [gRPC Stateful Session Affinity Proposal](https://github.com/grpc/proposal/blob/master/A55-xds-stateful-session-affinity.md) (info on session draining and session persistence in gRPC) 916 - [Kube-Proxy Session Affinity](https://kubernetes.io/docs/reference/networking/virtual-ips/#session-affinity) 917 - [GEP-713: Metaresources and PolicyAttachment](/geps/gep-713/) 918 - [RFC6265](https://www.rfc-editor.org/rfc/rfc6265) 919 - [Policy Attachment](https://gateway-api.sigs.k8s.io/reference/policy-attachment/#direct-policy-attachment) 920 - [Envoy Session Persistence Design Doc](https://docs.google.com/document/d/1IU4b76AgOXijNa4sew1gfBfSiOMbZNiEt5Dhis8QpYg/edit#heading=h.sobqsca7i45e) 921 - [Envoy Session Persistence Issue](https://github.com/envoyproxy/envoy/issues/16698)