StatefulSessionPerRoute

Trying to setup StatefulSessionPerRoute but not clear on how to do it via EnvoyFilter.

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: session-per-route-gw
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
  - applyTo: NETWORK_FILTER
    match:
      context: GATEWAY
      listener:
        portNumber: 8080 
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
    patch:
      operation: MERGE
      value:
              name: envoy.filters.network.http_connection_manager
              typedConfig:
                '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                route_config:
                  name: route_config_global
                  virtual_hosts:
                  - name: route_config_global_vh_all
                    domains:
                    - "sess1-a-test.ecom1.joecloudy.com"
                    typed_per_filter_config:
                      envoy.filters.http.stateful_session:
                        "@type": type.googleapis.com/envoy.extensions.filters.http.stateful_session.v3.StatefulSessionPerRoute
                        stateful_session:
                          session_state:
                            name: envoy.http.stateful_session.cookie.route.gw
                            typed_config:
                              "@type": type.googleapis.com/envoy.extensions.http.stateful_session.cookie.v3.CookieBasedSessionState
                              cookie:
                                name: global-session-cookie-vh-all
                                ttl: 600s
---
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: session-per-route-gw-http
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  # workloadSelector:
  #   labels:
  #     app: sess1-a
  configPatches:
  - applyTo: HTTP_FILTER  
    match:      
      context: GATEWAY
      listener:
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager" 
            subFilter:
              name: "envoy.filters.http.router"            
    patch:
      operation: INSERT_BEFORE
      value:
        name: "envoy.filters.http.stateful_session" 
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.http.stateful_session.v3.StatefulSessionPerRoute
          stateful_session:
            session_state:
              name: envoy.http.stateful_session.cookie.route.gw
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.http.stateful_session.cookie.v3.CookieBasedSessionState
                cookie:
                  name: global-session-cookie-vh-all
                  ttl: 600s
  
1 Like

Cookie does not get created but not sure how to tie these two together. I does work by just using HTTP_FILTER with just StatefulSession but we need a cookie per route

Hi @Jose_Retelny
You would need to add the filter at listener level too (with empty config).
After that your per route filter will start working.

  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: GATEWAY
      listener:
        filterChain:
          filter:
            name: envoy.filters.network.http_connection_manager
            subFilter:
              name: envoy.filters.http.router      
        portNumber: 443
    patch:
      operation: INSERT_BEFORE
      value:
        name: envoy.filters.http.stateful_session
        typed_config:
          '@type': type.googleapis.com/envoy.extensions.filters.http.stateful_session.v3.StatefulSession
  workloadSelector:
    labels:
      istio: ingressgateway

see this → Cannot use stateful session on route level without enabling it on listener level · Issue #20658 · envoyproxy/envoy · GitHub

Enable at listener level + override at route level. That is how it is supposed to be used.

How about for other components upstream? I think I have it working but not sure what is the best way that I don’t mess up any other settings configured in istio.

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: session-per-route-app
namespace: sess1-a-ns
spec:

workloadSelector:

labels:

app: sess1-a

configPatches:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: session-per-route-app
  namespace: sess1-a-ns
spec:
  # workloadSelector:
  #   labels:
  #     app: sess1-a
  configPatches:
  - applyTo: NETWORK_FILTER
    match:
      context: ANY
      listener:
        portNumber: 80
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
    patch:
      operation: MERGE
      value:
        name: envoy.filters.network.http_connection_manager
        typedConfig:
          '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          route_config:
            name: route_config_global-app
            virtual_hosts:
            - name: route_config_global_vh_all_app-sess1-a
              domains:
              - "sess1-a*"
              routes:
              - match: { prefix: "/" }
                route: { cluster: "outbound|80||sess1-a.sess1-a-ns.svc.cluster.local" }
                typed_per_filter_config:
                  envoy.filters.http.stateful_session:
                    "@type": type.googleapis.com/envoy.extensions.filters.http.stateful_session.v3.StatefulSessionPerRoute
                    stateful_session:
                      session_state:
                        name: "envoy.http.stateful_session.cookie"
                        typed_config:
                          "@type": type.googleapis.com/envoy.extensions.http.stateful_session.cookie.v3.CookieBasedSessionState
                          cookie:
                            name: global-sess1-a-session-cookie-vh-all-app
                            ttl: 600s
            - name: route_config_global_vh_all_app-service-b
              domains:
              - "service-b*"
              routes:                            
              - match: { prefix: "/" }
                route: { cluster: "outbound|80||service-b.sess1-a-ns.svc.cluster.local" }
                typed_per_filter_config:
                  envoy.filters.http.stateful_session:
                    "@type": type.googleapis.com/envoy.extensions.filters.http.stateful_session.v3.StatefulSessionPerRoute
                    stateful_session:
                      session_state:
                        name: "envoy.http.stateful_session.cookie"
                        typed_config:
                          "@type": type.googleapis.com/envoy.extensions.http.stateful_session.cookie.v3.CookieBasedSessionState
                          cookie:
                            name: global-service-b-session-cookie-vh-all-app
                            ttl: 600s  
            - name: route_config_global_vh_all_app-service-c
              domains:
              - "service-c*"
              routes:                            
              - match: { prefix: "/" }
                route: { cluster: "outbound|80||service-c.sess1-a-ns.svc.cluster.local" }
                typed_per_filter_config:
                  envoy.filters.http.stateful_session:
                    "@type": type.googleapis.com/envoy.extensions.filters.http.stateful_session.v3.StatefulSessionPerRoute
                    stateful_session:
                      session_state:
                        name: "envoy.http.stateful_session.cookie"
                        typed_config:
                          "@type": type.googleapis.com/envoy.extensions.http.stateful_session.cookie.v3.CookieBasedSessionState
                          cookie:
                            name: global-service-c-session-cookie-vh-all-app
                            ttl: 600s             
            - name: route_config_global_vh_all_app-service-d
              domains:
              - "service-d*"
              routes:                            
              - match: { prefix: "/" }
                route: { cluster: "outbound|80||service-d.sess1-a-ns.svc.cluster.local" }
                typed_per_filter_config:
                  envoy.filters.http.stateful_session:
                    "@type": type.googleapis.com/envoy.extensions.filters.http.stateful_session.v3.StatefulSessionPerRoute
                    stateful_session:
                      session_state:
                        name: "envoy.http.stateful_session.cookie"
                        typed_config:
                          "@type": type.googleapis.com/envoy.extensions.http.stateful_session.cookie.v3.CookieBasedSessionState
                          cookie:
                            name: global-service-d-session-cookie-vh-all-app
                            ttl: 600s                                                                                  
  - applyTo: HTTP_FILTER  
    match:      
      context: SIDECAR_OUTBOUND
      listener:
        portNumber: 80
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager" 
    patch:
      operation: INSERT_BEFORE
      value:
        name: "envoy.filters.http.stateful_session" 
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.http.stateful_session.v3.StatefulSessionPerRoute

One problem that I am trying to fix is that the latest merge is not consistent with the full virtual service settings and actually it is overwriting other important configuration. So any outbound request now I get 404. I am slowly, trial and error, doing comparisons to make it work and do the patches at the right level to avoid other side effects