代理至example.com时Envoy配置出现SSL错误问题排查
问题描述
使用以下Envoy TCP透传配置代理内部服务时完全正常:
static_resources: listeners: - address: socket_address: address: 0.0.0.0 port_value: 10000 filter_chains: - filters: - name: envoy.filters.network.tcp_proxy typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy cluster: service-https stat_prefix: https_passthrough clusters: - name: service-https type: STRICT_DNS lb_policy: ROUND_ROBIN load_assignment: cluster_name: service-https endpoints: - lb_endpoints: - endpoint: address: socket_address: address: service-https port_value: 443
执行请求可正常访问:
curl -k https://10.0.0.1:10003/
但将集群目标地址修改为example.com后:
address: example.com
执行相同请求时出现SSL错误:
curl -k https://10.0.0.1:10003/ curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 10.0.0.1:10003
已确认Envoy实例可直接访问example.com(不通过Envoy代理)。
原因分析
问题核心是HTTPS SNI(Server Name Indication)校验不匹配:
- TCP透传模式下,Envoy仅原封不动转发客户端的所有TCP流量,包括SSL握手阶段的SNI字段。
- 你的curl请求目标是
https://10.0.0.1:10003,此时curl会自动将SNI设置为10.0.0.1,HTTP Host头也会设为该IP。 - 内部服务通常不校验SNI或允许任意SNI值,因此请求可正常完成;但
example.com的HTTPS服务器会严格校验SNI,仅接受SNI为example.com的请求,直接拒绝不符合要求的握手请求,最终导致SSL连接失败。
解决方法
针对该场景,有两种可行的解决方式:
方式1:修改客户端请求,指定正确的SNI和Host
使用curl的--resolve参数,将example.com的请求映射到Envoy代理地址,让curl自动发送符合要求的SNI和Host头:
curl -k https://example.com:10003/ --resolve example.com:10003:10.0.0.1
其他客户端也需要配置类似逻辑,确保请求目标域名为example.com,并将该域名解析到Envoy的代理地址。
方式2:将Envoy改为TLS终止模式(非透传)
如果需要对客户端透明处理SNI问题,可以将Envoy配置为终止客户端的TLS连接,再重新发起HTTPS请求到example.com,此时Envoy可自行指定正确的SNI:
修改后的核心配置示例:
static_resources: listeners: - address: socket_address: address: 0.0.0.0 port_value: 10000 filter_chains: - filters: - name: envoy.filters.network.http_connection_manager typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager stat_prefix: ingress_http codec_type: AUTO route_config: name: local_route virtual_hosts: - name: service domains: ["*"] routes: - match: { prefix: "/" } route: { cluster: service-https } http_filters: - name: envoy.filters.http.router typed_config: {} transport_socket: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext # 可配置Envoy的证书,或使用自签证书配合客户端-k参数 fake_protocols: ["http/1.1"] clusters: - name: service-https type: STRICT_DNS lb_policy: ROUND_ROBIN transport_socket: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext sni: example.com load_assignment: cluster_name: service-https endpoints: - lb_endpoints: - endpoint: address: socket_address: address: example.com port_value: 443
这种方式下,客户端可继续使用https://10.0.0.1:10003访问,Envoy会处理TLS终止并向后端发送正确的SNI。
内容的提问来源于stack exchange,提问作者Betflop
相关产品推荐
相关产品推荐

