openssl x509、openssl verify、s_client、curl 区分证书过期、信任链和域名问题。隔离边界:所有文件和监听都放在一次性 Linux 虚拟机或本地容器的 /tmp/lab-cert 与 127.0.0.1:8443,不要替换宿主机或生产环境的证书,不要修改系统信任库。需要 OpenSSL 1.1.1+ 和 curl。
openssl version
mkdir -p /tmp/lab-cert
cd /tmp/lab-cert
本页用 openssl x509 -req -days -1 签发 notAfter 在过去的证书。生成后必须检查日期;如果本机 OpenSSL 不接受负数天数,请改用 Linux 虚拟机或 OpenSSL 容器执行。
先生成 CA,再签发一张已经过期的服务器证书:
cd /tmp/lab-cert
openssl req -x509 -newkey rsa:2048 -nodes -sha256 -days 30 \
-keyout ca.key -out ca.crt -subj '/CN=Lab CA'
openssl req -new -newkey rsa:2048 -nodes -sha256 \
-keyout server.key -out server.csr -subj '/CN=lab.local'
printf 'subjectAltName=DNS:lab.local\n' > server.ext
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-days -1 -sha256 -extfile server.ext -out server.crt
openssl x509 -in server.crt -noout -subject -issuer -dates
预期 notAfter 已经早于当前时间。启动只监听回环地址的 HTTPS 服务:
timeout 180 openssl s_server -accept 127.0.0.1:8443 \
-cert server.crt -key server.key -www > /tmp/lab-cert/s_server.log 2>&1 &
echo $! > /tmp/lab-cert/s_server.pid
sleep 2
timeout 180 是兜底,服务最多存活 3 分钟;不要把它改成公网监听地址。
openssl x509 -in server.crt -noout -dates -checkend 0; echo "checkend_exit=$?"
openssl verify -CAfile ca.crt server.crt; echo "verify_exit=$?"
curl -sv --cacert ca.crt --resolve lab.local:8443:127.0.0.1 \
https://lab.local:8443/ -o /dev/null 2>&1 | grep -E 'expired|SSL certificate|subject|issuer'
预期 -checkend 0 退出码为 1,openssl verify 报 error 10 at 0 depth lookup: certificate has expired,curl 报 SSL certificate problem: certificate has expired。如果 curl 报 self-signed certificate,说明 --cacert 没生效;如果报 no alternative certificate subject name matches,说明 SAN 配置有问题。这两类错误与过期不是一回事。
用 s_client 看服务端实际下发的证书:
echo | openssl s_client -connect 127.0.0.1:8443 \
-servername lab.local -CAfile ca.crt 2>&1 | \
grep -E 'Verify return code|verify error|subject=|issuer='
预期 Verify return code: 10 (certificate has expired)。这一步验证服务确实在使用这张过期证书,而不是客户端缓存了旧证书。
openssl x509 -noout -dates 看有效期,再用 date -u 对比当前时间。客户端时钟漂移也会造成“看起来过期”。openssl verify -CAfile 单独验证证书链;用 s_client -servername 验证服务端实际下发的证书。两者结果可能不同,不能只看其中一个。curl -v 看错误文本:certificate has expired 是过期,self-signed certificate 是信任链问题,no alternative certificate subject name 是 SAN/主机名问题,unable to get local issuer certificate 是中间证书缺失。用同一个 CA 重新签发有效期正常的证书,替换后重启服务:
cd /tmp/lab-cert
openssl req -new -newkey rsa:2048 -nodes -sha256 \
-keyout server-new.key -out server-new.csr -subj '/CN=lab.local'
openssl x509 -req -in server-new.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
-days 30 -sha256 -extfile server.ext -out server-new.crt
kill "$(cat /tmp/lab-cert/s_server.pid)" 2>/dev/null || true
sleep 1
mv server-new.crt server.crt && mv server-new.key server.key
timeout 120 openssl s_server -accept 127.0.0.1:8443 \
-cert server.crt -key server.key -www > /tmp/lab-cert/s_server.log 2>&1 &
echo $! > /tmp/lab-cert/s_server.pid
sleep 2
curl -s --cacert ca.crt --resolve lab.local:8443:127.0.0.1 \
https://lab.local:8443/ -o /dev/null -w 'http_code=%{http_code}\n'
http_code=200 表示新证书可用。生产环境应该用受信 CA 签发并通过 cert-manager、Vault 或云证书服务自动续期;轮换后要验证服务端实际下发的证书序列号和到期时间。
kill "$(cat /tmp/lab-cert/s_server.pid)" 2>/dev/null || true
rm -rf /tmp/lab-cert
本页没有修改系统信任库和 Kubernetes 对象。如果误将证书写到了其他路径,先核对路径再删除,不要对 /etc/ssl 执行递归删除。
curl 报 certificate has expired 与 self-signed certificate 分别说明什么?