news 2026/9/17 10:40:53

cosign verify-attestation 完全指南:容器镜像 in-toto 证明(Attestation)校验实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
cosign verify-attestation 完全指南:容器镜像 in-toto 证明(Attestation)校验实战

cosign verify-attestation 完全指南:容器镜像 in-toto 证明(Attestation)校验实战

【免费下载链接】cosignCode signing and transparency for containers and binaries项目地址: https://gitcode.com/GitHub_Trending/co/cosign

导读

cosign verify-attestation是 sigstore 生态工具 cosign 提供的用于校验容器镜像上 in-toto 格式证明(Attestation)的核心命令。本文以 doc/cosign_verify-attestation.md 为骨架,结合本仓库源码深入讲解其工作流程、全部命令行参数、多种密钥来源与策略校验用法,帮助读者掌握从"验证证明签名"到"用 CUE/Rego 策略约束证明内容"的完整技能。


一、命令概述:校验镜像上的 Attestation

cosign verify-attestation用于校验已附加到容器镜像上的 in-toto attestation(证明)。与cosign verify校验普通签名不同,attestation 校验的核心对象是遵循 in-toto 规范的 Statement 结构——它由 DSSE 信封包装,内含 subject(镜像摘要)与 predicate(如 SLSA provenance、SPDX SBOM、漏洞扫描结果等)。

官方 Synopsis 对它的定位是:

Verify an attestation on an image by checking the claims against the transparency log.

即:校验镜像上的 attestation,并将其中的 claims 与透明日志(Rekor)进行比对,确保证明内容可公开验证、可追溯。

命令基础语法:

cosign verify-attestation [flags]

完整命令声明位于 cmd/cosign/cli/verify.go,其核心执行逻辑由 cmd/cosign/cli/verify/verify_attestation.go 中的VerifyAttestationCommand.Exec承担。

1.1 与cosign attest的配对关系

verify-attestation通常验证的是cosign attest命令(实现见 cmd/cosign/cli/attest/attest.go)生成的证明。attest会构建 in-toto Statement、签名后将 attestation 以 OCI artifact 形式写回镜像仓库;verify-attestation则从仓库拉取这些 attestation,先做签名/证书/透明日志校验,再按 predicate type 过滤并输出。


二、完整命令示例(继承原文档并逐条解读)

原文档给出的示例覆盖了密钥验证、多镜像、注解、本地镜像、KMS/URL 密钥、策略校验等全部典型场景:

cosign verify-attestation --key <key path>|<key url>|<kms uri> <image uri> [<image uri> ...]

2.1 基础用法

# 对镜像上的 cosign attestation 进行验证(校验其与透明日志的一致性) cosign verify-attestation <IMAGE> # 一次校验多个镜像 cosign verify-attestation <IMAGE_1> <IMAGE_2> ... # 额外校验指定的注解 cosign verify-attestation -a key1=val1 -a key2=val2 <IMAGE>

说明:

  • 第一个示例不带--key,走的是keyless 流程(依赖 Fulcio 证书 + 透明日志)。
  • 多镜像场景在源码中体现为Exec中的for _, imageRef := range images循环(verify_attestation.go),每个镜像独立完成抓取与校验。
  • -a/--annotation来自AnnotationOptions,会注入CheckOpts.Annotations,校验时要求证明携带匹配的注解。

2.2 使用公钥验证

# 使用本地公钥文件验证镜像 cosign verify-attestation --key cosign.pub <IMAGE> # 验证来自 'cosign save' 的本地磁盘镜像 cosign verify-attestation --key cosign.pub --local-image <PATH> # 使用 URL 提供的公钥验证 cosign verify-attestation --key https://host.for/<FILE> <IMAGE>

--local-image对应源码中的VerifyLocalImageAttestations分支(verify_attestation.go),用于验证cosign save保存到本地的镜像布局;同时会自动检测本地镜像中的 bundle 格式(HasLocalAttestationBundles)。

2.3 使用 KMS / 密钥托管服务中的公钥验证

