私有 CA 备份:加密归档还是 HSM 密钥托管
加密归档或 HSM 封装的密钥:每种 VPN CA 备份模式如何恢复、必须包含什么,以及你真正能承受哪种故障。
决定其中大部分问题的,不是如何加密归档。你的 CA 私钥能否离开它的容器才是关键。如果密钥是文件,你可以把整个 CA 目录复制进一个加密块,几分钟就能完成。如果它住在 HSM 或标记密钥不可导出的令牌里,那份副本就不存在,你的计划会变成关于厂商封装与恢复流程的计划。两种模式都能用,失败方式不同,而你能扛住的那种失败才值得围绕它来设计。
两种备份模式在哪里分道
模型 A 是目录复制。OpenSSL 风格的 CA 是一个工作目录,而不是单个证书:ca.key 或 cakey.pem、ca.crt、签发数据库、serial 与 crlnumber 计数器,以及 openssl.cnf。用对称密码把这个目录封起来,把结果移到第二个介质,恢复就意味着解包、校验、签名。签发者需要的一切都一起走,包括没人记得写过的数周吊销历史。
模型 B 是密钥封存。密钥在 PKCS#11 模块内生成并标记为不可导出;模块可以为备份而封装它,但没有任何进程会读取原始字节。于是你的备份是两件必须按正确顺序恢复的东西:只有那个模块家族才能解开的封装密钥块,以及数据库、配置和证书的普通副本。
| Attribute | Encrypted archive | HSM key backup |
|---|---|---|
| What you store | one encrypted file | wrapped blob plus CA records |
| Who can restore it | anyone holding the passphrase | holder of the module and the blob, often vendor support |
| If a copy leaks | attacker with the passphrase becomes the CA | blob is inert without the matching module |
| What usually breaks it | forgotten passphrase, one damaged copy | replacement module rejects the blob, contract gap |
比较从来不是哪种模式在抽象上更强。而是你的团队在凌晨 2 点、和真正醒着的人一起,能恢复哪一种。谁都解不开的归档和谁都没测过的 HSM 块同样没用。区别在于:归档的故障会出现在密码管理器里,而 HSM 的故障藏在支持合同里。
每份 CA 备份必须包含什么
两种模式需要同一套记录。在 OpenSSL CA 中,这些文件是 index.txt,每张签发证书一行,覆盖状态、到期、serial 和主体,然后是 index.txt.attr、保存下一个待签发序列号的 serial、保存下一个 CRL 号的 crlnumber,以及带有 CA 实际运行所用 dir、policy 和 default_days 的 openssl.cnf。openssl-ca 手册说明了这些计数器各自控制什么。easy-rsa 把同样的数据放在 pki/ 下,由 vars 文件决定证书字段。
密钥和证书是无法重建的部分。数据库是无法凭记忆重建的部分。跳过 index.txt 仍然能签发新证书,这正是陷阱:直到客户第一次询问某张证书是否被吊销时,你才发现它缺了。把 CA 的指纹记录在备份之外,这样恢复时对照的是你信任的值,而不是你刚刚恢复的文件。
openssl x509 -in ca.crt -noout -fingerprint -sha256
tar czf ca-state.tar.gz ca.crt ca.key index.txt* serial* crlnumber* openssl.cnf
openssl enc -aes-256-cbc -pbkdf2 -iter 200000 -salt -in ca-state.tar.gz -out ca-state.tar.gz.enc
openssl ca -config openssl.cnf -gencrl -out crl.pem
不会分叉签发者的恢复测试
两张主体相同、密钥相同的在线 CA,在信任原件的每个客户端看来完全一样。两张编号相同但内容不同的 CRL,就是客户端悄悄接受你已吊销证书的方式。在没有通往客户端路由的主机上、或在一次性 VM 里运行恢复,并且绝不发布测试产生的 CRL。
只证明归档能打开的测试,对签发毫无证明。真正重要的是这个顺序:把恢复后的 ca.crt 指纹与你记录的值对比,确认 serial 与最后签发证书所暗示的一致,为一次性 CN 签发一张证书并观察 index.txt 增加一行,然后吊销那张证书并重新生成 CRL。
openssl verify -CAfile ca.crt -CRLfile crl.pem -crl_check client.crt
openssl crl -in crl.pem -noout -lastupdate -nextupdate
用 HSM 时,同样的测试要经过模块。把块解封到替换设备,确认模块报告的 CA 证书与你记录的指纹一致,然后才允许它签名。如果模块有自己的对象存储,封装必须覆盖密钥对象及其标签,因为把密钥恢复到不同标签下会破坏指向它的配置。
决定选择的故障模式
五种故障解释了大多数真实损失。归档口令被遗忘且没有独立的口令副本,会让归档变成砖头。单盘上的唯一副本随盘一起死,而校验和从不告诉你解密是否还能用。备份日期之后被吊销的证书在恢复后又会看起来有效,所以备份间隔也是你的吊销盲区。恢复较旧的 serial 计数器会重用序列号,并扰乱以 serial 为键的缓存和 CRL 查询。替换用 HSM 拒绝被封装的块,会让一次硬件更换变成全面重新签发。
模型 A 对前四点的处理很糟,但看得见。模型 B 处理得很好,直到模块或厂商流程失败。如果你的密钥可导出且团队很小,加密归档是诚实的选择,由两份介质和书面口令流程支撑。如果密钥不可导出,你根本没有选择,工作就转向在你需要它之前证明厂商的恢复路径。
选择模式并排期
三个条件决定选择。密钥能否在没有厂商流程的情况下导出?恢复是否必须落在你尚不拥有的硬件上?在和厂商支持争论时,签发能停多久?回答这三条,模式就定了;之后全是排期。
每次签名仪式之后、任何配置变更之前都要备份,因为配置也是状态的一部分。把两份副本放在不同地点的不同介质上,其中一份离线,并把解密口令放在与副本不同的信任域里。把最后一次成功恢复的日期写在备份记录上。从未恢复过的备份只是假设,不是控制措施。
在关闭工单之前,确认这五点:
- ca.crt 的指纹记录在备份之外的某个地方。
- index.txt、serial、crlnumber 和 openssl.cnf 全都在归档或块集合之内。
- 口令或封装密钥的保管有记录,并且由归档所有者之外的人持有。
- 已在隔离主机上用一次签发和一次吊销测试过恢复。
- 备份间隔所隐含的吊销空窗已书面接受或缩短。