cosign verify-blob-attestation 完全指南:基于密钥、KMS 与 keyless 的 blob 断言验证
【免费下载链接】cosignCode signing and transparency for containers and binaries项目地址: https://gitcode.com/GitHub_Trending/co/cosign
本指南系统讲解 sigstore cosign 的verify-blob-attestation子命令:如何对 blob 文件上携带的 in-toto 格式 attestation(断言)进行签名验证,涵盖 keyless(Fulcio 证书 + OIDC 身份)、公钥、Azure/AWS/GCP/HashiCorp Vault KMS 以及硬件安全密钥等全部验证路径,并深入源码揭示其参数校验、断言摘要比对与 predicate 类型匹配的底层实现。读完本文,你将能独立完成 blob attestation 从生成 bundle 到离线/在线验证的完整闭环。本文对应的官方命令参考文档位于 doc/cosign_verify-blob-attestation.md,核心命令入口见 cmd/cosign/cli/verify/verify_blob_attestation.go。
命令定位:为什么要验证 blob 上的 attestation
cosign verify-blob-attestation用于验证「作用于某个 blob 输入」的 attestation。与cosign verify-blob(验证 blob 的普通签名)不同,attestation 的签名材料以DSSE 信封(envelope)形式存在,内容遵循 in-toto Statement 规范,因此验证逻辑需要额外完成两件事:一是验证 DSSE 信封的签名有效性,二是校验 Statement 中 subject 的摘要与所给 blob(或 --digest)一致,三是确认 predicate 类型匹配预期。
该命令的官方 Synopsis 明确了两点输入约束:
- 签名材料通过
--bundle标志提供(bundle 文件即cosign attest-blob生成、或从远端拉取的 Sigstore bundle); - blob 可以通过文件路径指定(也支持不传 blob、仅凭
--digest进行验证)。
从源码结构看,命令的 CLI 参数定义在 cmd/cosign/cli/options/verify.go 的VerifyBlobAttestationOptions,实际执行逻辑则在VerifyBlobAttestationCommand.Exec。Exec 入口处 cmd/cosign/cli/verify/verify_blob_attestation.go 依次做了四类前置校验,是理解命令行为的关键:
- 必须提供
--signature或--bundle之一,否则报错please specify path to the DSSE envelope signature via --signature or --bundle; - 必须提供密钥/证书/bundle 三者之一(
--key、--sk、--certificate、--bundle),否则报错provide a key with --key or --sk, a certificate to verify against with --certificate, or a bundle with --bundle; --key与--certificate-identity/--certificate-identity-regexp互斥(不可同时指定),违反时报KeyAndIdentityParseError;--key与--sk互斥,违反时报KeyParseError。
这些互斥规则同样被单元测试覆盖,见 cmd/cosign/cli/verify/verify_blob_attestation_test.go 的TestVerifyBlobAttestationMutuallyExclusiveFlags。
典型用法示例(对应官方 Examples)
官方文档给出了五种验证方式,均可直接复制运行(<blob>替换为实际 blob 文件路径):
# 通用形式:bundle + 证书身份 + OIDC issuer cosign verify-blob-attestation --bundle <path> --certificate-identity <identity> --certificate-oidc-issuer <issuer> <blob> # keyless 模式验证 blob attestation cosign verify-blob-attestation --bundle artifact.sigstore.json --certificate-identity foo@example.com --certificate-oidc-issuer https://accounts.google.com <blob> # 使用公钥验证 cosign verify-blob-attestation --bundle artifact.sigstore.json --key cosign.pub <blob> # Azure KMS cosign verify-blob-attestation --bundle artifact.sigstore.json --key azurekms://[VAULT_NAME][VAULT_URI]/[KEY] <blob> # AWS KMS cosign verify-blob-attestation --bundle artifact.sigstore.json --key awskms://[ENDPOINT]/[ID/ALIAS/ARN] <blob> # GCP KMS cosign verify-blob-attestation --bundle artifact.sigstore.json --key gcpkms://projects/[PROJECT]/locations/global/keyRings/[KEYRING]/cryptoKeys/[KEY] <blob> # HashiCorp Vault cosign verify-blob-attestation --bundle artifact.sigstore.json --key hashivault://[KEY] <blob>注意 keyless 模式与公钥/KMS 模式的区别:keyless 验证需要同时提供--certificate-identity(或--certificate-identity-regexp)与--certificate-oidc-issuer(或--certificate-oidc-issuer-regexp),这在 options/certificate.go 的Identities()方法中强制校验;而使用--key时无需这些身份参数,二者互斥。
完整参数参考(Options)
核心验证参数
| 参数 | 类型/默认值 | 说明 |
|---|---|---|
--bundle string | 无默认 | 指向 bundle 文件的路径,bundle 内包含签名、证书及(可选)Rekor 包含证明与时间戳 |
--key string | 无默认 | 公钥文件路径、KMS URI 或 Kubernetes Secret,详见KeyOpts解析 |
--type string | "custom" | 指定 predicate 类型:slsaprovenance、slsaprovenance02、slsaprovenance1、link、spdx、spdxjson、cyclonedx、vuln、openvex、custom,或直接传一个 predicate URI |
--check-claims | true | 为 true 时校验摘要存在于 in-toto subject 中(使用提供的 digest+digestAlg,或对 blob 计算 sha256);为 false 时仅验证 DSSE 信封本身 |
--digest string | 无默认 | 不提供 blob 时,用它替代 blob 进行 in-toto subject 校验 |
--digestAlg string | 无默认 | 与--digest配套的摘要算法(sha256/sha384/sha512) |
--allow-certificate-chain | false | 允许 v0.3+ bundle 验证材料中包含 X.509 证书链 |
--use-signed-timestamps | false | 验证 RFC3161 时间戳 |
--trusted-root string | 无默认 | Sigstore TrustedRoot JSON 文件路径(用于 bundle 验证的服务密钥与证书) |
--max-workers int | 10 | 并行执行的最大 worker 数 |
keyless 身份与证书参数
| 参数 | 说明 |
|---|---|
--certificate-identity string | 合法 Fulcio 证书中期望的身份,支持邮箱、DNS 名、IP 与 URI;keyless 流程中与--certificate-identity-regexp二选一必填 |
--certificate-identity-regexp string | --certificate-identity的正则替代形式,采用 Go 正则语法(RE2) |
--certificate-oidc-issuer string | 合法 Fulcio 证书中期望的 OIDC issuer,如https://token.actions.githubusercontent.com或https://oauth2.sigstore.dev/auth;与 regexp 版二选一必填 |
--certificate-oidc-issuer-regexp string | 上述参数的正则替代形式 |
--certificate-github-workflow-name string | GitHub OIDC Identity token 中workflowclaim,即执行的 workflow 名称 |
--certificate-github-workflow-ref string | token 中refclaim,即 workflow 运行基于的 git ref |
--certificate-github-workflow-repository string | token 中repositoryclaim,即 workflow 运行所在的仓库 |
--certificate-github-workflow-sha string | token 中shaclaim,即 workflow 运行基于的 commit SHA |
--certificate-github-workflow-trigger string | token 中event_nameclaim,即触发 workflow 运行的事件名 |
这些 GitHub Workflow 相关的 claim 会被写入CheckOpts并在证书扩展验证阶段比对,见 verify_blob_attestation.go 中co := &cosign.CheckOpts{...}的赋值。
安全性与信任边界参数
| 参数 | 说明 |
|---|---|
--insecure-ignore-sct | 为 true 时不检查证书是否内嵌 SCT(证书透明度日志包含证明) |
--insecure-ignore-tlog | 忽略透明度日志验证,用于签名未上传到日志的场景;注意未入日志的工件无法被公开验证 |
--sk | 是否使用硬件安全密钥(如 YubiKey/PIV) |
--slot string | 安全密钥槽位,取值为authentication、signature、card-authentication、key-management(默认signature) |
-h, --help | 显示帮助 |
父命令继承参数
| 参数 | 说明 |
|---|---|
--output-file string | 将日志输出到指定文件 |
-t, --timeout duration | 命令超时时间,默认3m0s |
-d, --verbose | 输出调试日志 |
底层验证流程:从参数到 "Verified OK"
Exec的完整流程(cmd/cosign/cli/verify/verify_blob_attestation.go)可以拆解为五个阶段:
- 加载验证器:调用
LoadVerifierFromKeyOrCert,根据--key/--sk/--certificate构造公钥验证器。当HashAlgorithm未设置时,验证器会按密钥类型自动选择匹配的摘要算法(例如 P-521 ECDSA 密钥不会硬编码为 SHA-256),见源码中 L89-L92 的注释说明。 - 计算/收集摘要:若
--check-claims=true且提供了 blob 路径,则打开文件(走filepath.Clean清理路径)、校验大小限制后按默认sha256(或--digestAlg指定的算法)计算摘要,并通过cosign.IntotoSubjectClaimVerifier作为 claim 验证器;若提供--digest与--digestAlg则直接使用十六进制解码后的摘要。 - 装配信任材料:
SetTrustedMaterial将--trusted-root、证书链、CA 根等注入CheckOpts。 - 核心签名验证:新 bundle 格式(v0.3+)走
cosign.VerifyNewBundle+sigstore-go的WithArtifact/WithArtifactDigest策略;旧格式则通过static.NewAttestation组装签名对象后调用cosign.VerifyBlobAttestation(定义于 pkg/cosign/verify.go,其内部复用verifyInternal+verifyOCIAttestation)。若 bundle 内含证书,还会校验 CLI 传入的--certificate与 bundle 证书一致,不一致直接报错the cert passed in does not match the cert in the provided bundle。 - predicate 类型检查:调用
policy.AttestationToPayloadJSON将 DSSE 信封转为可消费的 predicate 负载;若返回空 payload 且无错误,说明断言不属于所给 predicate 类型,报错invalid predicate type, expected %s got %s。全部通过后输出Verified OK。
新旧 bundle 格式分支
从源码看,命令同时支持两种验证路径(L209-L289):
- 新 bundle 格式(v0.3+,默认):要求
--trusted-root,通过sgbundle.LoadJSONFromPath加载 bundle,用sgverify.WithArtifact(传 blob 文件)或WithArtifactDigest(传摘要)构造 artifact 策略。选择WithoutArtifactUnsafe仅在--check-claims=false时出现。 - 旧 bundle 格式:
--trusted-root与之不兼容(直接报错--trusted-root only supported with --new-bundle-format),改由FetchLocalSignedPayloadFromPath解析本地 bundle JSON 并提取base64Signature与证书。
digest 摘要算法白名单
--digestAlg仅接受sha256、sha384、sha512三个值,由 parseBlobHashAlgorithm 映射到crypto.Hash,且大小写敏感(SHA256也会被拒绝)。对应测试见 verify_blob_attestation_test.go 的TestParseBlobHashAlgorithm,其中sha1、md5、空字符串、SHA256均为错误用例。
predicate 类型解析:别名到 URI 的映射
--type的取值由 cmd/cosign/cli/options/predicate.go 的PredicateTypeMap定义。别名与底层 predicate URI 的对应关系如下:
| CLI 别名 | predicate URI |
|---|---|
custom(默认) | cosign.sigstore.dev/attestation/v1(CosignCustomProvenanceV01) |
slsaprovenance | https://slsa.dev/provenance/v0.2 |
slsaprovenance02 | https://slsa.dev/provenance/v0.2 |
slsaprovenance1 | https://slsa.dev/provenance/v1 |
link | in-totolinkpredicate v1 |
spdx/spdxjson | in-toto SPDX predicate |
cyclonedx | in-toto CycloneDX predicate |
vuln | cosign.sigstore.dev/attestation/vuln/v1 |
openvex | OpenVEX namespace |
如果传入的--type不在映射表中,ParsePredicateType会尝试将其解析为合法 URI(url.ParseRequestURI),失败则报invalid predicate type。因此你可以直接传自定义 predicate 的完整 URI 而无需依赖内置别名。注意slsaprovenance与slsaprovenance02指向同一 URI,测试用例TestVerifyBlobAttestation中错误 predicate(如custom与notreallyslsaprovenance)均被正确拒绝,见 verify_blob_attestation_test.go。
验证行为细节与边界
--check-claims 的双重语义
--check-claims=true(默认):要求 in-toto Statement 的 subject 摘要与 blob 的实际 sha256(或--digest)匹配。测试表明,subject 为空、缺失 sha256 digest、多 subject 中没有一个匹配时均验证失败(verify_blob_attestation_test.go);而多 subject 中「至少一个」匹配即可通过。--check-claims=false:只验证 DSSE 信封的签名,不关心 subject 摘要。此时即使 blob 路径指向另一个文件甚至/dev/null也能通过——这正是测试TestVerifyBlobAttestationNoCheckClaims所验证的行为(L188-L252)。
blob 大小限制
当--check-claims=true且传入 blob 文件时,代码会调用payloadsize.CheckSize检查文件大小,默认上限为128MiB,定义于 internal/pkg/cosign/payload/size/size.go。可通过环境变量COSIGN_MAX_ATTACHMENT_SIZE(接受 humanize 格式,如128MB、1GB)覆盖;测试override file size limit展示了设置较小上限后大 blob 被拒绝的场景(verify_blob_attestation_test.go)。
用 --digest 替代 blob
--digest与--digestAlg允许你在不持有 blob 文件本身的情况下,仅凭摘要验证 attestation。测试verify with digest instead of blob直接以blobSha256完成验证(L144-L149)。源码中若同时传入 blob 与--digest,会以 blob 为准并打印警告Ignoring provided --digest in favor of provided blob。
与 attest-blob 的配套使用闭环
verify-blob-attestation的典型上游是cosign attest-blob(实现见 cmd/cosign/cli/attest/attest_blob.go)。attest-blob读取 blob 计算 SHA-256 摘要,用--predicate/--statement组装 in-toto Statement 与 DSSE 信封,最终写出 bundle 文件(新格式直接写 protobuf JSON bundle;旧格式写出base64Signature+ 证书的 legacy bundle)。因此推荐工作流为:
# 1. 为 blob 生成带 attestation 的 bundle cosign attest-blob --predicate predicate.json --type slsaprovenance --bundle artifact.sigstore.json <blob> # 2. 用公钥验证(注意 attest-blob 需用对应私钥签名) cosign verify-blob-attestation --bundle artifact.sigstore.json --key cosign.pub <blob> # 3. 或 keyless 验证 cosign verify-blob-attestation --bundle artifact.sigstore.json \ --certificate-identity foo@example.com \ --certificate-oidc-issuer https://accounts.google.com <blob>常见错误与排查速查
| 错误信息 | 原因 | 解决 |
|---|---|---|
please specify path to the DSSE envelope signature via --signature or --bundle | 未提供任何签名材料 | 补传--bundle |
provide a key with --key or --sk, a certificate to verify against with --certificate, or a bundle with --bundle | 无任何信任锚点 | 至少指定 key/certificate/bundle 之一 |
KeyAndIdentityParseError | --key与--certificate-identity*同时使用 | 二选一 |
KeyParseError | --key与--sk同时使用 | 二选一 |
invalid predicate type, expected %s got %s | bundle 内 predicate 与--type不匹配 | 检查--type或改用自定义 URI |
--trusted-root only supported with --new-bundle-format | 旧格式 + trusted-root 混用 | 使用新 bundle 格式 |
--certificate-identity or --certificate-identity-regexp is required for verification in keyless mode | keyless 缺少身份参数 | 补传身份与 OIDC issuer 参数 |
unsupported --digestAlg | --digestAlg不在白名单 | 使用sha256/sha384/sha512 |
MaxLayerSizeExceeded | blob 超过 128MiB 上限 | 调大COSIGN_MAX_ATTACHMENT_SIZE或改用--digest |
小结
cosign verify-blob-attestation是 sigstore blob 供应链验证体系中专用于 DSSE/in-toto attestation 的校验入口,其能力覆盖 keyless、公钥、四大 KMS 与硬件安全密钥,并通过--check-claims、--type、--digest/--digestAlg提供细粒度控制。建议在生产实践中始终使用--bundle携带完整验证材料(签名 + 证书 + Rekor 包含证明 + 时间戳),结合--trusted-root实现可离线、可审计的强验证。命令参考的其余相关入口还包括 doc/cosign.md(全局命令索引)与 doc/cosign_attest-blob.md(对应签名侧命令)。
【免费下载链接】cosignCode signing and transparency for containers and binaries项目地址: https://gitcode.com/GitHub_Trending/co/cosign
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考