EKS集群gRPC Server启用TLS后拒绝连接问题求助
gRPC TLS 配置故障排查与解决方案
问题背景
使用cert-manager生成的tls.crt、tls.key和ca.crt搭建带客户端认证的gRPC TLS服务器,结合Istio网格部署。仅当SERVER_TLS_ENABLED=false时调用正常,开启TLS后遇到多类错误,包括Istio SDS相关报错、连接终止、证书信任问题,同时健康探针在TLS开启时失败。
错误场景回顾
- 场景1:开启TLS+配置Istio DestinationRule/PeerAuthentication,grpcurl调用报错:
❯ grpcurl -proto ../grpc-server/proto/greeter.proto -d '{ "name": "Chase" }' grpc-server.dev-cluster.xxx.xxxx.xx.com:31111 example.Greeter/SayHello ERROR: Code: Unavailable Message: upstream connect error or disconnect/reset before headers. retried and the latest reset reason: remote connection failure, transport failure reason: TLS error: Secret is not supplied by SDS - 场景2:开启TLS但删除Istio规则,带客户端证书调用报错:
❯ grpcurl -proto ../grpc-server/proto/greeter.proto -d '{ "name": "Chase" }' -cert="tls.crt" -key="tls.key" grpc-server.dev-cluster.xxx.xxxx.xx.com:31111 example.Greeter/SayHello ERROR: Code: Unavailable Message: upstream connect error or disconnect/reset before headers. reset reason: connection termination - 场景3:额外指定CA证书后出现信任错误:
❯ grpcurl -proto ../grpc-server/proto/greeter.proto -d '{ "name": "Chase" }' -cacert="ca.crt" -cert="tls.crt" -key="tls.key" grpc-server.dev-cluster.xxx.xxxx.xx.com:31111 example.Greeter/SayHello Failed to dial target host "grpc-server.dev-cluster.xxx.xxxxx.xx.com:31111": tls: failed to verify certificate: x509: certificate signed by unknown authority - 场景4:关闭TLS时调用正常,健康探针也正常。
排查与解决步骤
1. 解决Istio SDS证书供应问题(场景1)
当Istio PeerAuthentication开启严格TLS模式时,sidecar会期望通过SDS(Secret Discovery Service)获取证书,而非直接挂载Kubernetes Secret:
- 替换cert-manager颁发者为IstioIssuer/ClusterIstioIssuer,普通ClusterIssuer/Issuer无法被Istio SDS识别。
- 同步DestinationRule的TLS配置与PeerAuthentication模式:
apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: grpc-server spec: host: grpc-server.dev-cluster.svc.cluster.local trafficPolicy: tls: mode: STRICT credentialName: grpc-server-tls # 对应cert-manager生成的Secret名称 - 验证sidecar证书加载状态:
确认kubectl exec -it <pod-name> -c istio-proxy -- curl http://localhost:15000/certsgrpc-server-tls对应的证书状态为READY。
2. 修复gRPC服务端TLS配置(场景2、3)
证书SAN匹配检查
验证服务端证书的**Subject Alternative Name(SAN)**是否包含外部访问域名:
openssl x509 -in tls.crt -text -noout | grep -A 1 "Subject Alternative Name"
若缺失目标域名,更新cert-manager的Certificate资源:
apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: grpc-server-tls spec: dnsNames: - grpc-server.dev-cluster.svc.cluster.local - grpc-server.dev-cluster.xxx.xxxx.xx.com # 添加外部访问域名 issuerRef: name: your-istio-issuer kind: ClusterIstioIssuer
证书信任链修复(场景3)
验证CA证书是否能正确验证服务端证书:
openssl verify -CAfile ca.crt tls.crt
若验证失败,确保cert-manager生成的Secret包含完整证书链,同时在Certificate资源中指定正确的证书用途:
spec: usages: - server auth - client auth
服务端TLS代码校验
确保服务端正确加载证书并启用客户端认证:
// 加载服务端证书 serverCert, err := tls.LoadX509KeyPair("tls.crt", "tls.key") if err != nil { log.Fatalf("Failed to load server cert: %v", err) } // 加载CA证书用于验证客户端 caCert, err := os.ReadFile("ca.crt") if err != nil { log.Fatalf("Failed to read CA cert: %v", err) } certPool := x509.NewCertPool() if !certPool.AppendCertsFromPEM(caCert) { log.Fatalf("Failed to add CA cert to pool") } // 配置TLS creds := credentials.NewTLS(&tls.Config{ Certificates: []tls.Certificate{serverCert}, ClientCAs: certPool, ClientAuth: tls.RequireAndVerifyClientCert, }) // 启动gRPC服务器 server := grpc.NewServer(grpc.Creds(creds))
3. 修复健康探针问题
开启TLS后,grpc_health_probe需指定TLS参数:
livenessProbe: exec: command: - grpc_health_probe - -addr=:50051 - -tls - -tls-cert=/mnt/certs/tls.crt - -tls-key=/mnt/certs/tls.key - -tls-ca-cert=/mnt/certs/ca.crt initialDelaySeconds: 5 periodSeconds: 10
确保命令中证书路径与容器内挂载路径一致。
4. 端到端流量路径验证
- 检查Istio Gateway配置(通过Ingress访问时):
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: grpc-gateway spec: selector: istio: ingressgateway servers: - port: number: 31111 name: grpc-tls protocol: GRPC tls: mode: SIMPLE credentialName: grpc-server-tls hosts: - grpc-server.dev-cluster.xxx.xxxx.xx.com - 直接测试Pod IP访问:若绕过Istio后调用正常,说明问题出在Istio配置;若仍失败,排查服务端TLS本身的问题。
内容的提问来源于stack exchange,提问作者Cdhippen
相关产品推荐
相关产品推荐

