cosign verify 完全指南:容器镜像签名验证的原理、参数与实战
2026/9/17 2:20:10 网站建设 项目流程

cosign verify 完全指南:容器镜像签名验证的原理、参数与实战

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

本篇技术指南围绕 sigstore cosign 项目的cosign verify命令展开,系统讲解其命令语法、全部命令行参数、多场景验证示例(公开密钥、KMS、keyless 证书链、本地镜像等),并结合仓库源码(cmd/cosign/cli/verify/verify.gopkg/cosign/verify.go)深入剖析透明日志(Transparency Log)、claims 校验、证书链验证等底层机制。读完本文,你将能够独立完成对任意已签名容器镜像的签名真实性、归属身份与注解信息的完整校验,并理解验证失败时的排查方向。

一、命令定位:cosign verify 做什么

cosign verify用于验证指定容器镜像(container image)上的签名,通过将签名中的 claims 与透明度日志(transparency log)进行核对,从而确认镜像的签名真实有效、未被篡改。命令入口定义在 cmd/cosign/cli/verify.go,其职责声明为:

Verify a signature on the supplied container image —— 验证所提供容器镜像上的签名

底层实际执行逻辑位于 cmd/cosign/cli/verify/verify.go 的VerifyCommand.Exec方法,它负责组装cosign.CheckOpts校验选项、加载验证器与信任材料,并逐镜像执行校验。从源码可以看到,命令要求至少传入一个镜像参数(Args: cobra.MinimumNArgs(1),见 cmd/cosign/cli/verify.go),即不带任何参数运行时会直接报错退出。

二、命令语法

cosign verify [flags]

cosign verify的完整调用形态为:

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

其中:

  • --key指定用于验证的公钥来源(文件路径、URL、KMS URI 或 Kubernetes Secret);
  • <image uri>为一个或多个待验证的镜像引用,支持同时传入多个镜像批量验证。

三、实战示例:从最简单到企业级场景

原文档给出了从基础到复杂的一整套验证示例,下面逐一展开讲解其适用场景与关键点(示例源见 cmd/cosign/cli/verify.go)。

3.1 验证 cosign claims 与签名证书(keyless 默认路径)

# verify cosign claims and signing certificates on the image with the transparency log cosign verify <IMAGE>

这是最基础也是最常用的形态:不显式指定--key,走keyless 验证。此时 cosign 会从镜像的签名附件中提取 X.509 证书,将其链到 Fulcio 根信任(或用户通过--trusted-root提供的信任根),并同时核对 Rekor 透明度日志中的条目。从源码看,未指定 key 且不使用安全密钥时,会要求提供证书身份与 OIDC issuer 的匹配条件(Identities()逻辑,见 cmd/cosign/cli/options/certificate.go)。

3.2 批量验证多个镜像

# verify multiple images cosign verify <IMAGE_1> <IMAGE_2> ...

Exec中对传入的images []string做循环遍历(cmd/cosign/cli/verify/verify.go),逐个镜像独立执行验证并输出结果。注意:所有镜像必须能被同一组验证条件(同一个 key / 身份 / issuer)通过,否则对应的镜像校验会报错。

3.3 额外校验注解

# additionally verify specified annotations cosign verify -a key1=val1 -a key2=val2 <IMAGE>

-a, --annotationskey=value形式,可多次指定)要求签名 payload 中必须包含这些注解。注解校验在 claims 校验阶段完成——CheckOpts.Annotations字段被填充后,ClaimVerifier会对其逐一核对(见 pkg/cosign/verify.go)。

3.4 使用磁盘上的公钥验证(key-based)

# verify image with an on-disk public key cosign verify --key cosign.pub <IMAGE>

--key指向本地公钥文件(如cosign.pub,可用cosign generate-key-pair生成)。加载公钥的路径在LoadVerifierFromKeyOrCert中:当keyRef != ""时调用PublicKeyFromKeyRefWithHashAlgo构建验证器(见 cmd/cosign/cli/verify/common.go)。此模式下不再需要 Fulcio 证书,属于"显式公钥验证"路径。

3.5 验证本地保存的镜像(离线)

# verify image with an on-disk signed image from 'cosign save' cosign verify --key cosign.pub --local-image <PATH>