# Google Cloud KMS cosign verify-attestation --key gcpkms://projects/<PROJECT>/locations/global/keyRings/<KEYRING>/cryptoKeys/<KEY> <IMAGE> # Hashicorp Vault cosign verify-attestation --key hashivault:///<KEY> <IMAGE> # GitLab(按项目名) cosign verify-attestation --key gitlab://[OWNER]/[PROJECT_NAME] <IMAGE> # GitLab(按项目 ID) cosign verify-attestation --key gitlab://[PROJECT_ID] <IMAGE>

--key参数支持三类来源:本地文件路径、KMS URI、Kubernetes Secret(见 options/verify.go)。KMS URI 通过LoadVerifierFromKeyOrCertPublicKeyFromKeyRefWithHashAlgo加载(verify/common.go)。

2.4 基于策略的证明内容校验

# 使用 Rego 策略校验 attestation cosign verify-attestation --key cosign.pub --type <PREDICATE_TYPE> --policy <REGO_POLICY> <IMAGE> # 使用 CUE 策略校验 attestation cosign verify-attestation --key cosign.pub --type <PREDICATE_TYPE> --policy <CUE_POLICY> <IMAGE>

这是verify-attestation区别于普通verify的杀手锏:签名校验只回答"证明是谁签的",策略校验回答"证明内容是否满足约束"


三、Attestation 校验的底层工作流程

从 verify_attestation.go 的Exec源码可以还原完整校验流水线:

  1. 参数互斥检查--key--certificate-identity--key--sk不可同时出现(options.NOf(...) > 1时报KeyAndIdentityParseError/KeyParseError)。
  2. 构造客户端ClientOpts构建 OCI registry 客户端选项;--allow-http-registry/--allow-insecure-registry时附加name.Insecure
  3. 组装CheckOpts:注入身份(Identities)、GitHub Workflow 断言、SCT/透明日志开关、MaxWorkers并发数等。
  4. 本地/远端镜像分流--local-imagecosign.VerifyLocalImageAttestations,否则走cosign.VerifyImageAttestations(内部包含 DSSE 签名验证、Fulcio 证书链验证、透明日志包含性证明校验)。
  5. 策略文件分类:根据扩展名把--policy文件分为.rego.cue两类,其他扩展名直接报invalid policy format
  6. predicate 类型匹配:通过policy.AttestationToPayloadJSON(pkg/policy/attestation.go)解析 DSSE 信封,解码 base64 的 payload,反序列化 in-toto Statement,只有当statement.PredicateType == 期望的 predicateURI时才进入策略校验;不匹配的证明会被跳过并记录实际类型,最终给出 "none of the attestations matched the predicate type" 的提示,便于用户发现--type拼写错误。
  7. CUE/Rego 策略执行cue.ValidateJSONrego.ValidateJSON对 payload 进行校验,任一失败都会累计validationErrors并在最后汇总输出。
  8. 结果输出PrintVerificationHeader打印校验摘要(claims 校验、透明日志存在性、公钥校验、证书校验等),再以 text 或 json 格式打印证明内容。

3.1 predicate 类型映射表

--type的取值由 options/predicate.go 中的PredicateTypeMap定义:

--type取值对应的 predicate URI
custom(默认)https://cosign.sigstore.dev/attestation/v1
slsaprovenance/slsaprovenance02SLSA Provenance v0.2
slsaprovenance1SLSA Provenance v1
spdx/spdxjsonin-toto SPDX
cyclonedxin-toto CycloneDX
linkin-toto Link v1
vulnhttps://cosign.sigstore.dev/attestation/vuln/v1
openvexOpenVEX 命名空间
任意合法 URI直接作为 predicate URI 使用(url.ParseRequestURI校验)

注意:--type默认值为custom,如果镜像上的证明是 SLSA 等类型而--type未指定,会因为 predicate 不匹配而被跳过并提示实际找到的类型。


四、全部选项(Flags)详解

4.1 证书与身份校验类

