错误信息
remote error: tls: bad certificate
Go 服务器记录的日志为“http: TLS handshake error from <client>: remote error: tls: bad certificate”。基于 OpenSSL 的客户端在同样的拒绝情况下发送的是别的告警(TLS 1.2 下为 unknown_ca),因此服务器端的文本取决于客户端的 TLS 库。
Go crypto/tls — TLS alert 42 received from the peer; typically logged by a Go server whose certificate a Go client rejected
含义
对端发送了 TLS 告警 42(bad_certificate)。出现在 Go 服务器的日志中(“http: TLS handshake error from …: remote error: tls: bad certificate”)时,它表示某个客户端拒绝了服务器的证书;Go 客户端在任何验证失败时(CA 未知、证书过期、名称错误)都会发送这个告警。出现在 Go 客户端中时,它表示服务器在双向 TLS 中拒绝了客户端证书。真正的原因只有发送告警的一方才能看到。
原因
Go 客户端不信任服务器的证书
常见自签名证书或私有 CA 签发的证书、缺少中间证书、证书过期或名称错误;客户端自己的日志会显示“x509: …”。
双向 TLS:服务器拒绝了客户端证书
常见当客户端证书已过期、由不受信任的 CA 签发或缺少 clientAuth 用途时,会在客户端一侧看到这个错误。
Kubernetes 准入 Webhook 和 Operator
偶见当 caBundle 不匹配时,API 服务器(一个 Go 客户端)会拒绝 Webhook 的证书,Webhook 服务器则会在日志中把它记录为 bad certificate。
修复方法
- 1.
找到拒绝证书的客户端并查看它的错误
日志中的客户端地址指明了该查看哪个服务;该服务的错误会说明实际的验证失败原因。
bash # The log line names the client; its own error message says why it rejected the certificate journalctl -u myservice | grep 'remote error: tls: bad certificate' | grep -oE 'from [0-9a-f.:]+' | sort | uniq -c - 2.
提供完整且受信任的证书链
为 Go 服务器配置包含完整证书链的 PEM 文件,证书由所有客户端都信任的 CA 签发。
go // Serve the full chain: leaf first, then intermediates, in one PEM file log.Fatal(http.ListenAndServeTLS(":443", "fullchain.pem", "server.key", nil)) - 3.
Kubernetes:检查 Webhook 的 caBundle
caBundle 必须包含签发 Webhook 服务证书的 CA;cert-manager 的 CA 注入器(CA injector)会让两者保持同步。
bash # Kubernetes webhooks: the API server verifies the webhook's certificate with caBundle kubectl get validatingwebhookconfiguration my-webhook -o jsonpath='{.webhooks[0].clientConfig.caBundle}' \ | base64 -d | openssl x509 -noout -subject -enddate