--local-image表示<PATH>是通过cosign save保存到本地的镜像目录而非远程仓库引用。此时验证完全离线进行,调用cosign.VerifyLocalImageSignatures(pkg/cosign/verify.go),从本地 OCI layout 中读取签名并校验,不发起任何网络请求。

3.6 使用 TrustedRoot 信任根验证

# verify image with a trusted root cosign verify --trusted-root trusted_root.json <IMAGE>

--trusted-root指向一个 Sigstore TrustedRoot JSON 文件,其中包含 Rekor、Fulcio、CT log、TSA 等服务密钥与证书,可在离线/隔离环境中提供完整的信任锚点。源码中通过root.NewTrustedRootFromPath加载(见 cmd/cosign/cli/verify/common.go)。提供了 TrustedRoot 后,cosign 不再从 TUF 仓库在线拉取各服务密钥。

3.7 通过 URL 提供公钥

# verify image with public key provided by URL cosign verify --key https://host.for/[FILE] <IMAGE>

--key支持http(s)://URL,cosign 会先下载公钥内容再构建验证器。

3.8 公钥存储在环境变量中

# verify image with a key stored in an environment variable cosign verify --key env://[ENV_VAR] <IMAGE>

env://前缀表示从指定环境变量读取公钥内容,适合 CI/CD 流水线中通过 secret 注入密钥的场景。

3.9 KMS 与密钥管理服务集成

# verify image with public key stored in Google Cloud KMS cosign verify --key gcpkms://projects/[PROJECT]/locations/global/keyRings/[KEYRING]/cryptoKeys/[KEY] <IMAGE> # verify image with public key stored in Hashicorp Vault cosign verify --key hashivault://[KEY] <IMAGE> # verify image with public key stored in a Kubernetes secret cosign verify --key k8s://[NAMESPACE]/[KEY] <IMAGE>

--key支持多种 KMS 前缀:gcpkms://(Google Cloud KMS)、hashivault://(HashiCorp Vault)、k8s://(Kubernetes Secret)。这些 URI 在PublicKeyFromKeyRefWithHashAlgo中被统一解析,最终返回对应的公钥验证器。

3.10 GitLab 托管公钥

# verify image with public key stored in GitLab with project name cosign verify --key gitlab://[OWNER]/[PROJECT_NAME] <IMAGE> # verify image with public key stored in GitLab with project id cosign verify --key gitlab://[PROJECT_ID] <IMAGE>

gitlab://前缀支持按项目名(OWNER/PROJECT_NAME)或项目 ID 两种方式引用存储在 GitLab 中的公钥。

四、参数详解

4.1 verify 专属参数

以下参数完整继承自原文档,并补充了源码中的默认值与行为说明(选项定义见 cmd/cosign/cli/options/verify.go 与 cmd/cosign/cli/options/certificate.go):

