跨防火墙Envoy双向TLS代理的SNI适配配置问题求助
跨防火墙Envoy双向TLS代理的SNI适配配置问题求助
大家好,我最近在部署跨防火墙的Envoy代理架构时遇到了SNI相关的流量拦截问题,想请各位帮忙看看怎么解决。先给大家介绍下整体情况:
架构背景
我们的网络分为客户侧和服务商侧,中间隔着客户防火墙,这个防火墙有严格的HTTP和SNI过滤策略,只有envoy-b.example.com这个域名的SNI是被允许的,其他任何域名的流量都会被直接丢弃。
整体架构如下:
┌────────────────────────────────────────┐ ┌────────────────────────────────────────┐ │ ┌──────────┬────────┘ │ │Provider Network └──┬──────────────┘ │ │ Customer Network │ │ │ ┌─────────┴─┐ │ │ │ │ │ ┌─────┤ Envoy - B ├───────┐ │ │ │ │ │ │ └─────┬─────┘ │ │ │ ┌──────┴─────┐ │ │ │ │ │ │ │ ┌─────────┐ │ │ │ │ ┌────┴────┐ ┌───┴─────┐ ┌────┴────┐ │ │ │ Client ├────┤ Envoy - A │ │ │ │ Service │ │ Service │ │ Service │ │ │ └─────────┘ │ │ │ │ └─────────┘ └─────────┘ └─────────┘ │ │ └────────────┘ │ │ │ │ │ │ │ └────────────────────────────────────────┘ └────────────────────────────────────────┘
- 客户侧:Client → Envoy-A → 客户防火墙
- 服务商侧:服务商防火墙 → Envoy-B → 后端服务(都是HTTP/HTTPS协议)
现有Envoy配置
目前我已经配置了Envoy-A和Envoy-B的基础转发规则:
Envoy-A 配置
Envoy-A监听80和443端口:
- 80端口:接收HTTP请求,用HTTP2 + TLSv1.3加密转发给Envoy-B的8888端口,这里SNI会被替换成
envoy-b.example.com,能正常过防火墙。 - 443端口:做TCP透传,直接把客户端的HTTPS流量转发给Envoy-B的8889端口,这时候SNI还是原请求的
private.service.example.com,直接被防火墙拦了。
完整配置如下:
static_resources: listeners: # HTTP - name: http_forwarder address: socket_address: protocol: TCP address: 0.0.0.0 port_value: 80 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 route_config: name: http_route virtual_hosts: - name: http_forwarder domains: [ "*" ] routes: - match: prefix: "/" route: cluster: forwarder_to_envoy_b_http http_filters: - name: envoy.filters.http.router typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router # HTTPS/TLS - name: https_forwarder address: socket_address: protocol: TCP address: 0.0.0.0 port_value: 443 filter_chains: - filters: - name: envoy.filters.network.tcp_proxy typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy cluster: forwarder_to_envoy_b_tls stat_prefix: https_passthrough access_log: - name: envoy.access_loggers.stdout typed_config: "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog clusters: - name: forwarder_to_envoy_b_http type: STRICT_DNS lb_policy: ROUND_ROBIN load_assignment: cluster_name: forwarder_to_envoy_b_http endpoints: - lb_endpoints: - endpoint: address: socket_address: address: envoy-b.example.com port_value: 8888 dns_resolution_config: resolvers: - socket_address: address: "1.1.1.1" port_value: 53 dns_resolver_options: no_default_search_domain: true transport_socket: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext common_tls_context: tls_params: tls_minimum_protocol_version: TLSv1_3 tls_maximum_protocol_version: TLSv1_3 - name: forwarder_to_envoy_b_tls type: STRICT_DNS lb_policy: ROUND_ROBIN load_assignment: cluster_name: forwarder_to_envoy_b_tls endpoints: - lb_endpoints: - endpoint: address: socket_address: address: envoy-b.example.com port_value: 8889 dns_resolution_config: resolvers: - socket_address: address: "1.1.1.1" port_value: 53 dns_resolver_options: no_default_search_domain: true
Envoy-B 配置
Envoy-B监听8888和8889端口:
- 8888端口:接收Envoy-A发来的HTTP2+TLSv1.3流量,解密后转发给后端HTTP服务。
- 8889端口:做TCP透传,直接把流量转发给后端HTTPS服务。
完整配置如下:
static_resources: listeners: - name: http_listener_0 address: socket_address: protocol: TCP address: 0.0.0.0 port_value: 8888 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 route_config: name: local_route virtual_hosts: - name: local_service domains: [ "*" ] routes: - match: prefix: "/" route: cluster: http_cluster http_filters: - name: envoy.filters.http.router typed_config: "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router transport_socket: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext common_tls_context: tls_params: tls_minimum_protocol_version: TLSv1_3 tls_maximum_protocol_version: TLSv1_3 tls_certificates: certificate_chain: filename: /certs/proxy-crt.pem private_key: filename: /certs/proxy-key.pem alpn_protocols: HTTP2 - name: tls_listener_0 address: socket_address: protocol: TCP address: 0.0.0.0 port_value: 8889 filter_chains: - filters: - name: envoy.filters.network.tcp_proxy typed_config: "@type": type.googleapis.com/envoy.extensions.filters.network.tcp_proxy.v3.TcpProxy cluster: tls_cluster stat_prefix: https_passthrough access_log: - name: envoy.access_loggers.stdout typed_config: "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog clusters: - name: http_cluster type: STRICT_DNS lb_policy: ROUND_ROBIN load_assignment: cluster_name: http_cluster endpoints: - lb_endpoints: - endpoint: address: socket_address: address: private.service.example.com port_value: 80 dns_resolution_config: resolvers: - socket_address: address: "1.1.1.1" port_value: 53 dns_resolver_options: no_default_search_domain: true - name: tls_cluster type: STRICT_DNS lb_policy: ROUND_ROBIN load_assignment: cluster_name: tls_cluster endpoints: - lb_endpoints: - endpoint: address: socket_address: address: private.service.example.com port_value: 443 dns_resolution_config: resolvers: - socket_address: address: "1.1.1.1" port_value: 53 dns_resolver_options: no_default_search_domain: true
核心问题
HTTP请求一切正常,但HTTPS请求因为Envoy-A只是透传TCP流,原请求的SNI是private.service.example.com,被防火墙直接丢弃了。我想要实现的是:让Envoy-A把TCP代理的HTTPS流量重新加密,替换SNI为envoy-b.example.com,这样能通过防火墙,同时Envoy-B还能拿到原请求的SNI来转发到对应服务。
已尝试的修改(未生效)
我尝试给两边的相关配置添加了TLS传输套接字,但没起作用:
Envoy-A 修改点
在clusters > forwarder_to_envoy_b_tls下添加了TLS上游配置:
transport_socket: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext common_tls_context: tls_params: tls_minimum_protocol_version: TLSv1_3 tls_maximum_protocol_version: TLSv1_3
Envoy-B 修改点
在listener > tls_listener_0下添加了TLS下游配置:
transport_socket: name: envoy.transport_sockets.tls typed_config: "@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext common_tls_context: tls_params: tls_minimum_protocol_version: TLSv1_3 tls_maximum_protocol_version: TLSv1_3 tls_certificates: certificate_chain: filename: /certs/proxy-crt.pem private_key: filename: /certs/proxy-key.pem alpn_protocols: HTTP2
额外限制条件
还有几个限制需要注意:
- 客户端不接受Envoy-B把HTTPS转成HTTP再转发的方式,因为这样证书链会变化,用户体验受影响。
- 我们没有后端服务的私钥,没法做证书重签或者中间人代理。
- Envoy-B必须依靠原请求的SNI来判断转发到哪个服务,所以不能丢失这个信息。
有没有大佬知道怎么调整配置才能实现需求?谢谢大家!
备注:内容来源于stack exchange,提问作者M.A. Heshmat Khah
相关产品推荐
相关产品推荐

