3、远程证明与验证:远程证明协议、验证服务器搭建、引用完整性度量与证明策略配置
远程证明这东西,说白了就是让一台机器向另一台机器证明「我没撒谎」。你想想看,在可信计算体系里,TPM 在本地做了启动度量,生成了 PCR 值,但远程的服务端怎么知道这些值是真的?它怎么判断你这台机器是不是已经被攻破了?
我早年做第一个可信云项目时,就被这个问题卡了很久。本地度量做得再漂亮,远程不信,等于零。后来我才真正理解——远程证明才是可信计算从「自证」走向「他证」的关键一跳。
3.1 远程证明协议:DAA 与 AK
远程证明的核心,是解决「你是谁」和「你状态如何」两个问题。这里涉及两个关键协议:DAA(Direct Anonymous Attestation,直接匿名证明)和基于 AK(Attestation Key,证明密钥)的经典证明方案。
| 特性 | DAA | AK 方案 |
|---|---|---|
| 隐私保护 | 强(平台匿名) | 弱(平台可识别) |
| 是否需要 Privacy CA | 不需要 | 需要 |
| 适用场景 | 公有云、联盟链 | 企业内部、私有云 |
| 协议复杂度 | 高(基于群签名) | 中(基于证书链) |
| TPM 版本支持 | TPM 2.0 | TPM 1.2 / 2.0 |
AK 方案,我习惯叫它「经典路线」。TPM 内部有一个唯一的 EK(Endorsement Key,背书密钥),这是芯片出厂时烧录的。但 EK 不能直接用来签名,因为会暴露平台身份。所以 TPM 会派生一个 AK,用 EK 签名 AK 证书,然后交给 Privacy CA(隐私证书颁发机构)验证。验证服务器拿到 AK 证书后,就能确认这台 TPM 是合法的。
DAA 方案,则是为了解决 Privacy CA 的单点瓶颈和隐私泄露问题。它基于群签名技术,验证者只知道签名来自一个合法的 TPM 群组,但不知道具体是哪一台。我在做金融级可信计算项目时,监管要求必须能追溯到具体设备,所以用了 AK 方案;而在做公有云的多租户场景时,租户之间需要隔离身份,DAA 更合适。
核心区别一句话:AK 方案是「我知道你是谁,我才信你」;DAA 方案是「我知道你来自一个可信群体,我就信你」。
3.2 验证服务器搭建
验证服务器(Verifier)是整个远程证明的裁判。它接收来自客户端的证明请求,验证签名、检查 PCR 值、比对基准值,最后给出 verdict(裁决)。
我推荐使用 Keylime 作为验证服务器的基础框架。它开源、成熟,支持 TPM 2.0,而且社区活跃。搭建步骤大致如下:
- 安装依赖:Python 3.8+、TPM2-TSS、swtpm(模拟 TPM 时用)
- 配置 Keylime Verifier:编辑
/etc/keylime/verifier.conf,设置监听地址、端口、TLS 证书 - 启动服务:
keylime_verifier启动后,默认监听端口 8881 - 注册代理:在每台被验证的机器上安装 keylime_agent,向 Verifier 注册
- 配置引用完整性度量(RIMM)策略:定义哪些文件、内核模块、启动项的哈希值需要被度量
# 示例:Keylime Verifier 配置文件关键参数
[verifier]
ip = 0.0.0.0
port = 8881
tls_dir = /etc/keylime/certs
check_client_cert = True
[web]
port = 443
我的经验:第一次搭建时,记得把 TPM 模拟器(swtpm)和真实 TPM 区分开。开发阶段用模拟器,生产环境必须用硬件 TPM。我曾经在测试环境用模拟器跑了一周,切到真机时发现 PCR 扩展行为有细微差异,排查了两天。
3.3 引用完整性度量(RIMM)
RIMM(Reference Integrity Measurement Manifest,引用完整性度量清单)是验证服务器判断「什么是可信状态」的依据。它本质上是一份白名单,记录了所有被度量组件的预期哈希值。
RIMM 的组成通常包括:
- BIOS/固件度量:PCR 0-7 的预期值
- 内核度量:vmlinuz、initramfs 的哈希
- 关键文件度量:/etc/passwd、/etc/shadow、SSH 配置等
- 运行时代码度量:IMA(Integrity Measurement Architecture)记录的进程哈希
生成 RIMM 的过程,我建议分三步走:
- 黄金镜像阶段:在干净、可信的环境中安装系统,记录所有组件的哈希值
- 策略裁剪阶段:去掉不必要的度量项,减少验证开销。比如,只度量关键系统文件,不度量临时文件
- 版本管理阶段:每次系统更新后,重新生成 RIMM,并签名发布
# 使用 keylime 的 ripm 工具生成 RIMM
keylime_ripm --create --dir /etc/keylime/ripm.d --output /etc/keylime/ripm.json
# RIMM 文件示例片段
{
"meta": {
"version": "1.0",
"hash_alg": "sha256"
},
"measurements": [
{
"path": "/boot/vmlinuz-5.10.0",
"hash": "a1b2c3d4e5f6...",
"pcr": 8
},
{
"path": "/etc/ssh/sshd_config",
"hash": "f6e5d4c3b2a1...",
"pcr": 9
}
]
}
避坑指南:我曾经遇到过 RIMM 更新不及时导致大规模误报的情况。系统打了安全补丁后,内核哈希变了,但 RIMM 没更新,结果所有节点都被判定为「不可信」。建议把 RIMM 的更新流程纳入 CI/CD 管道,每次构建新镜像时自动生成并部署。
3.4 证明策略配置
证明策略,就是定义「什么情况下算通过,什么情况下算失败」。它不是简单的哈希比对,而是一套灵活的规则引擎。
常见的策略类型包括:
- 精确匹配策略:PCR 值必须完全等于预期值。最严格,但维护成本高
- 范围匹配策略:PCR 值落在某个可信区间内。适合固件版本有多个变体的场景
- 掩码策略:只检查 PCR 的某些位。用于忽略不重要的度量项
- 复合策略:组合多个条件,比如「PCR 0-7 精确匹配,且 PCR 8 范围匹配」
在 Keylime 中,策略配置通过 JSON 文件定义:
{
"policy": {
"name": "production-strict",
"version": "2.1",
"rules": [
{
"pcr": 0,
"type": "exact",
"value": "0000000000000000..."
},
{
"pcr": 8,
"type": "range",
"min": "a1b2c3d4e5f6...",
"max": "a1b2c3d4e5ff..."
},
{
"pcr": 9,
"type": "mask",
"mask": "0xFFFF0000",
"value": "a1b200000000..."
}
],
"action_on_failure": "quarantine"
}
}
我的建议:策略配置要遵循「最小必要原则」。不要一股脑把所有 PCR 都配成精确匹配,那样你会被频繁的误报逼疯。先配核心 PCR(0-7),跑通后再逐步加严。我在一个项目中只配了 5 个 PCR,覆盖了 90% 的攻击面,运维压力小了很多。
3.5 远程证明全流程(SVG 图)
下面这张图展示了远程证明的完整交互流程,从客户端发起挑战到验证服务器返回裁决:
3.6 实战中的几个关键点
远程证明看起来流程清晰,但落地时坑不少。我挑几个最常见的说说:
- 时间同步:证明过程中涉及证书有效期、时间戳验证。NTP 不同步会导致签名验证失败。我见过最离谱的案例,一台机器的系统时间差了两年,所有证明请求都被拒绝
- 证书轮换:AK 证书有有效期,过期前必须轮换。建议设置提前 30 天的告警,别等到证书过期了才手忙脚乱
- 性能开销:每次远程证明涉及 TPM 签名、网络传输、哈希比对。如果每秒验证上千台机器,验证服务器会成为瓶颈。我习惯在 Verifier 前面加一层缓存,对短时间内重复的证明请求直接返回缓存结果
- 降级策略:当验证服务器不可用时,被证明节点应该怎么办?是拒绝所有请求,还是允许降级运行?这需要根据业务风险决定。我的做法是:默认拒绝,但允许管理员手动设置一个「宽限期」
总结一下:远程证明不是一锤子买卖,而是一个持续的过程。从协议选择到服务器搭建,从 RIMM 生成到策略配置,每一步都需要结合你的实际场景做取舍。没有银弹,只有权衡。