Netflix Zuul 如何配置Squid等出站代理的TLS透传HTTP CONNECT调用
问题根因说明
配置JVM级别的https.proxyHost、https.proxyPort参数后,Zuul没有按预期建立TLS透传连接、反而和代理完成TLS终止,核心原因是Zuul底层依赖的Ribbon、Apache HttpClient组件默认开启了系统代理自动识别逻辑:该逻辑会把代理服务直接判定为HTTPS请求的最终目标,直接和代理完成全流程TLS握手,跳过了建立HTTP CONNECT隧道的步骤,代理因此可以解密所有请求内容,完全具备篡改请求的能力。
适配Squid式透传代理的核心配置方案
核心思路是绕过JVM全局代理的自动识别逻辑,手动指定底层HTTP客户端为HTTPS请求强制建立CONNECT隧道,全程让代理只做TCP字节转发,不接触解密后的请求明文。
- 关闭组件的系统代理自动识别能力
首先要禁用Ribbon对JVM全局代理参数的读取,避免触发默认的TLS终止逻辑,在application.yml中补充配置:
同时要移除JVM启动参数里的ribbon: UseSystemProxy: false-Dhttps.proxyHost、-Dhttps.proxyPort、-Dhttp.proxyHost这类全局代理配置,这类参数会强制触发JDK网络栈的代理握手逻辑,覆盖自定义的隧道配置。 - 自定义带CONNECT隧道策略的Zuul底层HttpClient
替换Zuul默认加载的Apache HttpClient实例,强制所有HTTPS路由请求通过代理建立透传隧道,示例配置类:
该配置的运行逻辑是:Zuul给目标HTTPS服务发请求时,首先通过明文HTTP连接给Squid代理发送@Bean public CloseableHttpClient zuulTunnelHttpClient() { // 替换为你的Squid代理的地址和端口 HttpHost proxyHost = new HttpHost("squid-proxy-ip", squid_proxy_port); // 自定义隧道策略:所有HTTPS目标请求强制走CONNECT隧道,不做TLS终止 TunnelStrategy connectOnlyStrategy = (route, httpContext) -> "https".equalsIgnoreCase(route.getTargetHost().getSchemeName()); return HttpClients.custom() .setProxy(proxyHost) .setTunnelStrategy(connectOnlyStrategy) // 和代理的初始连接保持明文HTTP,不要在和代理的连接上叠加TLS .setDefaultConnectionConfig(ConnectionConfig.custom() .setTimeToLive(30, TimeUnit.SECONDS) .build()) .build(); }CONNECT target-domain:443 HTTP/1.1请求,等代理打通到目标的TCP通道后,Zuul直接在这个透传通道里和目标服务完成全流程TLS握手,代理全程仅做字节转发,无法解密请求内容。 - 调整Zuul的路由透传规则
保证CONNECT请求和后续隧道内的请求不会被Zuul篡改掉必要的标识头,在配置中补充:zuul: # 仅保留需要过滤的敏感头,不要覆盖原始Host头 sensitive-headers: Cookie,Set-Cookie,Authorization host: connect-timeout-millis: 30000 socket-timeout-millis: 60000
常见踩坑排查
- 确认Squid代理本身开启了CONNECT方法支持,默认Squid配置允许CONNECT到443等HTTPS端口,如果Squid侧禁用了CONNECT方法,Zuul侧的配置无法生效。
- 不要在配置HttpClient时给到代理的连接叠加TLS层,否则会再次回到代理做TLS终止的状态——只有和目标服务之间的连接是通过隧道透传的TLS才是合规的透传模式。
- 不要把代理地址直接配置为Zuul路由的目标URL,那样会让Zuul把代理当成后端服务,直接完成TLS握手,失去透传能力。
内容的提问来源于stack exchange,提问作者Anant Laxmikant Bobde
相关产品推荐
相关产品推荐

