Envoy QUIC 上游客户端证书支持:从静默失效到 mTLS 完备的配置与实现解析
Envoy QUIC 上游客户端证书支持从静默失效到 mTLS 完备的配置与实现解析【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy本文围绕 Envoy 的 QUICHTTP/3上游连接行为变更展开核心主题是上游 QUIC 连接现在能够正确出示在 cluster 的 upstream TLS context 中配置的客户端证书从而让 Envoy 作为客户端与要求双向 TLSmTLS的上游 HTTP/3 服务正常握手。读完本文你将掌握 QUIC 上游客户端证书的配置方法、private key provider 限制的成因、运行时开关envoy.reloadable_features.quic_upstream_client_certificates的回退机制以及这一行为变更背后的源码实现与测试证据。一、变更背景HTTP/3 上游 mTLS 的静默失效问题在本次行为变更之前Envoy 存在一个隐蔽的问题如果运维人员在 cluster 的 upstream TLS context 中配置了客户端证书而该 cluster 使用 QUICHTTP/3作为上游传输协议那么配置的客户端证书会被静默地不发送——即上游服务器请求客户端证书require_client_certificate时Envoy 并不会出示证书导致 mTLS 握手失败。由于证书配置看起来是存在的排查这类问题往往需要深入抓包才能发现根因。本次变更记录于 changelogs/current/new_features/quic__upstream_client_certificates.rst解决了该问题上游 QUIC 连接现在会在上游服务器请求客户端证书时真正出示 cluster 的 upstream TLS context 中配置的客户端证书。二、配置方式QuicUpstreamTransport 与 upstream TLS contextQUIC 上游传输的配置入口是QuicUpstreamTransport消息定义于 api/envoy/extensions/transport_sockets/quic/v3/quic_transport.proto// Configuration for Upstream QUIC transport socket. This provides Googles // implementation of Google QUIC and IETF QUIC to Envoy. message QuicUpstreamTransport { tls.v3.UpstreamTlsContext upstream_tls_context 1 [(validate.rules).message {required: true}]; }它只有唯一字段upstream_tls_context必填类型为tls.v3.UpstreamTlsContext。也就是说QUIC 上游的 TLS 参数完全复用标准的 upstream TLS context 语义客户端证书就在其中的common_tls_context.tls_certificates里配置。一个可用的 cluster 配置示例HTTP/3 上游 客户端证书clusters: - name: http3_upstream_with_mtls connect_timeout: 5s type: STRICT_DNS lb_policy: ROUND_ROBIN dns_lookup_family: V4_ONLY typed_extension_protocol_options: envoy.extensions.upstreams.http.v3.HttpProtocolOptions: type: type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions explicit_http_config: http3_protocol_options: {} transport_socket: name: envoy.transport_sockets.quic typed_config: type: type.googleapis.com/envoy.extensions.transport_sockets.quic.v3.QuicUpstreamTransport upstream_tls_context: common_tls_context: tls_certificates: - certificate_chain: filename: /etc/envoy/certs/client-cert.pem private_key: filename: /etc/envoy/certs/client-key.pem alpn_protocols: - h3 sni: http3.example.internal要点说明transport_socket.name固定为envoy.transport_sockets.quictyped_config的类型为envoy.extensions.transport_sockets.quic.v3.QuicUpstreamTransport两者缺一不可upstream_tls_context中的tls_certificates用于配置客户端证书链与私钥这正是本次变更后会被真正发送到上游的证书alpn_protocols需要包含h3QUIC 连接才会被协商为 HTTP/3sni用于上游证书校验与 SNI 扩展建议与上游服务的证书域名保持一致。从源码上看QuicClientTransportSocketConfigFactory::createTransportSocketFactory见 source/common/quic/quic_client_transport_socket_factory.cc会把QuicUpstreamTransport反序列化校验后将其中的upstream_tls_context交给标准的ClientContextConfigImpl::create解析随后创建QuicClientTransportSocketFactory。也就是说TLS 证书解析、SDS 支持等能力与普通 TLS 上游完全同源。三、实现原理客户端证书如何装入 QUICHE 握手上下文QUIC 的 TLS 握手由 QUICHEChromium 的 QUIC 实现驱动其客户端握手器要求直接访问私钥并且 SSL 上下文基于CRYPTO_BUFFER而非传统的X509对象来管理证书链。因此证书安装流程与普通 TLS 略有不同核心实现在 quic_client_transport_socket_factory.cc从 TLS context 中取出已解析的证书链tls_context.cert_chain_与私钥SSL_CTX_get0_privatekey使用i2d_X509将证书逐个转换为 DER 编码再包装为CRYPTO_BUFFER形成 QUICHE 可用的链包含叶子证书与中间证书通过SSL_CTX_set_chain_and_key把链与私钥安装到 QUICHE 的客户端 SSL 上下文上该 API 支持CRYPTO_BUFFER方式的链而非基于X509的SSL_CTX_use_certificate系列接口。证书是在每次生成QuicCryptoClientConfig时安装的quic_client_transport_socket_factory.cc当 TLS context 更新例如 SDS 推送了新证书后getCryptoConfig()会重建 crypto config 并重新调用configureQuicClientCertChain。若安装失败工厂会失败关闭fail closed返回空 crypto config 并触发ENVOY_BUG而不是带着缺失证书的配置继续建连——因为兼容性问题理论上在配置加载阶段已被拦截。测试用例ClientCertificateConfigured见 test/common/quic/quic_transport_socket_factory_test.cc验证了这一点配置客户端证书后生成的QuicCryptoClientConfig的 SSL 上下文中确实存在私钥SSL_CTX_get0_privatekey非空对应的NoClientCertificate用例则验证未配置证书时私钥为空。四、重要限制private key provider 在 QUIC 上不被支持这是本次变更中最重要的限制使用 private key provider 的客户端证书在 QUIC 上不被支持并且会在配置加载时被直接拒绝而不是像以前一样静默不发送。原因如前所述——QUICHE 客户端握手器需要直接访问私钥EVP_PKEY而 private key provider 的设计初衷是把私钥操作外包给外部组件如 HSM、加密芯片私钥本身对 Envoy 不可见。validateClientCertificatesForQuicquic_client_transport_socket_factory.cc会遍历所有tlsCertificates()一旦发现某个证书配置了privateKeyMethod()立即返回absl::UnimplementedError。三个相关行为需要区分静态配置config loadQuicClientTransportSocketFactory::create中会先执行校验再初始化L100-L103配置不合法时 cluster 创建直接失败报错信息为client certificates with a private key provider are not supported on QUICSDS 动态更新通过setSecretUpdateValidationHook注册了校验钩子L139-L144SDS 推送携带 private key provider 的证书时更新会被拒绝并保留旧的 SSL 上下文错误以常规的配置拒绝信号暴露而不是连接在运行期失败运行时开关关闭时校验钩子直接放行恢复证书不发送的旧行为见下一节。对应的测试覆盖了这三种路径PrivateKeyProviderRejectedAtConfigLoad期望kUnimplemented状态码、PrivateKeyProviderRejectedOnSdsUpdate期望不创建新 SSL context 且更新被拒绝、PrivateKeyProviderAllowedWhenRuntimeDisabled开关关闭时允许加载。五、运行时开关如何回退到旧行为本次变更受运行时开关runtime guard控制可通过设置以下运行时键回退到旧行为envoy.reloadable_features.quic_upstream_client_certificates将该键设为false后客户端证书不再被安装到 QUICHE SSL 上下文即恢复证书静默不发送的旧行为private key provider 的证书也不会在配置加载时被拒绝恢复旧行为。该 guard 在 source/common/runtime/runtime_features.cc 中以RUNTIME_GUARD宏声明注册RUNTIME_GUARD(envoy_reloadable_features_quic_upstream_client_certificates);关键语义是guard 在 cluster 的 transport socket 被创建时评估latchQuicClientTransportSocketFactory构造函数中读取一次该开关并缓存到成员client_certificates_enabled_L128-L129。因此翻转开关只对之后新建或更新的 cluster 生效集群 transport socket 重建时重新评估已经创建、且未更新的 cluster 会继续使用创建时 latch 的开关值静态校验与 SDS 更新校验都使用同一个 latch 值保证了两条路径行为一致。测试ClientCertificateRuntimeDisabledtest/common/quic/quic_transport_socket_factory_test.cc验证了开关关闭时即使配置了证书生成的 crypto config 中私钥仍为空而FailClosedWhenCertificateCannotBeInstalledL587-L607验证了证书安装失败这一理论上不可达的路径会触发ENVOY_BUG并返回空 crypto config。六、升级与运维注意事项结合上述行为升级或部署涉及 QUIC 上游 mTLS 的场景时建议关注以下几点排查证书没生效的旧配置如果此前 cluster 已配置客户端证书但上游 mTLS 一直失败升级后需确认开关处于默认开启状态并验证证书确实随握手发送可结合quic_client_transport_socket_factory相关日志与上游侧握手日志核对清理 private key provider 配置凡是在 QUIC 上游使用了 private key provider如envoy.tls.certificates.private_key_provider系列扩展的 cluster配置加载会被拒绝需改用直接加载私钥文件的方式或将此类上游降级为 TCP/TLS 传输灰度回退若在升级窗口内遇到握手行为变化导致的兼容性问题可将envoy.reloadable_features.quic_upstream_client_certificates置为false回退但要注意回退仅影响之后创建或更新的 cluster且回退后私有密钥提供者不会被拒绝、证书也不会发送SDS 更新路径通过 SDS 动态下发客户端证书的场景不受影响但若 SDS 推送的证书使用了 private key provider更新会被拒绝——这属于预期行为便于在运行期用常规的配置拒绝信号提前发现而不是等到连接失败。七、小结本次变更让 Envoy 的 QUIC 上游连接补齐了客户端证书支持配置在QuicUpstreamTransport.upstream_tls_context中的证书现在会真正参与 HTTP/3 握手与此同时受限于 QUICHE 握手器对私钥的直接访问要求private key provider 证书被明确拒绝且错误前移到了配置加载期。整个行为由运行时开关envoy.reloadable_features.quic_upstream_client_certificates统一控制为升级提供了平滑回退通道。从配置quic_transport.proto、实现quic_client_transport_socket_factory.cc到测试quic_transport_socket_factory_test.cc本文给出的路径均可作为继续深入研读的入口。【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考