错误信息
x509: certificate relies on legacy Common Name field, use SANs instead
也可能输出为
- tls: failed to verify certificate: x509: certificate relies on legacy Common Name field, use SANs instead
在 TLS 拨号中(Go 1.20+),这段文本前面会加上“tls: failed to verify certificate: ”,HTTP 客户端还会加上“Get \"https://…\": ”。用 Go 构建的程序(kubectl、Terraform、Docker、Prometheus、Vault CLI)打印的是同样的文本。
Go crypto/x509 — HostnameError for a certificate without subjectAltName (Go 1.15+)
含义
服务器证书没有主题备用名称(SAN)扩展,因此主机名只出现在主体的通用名称中。按照 RFC 6125 和 CA/Browser Forum 的规则,Go 从 Go 1.15 开始不再接受通用名称中的主机名(自 1.17 起完全不接受),并且在 CN 本来可以匹配时会明确说明这一点。修复方法是使用带 SAN 的证书;客户端已经没有可以打开的开关了。
原因
生成证书时没有加 subjectAltName
常见不带 -addext subjectAltName 的 openssl req -x509 -subj "/CN=host",或者签名 CSR 时不带 -copy_extensions/-extfile 的 openssl x509 -req,生成的正是这种证书。
内部 CA 的证书模板早于 SAN 要求
常见旧的 Active Directory 证书服务模板、遗留脚本以及硬件设备内置的 CA,常常签发只有 CN 的证书。
设备和旧软件自行生成的证书
偶见一些硬件设备、数据库和中间件会在首次启动时生成只有 CN 的证书。
修复方法
- 1.
确认缺少 SAN 扩展
打印服务器所提供证书的主体和 subjectAltName。
bash echo | openssl s_client -connect api.example.com:443 -servername api.example.com 2>/dev/null \ | openssl x509 -noout -subject -ext subjectAltName # No "X509v3 Subject Alternative Name" in the output -> reissue the certificate - 2.
带上 subjectAltName 重新签发
把每个 DNS 名称(如果客户端使用 IP 地址,也包括 IP 地址)都写进 subjectAltName。用 openssl x509 -req 签名 CSR 时,除非传入 -copy_extensions copy 或 -extfile,否则 CSR 中的扩展会被丢弃。
bash openssl req -new -key server.key -subj "/CN=api.example.com" \ -addext "subjectAltName=DNS:api.example.com" -out server.csr # when signing with "openssl x509 -req", keep the extension: openssl x509 -req -in server.csr -CA ca.pem -CAkey ca.key -days 90 -copy_extensions copy -out server.pem - 3.
不要寻找 Go 的开关
临时的 GODEBUG=x509ignoreCN=0 应急开关已在 Go 1.17 中移除,因此重新签发证书是唯一的修复方法。
text GODEBUG=x509ignoreCN=0 only worked in Go 1.15–1.16 and was removed in Go 1.17; there is no switch left in current Go releases. The certificate must carry SANs.
相关错误
x509: certificate is valid for example.com, not api.example.comGo crypto/x509x509: certificate is not valid for any names, but wanted to match api.example.c…Go crypto/x509No subject alternative names presentJava (JSSE HostnameChecker)tls: failed to verify certificate: x509: certificate signed by unknown authorityGo crypto/tls (Go ≥ 1.20)