在 TPM 2.0 芯片中存储密钥并验证容器签名

解读

国内金融、政务云及等保 2.0 三级以上场景,普遍要求密钥不出硬件。TPM 2.0 作为主板级可信根,可提供持久化 SRK(Storage Root Key)与 NV 索引区,满足“密钥硬件绑定 + 远程证明”合规需求。Docker 容器镜像签名若能在 TPM 内部完成验签,即可实现“镜像完整性 → 节点可信 → 运行时拒绝篡改”的闭环,解决传统 cosign verify 仅把公钥放文件系统、易被替换的痛点。面试官想确认候选人是否能把Docker 内容信任机制与**国产 TPM 2.0 芯片(国民技术、国芯、信大捷安等)**打通,落地到 CI/CD 与 K8s 准入控制。

知识点

  1. TPM 2.0 密钥层次:SRK → RSA/ECC 子密钥 → NV 索引;密钥模板固定为 TPM2_RH_OWNER,属性位 fixedTPM|fixedParent|sensitiveDataOrigin 保证私钥不可导出。
  2. Docker 镜像签名规范OCI Image Layout + SimpleSigning JSON;摘要算法国内要求SM3 或 SHA-256;签名格式支持 RSA-PSS 与 ECDSA-P256,与 TPM 2.0 默认算法兼容。
  3. 验签流程docker pullcontainerd 调用 NotationCosign → 插件从 TPM 2.0 加载公钥证书 → 使用 TPM2_VerifySignature 命令完成摘要校验 → 结果写入 Attestation Key 供节点远程证明。
  4. 密钥密封:把签名私钥密封到 TPM NV 索引,绑定 PCR0~7(BIOS、GRUB、内核、systemd、Docker 版本)值;节点启动时若 PCR 值变动,TPM 拒绝解封,容器无法解密签名密钥,直接阻断启动
  5. 国产算法适配:若芯片仅支持 SM2/SM3,需把 Cosignx509.Verify 替换为 国密 GM/T 0009 验签库,并在 TPM2_CreateLoaded 时指定 TPM_ALG_SM2 算法标识(0x001B),此步骤需重新编译 tpm2-tsstpm2-openssl 引擎。
  6. CI/CD 集成:在 GitLab-RunnerJenkins in Kubernetes 阶段,调用 tpm2-tools 容器(privileged 模式)把公钥证书写入 ConfigMap,私钥句柄0x81000002 形式注入;准入控制器(如 Kyverno)通过 TPM2_Quote 验证节点 PCR 值后再放行 Pod。
  7. 故障排查tpm2_getcap handles-persistent 查看句柄是否丢失;tpm2_pcrread sha256:0,1,2,3 核对 PCR 值;journalctl -u docker 检查 dockerd 是否启用 cri-containerdverity-plugin;若出现 TPM_RC_PCR_CHANGED,需重新密封密钥或更新白名单。

答案

  1. 在节点上安装 tpm2-tss 3.2.0tpm2-abrmdtpm2-tools 5.5,确认 /dev/tpmrm0 存在;
  2. 生成签名密钥对
    tpm2_createprimary -C o -g sha256 -G rsa2048 -c primary.ctx
    tpm2_create -C primary.ctx -g sha256 -G rsa2048:rsapss:null -u key.pub -r key.priv -a "fixedtpm|fixedparent|sensitivedataorigin|userwithauth|sign"
    tpm2_load -C primary.ctx -u key.pub -r key.priv -c key.ctx
    tpm2_evictcontrol -C o -c key.ctx -F 0x81000002
    
    私钥句柄 0x81000002 永驻 TPM,不可导出
  3. 在 CI 阶段用 cosign 签名镜像:
    cosign sign --key tpmkms://0x81000002 registry.cn-shanghai.aliyuncs.com/myapp:v1.2.0
    
    tpmkms 插件需提前编译进 cosign,底层调用 TPM2_Sign 完成 SM2/RSA-PSS 签名;
  4. 节点端配置 docker-content-trust=0,由 containerd 接管;在 /etc/containerd/config.toml 启用 cri 插件的 enable_tls_streaming = true,并加载 verity 快照插件;
  5. 创建 Kyverno ClusterPolicy
    verifyImages:
    - image: "registry.cn-shanghai.aliyuncs.com/myapp*"
      key: |
        -----BEGIN PUBLIC KEY-----
        MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
        -----END PUBLIC KEY-----
      attestors:
      - entries:
        - tpm:
            quote:
              nonce: "{{ random }}"
              pcr: ["0","1","2","3"]
              publicKeyHandle: "0x81000003"
    
    其中 0x81000003AK(Attestation Key) 句柄,policy 要求 PCR 值与密封时一致;
  6. 当 Pod 调度到节点,kubelet 调用 containerd 拉取镜像,verity-plugin 通过 tpm2_verifyquote 校验节点 PCR,再用 TPM2_VerifySignature 验证镜像签名;任一环节失败,Pod 创建事件返回 FailedCreatePodSandBox,并提示 tpm: signature verification failed
  7. 升级维护:节点内核升级导致 PCR 值变化,需提前在 维护窗口 使用 tpm2_policypcr 重新计算新 PCR 摘要,并执行 tpm2_unsealtpm2_seal 把签名密钥密封到新的 PCR 策略,保证业务容器可继续启动

拓展思考

  • 双因子加固:把 TPM 2.0 与 国密 USBKey(SKF 接口) 做“协同签名”,私钥分片分别存于 TPM 和 USBKey,验签时需同时在线,满足**人行《金融容器云安全指引》**对“多因子密钥拆分”要求。
  • 零信任网络:结合 Istio + SPIFFE 把 TPM 的 AK 证书作为 nodeattestorEnvoy SDS 动态下发 mTLS 证书,实现“容器签名验证 → 节点身份 → 东西向流量加密”全链路可信;
  • 跨云灾备:利用 TPM 2.0 的 Duplication 功能,把签名密钥安全迁移到异地机房 TPM,流程需授权策略 TPM2_PolicyAuthorize 并由国密 CA 签发跨域证书,解决“密钥不离境”前提下的多云容灾难题;
  • 性能调优:TPM 2.0 单核频率仅 100 MHz,RSA-2048 签名 QPS ≈ 30;高并发场景可启用 tpm2-abrmd连接池 + 批量验签缓存,或把摘要计算 offload 到 CPUSM3 扩展指令,降低 40% 延迟;
  • 合规审计:通过 tpm2_eventlog 把节点启动度量写入 Lark/钉钉机器人PCR 值与镜像签名验证结果实时推送至等保测评平台,满足公安部 151 号文对“关键操作可追溯”要求。