4、CRL分发点(CDP):核心概念与高可用设计

CRL分发点,英文叫CDP(CRL Distribution Point)。说白了,它就是告诉客户端「你去哪儿下载吊销列表」的一个地址。我刚开始接触PKI时,觉得这玩意儿不就是个URL嘛,有啥好讲的?后来踩了坑才明白——CDP配置得好不好,直接决定了你的证书体系能不能扛住生产压力。

4.1 CDP到底是什么?

CDP是X.509v3证书扩展中的一个字段。它包含一个或多个URI,指向CRL文件的存放位置。客户端验证证书时,会先读这个扩展,然后去对应地址拉取CRL,检查当前证书是否已被吊销。

嗯,这里要注意:CDP不是CRL本身,它只是个「导航牌」。你想想看,如果证书里没有CDP,客户端就不知道上哪儿找CRL,那吊销检查就无从谈起。

核心要点:CDP扩展是强制性的。没有CDP的证书,在严格PKI环境下会被视为「不可吊销」,很多安全策略会直接拒绝这类证书。

4.2 CDP在证书中长什么样?

我们直接看一个实际证书里的CDP扩展。用OpenSSL命令就能解析出来:

openssl x509 -in cert.pem -text -noout | grep -A 5 "CRL Distribution Points"

输出大概是这样:

X509v3 CRL Distribution Points:

    Full Name:
      URI:http://crl.example.com/ca.crl
      URI:ldap://ldap.example.com/cn=CA,o=Example,c=US?certificateRevocationList;binary
      URI:http://crl2.example.com/ca.crl

看到没?一个CDP里可以配多个URI。客户端会按顺序尝试,直到成功拉取到CRL为止。我个人习惯至少配两个HTTP地址,再加一个LDAP地址做兜底。

4.3 如何在证书中配置CDP扩展

配置CDP有两种常见方式:一种是在CA的配置文件中写死,另一种是在签发证书时动态指定。我推荐前者,因为一致性更好。

以OpenCA或自建CA为例,在openssl.cnf中这样配:

[ crl_distribution_points ]
crlDistributionPoints = @cdp_section

[ cdp_section ]
fullname = URI:http://crl.trustanchor.cn/root.crl
fullname = URI:http://crl2.trustanchor.cn/root.crl
fullname = LDAP://ldap.trustanchor.cn/cn=RootCA,o=TrustAnchor,c=CN?certificateRevocationList;binary
reasons = keyCompromise, CACompromise
CRLissuer = dirName:issuer_section

这里有几个关键参数:

  • fullname:CRL文件的完整URI,可以配多个
  • reasons:可选,指定这个分发点只包含特定吊销原因的CRL
  • CRLissuer:可选,如果CRL由另一个实体签发,这里指定签发者

我的经验:reasons字段我一般不用。分开维护多个CRL太麻烦,而且客户端支持度参差不齐。统一用一个全量CRL,省心。

4.4 CDP的高可用设计

这是重头戏。CDP一旦挂了,客户端就拉不到CRL。很多客户端在拉取CRL失败时的行为是「软失败」——直接放行证书。你想想看,这等于吊销机制形同虚设。

我在项目中遇到过一起事故:某金融客户的CDP服务器磁盘满了,CRL更新失败。结果所有新证书的吊销检查都跳过,一个被吊销的证书居然用了三天才被发现。嗯,从那以后我对CDP高可用格外上心。

4.4.1 多URI冗余

最基础的做法,就是在CDP里配多个URI。客户端会按顺序尝试:

  1. 先试第一个URI
  2. 如果失败(超时、404、DNS解析失败等),自动切换到第二个
  3. 以此类推,直到成功或全部失败

我建议至少配三个:

优先级 协议 示例地址 说明
1 HTTP http://crl-primary.trustanchor.cn/root.crl 主节点,低延迟
2 HTTP http://crl-secondary.trustanchor.cn/root.crl 备用节点,不同机房
3 LDAP ldap://ldap.trustanchor.cn/... 兜底,目录服务

4.4.2 网络架构层面的高可用

光配多个URI还不够。背后的网络架构也得扛得住。我常用的方案:

  • DNS轮询或负载均衡:同一个域名解析到多台服务器,用Nginx或HAProxy做反向代理
  • CDN加速:CRL文件是静态的,很适合放CDN。但要注意缓存刷新策略,CRL更新后要能及时清除CDN缓存
  • 多地域部署:在国内,至少部署华北、华东、华南三个节点。客户端按地理位置就近拉取

注意:CRL文件有有效期(nextUpdate字段)。客户端会缓存CRL直到过期。所以即使CDP短暂不可用,只要客户端本地缓存还在,就不会影响验证。但缓存过期后如果还拉不到,问题就来了。

4.4.3 自动化同步与监控

CRL文件必须从CA服务器同步到所有分发节点。我见过有人手动scp,这太原始了。建议用rsync或专门的同步工具:

#!/bin/bash
# CRL同步脚本,每10分钟执行一次
CRL_SOURCE="/var/ca/crl/root.crl"
SYNC_TARGETS="node1:/data/crl/ node2:/data/crl/ node3:/data/crl/"

for target in $SYNC_TARGETS; do
    rsync -avz --timeout=30 $CRL_SOURCE $target
    if [ $? -ne 0 ]; then
        echo "Sync to $target failed at $(date)" >> /var/log/crl_sync.log
        # 触发告警
        curl -X POST http://alertmanager:9093/api/v1/alerts \
             -d '{"labels":{"alertname":"CRLSyncFailed","target":"'$target'"}}'
    fi
done

监控方面,我建议盯三个指标:

  • CRL文件新鲜度:每个分发节点上的CRL文件修改时间,不能晚于CA签发时间超过30分钟
  • HTTP可达性:定时curl每个CDP地址,检查返回码和响应时间
  • CRL序列号一致性:对比各节点的CRL序列号,确保所有节点持有同一版本

4.5 CDP设计的常见误区

我总结几个坑,你遇到了可以少走弯路:

  • 只用HTTP不用HTTPS:CRL本身有CA签名,不怕篡改。但HTTP可能被中间人劫持返回旧CRL。我建议能用HTTPS就用HTTPS
  • 所有URI指向同一台服务器:这等于没有冗余。一台挂了全挂
  • LDAP地址写错格式:LDAP URI的DN必须和CA证书中的Issuer完全一致,大小写都不能错。我曾经因为这个排查了一整天
  • 忽略CRL文件大小:企业CA的CRL可能几十MB,客户端下载慢。考虑用Delta CRL或分片CRL

4.6 一张图看懂CDP架构

下面这张图展示了CDP从CA签发到客户端拉取的完整链路:

CDP 高可用架构图 CA 服务器 生成 CRL 文件 同步分发(rsync) CDP 节点 1 crl1.trustanchor.cn CDP 节点 2 crl2.trustanchor.cn CDP 节点 3 crl3.trustanchor.cn 客户端(浏览器/应用) 按顺序尝试 CDP URI 说明: 客户端按 CDP 扩展中的 URI 顺序尝试拉取 CRL。节点 1 失败则自动切换到节点 2,以此类推。 所有节点通过 rsync 从 CA 同步 CRL 文件,确保数据一致性。

4.7 小结

CDP是CRL体系的「门面」。配得好,客户端流畅验证;配不好,吊销机制形同虚设。我个人建议你从三个层面入手:证书扩展里配多个URI、网络架构做冗余、同步监控自动化。这三板斧砍下去,CDP的高可用基本就稳了。