选项说明
--certificate-github-workflow-name stringGitHub OIDC token 的workflowclaim,即工作流名称
--certificate-github-workflow-ref stringGitHub OIDC token 的refclaim,即工作流运行所基于的 git ref
--certificate-github-workflow-repository stringGitHub OIDC token 的repositoryclaim,即工作流所属仓库
--certificate-github-workflow-sha stringGitHub OIDC token 的shaclaim,即工作流运行所基于的 commit SHA
--certificate-github-workflow-trigger stringGitHub OIDC token 的event_nameclaim,即触发工作流运行的事件名
--certificate-identity stringFulcio 证书中期望的身份,可取 email、DNS 名、IP、URI;keyless 流程中必须与--certificate-identity-regexp二选一
--certificate-identity-regexp string--certificate-identity的正则替代版(Go RE2 语法)
--certificate-oidc-issuer string期望的 OIDC issuer,如https://token.actions.githubusercontent.comhttps://oauth2.sigstore.dev/auth
--certificate-oidc-issuer-regexp stringOIDC issuer 的正则替代版
--insecure-ignore-sct不校验证书是否内嵌 SCT(证书透明日志包含性证明)

这些选项由CertVerifyOptions(options/certificate.go)注册。keyless 流程强制要求身份断言Identities()方法在--certificate-identity/--certificate-identity-regexp--certificate-oidc-issuer/--certificate-oidc-issuer-regexp均未提供时报错。测试 verify_attestation_test.go 分别验证了"缺 identity 报错"和"缺 issuer 报错"两个场景。

4.2 签名材料与透明日志类

