envoyproxy/envoy

External Auth providers can't set multiple headers of the same key w/ gRPC

Open

#40.255 aberto em 16 de jul. de 2025

Ver no GitHub
 (3 comments) (0 reactions) (0 assignees)C++ (5.373 forks)batch import
area/ext_authzbughelp wanted

Métricas do repositório

Stars
 (27.997 stars)
Métricas de merge de PR
 (Mesclagem média 8d) (378 fundiu PRs em 30d)

Description

I have a gRPC service implementing the externalAuth xDS service. It is returning headers to add to the request to the upstream service. This works perfectly if you just send one. If I want to send multiple copies of the header, only the last one get's sent.

Versions: envoy version: 8d14f6fc8fe9703ff17d4377d9053b3cbbe85dea/1.33.3-dev/Clean/RELEASE/BoringSSL from istio 1.25.2

I see in the docs here that the

Note that the [append field in HeaderValueOption](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/base.proto#envoy-v3-api-field-config-core-v3-headervalueoption-append) defaults to false when used in this message. By setting the append field to true, the filter will append the correspondent header value to the matched request header. By leaving append as false, the filter will either add a new header, or override an existing one if there is a match.

That's a deprecated field. But I tried it either way. I even attempted to use the proper non-deprecated option(which happens to be the 0 option in enum, so it's identical to not setting)

Here is the OK auth response that my service sent back to envoy

status {
}
ok_response {
  headers {
    header {
      key: "trial-1"
      value: "a"
    }
  }
  headers {
    header {
      key: "trial-1"
      value: "b"
    }
  }
  headers {
    header {
      key: "trial-2"
      value: "a"
    }
    append {
      value: true
    }
  }
  headers {
    header {
      key: "trial-2"
      value: "b"
    }
    append {
      value: true
    }
  }
  headers {
    header {
      key: "trial-3"
      value: "a"
    }
  }
  headers {
    header {
      key: "trial-3"
      value: "b"
    }
  }
}

Only tiral-1 and trial-3 headers were added to the authenticated upstream request. And only b. The a value was overwritten.

It seems like append means only append if it was there first. and non-append means overwrite.

The code for setting all 3 of these response headers looked like

    private fun trial1(string: String): HeaderValueOption? = HeaderValueOption.newBuilder()
        .setAppendAction(HeaderValueOption.HeaderAppendAction.APPEND_IF_EXISTS_OR_ADD)
        .setHeader(
            HeaderValue.newBuilder()
                .setKey("trial-1")
                .setValue(string),
        ).build()
    private fun trial2(string: String): HeaderValueOption? = HeaderValueOption.newBuilder()
        .setAppend(BoolValue.of(true))
        .setAppendAction(HeaderValueOption.HeaderAppendAction.APPEND_IF_EXISTS_OR_ADD)
        .setHeader(
            HeaderValue.newBuilder()
                .setKey("trial-2")
                .setValue(string),
        ).build()
    private fun trial3(string: String): HeaderValueOption? = HeaderValueOption.newBuilder()
        .setHeader(
            HeaderValue.newBuilder()
                .setKey("trial-3")
                .setValue(string),
        ).build()

The ext-auth config in the istio envoy filter is

      patch:
        operation: INSERT_AFTER
        value:
          name: envoy.filters.http.ext_authz
          typed_config:
            "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz
            grpc_service:
              envoy_grpc:
                cluster_name: outbound|50051||api-authz-xds.public-sandbox-ingress.svc.cluster.local
                authority: api-authz-xds.public-sandbox-ingress.svc.cluster.local
              timeout: 0.5s
            include_peer_certificate: true
            transport_api_version: V3
            allowed_headers:
              patterns:
                - exact: "partner-cert-subject"
                - exact: "content-type"
                - exact: ":method"
                - exact: ":path"
                - exact: ":authority"

This is working, and we're currently using an added request header and CSVing the values, but the ideal way is to have the repeated headers.

I've seen a few other issues about this from a while back, I'll attempt to rediscover them and link them after.

Guia do colaborador