Istio访问容器SSL端点:K8s HTTPS访问及客户端证书转发问题
解决K8s下双向认证SSL NodeJS服务的HTTPS访问及证书转发问题
先排查503错误的核心原因
503通常是Gateway无法关联到后端服务或健康检查失败,先从以下几点确认:
- 检查后端Service的标签选择器是否与Pod标签完全匹配,执行
kubectl describe service <service-name>查看Endpoints列表是否包含正常运行的Pod - 验证Pod的存活/就绪探针配置是否正确,进入容器内执行
curl -k https://localhost:<port>确认NodeJS服务在指定端口正常监听 - 确认Gateway与后端Service的Namespace是否一致,跨Namespace访问需确保Gateway有足够权限引用目标Service
配置K8s通过HTTPS访问容器
假设使用Gateway API(对应你提到的Gateway/VirtualHost),分两种常见场景:
场景1:Gateway终止SSL(推荐)
由Gateway处理SSL握手,后端仅处理HTTP流量,简化服务配置:
- 创建Gateway使用的SSL证书Secret:
kubectl create secret tls gateway-tls --cert=./server.crt --key=./server.key -n <gateway-namespace>
- 定义Gateway资源,开启HTTPS监听并关联证书:
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: my-gateway namespace: <gateway-namespace> spec: gatewayClassName: <your-gateway-class> # 如nginx、istio,需匹配你的Ingress Controller类型 listeners: - name: https port: 443 protocol: HTTPS tls: mode: Terminate certificateRefs: - name: gateway-tls
- 配置HTTPRoute关联后端Service:
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: nodejs-service-route namespace: <service-namespace> spec: parentRefs: - name: my-gateway namespace: <gateway-namespace> hostnames: - "your-domain.com" rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: nodejs-service port: <service-port> # 对应NodeJS服务的监听端口,如3000
场景2:SSL直通(后端处理SSL)
让SSL流量直接转发到后端NodeJS服务,由服务自行处理SSL握手:
apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: my-gateway namespace: <gateway-namespace> spec: gatewayClassName: <your-gateway-class> listeners: - name: https-passthrough port: 443 protocol: TLS tls: mode: Passthrough --- apiVersion: gateway.networking.k8s.io/v1 kind: TLSRoute metadata: name: nodejs-tls-route namespace: <service-namespace> spec: parentRefs: - name: my-gateway namespace: <gateway-namespace> hostnames: - "your-domain.com" rules: - backendRefs: - name: nodejs-service port: <nodejs-ssl-port> # 如443,后端服务的SSL监听端口
客户端SSL证书转发至容器
根据SSL处理场景不同,配置方式有差异:
场景1:Gateway终止SSL时转发证书
需要让Gateway提取客户端证书内容,通过请求头传递给后端:
- 修改Gateway的HTTPS监听,启用双向认证(要求客户端提供证书):
listeners: - name: https port: 443 protocol: HTTPS tls: mode: Terminate certificateRefs: - name: gateway-tls clientCertificate: certificateRefs: - name: ca-cert # 存放信任CA根证书的Secret
创建信任CA的Secret:
kubectl create secret generic ca-cert --from-file=ca.crt=./ca-root.crt -n <gateway-namespace>
- 修改HTTPRoute,添加请求头转发配置:
apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: nodejs-service-route namespace: <service-namespace> spec: parentRefs: - name: my-gateway namespace: <gateway-namespace> hostnames: - "your-domain.com" rules: - matches: - path: type: PathPrefix value: / filters: - type: RequestHeaderModifier requestHeaderModifier: set: - name: X-Client-Cert value: "%{SSL_CLIENT_CERT}" # 变量语法需匹配Gateway Controller,Nginx用$ssl_client_cert,Istio用%DOWNSTREAM_PEER_CERT% backendRefs: - name: nodejs-service port: <service-port>
- 后端NodeJS服务从请求头提取证书:
app.get('/', (req, res) => { const clientCert = req.headers['x-client-cert']; if (clientCert) { // 解析证书内容,验证合法性等 res.send(`Received client cert: ${clientCert}`); } else { res.status(403).send('Client certificate required'); } });
场景2:SSL直通时转发证书
此场景下,客户端证书会在SSL握手阶段直接传递给后端NodeJS服务,无需额外配置Gateway,后端可通过NodeJS的内置API获取:
https.createServer({ key: fs.readFileSync('./server.key'), cert: fs.readFileSync('./server.crt'), ca: fs.readFileSync('./ca-root.crt'), requestCert: true, rejectUnauthorized: true }, (req, res) => { const clientCert = req.socket.getPeerCertificate(); // 处理客户端证书 res.send(`Client cert subject: ${clientCert.subject.CN}`); }).listen(443);
内容的提问来源于stack exchange,提问作者Antoine
相关产品推荐
相关产品推荐

