配置 Gateway 网络拓扑

向目的地的工作负载转发外部客户端属性(IP 地址、证书信息)

许多应用程序需要知道发起源请求的客户端 IP 地址和证书信息才能正常工作。 值得注意的是填充了客户端 IP 的日志、验证工具以及安全工具。 例如 Web Application Firewall(WAF),它应用这些信息来运行正确的规则集。 反向代理的主要工作内容是给服务提供客户端属性。为了向目的地的工作负载转发这些客户端属性, 代理使用 X-Forwarded-For(XFF)和 X-Forwarded-Client-Cert(XFCC)请求头。

如今的网络千差万别,无论网络拓扑结构如何,对这些多样化属性的支持都是必要的。 不管网络使用的是基于云的负载均衡、前置负载均衡、直接暴露在网络上的 Gateway、 为许多中间代理服务的 Gateway,还是没有指定其他部署拓扑等,这些信息都是需要保存和转发。

虽然 Istio 提供一个 Ingress Gateway, 但鉴于上述多样化架构的复杂性,无法提供合理的默认值,将客户端属性正确转发到目标工作负载。 随着 Istio 多集群部署模式越来越普遍,这个问题需要被越来越重视。

了解关于 X-Forwarded-For 更多信息,参考 IETF 的 RFC

配置网络拓扑

XFF 和 XFCC 请求头的配置可以通过 MeshConfig 为所有 Gateway 工作负载进行全局设置, 也可以通过使用 Pod 注解给每个 Gateway 配置。例如,在安装或者升级期间,使用 IstioOperator 自定义资源去配置全局设置:

spec:
  meshConfig:
    defaultConfig:
      gatewayTopology:
        numTrustedProxies: <VALUE>
        forwardClientCertDetails: <ENUM_VALUE>

在您的 Istio Ingress Gateway Pod 的 Spec 通过添加 proxy.istio.io/config 注解可以设置这两个配置。

...
  metadata:
    annotations:
      "proxy.istio.io/config": '{"gatewayTopology" : { "numTrustedProxies": <VALUE>, "forwardClientCertDetails": <ENUM_VALUE> } }'

配置 X-Forwarded-For 头

应用程序依靠反向代理来转发请求的客户端属性,如 X-Forwarded-For 请求头。 然而由于 Istio 可以部署多样性的网络拓扑,您必须设置 Istio 网关代理上游的可信代理数量 numTrustedProxies, 这样才能正确提取客户端地址。因为它将控制 Ingress Gateway 在 X-Envoy-Eternal-Address 头中填充的值, 该值可以被上游服务可靠地用于访问客户的原始 IP 地址。

例如,如果在 Istio Gateway 之前,有一个基于云的负载均衡和一个反向代理,设置 numTrustedProxies2

httpbin X-Forwarded-For 示例

  1. 运行以下命令去创建一个 topology.yaml 的文件,并且设置 numTrustedProxies2,然后安装 Istio:

    $ cat <<EOF > topology.yaml
    apiVersion: install.istio.io/v1alpha1
    kind: IstioOperator
    spec:
      meshConfig:
        defaultConfig:
          gatewayTopology:
            numTrustedProxies: 2
    EOF
    $ istioctl install -f topology.yaml
    
  2. 创建一个 httpbin 命名空间:

    $ kubectl create namespace httpbin
    namespace/httpbin created
    
  3. 启用 Sidecar 注入,设置 istio-injection 标签为 enabled

    $ kubectl label --overwrite namespace httpbin istio-injection=enabled
    namespace/httpbin labeled
    
  4. httpbin 命名空间部署 httpbin

    Zip
    $ kubectl apply -n httpbin -f @samples/httpbin/httpbin.yaml@
    
  5. 部署一个 httpbin 相关的 Gateway:

Zip
$ kubectl apply -n httpbin -f @samples/httpbin/httpbin-gateway.yaml@
  1. 基于您的 Istio Ingress Gateway 设置一个本地环境变量 GATEWAY_URL
