3、故障排查工具:openssl命令行工具、keytool工具、curl与wget的证书验证、日志分析技巧

说实话,证书轮换出问题的时候,最怕的就是两眼一抹黑。你明明觉得配置没问题,但服务就是报错。这时候,手里有几把趁手的工具就特别重要了。

我个人习惯,排查证书问题从来不用图形界面。命令行工具才是王道。它们直接、快速,而且能让你看到最原始的数据。今天我就把压箱底的几样工具拿出来,跟你好好聊聊。

核心思路: 证书问题的本质是信任链断裂或格式不匹配。所有工具都是围绕「验证证书内容」和「验证信任链」这两个点展开的。

3.1 openssl:瑞士军刀,没有之一

openssl 是我用得最多的工具。它几乎能解决所有跟证书相关的疑问。你想想看,一个命令就能把证书的里里外外看个透。

3.1.1 查看证书详情

拿到一个 .crt 或 .pem 文件,第一件事就是看它的内容。别信文件名,信命令输出。

# 查看 PEM 格式证书
openssl x509 -in server.crt -text -noout

# 查看 DER 格式证书(Windows 常见)
openssl x509 -in server.der -inform DER -text -noout

输出里重点看这几个字段:

  • Subject:证书颁发给谁
  • Issuer:谁颁发的
  • Validity:有效期,Not Before 和 Not After
  • Subject Public Key Info:密钥算法和长度
  • X509v3 extensions:特别是 Subject Alternative Name (SAN)

我的习惯: 每次轮换后,我都会用这个命令对比新旧证书的序列号。如果序列号一样,说明你根本没换成功。我曾经遇到过运维同事跑错了脚本,新旧证书是同一张,排查了半天。

3.1.2 验证证书链

单张证书没问题,不代表链没问题。这是最坑的地方。

# 验证证书链
openssl verify -CAfile ca-chain.pem server.crt

# 如果有多级中间证书
openssl verify -CAfile root.pem -untrusted intermediate.pem server.crt

输出 server.crt: OK 才算通过。如果报错,常见的有:

  • unable to get local issuer certificate:找不到颁发者证书,链不完整
  • certificate has expired:证书过期了
  • self-signed certificate in chain:链里混进了自签名证书

注意: openssl verify 默认不检查 SAN 和 CN 匹配。它只检查证书链的合法性。域名匹配要用其他方法。

3.1.3 测试 SSL/TLS 连接

服务端证书到底有没有生效?直接连上去看看。

# 连接服务并显示证书
openssl s_client -connect example.com:443 -servername example.com

# 指定 CA 证书验证
openssl s_client -connect example.com:443 -CAfile ca-chain.pem

# 显示完整证书链
openssl s_client -connect example.com:443 -showcerts

-servername 参数很重要。SNI(Server Name Indication)依赖它。不加这个参数,你可能拿到的是默认证书,而不是你想要的。

我记得有一次,客户说证书轮换后手机端报错,但浏览器正常。我用 openssl s_client 一测,发现不传 SNI 时返回的是旧证书。原来是负载均衡器配置没更新,SNI 匹配规则有问题。

3.2 keytool:Java 生态的守门员

如果你跟 Java 应用打交道,keytool 是绕不开的。它管理的是 Java KeyStore (JKS) 或 PKCS12 格式的密钥库。

3.2.1 查看密钥库内容

# 查看 JKS 内容
keytool -list -v -keystore keystore.jks -storepass changeit

# 查看 PKCS12 内容
keytool -list -v -keystore keystore.p12 -storetype PKCS12 -storepass changeit

输出会列出所有条目,包括:

  • 别名(Alias)
  • 条目类型(PrivateKeyEntry / trustedCertEntry)
  • 证书指纹(MD5、SHA1、SHA256)
  • 有效期

避坑指南: 我曾经遇到过开发人员把私钥和证书链分开导入,结果 alias 不一致,应用启动报错。建议统一使用一个 alias,比如用域名。

3.2.2 导入导出证书

# 导出证书
keytool -exportcert -alias mydomain -keystore keystore.jks -file mydomain.cer

# 导入信任证书
keytool -importcert -alias ca-root -file root.cer -keystore truststore.jks

这里有个坑:导入信任证书时,如果 truststore 不存在,keytool 会创建它。但默认密码是 changeit,很多人忘了改。

3.2.3 验证 SSL 连接(Java 视角)

# 用指定信任库连接服务
keytool -printcert -sslserver example.com:443 -J-Djavax.net.ssl.trustStore=truststore.jks

