cosign 根命令完全指南:容器签名、验证与 OCI 注册表存储
【免费下载链接】cosignCode signing and transparency for containers and binaries项目地址: https://gitcode.com/GitHub_Trending/co/cosign
本指南以当前仓库doc/cosign.md(cosign 根命令 CLI 参考)为骨架,结合源码、子命令文档与签名规范,系统讲解 cosign 的全局选项、全部子命令、签名存储机制与常见问题排查。读完本文,你将掌握 cosign 的命令行体系,能够独立完成容器镜像的密钥签名与无密钥(keyless)签名、验证、签名存储定位以及基于退出码的自动化脚本编写。
cosign 是什么
cosign 是一个"用于在 OCI 注册表中进行容器签名、验证与存储的工具"(A tool for Container Signing, Verification and Storage in an OCI registry),它由 Sigstore 项目孵化,致力于让签名成为"隐形基础设施"(invisible infrastructure)。它支持:
- 使用 Sigstore 公共 Fulcio 证书颁发机构和 Rekor 透明日志的"无密钥签名"(keyless signing,默认方式);
- 硬件令牌与 KMS 签名(Vault、AWS KMS、GCP KMS、Azure Key Vault);
- 使用 cosign 生成的加密私钥/公钥对进行签名;
- 在 OCI 注册表中存储、验证容器签名;
- 自带 PKI(Bring-your-own PKI)。
从源码结构看,cosign 的 CLI 采用 Cobra 命令框架实现:入口在 cmd/cosign/main.go,根命令在 cmd/cosign/cli/commands.go 的New()中注册全部子命令。本文档doc/cosign.md正是由该根命令生成的命令行参考。
全局选项(Global Options)
在根命令层级执行cosign --help可以看到如下全局选项:
-h, --help help for cosign --output-file string log output to a file -t, --timeout duration timeout for commands (default 3m0s) -d, --verbose log debug output这些选项全部声明为PersistentFlags(持久标志),因此对 cosign 的每一个子命令都生效。对应实现位于 cmd/cosign/cli/options/root.go:
| 选项 | 短标志 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
--output-file | — | string | 空 | 将日志输出重定向到指定文件 |
--timeout | -t | duration | 3m0s | 命令执行超时时间 |
--verbose | -d | bool | false | 输出调试日志 |
--output-file:在根命令的PersistentPreRunE中,cosign 会用os.Create创建该文件并把os.Stdout指向它(参见 cmd/cosign/cli/commands.go),命令结束后再恢复标准输出。适合把冗长日志落盘留存。--timeout:默认 3 分钟。与 Sigstore 各公共服务(Fulcio、Rekor、OIDC)交互耗时较长,网络环境不佳时可调大,例如cosign sign --timeout 5m <IMAGE>。--verbose:开启后会将 go-containerregistry 的logs.Debug输出到 stderr,便于排查注册表交互问题。
标志归一化:cert 系列别名
根命令还注册了一个全局标志归一化函数(cmd/cosign/cli/commands.go),把历史遗留的短名自动映射为长名:
--cert→--certificate--cert-email→--certificate-email--cert-chain→--certificate-chain--cert-oidc-issuer→--certificate-oidc-issuer--output-cert→--output-certificate--cert-identity→--certificate-identity
这保证了旧脚本中--cert-identity等写法仍能正常工作。
子命令全景:一套命令覆盖完整供应链签名闭环
根命令注册了以下子命令(见 cmd/cosign/cli/commands.go 与doc/cosign.md的 SEE ALSO 段落):
| 子命令 | 一句话说明 | 所属环节 |
|---|---|---|
cosign attest | 为指定容器镜像附加(in-toto)断言 | 签名/断言 |
cosign attest-blob | 为指定 blob 附加断言 | 签名/断言 |
cosign bundle | 与 Sigstore protobuf bundle 交互 | 验证材料 |
cosign clean | 移除镜像上的所有签名 | 管理 |
cosign completion | 生成 shell 补全脚本 | 辅助 |
cosign download | 下载制品及其附加产物(签名、SBOM、断言) | 获取 |
cosign env | 打印 cosign 环境变量 | 诊断 |
cosign generate-key-pair | 生成密钥对 | 密钥管理 |
cosign import-key-pair | 导入 PEM 编码的 RSA 或 EC 私钥 | 密钥管理 |
cosign initialize | 初始化 Sigstore 根(TUF),获取可信证书与密钥目标 | 信任初始化 |
cosign load | 将磁盘上已签名的镜像加载到远程注册表 | 传输 |
cosign login | 登录注册表 | 注册表 |
cosign piv-tool | 管理硬件令牌(YubiKey 等) | 密钥管理 |
cosign pkcs11-tool | 从 PKCS11 令牌检索信息 | 密钥管理 |
cosign public-key | 从密钥对中导出公钥 | 密钥管理 |
cosign save | 将容器镜像及关联签名保存到磁盘指定目录 | 传输 |
cosign sign | 为指定容器镜像签名 | 签名 |
cosign sign-blob | 为指定 blob 签名,输出 base64 编码签名到 stdout | 签名 |
cosign signing-config | 与 Sigstore protobuf signing config 交互 | 配置 |
cosign tree | 展示镜像的供应链安全产物(签名、SBOM、断言) | 查看 |
cosign trusted-root | 与 Sigstore protobuf trusted root 交互 | 信任 |
cosign verify | 验证指定容器镜像上的签名 | 验证 |
cosign verify-attestation | 验证指定容器镜像上的断言 | 验证 |
cosign verify-blob | 验证指定 blob 上的签名 | 验证 |
cosign verify-blob-attestation | 验证指定 blob 上的断言 | 验证 |
cosign version | 打印版本 | 辅助 |
注:
login、completion分别由 go-containerregistry 的 crane auth 与 autocomplete 库提供(见 cmd/cosign/cli/commands.go)。
核心实操一:无密钥签名与验证容器镜像
签名(keyless signing)
cosign sign $IMAGE执行流程输出大致如下:
Generating ephemeral keys... Retrieving signed certificate... Note that there may be personally identifiable information associated with this signed artifact. This may include the email address associated with the account with which you authenticate. ... By typing 'y', you attest that you grant (or have permission to grant) and agree to have this information stored permanently in transparency logs. Are you sure you would like to continue? [y/N] y Your browser will now be opened to: https://oauth2.sigstore.dev/auth/auth?... Successfully verified SCT... tlog entry created with index: 12086900 Pushing signature to: $IMAGE其底层流程是:cosign 生成临时密钥 → 通过 OIDC 交互登录(使用邮箱)→ 向 Fulcio 证书颁发机构申请代码签名证书(证书主体与登录邮箱一致)→ 将签名与证书写入 Rekor 透明日志 → 把签名上传到 OCI 注册表中镜像旁边。请务必基于镜像摘要(@sha256:...)而不是标签(:latest)签名,否则可能签错对象。cosign sign的完整参数见 doc/cosign_sign.md,常用的有:
--key <key path>|<kms uri>:使用本地密钥、KMS URI(azurekms://、awskms://、gcpkms://、hashivault://、k8s://)或环境变量密钥env://[ENV_VAR];-a key=value:附加签名注解;--recursive/-r:多架构镜像连同其引用的每个离散镜像一并签名;--tlog-upload=false:跳过透明日志上传;--upload=false:仅本地签名不上传;--fulcio-auth-flow:指定 OIDC 流程(normal|device|token|client_credentials);--sk/--slot:使用硬件安全密钥(默认槽位signature);COSIGN_DOCKER_MEDIA_TYPES=1:在不完全支持 OCI media types 的注册表上回退到传统类型。
验证(keyless)
cosign verify $IMAGE --certificate-identity=$IDENTITY --certificate-oidc-issuer=$OIDC_ISSUERkeyless 流程必须显式声明预期的证书主体(--certificate-identity)与证书签发者(--certificate-oidc-issuer),例如 GitHub Actions 场景为:
cosign verify-blob artifact \ --bundle artifact.sigstore.json \ --certificate-identity "https://github.com/ORG/REPO/.github/workflows/release.yml@refs/heads/main" \ --certificate-oidc-issuer "https://token.actions.githubusercontent.com"也可以用正则替代精确匹配:--certificate-identity-regexp、--certificate-oidc-issuer-regexp。cosign verify的完整参数见 doc/cosign_verify.md,包括--key(公钥文件/URL/KMS/K8s Secret/GitLab)、--local-image(验证cosign save保存的本地镜像)、--output json|text、--max-workers(默认 10)等。
使用公钥验证
$ cosign verify --key cosign.pub $IMAGE_URI:1h The following checks were performed on these signatures: - The cosign claims were validated - The signatures were verified against the specified public key {"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"sha256:87ef60f558bad79beea6425a3b28989f01dd417164150ab3baab98dcbf04def8"},"Type":"cosign container image signature"},"Optional":null}只要至少一个匹配公钥的 cosign 格式签名被找到,命令即返回 0。注意 payload 中内嵌了镜像摘要,因此"分离式"(detached)签名能确保覆盖正确的镜像。
核心实操二:blob 签名与验证
blob(二进制文件)的 keyless 签名与验证同样开箱即用:
$ cosign sign-blob artifact --bundle artifact.sigstore.json --yes $ cosign verify-blob artifact \ --bundle artifact.sigstore.json \ --certificate-identity "https://github.com/ORG/REPO/.github/workflows/release.yml@refs/heads/main" \ --certificate-oidc-issuer "https://token.actions.githubusercontent.com"--bundle会把离线验证所需的全部材料(Rekor 日志条目、证书、时间戳等)写入一个 JSON 文件,便于与工件一起分发;--yes跳过非破坏性操作的确认提示。
核心实操三:离线(air-gapped)环境验证
keyless 签名默认会在镜像 manifest 的注解中携带一个 bundle(见 签名规范 的 Properties 一节),因此可以完全离线验证:
cosign initialize # 拉取最新 TUF root(需网络) cosign save $IMAGE_NAME --dir ./path/to/dir # 把镜像连同签名保存到本地目录(需网络)然后在离线环境中:
cosign verify \ --certificate-identity $CERT_IDENTITY \ --certificate-oidc-issuer $CERT_OIDC_ISSUER \ --offline=true \ --new-bundle-format=false \ # 针对未使用新 protobuf bundle 格式签名的制品 --trusted-root ~/.sigstore/root/tuf-repo-cdn.sigstore.dev/targets/trusted_root.json \ # trusted root 默认位置 --local-image ./path/to/dir使用密钥对签名时同理:cosign verify --key cosign.pub --offline --local-image ./path/to/dir。
签名存储规范:签名到底存在哪里
cosign 把签名存放在 OCI 注册表中,并采用基于被签名对象 sha256 的命名约定定位签名索引(tag 机制):
规则(忽略主机名中的端口):把:替换为-,把@替换为:,再追加.sig后缀。例如镜像
reg.example.com/ubuntu@sha256:703218c0465075f4425e58fac086e09e1de5c340b12976ab9eb8ad26615c3715
的签名位于
reg.example.com/ubuntu:sha256-703218c0465075f4425e58fac086e09e1de5c340b12976ab9eb8ad26615c3715.sig
更规范的表述见 签名规范 的 Tag-based Discovery 一节:对象引用先解析为摘要,再把sha256:abcdef...编码进 tag(:→-,追加.sig)。
指定签名仓库(COSIGN_REPOSITORY)
默认签名存储在与镜像相同的仓库中;可用环境变量COSIGN_REPOSITORY指定其他仓库:
$ export COSIGN_REPOSITORY=gcr.io/my-new-repo $ cosign sign --key cosign.key $IMAGE_URI_DIGESTgcr.io/dlorenc-vmtest2/demo的签名将存放在gcr.io/my-new-repo/demo:sha256-DIGEST.sig。注意不同注册表对"repository"格式要求不同:
- GCR:
gcr.io/$REPO即可; - Artifact Registry:必须给完整镜像名
$LOCATION-docker.pkg.dev/$PROJECT/$REPO/$STORAGE_IMAGE,仅给仓库名不生效。
存储方式的已知权衡
- 签名与镜像之间只是弱引用:注册表不理解该关系,删除镜像时签名不会被垃圾回收;
- 多签名列表的写入采用"读-追加-写"模式,存在竞态条件(并发签名时最后写入者胜出);
- 优点是签名对象易于复制迁移,缺点是不会自动跟随镜像。
签名与密钥的格式
- 私钥:cosign 仅生成 ECDSA-P256 密钥、使用 SHA256 哈希;私钥以 PEM 编码 PKCS8 格式存储,并使用 scrypt 作为 KDF、nacl/secretbox 加密,PEM 头为
ENCRYPTED SIGSTORE PRIVATE KEY:
-----BEGIN ENCRYPTED SIGSTORE PRIVATE KEY----- ... -----END ENCRYPTED SIGSTORE PRIVATE KEY------ 公钥:PEM 编码的标准 PKIX 格式,头为
PUBLIC KEY:
-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELigCnlLNKgOglRTx1D7JhI7eRw99 QolE9Jo4QUxnbMy5nUuBL+UZF9qqfm/Dg1BNeHRThHzWh2ki9vAEgWEDOw== -----END PUBLIC KEY------ Payload 格式:cosign 采用 Red Hat Simple Signing 格式(可用
cosign generate $IMAGE_URI_DIGEST生成):
{ "critical": { "identity": { "docker-reference": "testing/manifest" }, "image": { "Docker-manifest-digest": "sha256:20be...fe55" }, "type": "cosign container image signature" }, "optional": { "creator": "Bob the Builder", "timestamp": 1458239713 } }在 OCI manifest 中,payload 作为 blob 被引用(media type 为application/vnd.dev.cosign.simplesigning.v1+json),签名以 base64 形式存放在 layer 注解dev.cosignproject.cosign/signature中,证书与证书链则存放在dev.cosignproject.cosign/certificate与dev.cosignproject.cosign/chain注解中(详见 签名规范 的 OCI Image Manifest V1 一节)。签名与镜像的绑定关系为两级哈希:Sign(sha256(SimpleSigningPayload(sha256(Image Manifest)))),哈希算法与注册表一致(实践中即 sha256)。
退出码:让验证结果可脚本化
cosign 为验证类错误定义了稳定的退出码(详见 doc/cosign_exit_codes.md 与 cmd/cosign/errors/exit_code_lookup.go):
| 退出码 | 含义 |
|---|---|
| 10 | 镜像无签名导致验证失败(ErrNoSignaturesFound) |
| 11 | 标签不存在导致验证失败(ErrImageTagNotFound) |
| 12 | 无匹配签名导致验证失败(ErrNoMatchingSignatures) |
| 13 | 签名上未找到证书导致验证失败(ErrNoCertificateFoundOnSignature) |
其余错误默认退出码为 1。入口在 cmd/cosign/main.go:当错误实现了CosignError接口时,按ExitCode()退出,否则log.Fatalf以 1 退出。CI 流水线中可直接用echo $?区分不同的失败原因。
环境变量与诊断
执行cosign env可打印全部已注册的 cosign 环境变量(描述与期望值),敏感变量默认以******遮蔽,可用--show-descriptions --show-sensitive-values展开(实现见 cmd/cosign/cli/env.go 与 cmd/cosign/cli/options/env.go)。常用变量包括:
COSIGN_REPOSITORY:指定签名存储仓库;COSIGN_DOCKER_MEDIA_TYPES=1:在不支持 OCI media types 的注册表上回退到 Docker 媒体类型;COSIGN_EXPERIMENTAL:开启实验特性(相关代码见 cmd/cosign/cli/options/experimental.go)。
此外,所有带-的 CLI 标志都可以用环境变量形式覆盖:根命令的 Viper 绑定逻辑(cmd/cosign/cli/options/root.go)会把--some-flag映射为COSIGN_SOME_FLAG。
常见问题排查
failed to verify timestamps: threshold not met for verified log entry integrated timestamps: 0 < 1:签名的验证需要 RFC3161 时间戳支持。升级到最新版 cosign;若使用 Cosign 2.6.x,可加--use-signed-timestamps。no signatures found:可能是该镜像签名需要 Rekor v2 透明日志支持,请升级到最新版 cosign。- 签名时 HTTP 错误:签名依赖多个 Sigstore 公共服务(Fulcio/Rekor/OIDC),服务故障时重试通常有效。
小结
从根命令的四个全局选项,到覆盖"密钥管理—签名—验证—存储—传输—审计"全链路的 26 个子命令,cosign 把容器与二进制的代码签名做成了标准化的供应链安全基础设施。本文介绍的签名存储定位规则(sha256-DIGEST.sigtag)、退出码约定与离线验证流程,可直接用于 CI/CD 与制品发布的安全审计实践;更底层的签名格式与发现机制细节,可继续阅读 签名规范 与 签名存储示意图。
【免费下载链接】cosignCode signing and transparency for containers and binaries项目地址: https://gitcode.com/GitHub_Trending/co/cosign
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考