参数类型/默认值说明
--allow-certificate-chainbool(默认 false)允许在 v0.3+ 版本 bundle 的验证材料中包含 X.509 证书链。设置后会在 OCI 客户端选项中追加sgbundle.AllowCertificateChain()(见 cmd/cosign/cli/verify/verify.go)
--allow-http-registrybool是否允许使用 HTTP 协议连接镜像仓库。仅限测试环境使用
--allow-insecure-registrybool是否允许不安全的仓库连接(如证书过期或自签名 TLS)。仅限测试环境使用
-a, --annotationsstrings额外的key=value注解对,需与签名中的注解完全匹配
--certificate-github-workflow-namestring期望的 GitHub OIDC Identity Token 中 workflow 名称 claim
--certificate-github-workflow-refstring期望的 git ref claim
--certificate-github-workflow-repositorystring期望的仓库 claim
--certificate-github-workflow-shastring期望的 commit SHA claim
--certificate-github-workflow-triggerstring期望的触发事件名(event_name)claim
--certificate-identitystring期望在有效 Fulcio 证书中的身份,支持邮箱、DNS 名、IP 地址和 URI。keyless 流程必须设置它或--certificate-identity-regexp
--certificate-identity-regexpstring--certificate-identity的正则表达式替代形式,使用 Go 正则语法(RE2)
--certificate-oidc-issuerstring期望的 OIDC issuer,如https://token.actions.githubusercontent.comhttps://oauth2.sigstore.dev/authkeyless 流程必须设置它或--certificate-oidc-issuer-regexp
--certificate-oidc-issuer-regexpstring上述 issuer 的正则表达式替代形式
--check-claimsbool(默认 true)是否校验签名中发现的 claims
-h, --helpbool查看 verify 帮助
--insecure-ignore-sctbool设置为 true 时不检查证书是否内嵌 SCT(证书透明度日志包含证明)
--insecure-ignore-tlogbool跳过透明度日志验证,用于签名未上传至透明日志的场景。未纳入日志的产物无法被公开验证
--k8s-keychainbool使用 Kubernetes keychain 替代默认 keychain(支持 workload identity)
--keystring公钥文件路径、KMS URI 或 Kubernetes Secret
--local-imagebool指定镜像为cosign save保存的本地路径
--max-workersint(默认 10)并行执行的最大 worker 数。源码中若设为 0 会直接报错提示设置为大于 0 的值(见 cmd/cosign/cli/verify.go),实际并行节流通过throttler实现(见 pkg/cosign/verify.go)
-o, --outputstring(默认json签名镜像信息的输出格式,可选jsontext
--registry-cacertstring连接仓库时使用的 X.509 CA 证书文件(PEM 格式)路径
--registry-client-certstringmTLS 客户端证书(PEM)路径
--registry-client-keystringmTLS 客户端私钥(PEM)路径,需与--registry-client-cert搭配
--registry-passwordstring仓库 basic auth 密码
--registry-server-namestring作为tls.ConfigServerName使用的 SAN 名,用于校验与仓库的 mTLS 连接
--registry-tokenstring仓库 bearer auth token
--registry-usernamestring仓库 basic auth 用户名
--skbool是否使用硬件安全密钥(如 YubiKey PIV)
--slotstring(默认signature安全密钥槽位:authenticationsignaturecard-authenticationkey-management
--trusted-rootstringSigstore TrustedRoot JSON 文件路径
--use-signed-timestampsbool验证 RFC3161 时间戳

注意:--certificate-github-workflow-*系列参数对应 Fulcio 证书中的 GitHub Actions OIDC 扩展字段,用于在 keyless 场景下将验证收紧到"某个特定 workflow 的某次运行",避免任何持有合法 Fulcio 证书的 GitHub 用户都能通过验证。

4.2 从父命令继承的参数

--output-file string log output to a file -t, --timeout duration timeout for commands (default 3m0s) -d, --verbose log debug output
  • --output-file:将日志输出到指定文件;
  • -t, --timeout:命令超时时间,默认 3 分钟。入口处通过context.WithTimeout(cmd.Context(), ro.Timeout)为整个验证流程设置超时(见 cmd/cosign/cli/verify.go);
  • -d, --verbose:输出调试日志。

五、验证流程的源码级解析

理解cosign verify的底层流程有助于准确排查验证失败原因。核心验证逻辑位于 pkg/cosign/verify.go 的verifyInternal(pkg/cosign/verify.go),整体流程如下:

  1. 信任材料准备SetTrustedMaterial(cmd/cosign/cli/verify/common.go)优先使用--trusted-root提供的 TrustedRoot;否则从 TUF 仓库在线获取。若仅使用公钥验证(--key且跳过 tlog 与时间戳),则无需信任根(verifyOfflineWithKey,见 cmd/cosign/cli/verify/common.go)。

  2. 构建验证器LoadVerifierFromKeyOrCert(cmd/cosign/cli/verify/common.go)按优先级处理——显式--key> 硬件安全密钥--sk> 证书--certificate。不提供三者时SigVerifier为 nil,验证器将从签名携带的证书构建(keyless 路径)。

  3. 拉取签名VerifyImageSignatures(pkg/cosign/verify.go)首先解析镜像 digest,然后从 OCI 仓库的签名 tag 或显式--signature引用拉取签名集合。

  4. 逐签名验证verifySignatures使用--max-workers控制的 worker 池并行处理每个签名(pkg/cosign/verify.go),对每个签名依次执行:

    • 透明日志核对:验证 Rekor bundle(离线可验),无 bundle 则通过RekorClient在线查询tlogValidateEntry(pkg/cosign/verify.go);
    • 证书链验证:证书链到可信根,并执行身份/issuer 策略匹配(CheckCertificatePolicy,见 pkg/cosign/verify.go)与 SCT 校验(除非--insecure-ignore-sct);
    • 密码学签名校验:用验证器对签名做实际签名验证;
    • claims 校验ClaimVerifier(默认SimpleClaimVerifier)检查镜像 digest 与注解是否与签名 payload 一致(cmd/cosign/cli/verify/verify.go);
    • 证书过期检查:优先使用 Rekor 集成时间或 RFC3161 时间戳时间,否则用当前时间(pkg/cosign/verify.go)。
  5. 输出结果:全部签名验证成功后,PrintVerificationHeader打印执行过的检查项清单,PrintVerification-o指定的格式输出(cmd/cosign/cli/verify/common.go)。

验证成功的标准输出

以默认json格式为例,验证通过后会先打印如下检查清单:

Verification for <IMAGE> -- The following checks were performed on each of these signatures: - The cosign claims were validated - Existence of the claims in the transparency log was verified offline - The signatures were verified against the specified public key

随后输出 JSON 数组,包含每个签名对应的Critical(docker 引用与镜像 manifest digest)与Optional字段(含 Subject、Issuer、Bundle 等信息)。使用-o text则会输出人类可读的证书主体、issuer URL、GitHub Workflow 信息以及 payload 明文。

六、keyless 验证的强制约束

从 cmd/cosign/cli/options/certificate.go 可以看到,keyless 验证(即不提供--key--sk)必须同时满足:

  • 提供--certificate-identity--certificate-identity-regexp
  • 提供--certificate-oidc-issuer--certificate-oidc-issuer-regexp

否则会直接返回错误。这是设计使然——keyless 模式下必须显式声明"谁"(身份)与"从哪里签发"(issuer)才可接受,防止任意持有证书者通过验证。同时,--key与证书身份参数互斥(NOf(...) > 1时报KeyAndIdentityParseError,见 cmd/cosign/cli/verify/verify.go)。

七、安全注意事项

  • --allow-http-registry--allow-insecure-registry--insecure-ignore-sct--insecure-ignore-tlog等带insecure/allow字样的参数都会削弱验证强度,原文档与源码均明确提示仅限测试环境使用
  • 跳过 tlog 验证时,cosign 会输出显式警告:Skipping tlog verification is an insecure practice that lacks transparency and auditability verification for the %s.(见 cmd/cosign/cli/verify.go 与 cmd/cosign/cli/verify.go);
  • 对于未上传至透明度日志的签名,--insecure-ignore-tlog是唯一选择,但这意味着产物无法被第三方公开验证,审计与防抵赖能力随之丧失。

八、与其他命令的配合

cosign verify是 cosign 验证体系的入口命令,与之配套的还包括:

  • cosign verify-attestation:验证镜像上的 in-toto attestation(声明性证据),支持 CUE/Rego 策略;
  • cosign verify-blob:验证二进制 blob 的签名;
  • cosign verify-blob-attestation:验证 blob 的 attestation;
  • cosign save:将镜像(含签名)保存到本地,配合--local-image离线验证;
  • cosign generate-key-pair:生成用于--key的公私钥对。

上述命令的入口均注册在 cmd/cosign/cli/verify.go 中,共享同一套CommonVerifyOptions(cmd/cosign/cli/options/verify.go),因此--trusted-root--max-workers--insecure-ignore-tlog等参数在全部 verify 系列命令中行为一致。主命令帮助文档见 doc/cosign.md。

九、常见验证失败与排查建议

失败现象常见原因排查方向
no matching signatures签名无法通过任一检查项检查 key 是否匹配、身份/issuer 条件是否与证书一致
none of the expected identities matched证书身份不匹配核对--certificate-identity与证书 SAN、--certificate-oidc-issuer与证书 OIDC issuer 扩展
no valid tlog entries found透明日志中无对应条目确认签名确实上传过 Rekor,或评估是否使用--insecure-ignore-tlog
certificate does not include required embedded SCT证书缺少 SCT 且未提供 detached SCT重新签发带 SCT 的证书,或仅在测试环境使用--insecure-ignore-sct
expected a signed timestamp to verify an expired certificate证书已过期且未提供时间戳使用--use-signed-timestamps或提供带 bundle 的签名材料
image tag not found镜像引用解析失败核对镜像 URI 与--allow-insecure-registry/--allow-http-registry设置
本地镜像验证失败--local-image路径不是cosign save产物确认目录结构为 OCI layout 且包含签名

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

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询