使用 Docker Content Trust 实现 OTA 升级签名
解读
在国内 DevOps 面试中,这道题表面问“OTA 升级签名”,实则考察候选人能否把 Docker Content Trust(DCT)与真实交付链路结合:从镜像签名、公钥分发、到边缘或车载设备热更新验证的完整闭环。面试官期望你跳出“docker trust sign”命令本身,给出可落地的国内方案,包括:
- 如何在没有 Notary 官方服务的情况下,用Harbor + 自建 Notary满足合规;
- 如何在设备端离线验证签名,防止中间人劫持;
- 如何与现有 OTA 通道(MQTT、HTTPS、CDN)解耦,做到“签名验证失败就回滚”。
一句话:不是问你会不会签名,而是问你能不能让千万台设备安全地“盲信”你的镜像。
知识点
- DCT 原理:镜像摘要经 Notary 用 TUF 框架签名,生成元数据;Docker CLI 通过本地 root 密钥与目标仓库的 timestamp/snapshot 密钥做层级验证。
- 国内合规要点:镜像与签名元数据必须落盘在境内服务器,因此需私有化部署 Notary v1 或 Harbor 2.5+ 内置 Notary。
- OTA 场景差异:设备通常无 docker 命令,需用轻量级验证库(如 go-tuf、python-tuf)在解压 root.json 后本地校验镜像摘要,再交由 containerd 或自定义 runtime 启动。
- 密钥托管:CI 侧用阿里云 KMS 或华为云 KMS托管签名密钥,避免私钥落盘;同时把 root 密钥离线加密存入保险库,仅授权构建节点。
- 回滚策略:设备端在校验失败后触发A/B 分区回滚,并上报签名摘要不一致事件到 Prometheus + Alertmanager,实现可观测。
答案
-
自建信任链
在境内 Harbor 实例启用 Notary,执行
export DOCKER_CONTENT_TRUST=1
docker trust signer add --key signer1.pub signer1 <镜像>
生成 root、targets、snapshot、timestamp 四元组,并把 root.json 离线烧录到设备固件,确保根信任不可篡改。 -
CI 集成签名
GitLab CI 阶段:
a) 构建完 multi-arch 镜像后,用阿里云 KMS 签名插件(kms-signer)完成 DCT 签名,私钥不出 KMS;
b) 把签名后的镜像摘要写入OTA 升级清单(json),连同 Harbor 的 timestamp.json 一起推到华为云 OBS CDN,供设备拉取。 -
设备端验证
设备用python-tuf客户端:
a) 本地 root.json 校验 CDN 返回的 timestamp/snapshot 签名链;
b) 比对要升级的镜像摘要是否在 targets.json 中且未被撤销;
c) 校验通过后再调用containerd cri解压并启动新容器;失败则触发 A/B 回滚并告警。 -
轮换与撤销
若签名私钥泄露,立即在 Harbor Notary 做docker trust revoke,并推送新的 root.json 到设备白名单通道(国密 VPN 或物理 U 盘),实现紧急吊销。
拓展思考
- 国密改造:Notary v1 默认 RSA/ECDSA,国内车联网要求 SM2/SM3。可二次开发 Notary 签名插件,把摘要算法换成国密,并在设备端集成国密 SSL 库完成验签。
- 零信任网络:即使 OTA 通道被劫持,只要 root.json 离线烧录、镜像摘要校验失败就拒绝启动,实现**“网络不可信,签名可信”**的零信任模型。
- 大规模密钥治理:当设备量>100 万时,采用分层密钥(root → delegation → product line),每型号设备只保存自己 product line 的 public key,降低 root 曝光面;同时用KMS 自动轮换 delegation 密钥,做到每日滚动签名而不影响离线设备。