如何签名镜像?

解读

在国内云原生交付场景中,“镜像签名”通常指对 OCI 容器镜像进行数字签名,确保镜像从构建到部署的完整性与来源可信。Rust 岗位问“如何签名镜像”,并不是让候选人背诵 docker 命令,而是考察三点:

  1. 是否理解供应链安全在 Rust 生态中的位置;
  2. 能否用 Rust 工具链(cosign-rust、sigstore、oci-distribution 等)完成签名与验签;
  3. 是否熟悉国内镜像仓库(阿里云 ACR、腾讯云 TCR、华为云 SWR)对签名格式的合规要求(SM2/SM3 国密算法支持、RAM 临时凭证、等保 2.0 审计)。
    面试时,HR 常把“签名镜像”当成一道安全 + 语言实战的综合题,答不到“Rust 侧实现”就容易被判定为“只用过 docker,不会写代码”。

知识点

  • OCI Image Spec:manifest、index、layer 的 digest 计算规则(SHA256)。
  • Sigstore 生态:cosign 的签名格式(ECDSA/P256 + PKIX 公钥,或 Fulcio 透明日志),以及 rust-sigstore 绑定库。
  • Rust 侧密钥管理:ring、aws-lc-rs 提供的椭圆曲线签名;pkcs8、sec1 编码解析;国内合规场景下国密 SM2 签名需使用 libsm 或 fastsm2 crate。
  • Registry Auth:阿里云 ACR 的RRSA 服务角色、腾讯云 TCR 的临时 STS 令牌,均需在签名前通过 rust-aliyun-openapi 或 qcloud-credential 获取。
  • 验签集成:在 K8s 集群中通过Policy Controller(Gatekeeper 或 Kyverno)调用 rust 写的 admission webhook,实现验签失败即拒绝 Pod 创建

答案

“我会用 Rust 完成镜像签名与验签,分四步落地:

  1. 准备密钥
    国内合规项目优先走国密双证书,我用 fastsm2 生成 SM2 密钥对,私钥存KMS 专属密钥域(阿里云 KMS 的硬件保护级别=HSM),公钥导出为 PEM 供后续验签。
  2. 计算镜像摘要
    通过 oci-distribution crate 先拉取镜像 manifest,按 OCI 规则本地计算 SHA256 摘要,确保不被中间网络篡改;摘要作为待签名 payload
  3. 签名并上传
    调用 KMS 的AsymmetricSign API(SM2-SM3),返回的 DER 签名用 Rust 组装成 cosign 兼容的simplesigning 格式(JSON 包装 critical.type=“cosign container image signature”),最后通过 registry 的扩展 API 把签名 layer push 到 …/manifests/sha256-xxx.sig
  4. 验签集成
    在 CI 最后阶段,用同一 Rust 二进制读取 KMS 公钥,重新计算 manifest 摘要并验签;生产集群通过我写的rust-webhook(基于 axum + serde_json)为 Admission Controller 提供 /verify 接口,验签失败直接返回 403,Pod 无法调度。
    整个过程零 docker CLI,全部 Rust 代码实现,符合国内等保 2.0 “镜像来源可信” 控制点。”

拓展思考

  • 多架构镜像签名:当镜像包含 linux/amd64、linux/arm64 两个索引时,需对 OCI Index 本身签名,而非单个 manifest;Rust 侧需递归校验所有子摘要,防止部分架构被替换的攻击。
  • 密钥轮换与撤销:在 Sigstore 透明日志模式下,可用 rust-rekor crate 上传签名条目,实现公开可审计;但国内私有云需自建 Rekor,需解决日志签名密钥的国密化7×24 高可用问题。
  • 性能优化:镜像层往往上百兆,Rust 签名过程只需对 manifest(几 KB)签名,无需扫描层文件;但验签侧若需批量扫描仓库内全部镜像,可用 tokio 并发 + 流式解析,单核 QPS 可拉到 1.2k,显著高于官方 cosign Go 实现。