Kubernetes Ingress默认的TLS处理方式是在Ingress Controller处终止TLS连接,解密后再将HTTP请求转发给后端Service。这种方式适用于绝大多数Web应用,但在某些特殊场景下,我们需要把TLS流量原封不动地送到后端Pod,由后端自行完成TLS握手和证书处理。例如后端服务本身实现了基于TLS的私有协议、需要验证客户端证书、或者要求端到端加密合规性。这时TLS passthrough就成了唯一的选择。

本篇文章将以最常见的Nginx Ingress Controller为例,深入讲解TLS passthrough的配置方法、工作原理以及生产环境中的注意事项。即使你使用的是Traefik、HAProxy等其他Ingress Controller,其核心概念也是相通的。
一、TLS passthrough与TLS termination的本质区别
要理解TLS passthrough,必须先清楚Ingress Controller处理TLS的两种基本模式:TLS termination(TLS终止)和TLS passthrough(TLS透传)。
在TLS termination模式下,Ingress Controller负责解密所有进入集群的HTTPS流量。它需要持有对应域名的TLS证书和私钥,当客户端发起TLS握手时,Controller作为服务端完成握手,解密出HTTP请求,再以明文HTTP的形式转发给后端的Service。这种模式的好处是:后端应用无需关心TLS细节,可以专注于业务逻辑;同时Ingress层可以统一管理证书、做HTTP路由、修改请求头等。但缺点是:流量在Controller和后端之间是明文传输(通常通过集群内部网络),并且后端无法获取到客户端的原始证书信息(除非Controller额外传递)。
而TLS passthrough则完全绕开了Controller的解密步骤。Controller在接收到TLS ClientHello时,会根据其中的SNI(Server Name Indication)字段判断该连接应该路由到哪个后端Service,然后直接将整个TCP连接(包括TLS握手和数据)原样转发过去。Controller不拥有任何证书,也不解密任何数据,它只做一个四层转发器。后端Service必须自己持有证书并完成TLS握手。这种模式带来了几个显著优势:
- 端到端加密:从客户端到后端Pod的整条链路上,数据始终保持加密状态,满足严格的安全合规要求。
- 后端证书控制:后端可以自行管理证书轮换、客户端证书验证等,无需在Ingress层重复配置。
- 支持非HTTP协议:由于不解析HTTP,任何基于TLS的应用层协议(如gRPC over TLS、数据库代理、私有二进制协议)都可以通过passthrough暴露。
当然,passthrough也有代价:Ingress Controller失去了对HTTP层内容的可见性,无法基于路径、Header等做七层路由,也无法修改请求或响应。因此,是否使用passthrough需要根据具体场景权衡。
二、使用Nginx Ingress Controller启用TLS passthrough
Nginx Ingress Controller从0.22.0版本开始支持TLS passthrough,但默认并不开启。需要满足两个条件:
- Controller启动参数中必须添加
--enable-ssl-passthrough。 - Ingress资源上添加注解
nginx.ingress.kubernetes.io/ssl-passthrough: "true"。
先来看启动参数。如果你使用Helm部署ingress-nginx,可以在values.yaml中设置:
controller:
extraArgs:
enable-ssl-passthrough: "true"
如果你使用Deployment直接部署,需要修改部署清单,在容器的args中加入--enable-ssl-passthrough。注意:一旦启用passthrough,Controller会监听一个额外的TCP端口(通常为442,或者通过--ssl-passthrough-proxy-port自定义),所有被标记为passthrough的流量都会进入这个端口处理。同时,controller会为每个passthrough的Ingress创建对应的TCP代理配置。
接下来准备一个后端服务用于测试。这里我们使用一个简单的TCP服务,它会在8443端口监听TLS连接,并返回握手成功后的信息。为了演示方便,我们可以直接用openssl的s_server命令作为Pod的主进程:
apiVersion: v1
kind: Pod
metadata:
name: tls-backend
labels:
app: tls-backend
spec:
containers:
- name: ssl-server
image: alpine/openssl
command: ["/bin/sh", "-c"]
args:
- |
openssl req -x509 -newkey rsa:2048 -keyout /tmp/key.pem -out /tmp/cert.pem -days 365 -nodes -subj "/CN=tls.ippipp.com"
openssl s_server -accept 8443 -cert /tmp/cert.pem -key /tmp/key.pem -www
ports:
- containerPort: 8443
再创建一个对应的Service:
apiVersion: v1
kind: Service
metadata:
name: tls-backend-svc
spec:
selector:
app: tls-backend
ports:
- port: 443
targetPort: 8443
注意Service的port设为443,这样在Ingress中可以直接引用443端口,语义更清晰。
现在编写Ingress资源,关键点是添加passthrough注解,并指定backend.protocol为HTTPS(可选,但建议明确):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-passthrough-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
spec:
rules:
- host: tls.ippipp.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tls-backend-svc
port:
number: 443
应用以上配置后,Nginx Ingress Controller会为tls.ippipp.com创建一个基于SNI的TCP转发规则。当客户端访问该域名时,TLS握手会直接穿透Controller到达后端Pod,由后端的openssl s_server完成握手。
需要特别强调的是:passthrough模式下,Ingress资源中不能同时配置TLS证书(即spec.tls段),因为Controller不会用到它们。如果配置了,Controller会忽略并可能报错。另外,Ingress Controller必须能够通过SNI识别流量对应的后端,因此客户端请求必须携带正确的SNI,即使用-servername参数或直接使用域名访问。
三、测试验证TLS passthrough是否生效
部署完成后,我们可以使用curl来验证passthrough是否正常工作。假设Controller的外部IP为192.168.1.100,域名tls.ippipp.com解析到该IP(可以在本地hosts文件添加)。执行以下命令:
curl -k -v https://tls.ippipp.com
在输出中,你应该能看到类似这样的信息:
* TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Certificate (11): ... * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 * ALPN, server did not agree to a protocol
如果能看到证书信息,并且证书的CN是tls.ippipp.com(因为后端openssl自签名证书的CN我们指定了该域名),说明TLS握手确实是后端完成的,而不是Ingress Controller。你也可以通过查看后端Pod日志来确认:
kubectl logs tls-backend
日志中会显示来自客户端的连接信息,证明流量到达了后端。
如果测试失败,最常见的错误是502 Bad Gateway。这通常意味着Controller无法正确转发连接或后端没有监听正确端口。检查以下几点:
- Controller是否真的启用了
--enable-ssl-passthrough?可以通过查看Controller Pod的启动命令或日志确认。 - Ingress注解是否拼写正确?注意注解值必须是字符串
"true",且不能有多余空格。 - Service的targetPort是否指向后端容器实际监听的端口。
- 后端是否真的支持TLS?如果后端是普通HTTP服务,passthrough会失败,因为后端无法完成TLS握手。
- 客户端是否发送了正确的SNI?使用curl时可以添加
--resolve tls.ippipp.com:443:192.168.1.100来强制指定。
另一个常见问题是:Ingress Controller默认监听的是80和443端口,而passthrough流量可能需要走另一个内部代理端口。实际上,启用passthrough后,Controller会在内部启动一个TCP代理监听在--ssl-passthrough-proxy-port指定的端口(默认442),而外部443端口仍然接收所有流量,Controller根据SNI判断该走HTTP/HTTPS还是passthrough,再将连接转发到内部代理端口。因此,外部端口443必须保持开放,并且流量能够路由到Controller的443端口。
四、生产环境中的注意事项与最佳实践
在生产环境中使用TLS passthrough时,有几个关键点需要牢记。
首先是SNI的唯一性。由于passthrough依赖SNI进行路由,如果多个Ingress使用相同的域名但不同的后端,Controller将无法区分。因此,每个passthrough的Ingress必须使用唯一的域名,且客户端必须发送SNI。不支持不带SNI的TLS连接(例如某些旧客户端或使用IP直连的场景)。
其次是性能影响。passthrough模式下,Controller对每个连接只进行TCP转发,不解析HTTP,因此CPU开销比TLS termination要低。但同时,Controller无法复用HTTP层面的连接管理(如keep-alive优化),后端需要自行处理TCP连接的建立与销毁。在高并发场景下,需要评估后端服务的TCP连接处理能力。
再者是证书管理。由于证书完全由后端管理,Ingress层面无法提供证书自动更新、监控和告警。你需要为每个后端Pod建立独立的证书轮换机制,比如使用cert-manager配合CSI驱动为Pod挂载证书,或者让后端应用直接集成证书管理逻辑。
还要注意与Nginx其他功能的兼容性。开启passthrough后,该Ingress上的很多七层注解会失效,例如nginx.ingress.kubernetes.io/rewrite-target、nginx.ingress.kubernetes.io/auth-url等,因为Controller无法解析HTTP内容。你需要重新设计认证、限流等横切关注点,这些逻辑可能需要下沉到后端应用或改用其他机制。
最后,如果集群中同时存在TLS termination和TLS passthrough的Ingress,它们可以共存,但要注意域名不能冲突。Controller会根据Ingress注解和SNI来决定处理方式,通常建议将passthrough的域名单独规划,避免与常规HTTPS应用混淆。
总结来说,Kubernetes Ingress的TLS passthrough是一项强大但相对小众的功能,它解决了特定场景下端到端加密和非HTTP协议暴露的问题。通过合理配置Nginx Ingress Controller的启动参数和Ingress注解,你可以轻松实现TLS流量的原样透传。但在生产环境中,务必做好SNI规划、后端证书管理和性能测试,才能确保服务稳定可靠。
Kubernetes IngressTLS passthroughSNI修改时间:2026-08-22 13:49:16