CA 证书详解:从原理到实践的完整教程 / 第 4 章:系统证书存储
第 4 章:系统证书存储
操作系统的证书信任存储是 PKI 体系在终端的"最后一公里"。本章详解各 Linux 发行版的证书存储机制、管理工具和更新流程。
4.1 证书存储概览
为什么需要系统证书存储
应用程序(curl, wget, Python requests, Go net/http ...)
│
▼
┌─────────────┐
│ 系统证书存储 │ ← 所有受信任的根 CA 证书
│ Trust Store │
└──────┬──────┘
│
├── 验证远程服务器证书
├── 构建信任链
└── 判断证书是否可信
各语言/工具如何使用系统证书存储
| 语言/工具 | 默认行为 | 自定义方式 |
|---|
| curl / wget | 使用系统证书存储 | --cacert / --ca-directory |
| Python requests | 使用 certifi 包(独立) | REQUESTS_CA_BUNDLE 环境变量 |
| Go | 使用系统证书存储 | SSL_CERT_FILE / SSL_CERT_DIR |
| Java | 使用 cacerts keystore | -Djavax.net.ssl.trustStore |
| Node.js | 使用系统证书存储(OpenSSL) | NODE_EXTRA_CA_CERTS |
| OpenSSL | 编译时指定的路径 | SSL_CERT_FILE / SSL_CERT_DIR |
⚠️ 注意:Python 的 requests 库默认使用 certifi 包自带的 CA 列表,不使用系统证书存储。如果你添加了自定义 CA 到系统存储,Python requests 不会自动信任它。
4.2 Debian / Ubuntu 证书存储
目录结构
/etc/ssl/
├── certs/ # 符号链接目录,指向实际证书文件
│ ├── ca-certificates.crt # 合并的 CA 证书文件
│ ├── DigiCert_Global_Root_CA.pem -> ...
│ └── ...
├── openssl.cnf # OpenSSL 配置文件
└── private/ # 私钥目录
/usr/share/ca-certificates/ # CA 证书源文件
├── mozilla/ # Mozilla 维护的根证书
│ ├── DigiCert_Global_Root_CA.crt
│ ├── ISRG_Root_X1.crt
│ └── ...
└── ...
/usr/local/share/ca-certificates/ # 用户自定义 CA 证书
ca-certificates 包
# 查看 ca-certificates 包信息
dpkg -l ca-certificates
apt show ca-certificates
# 包含的脚本
dpkg -L ca-certificates | grep -E "bin|sbin|script"
# /usr/sbin/update-ca-certificates
管理命令
# 更新证书存储(添加/删除后必须执行)
sudo update-ca-certificates
# 详细模式
sudo update-ca-certificates --fresh
# 查看当前信任的证书数量
ls /etc/ssl/certs/*.pem | wc -l
# 添加自定义 CA
sudo cp my-ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
# 输出: 1 added, 0 removed; done.
# 删除自定义 CA
sudo rm /usr/local/share/ca-certificates/my-ca.crt
sudo update-ca-certificates
# 输出: 0 added, 1 removed; done.
# 禁用某个 CA(blacklist)
sudo vim /etc/ca-certificates.conf
# 将对应行改为 ! 前缀:
# !mozilla/DigiCert_Global_Root_CA.crt
sudo update-ca-certificates
update-ca-certificates 工作原理
1. 读取 /etc/ca-certificates.conf(可禁用特定 CA)
2. 扫描 /usr/share/ca-certificates/(系统 CA)
3. 扫描 /usr/local/share/ca-certificates/(用户 CA)
4. 过滤掉标记为 ! 的证书
5. 在 /etc/ssl/certs/ 创建符号链接
6. 合并生成 /etc/ssl/certs/ca-certificates.crt
7. 运行 hooks(/etc/ca-certificates/update.d/)
4.3 RHEL / CentOS / Fedora 证书存储
目录结构
/etc/pki/
├── tls/
│ ├── certs/
│ │ └── ca-bundle.crt # 系统 CA 证书合集
│ ├── openssl.cnf
│ └── private/
└── ca-trust/
├── extracted/
│ └── pem/
│ └── tls-ca-bundle.pem # 提取的 TLS CA 证书
├── source/
│ ├── anchors/ # 用户信任的 CA 证书
│ └── blacklist/ # 用户不信任的 CA 证书
└── README
/usr/share/pki/ca-trust-source/
├── ca-bundle.trust.crt # 带信任信息的证书合集
└── ...
管理命令
# 更新证书存储
sudo update-ca-trust
# 提取模式
sudo update-ca-trust extract
# 查看当前信任的证书
trust list | head -30
# 添加自定义 CA
sudo cp my-ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust extract
# 黑名单 CA
sudo cp untrusted-ca.crt /etc/pki/ca-trust/source/blacklist/
sudo update-ca-trust extract
# 使用 trust 工具管理
sudo trust anchor --store my-ca.crt # 添加
sudo trust anchor --remove my-ca.crt # 删除
RHEL 9 / CentOS Stream 9 变化
# RHEL 9 使用 p11-kit 作为后端
# 查看信任策略
trust list --filter=ca-anchors | grep "DigiCert"
# 设置证书信任级别
sudo trust anchor --store --label "My CA" my-ca.crt
4.4 Alpine Linux 证书存储
# Alpine 使用 ca-certificates 包 + update-ca-certificates
apk add ca-certificates
# 证书目录
ls /etc/ssl/certs/
# 添加自定义 CA
cp my-ca.crt /usr/local/share/ca-certificates/
update-ca-certificates
# Alpine 的证书包基于 Mozilla 的证书列表
apk info ca-certificates
4.5 Arch Linux 证书存储
# Arch 使用 ca-certificates 基于 p11-kit
pacman -S ca-certificates
# 管理工具
trust list # 查看信任的 CA
sudo trust anchor my-ca.crt # 添加
sudo trust anchor --remove my-ca.crt # 删除
# 证书路径
ls /etc/ssl/certs/
4.6 各发行版对比
| 发行版 | 包名 | 更新命令 | 自定义 CA 路径 | 黑名单路径 |
|---|
| Debian/Ubuntu | ca-certificates | update-ca-certificates | /usr/local/share/ca-certificates/ | /etc/ca-certificates.conf |
| RHEL/CentOS | ca-certificates | update-ca-trust extract | /etc/pki/ca-trust/source/anchors/ | /etc/pki/ca-trust/source/blacklist/ |
| Fedora | ca-certificates | update-ca-trust extract | /etc/pki/ca-trust/source/anchors/ | /etc/pki/ca-trust/source/blacklist/ |
| Alpine | ca-certificates | update-ca-certificates | /usr/local/share/ca-certificates/ | 手动编辑 |
| Arch | ca-certificates | trust anchor | trust anchor 命令 | trust anchor --remove |
| SUSE | ca-certificates | update-ca-certificates | /usr/share/pki/trust/anchors/ | /usr/share/pki/trust/blacklist/ |
4.7 OpenSSL 的证书路径
编译时配置
# 查看 OpenSSL 的默认证书路径
openssl version -d
# OPENSSLDIR: "/usr/lib/ssl"
# 查看完整的编译配置
openssl version -a | grep -E "OPENSSLDIR|ENGINESDIR"
# 证书搜索路径
ls "$(openssl version -d | cut -d'"' -f2)/certs/"
ls "$(openssl version -d | cut -d'"' -f2)/cert.pem"
环境变量覆盖
# 覆盖默认证书文件
export SSL_CERT_FILE=/path/to/custom-ca-bundle.crt
openssl s_client -connect example.com:443 </dev/null
# 覆盖默认证书目录
export SSL_CERT_DIR=/path/to/custom-certs/
openssl s_client -connect example.com:443 </dev/null
# 同时设置(推荐)
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
export SSL_CERT_DIR=/etc/ssl/certs/
openssl.cnf 配置
# 查看默认配置文件位置
openssl version -d
# 编辑 openssl.cnf
cat /etc/ssl/openssl.cnf | grep -A5 "CA_default"
# 可以在配置文件中指定 CA 路径
# [ ca ]
# default_ca = CA_default
#
# [ CA_default ]
# dir = /etc/ssl/my-ca
# certs = $dir/certs
# crl_dir = $dir/crl
# database = $dir/index.txt
4.8 在容器中管理证书
Docker
# 方法 1:直接复制证书文件
FROM ubuntu:22.04
COPY my-ca.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates
# 方法 2:使用构建参数
FROM ubuntu:22.04
ARG CA_CERT
RUN echo "$CA_CERT" > /usr/local/share/ca-certificates/custom-ca.crt && \
update-ca-certificates
# Alpine
FROM alpine:3.18
COPY my-ca.crt /usr/local/share/ca-certificates/
RUN update-ca-certificates
# 构建时传入证书
docker build --build-arg CA_CERT="$(cat my-ca.crt)" -t myapp .
# 运行时挂载证书
docker run -v /path/to/my-ca.crt:/usr/local/share/ca-certificates/my-ca.crt:ro \
myapp sh -c "update-ca-certificates && my-command"
Kubernetes ConfigMap
# 将自定义 CA 作为 ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: custom-ca
data:
my-ca.crt: |
-----BEGIN CERTIFICATE-----
MIIDxxxxxxx...
-----END CERTIFICATE-----
---
# 挂载到 Pod
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: ca-volume
mountPath: /usr/local/share/ca-certificates/
readOnly: true
volumes:
- name: ca-volume
configMap:
name: custom-ca
4.9 系统证书存储的更新机制
Debian/Ubuntu 自动更新
# ca-certificates 包通过 apt 更新
sudo apt update && sudo apt install ca-certificates
# 查看最近更新
apt changelog ca-certificates | head -30
# 自动安全更新(unattended-upgrades)
cat /etc/apt/apt.conf.d/50unattended-upgrades | grep ca-certificates
RHEL/CentOS 自动更新
# 通过 yum/dnf 更新
sudo dnf update ca-certificates
# 查看包信息
rpm -qi ca-certificates
# 自动更新(yum-cron / dnf-automatic)
sudo dnf install dnf-automatic
sudo systemctl enable --now dnf-automatic-install.timer
更新频率建议
| 环境 | 更新策略 | 说明 |
|---|
| 开发环境 | 手动更新 | 无特殊要求 |
| 测试环境 | 月度更新 | 跟随系统补丁 |
| 生产环境 | 跟随安全更新 | 使用 unattended-upgrades |
| 容器基础镜像 | 定期重建 | 确保基础镜像包含最新 CA |
4.10 故障排查:证书存储相关问题
常见错误
# 错误 1: "certificate verify failed"
curl: (60) SSL certificate problem: unable to get local issuer certificate
# 诊断步骤
# 1. 检查系统证书存储是否完整
ls /etc/ssl/certs/ca-certificates.crt
ls -la /etc/ssl/certs/ | head -5
# 2. 检查 update-ca-certificates 是否正常
sudo update-ca-certificates --fresh
# 3. 检查 OpenSSL 的证书路径
openssl version -d
openssl s_client -connect example.com:443 -CApath "$(openssl version -d | cut -d'\"' -f2)/certs" </dev/null
# 4. 检查环境变量
echo $SSL_CERT_FILE
echo $SSL_CERT_DIR
# 错误 2: 自定义 CA 添加后仍不被信任
# 原因:某些应用使用自己的证书存储(如 Python requests)
# 解决方案
# Python
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
# 或
pip install --upgrade certifi
python -c "import certifi; print(certifi.where())"
# Java
keytool -import -trustcacerts \
-keystore $JAVA_HOME/lib/security/cacerts \
-storepass changeit \
-alias my-ca -file my-ca.crt
# Node.js
export NODE_EXTRA_CA_CERTS=/path/to/my-ca.crt
4.11 本章小结
| 主题 | 关键要点 |
|---|
| 存储位置 | 各发行版路径不同,但都遵循类似的目录结构 |
| 管理工具 | update-ca-certificates(Debian)/ update-ca-trust(RHEL) |
| 自定义 CA | 放入特定目录后执行更新命令 |
| 黑名单 | 通过配置文件或 blacklist 目录禁用特定 CA |
| 容器化 | 在 Dockerfile 中添加 CA 并更新证书存储 |
| 应用差异 | 不同语言/框架可能使用不同的证书存储 |
📚 扩展阅读
上一章:第 3 章:证书类型
下一章:第 5 章:证书管理 — 学习证书的添加、删除、更新、信任和黑名单管理。