在 Istio 中指定 HTTP Header 大小写

在 Istio 中指定 HTTP Header 大小写

问题背景

Envoy 缺省会把 HTTP Header 的 key 转换为小写,例如有一个 HTTP Header Test-Upper-Case-Header: some-value,经过 Envoy 代理后会变成 test-upper-case-header: some-value。这个在正常情况下没问题,RFC 2616 规范也说明了处理 HTTP Header 应该是大小写不敏感的。

部分场景下,业务请求对某些 Header 字段有大小写要求,此时被 Envoy 转换成为小些会导致请求出现问题。

解决方案

Envoy 支持几种不同的 Header 规则:

  • 全小写(默认规则)
  • 首字母大写

Envoy 1.8 之后新增支持:

  • 保留请求原本样式

基于以上能力,为了解决 Header 默认改为小写的问题在 Istio 1.8 及之前可配置成为首字母大写形式,Istio 1.10 及以后可以配置保留 Header 原有样式。

配置方法

Istio 1.8 之前可添加如下 EnvoyFilter 配置:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: http-header-proper-case-words
  namespace: istio-system
spec:
  configPatches:
    - applyTo: CLUSTER
      match:
        context: SIDECAR_OUTBOUND
        cluster:
          # 集群名称可通过 ConfigDump 查询
          name: "outbound|3000||test2.default.svc.cluster.local"
      patch:
        operation: MERGE
        value:
          http_protocol_options:
            header_key_format:
              proper_case_words: {}

在需要依赖大写 Header 的服务对应的集群中添加规则,将 Header 全部转为首字母大写的形式。

Istio 1.10 及之后可以添加如下 EnvoyFilter 配置:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: http-header-proper-case-words
  namespace: istio-system
spec:
  configPatches:
  # 配置保留发向 upstream 的 request header 大小写
  - applyTo: CLUSTER
    patch:
      operation: MERGE
      value:
        typed_extension_protocol_options:
          envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
            '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
            use_downstream_protocol_config:
              http_protocol_options:
                header_key_format:
                  stateful_formatter:
                    name: preserve_case
                    typed_config:
                      '@type': type.googleapis.com/envoy.extensions.http.header_formatters.preserve_case.v3.PreserveCaseFormatterConfig
  # 配置保留收到的 response header 大小写
  - applyTo: NETWORK_FILTER
    match:
      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:
              stateful_formatter:
                name: preserve_case
                typed_config:
                  '@type': type.googleapis.com/envoy.extensions.http.header_formatters.preserve_case.v3.PreserveCaseFormatterConfig

通过此配置可以让 Envoy 保持 Header 原有大小写形式。

Envoy 文档中对此的说明: https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/header_casing#config-http-conn-man-header-casing