强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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/Ubuntuca-certificatesupdate-ca-certificates/usr/local/share/ca-certificates//etc/ca-certificates.conf
RHEL/CentOSca-certificatesupdate-ca-trust extract/etc/pki/ca-trust/source/anchors//etc/pki/ca-trust/source/blacklist/
Fedoraca-certificatesupdate-ca-trust extract/etc/pki/ca-trust/source/anchors//etc/pki/ca-trust/source/blacklist/
Alpineca-certificatesupdate-ca-certificates/usr/local/share/ca-certificates/手动编辑
Archca-certificatestrust anchortrust anchor 命令trust anchor --remove
SUSEca-certificatesupdate-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 章:证书管理 — 学习证书的添加、删除、更新、信任和黑名单管理。