Istio中subjectPeerCertificate等API是否仅在网关作为服务端生效?
在Ingress和Egress网关中使用Lua过滤器,通过以下代码提取TLS握手时客户端与服务器的证书主题:
response_handle:headers():add("client-res", response_handle:connection():ssl():subjectLocalCertificate()) response_handle:headers():add("server-res", response_handle:connection():ssl():subjectPeerCertificate())
Ingress网关可成功提取两者的证书主题,但Egress网关提取失败,返回空请求头。经排查发现,当前提取的是Istio代理与Egress网关间MTLS使用的无主题证书,而非Egress网关与外部服务器间MTLS的证书主题。
疑问:response_handle:connection():ssl():subjectLocalCertificate()和response_handle:connection():ssl():subjectPeerCertificate()是否仅在网关作为服务端时生效,当网关作为客户端(Egress访问外部MTLS服务)时无法正常工作?
附使用的EnvoyFilter配置:
apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: name: example-namespace-envoy-filter namespace: example-namespace annotations: meta.helm.sh/release-name: example-namespace meta.helm.sh/release-namespace: example-namespace labels: app.kubernetes.io/managed-by: Helm spec: workloadSelector: labels: istio: example-namespace-egressgateway 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: # lua filter specification name: envoy.lua typed_config: "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua" inlineCode: | function envoy_on_response(response_handle) response_handle:logCritical("from response handle") response_handle:headers():add("server-res", response_handle:connection():ssl():subjectPeerCertificate()) response_handle:headers():add("client-res", response_handle:connection():ssl():subjectLocalCertificate()) end function envoy_on_request(request_handle) request_handle:logCritical("from request handle") request_handle:headers():add("server-req", request_handle:connection():ssl():subjectPeerCertificate()) request_handle:headers():add("client-req", request_handle:connection():ssl():subjectLocalCertificate()) end
是的,你当前调用的connection():ssl()获取的是网关作为服务端时的连接(即Istio Sidecar与Egress网关之间的内部MTLS连接),而非网关作为客户端与外部服务的upstream连接,所以在Egress场景下拿到的是内部无主题证书,而非外部服务的证书。
原因分析
你的EnvoyFilter将Lua过滤器挂载到了Egress网关的入口HTTP连接管理器(对应接收Sidecar请求的Listener),这里的connection()对象指向的是Sidecar到Egress网关的连接,完全不涉及Egress网关与外部服务的TLS握手过程,自然无法获取外部服务的证书信息。
解决方案
要获取Egress网关与外部服务的TLS证书主题,需要使用Envoy Lua API的upstream_connection()方法,该方法专门用于获取网关作为客户端发起请求时与上游服务的连接。修改后的Lua代码如下:
function envoy_on_response(response_handle) response_handle:logCritical("from response handle") -- 获取Egress与外部服务的upstream连接 local upstream_conn = response_handle:upstream_connection() if upstream_conn and upstream_conn:ssl() then -- 外部服务的证书主题(Peer为外部服务,Local为Egress用于对外的客户端证书) response_handle:headers():add("external-server-subject", upstream_conn:ssl():subjectPeerCertificate()) response_handle:headers():add("egress-client-subject", upstream_conn:ssl():subjectLocalCertificate()) end -- 可选:保留内部连接的证书信息用于对比 local local_conn = response_handle:connection() if local_conn and local_conn:ssl() then response_handle:headers():add("internal-sidecar-subject", local_conn:ssl():subjectPeerCertificate()) response_handle:headers():add("internal-egress-subject", local_conn:ssl():subjectLocalCertificate()) end end function envoy_on_request(request_handle) request_handle:logCritical("from request handle") -- 注意:请求阶段upstream连接尚未建立,无法获取外部服务证书信息 local local_conn = request_handle:connection() if local_conn and local_conn:ssl() then request_handle:headers():add("internal-sidecar-subject", local_conn:ssl():subjectPeerCertificate()) request_handle:headers():add("internal-egress-subject", local_conn:ssl():subjectLocalCertificate()) end end
关键说明
upstream_connection()仅在envoy_on_response阶段可用,因为此时Egress网关已经与外部服务完成TLS握手并收到响应,upstream连接已建立。connection()始终指向网关作为服务端时的客户端连接(即Sidecar到Egress的连接),无论Ingress还是Egress场景。
内容的提问来源于stack exchange,提问作者Priyansha Sharma

