RHEL 中更新内部 CA 证书之后,系统级工具如 curl、wget、dnf 仍然报证书验证失败,此时如果只是重复执行 update-ca-trust refresh,问题通常不会消失。这个命令本身只是一个集中刷新脚本,它不会自动扫描任意目录,也不会修正格式错误。源证书没有进入正确的锚点目录时,刷新多少次都不会出现在系统信任库中。所以排查重点应该放在 update-ca-trust 实际读取的源文件和生成结果上。

先理解 refresh 的行为:RHEL 使用 ca-certificates 软件包管理系统信任库,update-ca-trust 这个脚本会从多个源目录读取证书、黑名单和信任策略,再生成 /etc/pki/ca-trust/extracted/ 下的 PEM 文件和 Java keystore 等文件。不少情况下,注意力只放在 /etc/pki/tls/certs/ca-bundle.crt 上,但这个文件只是生成结果之一,直接修改它会被下一次 refresh 覆盖。因此,处理信任问题时,需要从源目录、生成文件和应用读取路径三个层面逐一确认。
update-ca-trust 刷新机制与常见故障现象
update-ca-trust refresh 实际上是 update-ca-trust extract 的快捷方式,它由 ca-certificates 包提供。在 RHEL 7 及之后的版本中,系统信任库的源目录包括 /usr/share/pki/ca-trust-source/ 和 /etc/pki/ca-trust/source/。其中 anchors 子目录存放用户和管理员添加的信任锚点,blacklist 存放不信任证书,policies 目录定义信任策略。执行 refresh 后,脚本会把所有锚点证书汇总为 /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem、/etc/pki/tls/certs/ca-bundle.crt、/etc/pki/ca-trust/extracted/openssl/ca-bundle.trust.crt 以及 /etc/pki/ca-trust/extracted/java/cacerts 等多个兼容格式文件。也就是说,curl、wget、openssl 这类依赖 OpenSSL 默认信任路径的程序,读取的是生成后的 bundle 文件。
最常见的故障现象有两种。第一种是管理员把内部根证书直接放到了 /etc/pki/tls/certs/ 下,认为系统会自动信任这个目录,但 update-ca-trust 并不把这个目录当作源。第二种是证书文件原本是 DER 二进制格式,或者从 Windows 导出的 .cer 文件,直接修改扩展名为 .crt 后放到锚点目录,refresh 时脚本尝试用 PEM 解析器读取,遇到非 PEM 内容会跳过而不报错,最终系统信任库中根本不包含该证书。判断方法可以用 file 命令和 openssl x509 命令检查文件内容,而不是只看扩展名。
# 检查证书实际格式 file /etc/pki/ca-trust/source/anchors/internal-ca.crt # 期望输出包含 PEM certificate # 尝试解析证书 openssl x509 -in /etc/pki/ca-trust/source/anchors/internal-ca.crt -text -noout | head -5 # 如果提示 unable to load certificate,说明需要转换格式 # 重新刷新并确认退出码 update-ca-trust refresh echo $?
证书文件格式与目录放置要求
自定义根证书必须放入 /etc/pki/ca-trust/source/anchors/ 目录,或者 /usr/share/pki/ca-trust-source/anchors/ 目录。企业环境中更推荐使用 /etc/ 下的路径,因为系统升级 ca-certificates 包时不会清空这里的自定义文件。文件名没有严格限制,但扩展名应当以 .crt 或 .pem 结尾,否则 update-ca-trust 可能不会处理该文件。例如 .der、.cer 或没有扩展名的文件,在某些版本中会被忽略。
如果证书来源是 DER 格式,必须先转换为 PEM。转换命令如下:
# 将 DER 证书转换为 PEM 格式 openssl x509 -inform DER -in internal-ca.der -out internal-ca.pem -outform PEM # 复制到锚点目录并刷新 cp internal-ca.pem /etc/pki/ca-trust/source/anchors/ update-ca-trust refresh
权限和 SELinux 也会影响刷新结果。通常锚点目录下的证书文件应当是 root:root 所有、权限至少 0644。如果 SELinux 处于 enforcing 状态,建议用 ls -lZ 查看文件安全上下文是否为 cert_t 类型。如果是从其他目录复制过来的文件,上下文可能继承自用户目录,导致 update-ca-trust 读取失败。可以用 restorecon -R /etc/pki/ca-trust/source/anchors/ 修复。另一个经常被忽略的点是:不要手工编辑 /etc/pki/ca-trust/extracted/ 下的生成文件,例如往 /etc/pki/tls/certs/ca-bundle.crt 里追加证书,因为这些文件都是刷新时重新生成的,手工修改会在下次 refresh 后丢失。
刷新后验证与排查步骤
执行 refresh 后,第一步应确认系统信任库中是否出现了自己的 CA。RHEL 提供了 trust 命令,可以列出当前所有信任锚点。用 trust list --filter=ca-anchors 输出较多,可以结合 grep 搜索证书主题中的组织名称。如果 grep 没有匹配结果,说明证书没有被纳入信任库,需要回到上一节检查源目录和格式。
# 过滤查看自定义 CA 是否进入信任库 trust list --filter=ca-anchors | grep -A 5 "Your Company Root CA" # 查看 curl 握手失败原因 curl -v https://internal.ipipp.com
curl -v 的输出中会包含 CAfile 路径和证书验证错误信息。如果看到 CAfile 不是默认的 /etc/pki/tls/certs/ca-bundle.crt,或者错误提示 unable to get local issuer certificate,说明应用可能没有读取系统刷新后的 bundle。检查环境变量 CURL_CA_BUNDLE 是否被设置过,它会把 curl 的信任库指向一个单一文件。类似地,git 可能通过 http.sslCAInfo 指定了自定义 CA 文件。这些变量和配置会绕过系统信任库,即使系统 refresh 成功,应用仍然不信任内部证书。可以临时用 --cacert 参数指向 /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem 进行测试。
还有一个低概率但实际存在的问题是系统时间错误。如果服务器时间早于证书的 notBefore 或晚于 notAfter,即使证书已进入信任库,握手仍会失败。检查 date 输出并与证书有效期比对,必要时使用 chronyd 同步时间。对于长期运行的容器,还要注意容器内没有继承宿主机的时区和时间同步。
非系统信任库场景:Java、Firefox 与容器
Java 应用不读取 RHEL 系统信任库,update-ca-trust refresh 也不会自动更新 Java 的 cacerts。虽然 update-ca-trust 会生成 /etc/pki/ca-trust/extracted/java/cacerts 文件,但大多数 Java 运行时使用自己安装目录下的 lib/security/cacerts。因此单独执行 refresh 后,Java 程序依然可能报 PKIX path building failed。需要手动使用 keytool 将内部根证书导入到实际使用的 JDK 或 JRE 的 cacerts 文件中。
# 导入内部 CA 到 Java 默认信任库 keytool -importcert -alias company-root-ca \ -keystore /usr/lib/jvm/java-11-openjdk/lib/security/cacerts \ -file /etc/pki/ca-trust/source/anchors/internal-ca.pem \ -storepass changeit -noprompt
Firefox 浏览器同样不读取系统信任库,它使用 profiles 目录下的 cert9.db 数据库。虽然可以通过导入证书到 Firefox 的证书管理器解决单台机器问题,但在企业环境中更推荐使用 p11-kit 提供的系统信任模块,或者通过 Firefox 策略文件添加证书。对于最小化服务器没有 Firefox 的情况,可以忽略这一步,但需要确认是否有基于 Java 的服务组件在运行。
容器场景需要单独处理。宿主机上的 update-ca-trust refresh 不会影响已经构建的镜像,因为系统信任库文件位于镜像层中。如果容器内部署的服务需要信任内部证书,应该在 Dockerfile 中安装 ca-certificates 包,并复制内部根证书到 /usr/local/share/ca-certificates/ 或 /etc/pki/ca-trust/source/anchors/ 后执行 update-ca-trust refresh。对于使用 Alpine 等非 RHEL 基础镜像的容器,命令会变为 update-ca-certificates,处理方式类似,但证书放置目录有所不同。
总之,update-ca-trust refresh 是一个可靠的集中刷新工具,但它只负责把规范放置的源证书生成到系统信任库中。遇到刷新后不生效时,先确认源目录、证书格式、权限和 SELinux 上下文,再检查应用是否真正读取系统信任库。把这两层边界理清,大多数证书信任故障都能在几分钟内定位。
RHEL证书刷新update-ca-trustca-certificates修改时间:2026-09-19 02:02:47