Rewrite headers with envoy

I need to rewrite the “set-cookie” headers returned by an application since some clients can only handle the uppercase style “Set-Cookie”. I’ve tried the following envoyfilter:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: fix-setcookie-case
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: GATEWAY
      listener:
        filterChain:
          filter:
            name: "envoy.http_connection_manager"
            subFilter:
              name: "envoy.router"
    patch:
      operation: INSERT_BEFORE
      value:
       name: envoy.lua
       typed_config:
         "@type": "type.googleapis.com/envoy.config.filter.http.lua.v2.Lua"
         inlineCode: |
            function envoy_on_response(response_handle)
              local originalCookie = response_handle:headers():get("SET-COOKIE")
              if originalCookie then
                response_handle:logWarn("Adding header Set-Cookie with content " .. originalCookie)
                response_handle:headers():replace("Set-Cookie", originalCookie)
              end 
              end

This doesn’t work, it seems that either something changes the headers back to lowercase after the lua script has run or the lua script itself ignores the case (thats why i wrote get(“SET-COOKIE”) --> this still successfully returns a set-cookie header). I also haven’t found a way on how to handle multiple set-cookie headers like this…

I’ve also tried telling the envoy use proper case:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: proper-case-headers-envoryfilter
  namespace: istio-system
spec:
  configPatches:
    - applyTo: CLUSTER
      match:
        context: ANY
      patch:
        operation: MERGE
        value:
          http_protocol_options:
            header_key_format:
              proper_case_words: {}

I’ve applied this to the namespace containing the app as well as the namespace containing the gateways.
When using

istioctl proxy-config cluster -n istio-system istio-ingressgateway-68fb7896f5-x7qr8 -o json

i get the expected output (truncated):

    "httpProtocolOptions": {
        "headerKeyFormat": {
            "properCaseWords": {}
        }
    }

Yet i still get a lowercase “set-cookie” header on our clients.

Responding to my own thread, since i’ve found the solution:

The http_protocol_options is the correct approach, but i’ve applied the config in the wrong section.
This config does the trick:

---
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: normalize-headers
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
  - applyTo: NETWORK_FILTER # http connection manager is a filter in Envoy
    match:
      # if context omitted then this applies to both sidecars and gateways
      context: GATEWAY
      listener:
        filterChain:
          filter:
            name: "envoy.http_connection_manager"
    patch:
      operation: MERGE
      value:
        typed_config:
          "@type": "type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager"
          http_protocol_options: 
            header_key_format:
              proper_case_words: {}

I used the same on Istio 1.9 with required changes on type and API version like:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: normalize-headers
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
  - applyTo: NETWORK_FILTER # http connection manager is a filter in Envoy
    match:
      # if context omitted then this applies to both sidecars and gateways
      context: GATEWAY
      listener:
        filterChain:
          filter:
            name: "envoy.filters.network.http_connection_manager"
    patch:
      operation: MERGE
      value:
        typed_config:
          "@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
          http_protocol_options:
            header_key_format:
              proper_case_words: {}

But the headers are still in lower case. Any idea what would be wrong