给 gRPC 加 TLS 之后,证书过期、域名不对、客户端没证书,分别会看到什么错误?已有连接会不会用上新证书?这篇用内存里生成的 CA 和证书逐项验证,所有错误文字都是真实输出。
调用:成功 服务端看到:TLS 版本 TLS 1.3;密码套件 TLS_AES_128_GCM_SHA256;ALPN 协商结果 "h2";客户端证书数 0
gRPC 用 HTTP/2,TLS 握手里通过 ALPN 协商 h2。服务端用 grpc.Creds 设置证书,客户端用 credentials 里的 TLS 设置根证书和 ServerName。
客户端不信任签发者(用另一个 CA 的池)
→ code=Unavailable message="connection error: desc = \"transport: authentication handshake failed: tls: failed to verify certificate: x509: certificate signed by unknown authority\""(1.3 ms)
域名对不上:证书只含 svc.demo.test,客户端要求 wrong.example
→ code=Unavailable message="connection error: desc = \"transport: authentication handshake failed: tls: failed to verify certificate: x509: certificate is valid for svc.demo.test, not wrong.example\""(1.2 ms)
证书已过期(昨天过期)
→ code=Unavailable message="connection error: desc = \"transport: authentication handshake failed: tls: failed to verify certificate: x509: certificate has expired or is not yet valid: current time 2026-10-12T19:17:38+08:00 is after 2026-10-11T11:17:38Z\""(1.5 ms)
证书里没有任何 SAN,只有 CN
→ code=Unavailable message="connection error: desc = \"transport: authentication handshake failed: tls: failed to verify certificate: x509: certificate relies on legacy Common Name field, use SANs instead\""(1.0 ms)
客户端没有配置根证书(用系统根,这台是 macOS 的系统验证器)
→ code=Unavailable message="connection error: desc = \"transport: authentication handshake failed: tls: failed to verify certificate: x509: “server” certificate is not trusted\""(15.6 ms)
服务端是明文,客户端用 TLS
→ code=Unavailable message="connection error: desc = \"transport: authentication handshake failed: tls: first record does not look like a TLS handshake\""(0.5 ms)
服务端最高只支持 TLS 1.2,客户端要求至少 TLS 1.3
→ code=Unavailable message="connection error: desc = \"transport: authentication handshake failed: remote error: tls: protocol version not supported\""(0.6 ms)
服务端 TLS,客户端用明文
→ code=Unavailable message="connection error: desc = \"error reading server preface: EOF\""(0.8 ms)握手失败时调用立即以 Unavailable 失败,具体原因(未知签发者、域名不对、过期、没有 SAN 等)写在 message 里,排查看这句话。
客户端没有证书 → code=Unavailable message="connection error: desc = \"error reading server preface: remote error: tls: certificate required\""(1.4 ms);服务端从证书读到的 CN="" 客户端有 other-ca 签发的证书(正常配置 Certificates) → code=Unavailable message="connection error: desc = \"error reading server preface: remote error: tls: certificate required\""(1.3 ms);服务端从证书读到的 CN="" 客户端证书由 other-ca 签发(强制发送) → code=Unavailable message="connection error: desc = \"error reading server preface: remote error: tls: unknown certificate authority\""(1.4 ms);服务端从证书读到的 CN="" 客户端证书由 demo-root-ca 签发 → 成功(1.5 ms);服务端从证书读到的 CN="client-A"
服务端要求客户端证书时,缺证书或证书不被信任都会让调用失败;成功后 handler 可以从 peer 的 TLSInfo 读到客户端证书,用证书里的身份做鉴权。
换证书之后,已有连接再调用:客户端累计握手次数 1,看到的证书 CN [server-v1] 新建一个连接:客户端累计握手次数 2,看到的证书 CN [server-v1 server-v2]
GetCertificate 回调能在服务端不重启的情况下换证书,但已建立的连接不受影响,只有新连接用新证书。
明文 新连接 + 第一次调用 0.3 ms(中位数) TLS ECDSA P-256 新连接 + 第一次调用 0.9 ms(中位数) TLS RSA 2048 新连接 + 第一次调用 1.7 ms(中位数)
握手只在新建连接时付一次;回环上 ECDSA 比 RSA 2048 快。真实网络还要加握手的往返延迟。