$ export GATEWAY_URL=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
  1. 运行下面的 curl 命令,模拟在 X-Forwarded-For 头中包含代理地址的请求:

    $ curl -s -H 'X-Forwarded-For: 56.5.6.7, 72.9.5.6, 98.1.2.3' "$GATEWAY_URL/get?show_env=true"
    {
    "args": {
      "show_env": "true"
    },
      "headers": {
      "Accept": ...
      "Host": ...
      "User-Agent": ...
      "X-B3-Parentspanid": ...
      "X-B3-Sampled": ...
      "X-B3-Spanid": ...
      "X-B3-Traceid": ...
      "X-Envoy-Attempt-Count": ...
      "X-Envoy-External-Address": "72.9.5.6",
      "X-Forwarded-Client-Cert": ...
      "X-Forwarded-For": "56.5.6.7, 72.9.5.6, 98.1.2.3,10.244.0.1",
      "X-Forwarded-Proto": ...
      "X-Request-Id": ...
    },
      "origin": "56.5.6.7, 72.9.5.6, 98.1.2.3,10.244.0.1",
      "url": ...
    }
    

上面的输出显示了 httpbin 工作负载收到的请求头。当 Istio Gateway 收到这个请求时, 它将 X-Envoy-External-Address 头设置为您 curl 命令中 X-Forwarded-For 头中的第二个到最后一个(numTrustedProxies: 2)地址。此外,Gateway 在将其转发到 httpbin 工作负载之前,会将自己的 IP 附加到 X-Forwarded-For 头中。

配置 X-Forwarded-Client-Cert 头

Envoy 文档 参考 XFCC:

配置如何处理 XFCC 头文件,需要在 IstioOperator 中设置 forwardClientCertDetails

apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
  meshConfig:
    defaultConfig:
      gatewayTopology:
        forwardClientCertDetails: <ENUM_VALUE>

其中 ENUM_VALUE 可以是以下类型:

ENUM_VALUE
UNDEFINED没有设置字段。
SANITIZE不要向下一跳地址发送 XFCC 头。
FORWARD_ONLY当客户端连接为 mTLS(Mutual TLS)时,在请求中转发 XFCC 请求头。
APPEND_FORWARD当客户端连接为 mTLS 时,将客户端证书信息附加到请求的 XFCC 请求头中并转发。
SANITIZE_SET当客户端连接为 mTLS 时,用客户端证书信息重置 XFCC 请求头,并将其发送到下一跳地址。这是 Gateway 的默认值。
ALWAYS_FORWARD_ONLY无论客户端连接是否为 mTLS,总是在请求中转发 XFCC 请求头。

参考 Envoy 文档, 了解并使用此功能的示例。

PROXY 协议

PROXY 协议允许在不依赖 HTTP、 X-Forwarded-ForX-Envoy-External-Address 头这类 7 层协议的情况下,在多个 TCP 代理之间交换和保存客户端属性。 此协议适用于外部 TCP 负载均衡器需要通过 Istio Gateway 将 TCP 流量代理到后端 TCP 服务并且仍然将客户端属性(例如源 IP) 暴露给上游 TCP 服务端点的场景。PROXY 协议可以通过 EnvoyFilter 启用。

如果外部负载均衡器配置为转发 TCP 流量并使用 PROXY 协议,Istio Gateway TCP 侦听器也必须配置为接受 PROXY 协议。 启用该功能需要在 Gateway 工作负载上使用 EnvoyFilter 添加 Envoy PROXY 协议过滤器。示例:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: proxy-protocol
  namespace: istio-system
spec:
  configPatches:
  - applyTo: LISTENER
    patch:
      operation: MERGE
      value:
        listener_filters:
        - name: envoy.listener.proxy_protocol
        - name: envoy.listener.tls_inspector
  workloadSelector:
    labels:
      istio: ingressgateway

客户端 IP 从 PROXY 协议中由 Gateway 获取,并在 X-Forwarded-ForX-Envoy-External-Address 头中设置(或附加)。 请注意,PROXY 协议与 X-Forwarded-ForX-Envoy-External-Address 等 L7 请求头互斥。 当 PROXY 协议与 gatewayTopology 配置一起使用时,在确定可信客户地址时会优先使用 numTrustedProxies 和接收到的 X-Forwarded-For 头,PROXY 协议客户端信息将被忽略。

请注意,上面的示例仅将 Gateway 配置为接受传入的 PROXY 协议 TCP 流量。 有关如何配置 Envoy 本身以使用 PROXY 协议与上游服务通信的示例,请参见 Envoy 文档

这些信息有用吗?
您是否有更多建议和改进意见?

感谢您的反馈!