选项说明
--allow-certificate-chain允许在 v0.3+ bundle 的校验材料中使用 X.509 证书链(对应sgbundle.AllowCertificateChain()
--check-claims是否校验 claims,默认true(为 true 时注入cosign.IntotoSubjectClaimVerifier
--insecure-ignore-tlog忽略透明日志校验,仅当证明未上传透明日志时使用;未入日志的工件无法被公开验证
--key string公钥文件路径、KMS URI 或 Kubernetes Secret
--local-image指定镜像为cosign save保存的本地路径
--trusted-root stringSigstore TrustedRoot JSON 文件路径(root.NewTrustedRootFromPath加载)
--use-signed-timestamps校验 RFC3161 时间戳(与TSACertChainPath任一非空即开启)

当使用--new-bundle-format(默认开启)时,CheckSigstoreBundleUnsupportedOptions(verify/common.go)会拒绝通过旧参数提供证书链、SCT、TSA 链等材料——这些必须统一走 bundle +--trusted-root

4.3 策略与输出类

选项说明
--policy strings指定用于校验的 CUE(.cue)或 Rego(.rego)策略文件,可重复传入
--type string指定 predicate 类型:slsaprovenanceslsaprovenance02slsaprovenance1linkspdxspdxjsoncyclonedxvulnopenvexcustom或任意 URI,默认custom
-o, --output string输出格式,json(默认)或text

4.4 安全密钥与 Registry 连接类

选项说明
--sk使用硬件安全密钥(PIV,对应pivkey.GetKeyWithSlot
--slot string安全密钥槽位:authenticationsignature(默认)、card-authenticationkey-management
--k8s-keychain使用 Kubernetes keychain 替代默认 keychain(支持 workload identity)
--max-workers int并行执行的最大 worker 数,默认10cosign.DefaultMaxWorkers
--allow-http-registry允许通过 HTTP 连接 registry(仅限测试)
--allow-insecure-registry允许不安全连接 registry(如过期或自签名 TLS 证书,仅限测试)
--registry-cacert string连接 registry 用的 X.509 CA 证书(PEM)路径
--registry-client-cert stringmTLS 客户端证书(PEM)路径
--registry-client-key string--registry-client-cert配套的私钥(PEM)路径
--registry-password stringregistry 基本认证密码
--registry-server-name stringmTLS 连接中tls.ConfigServerName(SAN 名)
--registry-token stringregistry bearer token
--registry-username stringregistry 基本认证用户名

4.5 继承自父命令的选项

--output-file string # 将日志输出到文件 -t, --timeout duration # 命令超时时间,默认 3m0s -d, --verbose # 输出调试日志

五、实战一:Keyless 验证 GitHub Actions 生成的证明

在 CI 场景中,证明通常由 GitHub Actions 的 OIDC 身份签名(Fulcio 证书内嵌 workflow 信息),验证方无需公钥即可完成信任建立:

cosign verify-attestation \ --certificate-identity "https://github.com/<ORG>/<REPO>/.github/workflows/build.yml@refs/heads/main" \ --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \ --type slsaprovenance1 \ ghcr.io/<ORG>/<IMAGE>@sha256:...

认证通过后,PrintVerification(verify/common.go)会解析证书扩展,输出Certificate subjectCertificate issuer URLGitHub Workflow Trigger/SHA/Name/Repository/Ref等溯源信息。


六、实战二:用 CUE / Rego 策略约束证明内容

6.1 CUE 策略示例

仓库测试用例 test/testdata/policies/cue-works.cue 提供了一个可直接参考的 CUE 策略:

import "time" before: time.Parse(time.RFC3339, "2049-10-09T17:10:27Z") // The predicateType field must match this string predicateType: "https://cosign.sigstore.dev/attestation/v1" // The predicate must match the following constraints. predicate: { Timestamp: <before }

使用方式:

cosign verify-attestation \ --key cosign.pub \ --type custom \ --policy cue-works.cue \ <IMAGE>

该策略断言:predicateType必须精确等于https://cosign.sigstore.dev/attestation/v1,且 predicate 中的Timestamp必须早于 2049 年(time.Parse为 CUE 内置函数)。

6.2 Rego 策略示例

Rego 策略文件同样通过--policy传入,cosign 会对策略引擎可消费的 JSON(经AttestationToPayloadJSON转换后的 Statement JSON)执行rego.ValidateJSON。仓库另有对应的失败用例 test/testdata/policies/cue-fails.cue、test/testdata/policies/cue-vuln-fails.cue 等,可用于对照验证策略的"通过/拦截"分支。

6.3 策略校验的源码行为细节

  • 扩展名必须是.rego.cue,否则直接报错invalid policy format, expected .cue or .rego
  • 校验失败会打印错误总数与逐条错误,并以非零退出码返回%d validation errors occurred
  • 若所有 attestation 的 predicate 类型都不匹配--type,返回none of the attestations matched the predicate type: <type>, found: <实际类型列表>——这一设计(attestation.go 返回实际 predicateType 供报错提示)能有效帮助用户排查--type拼写或类型选择错误。

七、验证测试与常见错误场景

仓库在 verify_attestation_test.go 中固化了以下校验规则:

测试场景期望结果
只给--certificate不给 identityneed --certificate-identity
只给 identity 不给 issuerneed --certificate-oidc-issuer
--key--certificate-identity同时给出KeyAndIdentityParseError(互斥)
--key--certificate-identity-regexp同时给出KeyAndIdentityParseError(互斥)
identity 与 identity-regexp 同时给出KeyAndIdentityParseError(互斥)
--key--sk同时给出KeyParseError(互斥)
--sk且无可用 PIV tokenopening piv token错误

此外,pkg/policy/attestation_test.go 还覆盖了 payload 解析的各类异常:非法 JSON、payload 非字符串、缺少 payload 字段、base64 解码失败、Payload()读取失败等,均会返回带明确上下文的错误信息。


八、与关联命令的协同

  • 生成证明用cosign attest(attest.go),验证用cosign verify-attestation
  • 验证普通镜像签名(非 attestation)用cosign verify,其文档见 doc/cosign_verify.md;
  • 验证二进制/文件 blob 的 attestation 用cosign verify-blob-attestation
  • 从镜像下载 attestation 内容可用cosign download attestation
  • --trusted-root、bundle 的打包与升级参见 doc/cosign_bundle.md 与 doc/cosign_trusted-root.md;
  • 父命令总览见 doc/cosign.md。

九、总结

cosign verify-attestation是 sigstore 供应链安全体系中连接"证明生成"与"策略执行"的关键一环。它既支持传统公钥验证、也支持 KMS/URL/本地多来源密钥,更通过--type+--policy组合将验证从"签名可信"提升到"内容合规"。理解其参数语义、predicate 类型映射与 CUE/Rego 策略机制,是在生产环境中落地可审计、可追溯的软件供应链验证的基础能力。

【免费下载链接】cosignCode signing and transparency for containers and binaries项目地址: https://gitcode.com/GitHub_Trending/co/cosign

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 10:40:17

手搓RTOS内核:GD32F103上实现极简双任务调度

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 10:35:21

MATLAB语音识别GUI:HMM+MFCC完整教学实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 10:33:38

UART发送器设计:波特率精度与状态机健壮性实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华