背景:
近日,CA/B论坛服务器证书工作组(SCWG)投票通过一项重大提案《SC-081v3: 引入缩短有效期和数据重复使用期的时间表》,最终决定:从2026年起SSL/TLS证书的最大有效期将从398天逐步缩短至47天,并计划在2029年全面落实执行。
这一变革旨在通过缩短证书有效期提升验证频次,减少因SSL证书密钥泄露带来的安全风险;然而这一变化也带来管理上的挑战,尤其应对证书频繁更新和部署方面的难点。
本篇文章旨在客户端的证书维护提供便利,便于在证书过期后,和对方接口不能连通,导致业务数据报错。服务器端后面再出一篇文章。
思路:
通过编制脚本实现安装的所有证书有效期查询,根据状态及时更新证书。
功能说明
- 查询所有证书:列出 Java 信任库中的所有证书
- 解析证书信息:
- 证书别名
- 证书主题(域名信息)
- 有效期截止日期
- 剩余天数
- 状态显示:
- 已过期(红色)
- 即将过期(30天内,黄色)
- 有效(绿色)
- 日志记录:所有操作记录到
/var/log/ssl_certificate_check.log
自定义选项
- 修改
JAVA_HOME
变量以指定不同的 Java 安装路径 - 修改
KEYSTORE_PASSWORD
变量以使用不同的 keystore 密码 - 修改
LOG_FILE
变量以更改日志文件位置
注意事项
- 脚本需要
keytool
和openssl
工具 - 需要有访问 Java 信任库的权限
- 默认 keystore 密码是
changeit
,如果您的环境使用其他密码,请修改脚本 - 脚本会显示彩色输出,在非终端环境下可能不会显示颜色
读者可将此脚本添加到 cron 任务中,定期检查证书有效期,当然也可以配置邮箱提醒。
实现:
编写一个通过 OpenSSL 查询已安装证书及其到期时间的脚本。脚本里有详细注释,可参考
新建文件:/app/script/check_ssl_certs.sh
#!/bin/bash
# 加载系统及用户环境变量
source /etc/profile
source ~/.bash_profile
# 设置默认值
JAVA_HOME="${JAVA_HOME:-${JAVA_HOME}}"
KEYSTORE_FILE="${JAVA_HOME}/jre/lib/security/cacerts"
KEYSTORE_PASSWORD="${KEYSTORE_PASSWORD:-changeit}"
LOG_FILE="/var/log/ssl_certificate_check.log"
TEMP_DIR=$(mktemp -d)
CERT_FILE="${TEMP_DIR}/certificate.cer"
# 检查 Java 环境
if [ ! -f "${KEYSTORE_FILE}" ]; then
echo "错误: 找不到 keystore 文件: ${KEYSTORE_FILE}" | tee -a "${LOG_FILE}"
exit 1
fi
# 检查 keytool 是否可用
if ! command -v keytool &> /dev/null; then
echo "错误: keytool 未安装" | tee -a "${LOG_FILE}"
exit 1
fi
# 检查 openssl 是否可用
if ! command -v openssl &> /dev/null; then
echo "错误: openssl 未安装" | tee -a "${LOG_FILE}"
exit 1
fi
# 获取证书列表并解析信息
echo "正在检查 Java 信任库中的证书($(date))..." | tee -a "${LOG_FILE}"
echo "====================================" | tee -a "${LOG_FILE}"
# 使用 keytool 列出所有证书
CERT_COUNT=$(keytool -list -keystore "${KEYSTORE_FILE}" -storepass "${KEYSTORE_PASSWORD}" | grep -E "trustedCertEntry" | grep -v '\[jdk\]' | wc -l)
echo "找到 ${CERT_COUNT} 个证书" | tee -a "${LOG_FILE}"
# 遍历所有证书
keytool -list -keystore "${KEYSTORE_FILE}" -storepass "${KEYSTORE_PASSWORD}" | grep -E "trustedCertEntry" | grep -v '\[jdk\]' | while read -r line; do
ALIAS=$(echo "${line}" | awk '{print $1}' | sed 's/,//')
# 获取证书信息
keytool -exportcert -alias "${ALIAS}" -keystore "${KEYSTORE_FILE}" -storepass "${KEYSTORE_PASSWORD}" -rfc > "${CERT_FILE}"
# 使用 openssl 解析证书信息
if openssl x509 -in "${CERT_FILE}" -noout -text &>/dev/null; then
SUBJECT=$(openssl x509 -in "${CERT_FILE}" -noout -subject | sed -n 's/^subject=\s*//p')
NOT_AFTER=$(openssl x509 -in "${CERT_FILE}" -noout -enddate | sed -n 's/^notAfter=\s*//p')
# 计算剩余天数
CURRENT_DATE=$(date +%s)
EXPIRE_DATE=$(date -d "${NOT_AFTER}" +%s)
DAYS_LEFT=$(( (EXPIRE_DATE - CURRENT_DATE) / 86400 ))
# 设置状态
if [ "${DAYS_LEFT}" -lt 0 ]; then
STATUS="已过期"
COLOR="\033[31m" # 红色
elif [ "${DAYS_LEFT}" -lt 30 ]; then
STATUS="即将过期 (30天内)"
COLOR="\033[33m" # 黄色
else
STATUS="有效"
COLOR="\033[32m" # 绿色
fi
# 输出结果
echo -e "别名: ${ALIAS}" | tee -a "${LOG_FILE}"
echo -e "主题: ${SUBJECT}" | tee -a "${LOG_FILE}"
echo -e "有效期至: ${NOT_AFTER}" | tee -a "${LOG_FILE}"
echo -e "剩余天数: ${DAYS_LEFT} 天" | tee -a "${LOG_FILE}"
echo -e "状态: ${COLOR}${STATUS}\033[0m" | tee -a "${LOG_FILE}"
echo "------------------------------------" | tee -a "${LOG_FILE}"
else
echo "警告: 无法解析证书 ${ALIAS}" | tee -a "${LOG_FILE}"
fi
done
# 清理临时文件
rm -rf "${TEMP_DIR}"
echo "证书检查完成" | tee -a "${LOG_FILE}"
使用说明
- 将脚本保存为 check_ssl_certs.sh
- 添加执行权限:
chmod +x
check_ssl_certs.sh - 运行脚本:
./
check_ssl_certs.sh
效果展示:
执行后的:
查看日志: