证书与公钥基础设施(PKI)
说实话,很多人觉得PKI就是“CA签证书那套东西”。对,但也不全对。我在项目里见过不少团队,证书配了一堆,结果审计日志传输还是裸奔——不是TLS没配对,就是证书链断了。说白了,PKI是个信任模型,你得搞清楚你的审计日志该信谁。
PKI的两个核心角色
PKI里最重要的,就是“谁发证”和“谁用证”。我给你拆开聊。
RA(注册机构) – 验证申请者身份,把请求转给CA。你想想看,CA要是自己验身份,效率太低了。
另一个角色是证书持有者(比如你的TLS服务端)。它拿私钥签名,公钥跟着证书曝光。审计日志客户端拿到证书后,沿着证书链往上追溯,直到找到自己信任的根CA。
嗯,这里要注意:证书链不能断。我在一个项目中排查日志告警,发现客户端报“无法验证证书”,查了半天——中间CA的证书没装到服务端上。断链了,信任就垮了。
X.509证书结构
现实中我们用得最多的就是X.509 v3证书。我摘几个关键字段,你配审计日志TLS时得盯着看:
| 字段 | 含义 | 配审计日志时要注意 |
|---|---|---|
| Subject | 证书所有者(如服务器域名) | 必须与TLS端点域名完全匹配 |
| Issuer | 签发者 | 如果自签,Issuer = Subject |
| Validity | 生效与过期时间 | 审计设备时钟不准?曾经有人栽在这上 |
| Subject Key Identifier | 公钥标识 | 做证书链追溯用的 |
| Authority Key Identifier | 签发者公钥标识 | 用来匹配父证书 |
| Extended Key Usage | 用途扩展 | 必须包含 serverAuth |
证书链验证流程
审计日志客户端收到服务端证书后,会做三件事:
- 检查有效期限 – 过期或未生效?直接拒。
- 验证签名 – 用父证书的公钥解签名,确保证书内容没被篡改。
- 追溯信任锚 – 顺着Issuer字段一层层找,直到本地信任的根证书。
这个流程,说白了就是“你朋友说你是真的,我信你朋友,但我得先确认你朋友是XX”。链断了或者中间证书没存本地,验证就过不了。
我习惯把根证书预装在审计日志客户端的信任存储里。中间证书由服务端在TLS握手时下发。你想想看,如果每个客户端都存几十个中间CA,运维会疯的。
自签名 vs 商业CA
审计日志场景里,两种方式我都用过:
| 方式 | 优点 | 缺点 |
|---|---|---|
| 自签名CA | 成本低、完全可控 | 客户端要手动导入根证书,难批量 |
| 商业CA | 浏览器/系统默认信任 | 年费不低,过期前续签容易忘 |
| 内部搭建私有CA(如OpenSSL) | 自由签发、链可控 | 需要维护CRL/OCSP服务 |
生成一套自签证书(实战片段)
用OpenSSL搭建迷你PKI,我经常这样干:
# 1. 生成根CA私钥和证书
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 \
-subj "/C=CN/O=AuditLab/CN=RootCA" -out rootCA.crt
# 2. 生成服务端私钥和证书请求
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/C=CN/O=AuditLab/CN=tls.audit.internal" -out server.csr
# 3. 用根CA签发
openssl x509 -req -in server.csr -CA rootCA.crt -CAkey rootCA.key \
-CAcreateserial -days 365 -sha256 -extfile ext.cnf -out server.crt
这里ext.cnf里要写上extendedKeyUsage = serverAuth,否则部分TLS库会拒。我遇到过客户端是Go版本,非要明确声明用途,不然握手失败。
SVG:PKI信任模型与证书链
下面这张图展示了审计日志场景下的信任链:从根CA出发,经过中间CA,到日志服务端证书,客户端正向验证。
CRL与OCSP
证书一旦泄露或误发,需要第一时间吊销。审计日志场景下,我见过两种策略:
- CRL(证书吊销列表) – 静态列表,客户端定期拉取。缺点:时效性差,列表可能很大。
- OCSP(在线证书状态协议) – 实时查询。不过OCSP服务器如果是单点,挂了会影响握手。
我个人习惯:内部审计日志环境用CRL就够了,每天夜里拉一次。OCSP太麻烦,尤其是小团队没必要为了完美牺牲可用性。
openssl crl -verify 的校验环节才堵上。
实践检查清单
配完PKI,我建议你逐条过一遍:
- 根证书是否已经安装到所有审计日志客户端的信任存储?
- 服务端证书的Subject(CN或SAN)是否与连接的域名完全一致?
- 证书链文件是否在服务端配置中串联正确?(rootCACert + intermediateCert + serverCert,顺序别搞反)
- 客户端是否开启了证书验证?(不少日志库默认不验证,得显式打开)
- 有没有设置证书过期前30天的自动告警?
说实话,大部分“TLS传输失败”的问题,照着这个清单扫一遍就能定位。我调试过的项目里,80%出在第二条——域名没配SAN,或者SAN里写的是IP但证书签了域名。OpenSSL 1.1.1之后对IP兼容也不好,尽量用域名。