这个命令能模拟 Java 应用的行为。如果这里报错,你的 Java 应用大概率也会报错。

3.3 curl 与 wget:HTTP 层的证书验证

这两个工具是我们日常测试 HTTPS 最常用的。但很多人只用来下载文件,忽略了它们的证书验证能力。

3.3.1 curl 的证书验证

# 显示证书信息
curl -vI https://example.com

# 指定 CA 证书
curl --cacert ca-chain.pem https://example.com

# 忽略证书验证(仅测试用)
curl -k https://example.com

-v 输出里,你会看到:

  • * SSL connection using TLSv1.3 / AES256-GCM-SHA384
  • * Server certificate:
  • * subject: CN=example.com
  • * start date: ...
  • * expire date: ...
  • * issuer: C=US; O=Let's Encrypt; CN=R3
  • * SSL certificate verify ok.

警告: -k 或 --insecure 只能用于临时测试。生产环境绝对不要用。我见过有人把 -k 写进脚本里,结果证书过期了都没发现。

3.3.2 wget 的证书验证

# 显示证书信息
wget -d https://example.com

# 指定 CA 证书
wget --ca-certificate=ca-chain.pem https://example.com

# 忽略证书验证
wget --no-check-certificate https://example.com

wget 的 -d(debug)输出比 curl 更详细,但可读性差一些。我个人更习惯用 curl。

3.3.3 对比总结

特性 curl wget
证书信息输出 简洁,易读 详细,但杂乱
指定 CA 证书 --cacert --ca-certificate
忽略验证 -k --no-check-certificate
支持协议 更多(HTTP/2, gRPC) 较少
脚本友好度 高 中

说白了,日常调试用 curl,批量下载用 wget。

3.4 日志分析技巧:从报错到根因

工具只能帮你拿到数据,真正的功夫在于分析日志。证书相关的错误日志,其实模式很固定。

3.4.1 常见错误模式

日志关键字 可能原因 排查方向
certificate has expired 证书过期 检查有效期,重新申请
unable to find valid certification path 信任链不完整 检查中间证书是否导入
hostname in certificate didn't match 域名不匹配 检查 SAN 和 CN
self-signed certificate 使用了自签名证书 导入 CA 证书到信任库
SSL handshake failed 协议或密码套件不匹配 检查 TLS 版本和密码套件

3.4.2 我的日志分析流程

  1. 先看时间戳:错误是轮换后立即出现,还是过了一段时间才出现?这能区分是配置问题还是证书过期问题。
  2. 再看错误栈:Java 的 javax.net.ssl.SSLHandshakeException 后面通常会跟一个 cause。这个 cause 才是根因。
  3. 最后看上下文:错误发生在哪个客户端?哪个服务端?是不是只有特定客户端报错?

我的经验: 有一次,Nginx 日志里全是 SSL: error:14094418,看起来像证书问题。但我用 openssl 测了没问题。最后发现是客户端时间不同步,差了 2 个小时,导致证书被认为「尚未生效」。所以,排查证书问题,别忘了检查系统时间。

3.4.3 日志分析命令

# 过滤证书相关错误
grep -i "certificate\|ssl\|handshake" /var/log/nginx/error.log

# 查看特定时间段的日志
sed -n '/2024-01-15 10:00/,/2024-01-15 11:00/p' /var/log/nginx/error.log | grep -i error

# 统计错误类型
awk '{for(i=1;i<=NF;i++) if($i ~ /error|failed/) print $i}' /var/log/nginx/error.log | sort | uniq -c | sort -rn

这些命令能帮你快速定位问题范围。

3.5 本章知识体系

下面这张图,总结了我们今天聊的所有工具和它们的使用场景。

证书故障排查工具知识体系 证书故障排查 openssl • 查看证书详情 • 验证证书链 • 测试 SSL 连接 keytool • 管理 JKS/PKCS12 • 导入导出证书 • 模拟 Java 验证 curl / wget • HTTP 层证书验证 • 指定 CA 证书 • 忽略验证(测试) 日志分析 • 识别错误模式 • 过滤关键字 • 定位根因 核心原则:验证证书内容 → 验证信任链 → 验证域名匹配 → 检查系统时间 💡 排查顺序建议 1. 先用 openssl 确认证书文件本身没问题 2. 再用 curl 测试 HTTP 层是否正常 3. 最后看应用日志,确认客户端是否报错

嗯,工具就这些。但记住,工具只是手段。真正值钱的是你分析问题的思路。下次遇到证书报错,别慌。按这个流程走一遍,大部分问题都能定位到。