Go实现mTLS必须设ClientAuth为tls.RequireAndVerifyClientCert且ClientCAs为非空*x509.CertPool,否则静默降级为单向;客户端需同时提供Certificates和RootCAs,私钥权限须0600、无密码,ServerName须匹配证书SAN,VerifyPeerCertificate用于增强校验但需手动补基础链验证。

Go 里配双向 TLS(mTLS)不是加两个证书就完事——ClientAuth 必须设为 tls.RequireAndVerifyClientCert,且 ClientCAs 必须是非空、已加载 PEM 内容的 *x509.CertPool,否则服务端静默降级为单向,你连错误都收不到。
服务端必须同时设置 ClientAuth 和 ClientCAs
只填 ClientCAs 但漏掉 ClientAuth: tls.RequireAndVerifyClientCert,连接照样成功,客户端证书根本不会被校验。这是最隐蔽的坑。
-
ClientAuth: tls.NoClientCert(默认):完全忽略客户端证书 -
ClientAuth: tls.VerifyClientCertIfGiven:客户端自愿提供才验,不强制 -
ClientAuth: tls.RequireAndVerifyClientCert:必须提供,且必须能被ClientCAs中的根证书链验证
服务端代码中要显式构造证书池并加载 CA:
pool := x509.NewCertPool()
caData, err := os.ReadFile("ca.pem")
if err != nil {
log.Fatal(err)
}
if !pool.AppendCertsFromPEM(caData) {
log.Fatal("failed to parse root CA")
}
config := &tls.Config{
Certificates: []tls.Certificate{serverCert},
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: pool,
}
客户端必须提供证书且 RootCAs 不可省略
客户端发起 mTLS 连接时,Certificates 和 RootCAs 缺一不可。漏掉前者,服务端收不到证书;漏掉后者,客户端无法验证服务端身份,报 x509: certificate signed by unknown authority。
立即学习“go语言免费学习笔记(深入)”;
-
Certificates填的是自己的证书+私钥对,用tls.LoadX509KeyPair("client.crt", "client.key")加载 -
RootCAs填的是服务端证书的签发 CA(即和上面服务端ClientCAs同源的ca.pem),不是客户端自己的证书 - 私钥文件权限必须是
0600,否则LoadX509KeyPair静默失败 - 私钥不能加密(不能有密码),
openssl genrsa -out client.key 2048 -nodes才合规
ServerName 是客户端证书验证的前提条件
客户端不设 ServerName,TLS 握手就不会发 SNI 扩展,服务端可能返回默认证书,或导致证书域名校验失败(如报 x509: certificate is valid for example.com, not my-service.internal)。
- HTTP 场景下,要通过
http.Transport.TLSClientConfig.ServerName设置 - gRPC 场景下,
grpc.WithTransportCredentials用的credentials.NewTLS也依赖该字段 - 若服务端证书 SAN 包含 IP,
ServerName可设为对应 IP 字符串(但不推荐,优先用 DNS)
VerifyPeerCertificate 不是替代方案,而是增强手段
默认链校验只检查是否能追溯到 ClientCAs,但业务常需 OU 过滤、序列号黑名单、SAN 匹配等逻辑。这时得用 VerifyPeerCertificate 回调。
- 回调接收的是原始 DER 字节
rawCerts,需手动x509.ParseCertificate - 一旦设置了该回调,Go 就不再自动执行基础链验证,你得先调
roots.Verify补上 - 别用
InsecureSkipVerify: true上线,它跳过全部校验,mTLS 安全性归零
真正难的不是写几行配置,而是确保服务端 CA 池加载成功、客户端证书链完整、私钥无密码、ServerName 和证书 SAN 对得上——这些地方错一个,错误信息就模糊得让人抓狂。


















