sigstore/cosign
GitHub: sigstore/cosign
基于 Sigstore 生态的容器与二进制工件签名验证工具,旨在通过透明度日志实现无密钥签名,保障软件供应链安全。
Stars: 5686 | Forks: 699
# cosign
使用 [Sigstore](https://sigstore.dev/) 签名 OCI 容器(及其他工件)!
[](https://goreportcard.com/report/github.com/sigstore/cosign)
[](https://github.com/sigstore/cosign/actions/workflows/e2e-tests.yml)
[](https://bestpractices.coreinfrastructure.org/projects/5715)
[](https://securityscorecards.dev/viewer/?uri=github.com/sigstore/cosign)
Cosign 旨在让签名成为**隐形的基础设施**。
Cosign 支持:
* 配合 Sigstore 公益 Fulcio 证书颁发机构和 Rekor 透明度日志进行“无密钥签名”(默认)
* 硬件和 KMS 签名
* 使用 cosign 生成的加密私钥/公钥对进行签名
* 在 OCI 注册表中进行容器签名、验证和存储。
* 自带 PKI(Bring-your-own PKI)
## 信息
`Cosign` 是作为 [`sigstore`](https://sigstore.dev) 项目的一部分开发的。
我们还有一个 [slack 频道](https://sigstore.slack.com)!
点击[此处](https://join.slack.com/t/sigstore/shared_invite/zt-2ub0ztl5z-PkWb_Ldwef5d6nb~oryaTA)获取邀请链接。
## 安装
关于 Homebrew、Arch、Nix、GitHub Action 和 Kubernetes 的安装方式,请参阅[安装文档](https://docs.sigstore.dev/cosign/system_config/installation/)。
关于 Linux 和 macOS 的二进制文件,请参阅 [GitHub release 资产](https://github.com/sigstore/cosign/releases/latest)。
:rotating_light: 如果您正在从我们的 GCS bucket 下载 cosign 版本,请参阅 2023 年 7 月 31 日的[弃用通知](https://blog.sigstore.dev/cosign-releases-bucket-deprecation/) :rotating_light:
## 开发者安装
如果您拥有 Go 1.22+,可以设置开发环境:
```
$ git clone https://github.com/sigstore/cosign
$ cd cosign
$ go install ./cmd/cosign
$ $(go env GOPATH)/bin/cosign
```
## 贡献
如果您有兴趣为 `cosign` 做贡献,请阅读[贡献文档](./CONTRIBUTING.md)。
未来的 Cosign 开发将集中在下一个主要版本上,该版本将基于
[sigstore-go](https://github.com/sigstore/sigstore-go)。维护者将专注于 sigstore-go 内部的功能开发。
我们非常感谢对 sigstore-go 的贡献,特别是在自带密钥和签名方面。
请查看 [issue 跟踪器](https://github.com/sigstore/sigstore-go/issues)来寻找适合新手的 issue。
Cosign 2.x 是一个稳定版本,将继续接收定期功能更新和错误修复。范围和规模较小的 PR 最有可能被快速审核。
显著修改或破坏 API 的 PR 将不被接受。规模较大但不引入破坏性更改的 PR 可能会被接受,但优先级将低于 sigstore-go 中的 PR。
## Dockerfile
以下是如何通过 ghcr.io/sigstore/cosign/cosign 镜像在 Dockerfile 中安装和使用 cosign:
```
FROM ghcr.io/sigstore/cosign/cosign:v2.4.1 as cosign-bin
# Source: https://github.com/chainguard-images/static
FROM cgr.dev/chainguard/static:latest
COPY --from=cosign-bin /ko-app/cosign /usr/local/bin/cosign
ENTRYPOINT [ "cosign" ]
```
## 快速入门
本节展示如何:
* 使用默认的基于身份的“无密钥签名”方法对容器镜像进行签名(详见[文档](https://docs.sigstore.dev/cosign/signing/overview/))
* 验证容器镜像
* 在 [Sigstore Cosign Quickstart](https://docs.sigstore.dev/quickstart/quickstart-cosign/) 中探索更广泛的无密钥 blob 签名/验证流程
### 签名容器并将签名存储在注册表中
请注意,您应始终基于镜像的摘要(`@sha256:...`)而不是标签(`:latest`)进行签名,
否则您可能会签署本无意签署的内容!
```
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.
This information will be used for signing this artifact and will be stored in public transparency logs and cannot be removed later.
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?access_type=online&client_id=sigstore&code_challenge=OrXitVKUZm2lEWHVt1oQWR4HZvn0rSlKhLcltglYxCY&code_challenge_method=S256&nonce=2KvOWeTFxYfxyzHtssvlIXmY6Jk&redirect_uri=http%3A%2F%2Flocalhost%3A57102%2Fauth%2Fcallback&response_type=code&scope=openid+email&state=2KvOWfbQJ1caqScgjwibzK2qJmb
Successfully verified SCT...
tlog entry created with index: 12086900
Pushing signature to: $IMAGE
```
Cosign 将提示您通过 OIDC 进行身份验证,您将使用电子邮件地址登录。
在底层,cosign 将向 Fulcio 证书颁发机构请求代码签名证书。
证书的主题将与您登录时使用的电子邮件地址匹配。
Cosign 随后将签名和证书存储在 Rekor 透明度日志中,并将签名上传到 OCI 注册表中您所签名镜像的旁边。
### 验证容器
要验证镜像,您需要通过 `--certificate-identity` 和 `--certificate-oidc-issuer` 标志传入预期的证书主题和证书颁发者:
```
cosign verify $IMAGE --certificate-identity=$IDENTITY --certificate-oidc-issuer=$OIDC_ISSUER
```
您也可以为证书身份和颁发者标志传入正则表达式,即 `--certificate-identity-regexp` 和 `--certificate-oidc-issuer-regexp`。
### 根据公钥验证容器
如果找到与公钥匹配的镜像的 *至少一个* `cosign` 格式签名,此命令将返回 `0`。
有关其他签名格式的信息和注意事项,请参阅下面的详细用法。
任何有效的 payload 都将以 JSON 格式打印到 stdout。
请注意,这些已签名的 payload 包含容器镜像的摘要,这就是我们要确保这些“分离式”签名覆盖正确镜像的方式。
```
$ 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}
```
### 在隔离环境(Air-gapped)中验证容器
**注意:** 本节内容已过时。
**注意:** 大多数验证工作流都需要定期从 TUF 存储库请求服务密钥。
要使用公益实例进行隔离环境下的签名验证,您需要从生产环境
TUF 存储库中检索 [trusted root](https://github.com/sigstore/root-signing/blob/main/targets/trusted_root.json) 文件。此文件的内容可能会在无通知的情况下更改。如果不使用 TUF,您将需要构建自己的机制来保持此文件的隔离副本是最新的。
Cosign 可以通过验证 [bundle](./specs/SIGNATURE_SPEC.md#properties) 来进行完全离线验证,该 bundle 通常作为注解分发在镜像 manifest 上。
只要存在此注解,就可以进行离线验证。
此 bundle 注解在无密钥签名中始终默认包含,因此默认的 `cosign sign` 功能将包含离线验证所需的所有材料。
要在隔离环境中验证镜像,镜像和签名必须在本地文件系统上可用。
可以使用 `cosign save` 在本地保存镜像(注意,此步骤必须通过网络连接完成):
```
cosign initialize # This will pull in the latest 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 \ # for artifacts signed without the new protobuf bundle format
--trusted-root ~/.sigstore/root/tuf-repo-cdn.sigstore.dev/targets/trusted_root.json \ # default location of trusted root
--local-image ./path/to/dir
```
您需要传入 `$CERT_IDENTITY` 和 `$CERT_OIDC_ISSUER` 的预期值才能正确验证此镜像。
如果您使用密钥对进行签名,只要本地存在公钥材料,同样的命令也有效:
```
cosign verify --key cosign.pub --offline --local-image ./path/to/dir
```
### 基于身份的 blob 签名和验证
使用无密钥 blob 签名(不带 `--key` 的 `cosign sign-blob`)并根据预期的签名者身份进行验证:
```
$ 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"
```
### 什么**未达到**生产就绪状态?
虽然 `cosign` 的部分功能已稳定,但我们仍在继续试验并添加新功能。
以下功能集尚未被视为稳定,但我们承诺随着时间的推移使其稳定!
#### 格式/规范
虽然用于上传、签名、检索和验证多种工件类型的 `cosign` 代码是稳定的,
但其中某些类型的格式规范可能尚未被视为稳定。
其中一些是在 `cosign` 项目之外开发的,因此我们正在等待它们先稳定下来。
这些包括:
* 用于在容器注册表中存储 SBOM 的 SBOM 规范
* In-Toto 证明格式
## 处理其他工件
OCI 注册表不仅用于存储容器镜像!
`Cosign` 还包含一些用于发布通用工件的实用程序,包括二进制文件、脚本和配置文件,均使用 OCI 协议。
本节展示如何利用这些工具构建一个易于使用、向后兼容且与 Sigstore 其余部分良好集成的工件分发系统。
有关更多信息,请参阅[文档](https://docs.sigstore.dev/cosign/signing/other_types/)。
### Blob
您可以使用 `cosign upload blob` 发布工件:
```
$ echo "my first artifact" > artifact
$ BLOB_SUM=$(shasum -a 256 artifact | cut -d' ' -f 1) && echo "$BLOB_SUM"
c69d72c98b55258f9026f984e4656f0e9fd3ef024ea3fac1d7e5c7e6249f1626
$ BLOB_NAME=my-artifact-$(uuidgen | head -c 8 | tr 'A-Z' 'a-z')
$ BLOB_URI=ttl.sh/$BLOB_NAME:1h
$ BLOB_URI_DIGEST=$(cosign upload blob -f artifact $BLOB_URI) && echo "$BLOB_URI_DIGEST"
Uploading file from [artifact] to [ttl.sh/my-artifact-f42c22e0:5m] with media type [text/plain]
File [artifact] is available directly at [ttl.sh/v2/my-artifact-f42c22e0/blobs/sha256:c69d72c98b55258f9026f984e4656f0e9fd3ef024ea3fac1d7e5c7e6249f1626]
Uploaded image to:
ttl.sh/my-artifact-f42c22e0@sha256:790d47850411e902aabebc3a684eeb78fcae853d4dd6e1cc554d70db7f05f99f
```
您的用户可以使用 curl 或 wget 等标准工具从“直接”URL 下载它:
```
$ curl -L ttl.sh/v2/$BLOB_NAME/blobs/sha256:$BLOB_SUM > artifact-fetched
```
摘要是直接嵌入在 URL 中的,因此他们也可以检查该摘要:
```
$ cat artifact-fetched | shasum -a 256
c69d72c98b55258f9026f984e4656f0e9fd3ef024ea3fac1d7e5c7e6249f1626 -
```
您可以使用常规的 `cosign sign` 命令和标志对其进行签名:
```
$ cosign sign --key cosign.key $BLOB_URI_DIGEST
Enter password for private key:
Pushing signature to: ttl.sh/my-artifact-f42c22e0
```
像往常一样,请务必通过摘要引用您签名的任何镜像,以确保您不会签署错误的对象!
#### Tekton Bundles
[Tekton](https://tekton.dev) bundles 可以上传并管理在 OCI 注册表中。
规范在[此处](https://tekton.dev/docs/pipelines/tekton-bundle-contracts/)。
这意味着它们也可以使用 `cosign` 进行签名和验证。
Tekton Bundles 目前可以使用 [tkn cli](https://github.com/tektoncd/cli) 上传,但我们可能会在未来向
`cosign` 添加此支持。
```
$ tkn bundle push us.gcr.io/dlorenc-vmtest2/pipeline:latest -f task-output-image.yaml
Creating Tekton Bundle:
- Added TaskRun: to image
Pushed Tekton Bundle to us.gcr.io/dlorenc-vmtest2/pipeline@sha256:124e1fdee94fe5c5f902bc94da2d6e2fea243934c74e76c2368acdc8d3ac7155
$ cosign sign --key cosign.key us.gcr.io/dlorenc-vmtest2/pipeline@sha256:124e1fdee94fe5c5f902bc94da2d6e2fea243934c74e76c2368acdc8d3ac7155
Enter password for private key:
tlog entry created with index: 5086
Pushing signature to: us.gcr.io/dlorenc-vmtest2/demo:sha256-124e1fdee94fe5c5f902bc94da2d6e2fea243934c74e76c2368acdc8d3ac7155.sig
```
#### WASM
Web Assembly 模块也可以使用此[规范](https://github.com/solo-io/wasm/tree/master/spec)存储在 OCI 注册表中。
Cosign 可以使用 `cosign wasm upload` 命令上传这些模块:
```
$ cosign upload wasm -f hello.wasm us.gcr.io/dlorenc-vmtest2/wasm
$ cosign sign --key cosign.key us.gcr.io/dlorenc-vmtest2/wasm@sha256:9e7a511fb3130ee4641baf1adc0400bed674d4afc3f1b81bb581c3c8f613f812
Enter password for private key:
tlog entry created with index: 5198
Pushing signature to: us.gcr.io/dlorenc-vmtest2/wasm:sha256-9e7a511fb3130ee4641baf1adc0400bed674d4afc3f1b81bb581c3c8f613f812.sig
```
#### eBPF
[eBPF](https://ebpf.io) 模块也可以使用此[规范](https://github.com/solo-io/bumblebee/tree/main/spec)存储在 OCI 注册表中。
下面的镜像是使用 `bee` 工具构建的。更多信息可以在[此处](https://github.com/solo-io/bumblebee/)找到。
Cosign 随后可以像签名任何其他 OCI 镜像一样对这些镜像进行签名。
```
$ bee build ./examples/tcpconnect/tcpconnect.c localhost:5000/tcpconnect:test
$ bee push localhost:5000/tcpconnect:test
$ cosign sign --key cosign.key localhost:5000/tcpconnect@sha256:7a91c50d922925f152fec96ed1d84b7bc6b2079c169d68826f6cf307f22d40e6
Enter password for private key:
Pushing signature to: localhost:5000/tcpconnect
$ cosign verify --key cosign.pub localhost:5000/tcpconnect:test
Verification for localhost:5000/tcpconnect:test --
The following checks were performed on each of these signatures:
- The cosign claims were validated
- The signatures were verified against the specified public key
[{"critical":{"identity":{"docker-reference":"localhost:5000/tcpconnect"},"image":{"docker-manifest-digest":"sha256:7a91c50d922925f152fec96ed1d84b7bc6b2079c169d68826f6cf307f22d40e6"},"type":"cosign container image signature"},"optional":null}]
```
#### In-Toto Attestations
Cosign 还内置了对 [in-toto](https://in-toto.io) attestations 的支持。
其规范定义在[此处](https://github.com/in-toto/attestation)。
您可以使用以下命令从本地 predicate 文件创建并签名一个 attestation:
```
$ cosign attest --predicate
--key cosign.key $IMAGE_URI_DIGEST
```
支持所有标准密钥管理系统。
Payload 使用 DSSE 签名规范进行签名,定义在[此处](https://github.com/secure-systems-lab/dsse)。
要验证:
```
$ cosign verify-attestation --key cosign.pub $IMAGE_URI
```
## 详细用法
有关更多信息,请参阅[用法文档](https://docs.sigstore.dev/cosign/signing/overview/)。
## 基于硬件的令牌
有关如何配合硬件使用 `cosign` 的信息,请参阅[硬件令牌文档](https://docs.sigstore.dev/cosign/key_management/hardware-based-tokens/)。
## 注册表支持
`cosign` 使用 [go-containerregistry](https://github.com/google/go-containerregistry) 进行注册表
交互,该库通常具有极佳的兼容性,但某些注册表可能存在一些怪癖。
目前,`cosign` 已在以下注册表中测试并正常工作:
* AWS Elastic Container Registry
* GCP's Artifact Registry and Container Registry
* Docker Hub
* Azure Container Registry
* JFrog Artifactory Container Registry
* The CNCF distribution/distribution Registry
* GitLab Container Registry
* GitHub Container Registry
* The CNCF Harbor Registry
* Digital Ocean Container Registry
* Sonatype Nexus Container Registry
* Alibaba Cloud Container Registry
* Red Hat Quay Container Registry 3.6+ / Red Hat quay.io
* Elastic Container Registry
* IBM Cloud Container Registry
* Cloudsmith Container Registry
* The CNCF zot Registry
* OVHcloud Managed Private Registry
我们的目标是支持广泛的注册表。要在尚不完全支持 [OCI media types](https://github.com/sigstore/cosign/blob/main/specs/SIGNATURE_SPEC.md) 的注册表中 `sign` 镜像,可能需要使用 `COSIGN_DOCKER_MEDIA_TYPES` 回退到旧版等效类型。例如:
```
COSIGN_DOCKER_MEDIA_TYPES=1 cosign sign --key cosign.key legacy-registry.example.com/my/image@$DIGEST
```
如果您发现问题,请帮助我们测试并提交错误报告!
说明可以在[跟踪 issue](https://github.com/sigstore/cosign/issues/40)中找到。
## 注意事项
### 故意缺失的功能
`cosign` 仅生成 ECDSA-P256 密钥并使用 SHA256 哈希,这既适用于临时无密钥签名,也适用于托管密钥签名。
密钥以 PEM 编码的 PKCS8 格式存储。
但是,您可以使用 `cosign` 以任何格式、来自任何算法存储和检索签名。
### 可能应该改变的事情
#### Payload 格式
`cosign` 仅支持 Red Hat 的 [simple signing](https://www.redhat.com/en/blog/container-image-signing)
格式用于 payload。
如下所示:
```
{
"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
}
}
```
**注意:** 可以使用 `cosign generate $IMAGE_URI_DIGEST` 为镜像引用生成此内容。
如果合理的话,我很乐意将此格式切换为其他格式。
参见 https://github.com/notaryproject/nv2/issues/40 以查看一个选项。
#### 注册表细节
`cosign` 签名作为单独的对象存储在 OCI 注册表中,仅通过弱引用指回它们“签名”的对象。
这意味着这种关系对注册表是不透明的,并且当镜像被删除时,签名 *不会* 被删除或被垃圾回收。
同样,它们 **可以** 轻松地从一个环境复制到另一个环境,但这不是自动的。
多个签名存储在一个列表中,不幸的是,这目前存在竞态条件。
要添加签名,客户端会编排一个“读取-追加-写入”操作,因此在发生争用时,
最后一次写入将获胜。
##### 指定注册表
`cosign` 默认将签名存储在与其签名镜像相同的仓库中。
要为签名指定不同的仓库,您可以设置 `COSIGN_REPOSITORY` 环境变量。
这将替换提供的镜像中的仓库,如下所示:
```
$ export COSIGN_REPOSITORY=gcr.io/my-new-repo
$ cosign sign --key cosign.key $IMAGE_URI_DIGEST
```
因此,`gcr.io/dlorenc-vmtest2/demo` 的签名将存储在 `gcr.io/my-new-repo/demo:sha256-DIGEST.sig` 中。
注意:不同的注册表可能对“repository”期望不同的格式。
* 要使用 [GCR](https://cloud.google.com/container-registry),如上例所示,
像 `gcr.io/$REPO` 这样的注册表名称就足够了。
* 要使用 [Artifact Registry](https://cloud.google.com/artifact-registry),
请指定完整的镜像名称,如
`$LOCATION-docker.pkg.dev/$PROJECT/$REPO/$STORAGE_IMAGE`,而不仅仅是
repository。例如,
$ export COSIGN_REPOSITORY=us-docker.pkg.dev/my-new-repo/demo$ cosign sign --key cosign.key $IMAGE_URI_DIGEST
其中 `sha256-DIGEST` 将与 `gcr.io/dlorenc-vmtest2/demo` 的摘要匹配。
仅指定像 `$LOCATION-docker.pkg.dev/$PROJECT/$REPO` 这样的 repo 在 Artifact Registry 中将不起作用。
## 签名规范
`cosign` 的灵感来源于 [minisign](https://jedisct1.github.io/minisign/) 和
[signify](https://www.openbsd.org/papers/bsdcan-signify.html) 等工具。
生成的私钥以 PEM 格式存储。
密钥使用 scrypt 作为 KDF,并使用 nacl/secretbox 进行加密。
它们具有 `ENCRYPTED SIGSTORE PRIVATE KEY` 的 PEM 标头:
```
-----BEGIN ENCRYPTED SIGSTORE PRIVATE KEY-----
...
-----END ENCRYPTED SIGSTORE PRIVATE KEY-----
```
公钥以带有 `PUBLIC KEY` 标头的 PEM 编码标准 PKIX 格式存储在磁盘上。
```
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELigCnlLNKgOglRTx1D7JhI7eRw99
QolE9Jo4QUxnbMy5nUuBL+UZF9qqfm/Dg1BNeHRThHzWh2ki9vAEgWEDOw==
-----END PUBLIC KEY-----
```
## 存储规范
`cosign` 将签名存储在 OCI 注册表中,并使用命名约定(基于我们要签名内容的 sha256 的标签)来定位签名索引。
`reg.example.com/ubuntu@sha256:703218c0465075f4425e58fac086e09e1de5c340b12976ab9eb8ad26615c3715` 的签名位于 `reg.example.com/ubuntu:sha256-703218c0465075f4425e58fac086e09e1de5c340b12976ab9eb8ad26615c3715.sig`
大致(忽略主机名中的端口):`s/:/-/g` 和 `s/@/:/g` 来查找签名索引。
有关此策略的一些注意事项,请参阅 [Race conditions](#registry-details)。
替代实现可以使用透明度日志、本地文件系统、单独的仓库注册表、对签名索引的显式引用、新的注册表 API、grafeas 等。
### 签名主体
`cosign` 目前仅适用于作为“manifests”存储在注册表中的工件。
提议的机制足够灵活,可以支持签署任意内容。
### KMS 支持
`cosign` 支持使用 KMS 提供商生成和签名密钥。
目前 cosign 支持 Hashicorp Vault、AWS KMS、GCP KMS、Azure Key Vault,我们希望未来支持更多!
有关更多详细信息,请参阅 [KMS 文档](https://docs.sigstore.dev/cosign/key_management/overview/)。
### OCI Artifacts
使用 [oras](https://github.com/deislabs/oras) 将工件推送到注册表(在这种情况下,是 `cosign` 本身!):
```
$ oras push us-central1-docker.pkg.dev/dlorenc-vmtest2/test/artifact ./cosign
Uploading f53604826795 cosign
Pushed us-central1-docker.pkg.dev/dlorenc-vmtest2/test/artifact
Digest: sha256:551e6cce7ed2e5c914998f931b277bc879e675b74843e6f29bc17f3b5f692bef
```
现在签名!当然使用 `cosign`:
```
$ cosign sign --key cosign.key us-central1-docker.pkg.dev/dlorenc-vmtest2/test/artifact@sha256:551e6cce7ed2e5c914998f931b277bc879e675b74843e6f29bc17f3b5f692bef
Enter password for private key:
Pushing signature to: us-central1-docker.pkg.dev/dlorenc-vmtest2/test/artifact:sha256-551e6cce7ed2e5c914998f931b277bc879e675b74843e6f29bc17f3b5f692bef.sig
```
最后,再次使用 `cosign` 验证 `cosign`:
```
$ cosign verify --key cosign.pub us-central1-docker.pkg.dev/dlorenc-vmtest2/test/artifact@sha256:551e6cce7ed2e5c914998f931b277bc879e675b74843e6f29bc17f3b5f692bef
The following checks were performed on each of these signatures:
- The cosign claims were validated
- The claims were present in the transparency log
- The signatures were integrated into the transparency log when the certificate was valid
- The signatures were verified against the specified public key
- The code-signing certificate was verified using trusted certificate authority certificates
{"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"sha256:551e6cce7ed2e5c914998f931b277bc879e675b74843e6f29bc17f3b5f692bef"},"Type":"cosign container image signature"},"Optional":null}
```
## 常见问题解答
### 为什么不使用 Notary v2
很难简短回答这个问题。
这篇文章包含一些比较:
[Notary V2 and Cosign](https://medium.com/@dlorenc/notary-v2-and-cosign-b816658f044d)
如果您发现其他比较文章,请在此处发送 PR,我们将全部链接起来。
### 为什么不使用 containers/image signing
`containers/image` 签名与 `cosign` 很接近,并且我们复用了 payload 格式。
`cosign` 的不同之处在于它使用 ECDSA-P256 密钥而不是 PGP 进行签名,并且将签名存储在注册表中。
### 为什么不使用 TUF?
我相信这个工具是对 TUF 的补充,它们可以一起使用。
我还没试过,但我认为我们也可以复用注册表进行 TUF 存储。
## 设计要求
* 无需外部服务进行签名存储、查询或检索
* 我们的目标是尽可能支持更多的注册表
* 一切都应通过注册表 API 进行
* 根本不需要 PGP。
* 用户必须能够找到镜像的所有签名
* 签名者可以在推送后对镜像进行签名
* 多个实体可以对镜像进行签名
* 对镜像进行签名不会改变镜像
* 纯 Go 实现
## 未来构想
### 注册表 API 变更
我们用于在注册表中存储内容的命名约定和读-修改-写更新模式有点“取巧 (hacky)”。
我认为它们是目前可用的最佳(唯一)选择,但如果注册表 API
发生变化,我们可以改进这些。
### 其他类型
`cosign` 可以签名注册表中的任何内容。
这些示例展示了签名单个镜像,但您也可以签名多平台 `Index`,
或任何其他类型的工件。
这包括 Helm Charts、Tekton Pipelines 以及当前使用 OCI 注册表
进行分发的任何其他内容。
这也意味着可以将新工件类型上传到注册表并进行签名。
一个值得存储和签名的有趣类型是 TUF 存储库。
我还没试过,但我相当确定 TUF 可以在此基础上实现。
### 标签签名
`cosign` 签名保护存储在注册表中的对象的摘要。
可选的 `annotations` 支持(通过 `cosign sign` 的 `-a` 标志)可用于向被签名
并受签名保护的 payload 添加额外数据。
此功能的一个用例是签署标签->摘要的映射。
如果您想证明特定标签(或一组标签)应指向某个摘要,您可以
运行如下命令:
```
$ docker push $IMAGE_URI
The push refers to repository [dlorenc/demo]
994393dc58e7: Pushed
5m: digest: sha256:1304f174557314a7ed9eddb4eab12fed12cb0cd9809e4c28f29af86979a3c870 size: 528
$ TAG=sign-me
$ cosign sign --key cosign.key -a tag=$TAG $IMAGE_URI_DIGEST
Enter password for private key:
Pushing signature to: dlorenc/demo:1304f174557314a7ed9eddb4eab12fed12cb0cd9809e4c28f29af86979a3c870.sig
```
然后,您可以使用 `cosign verify` 的 `-a` 标志来验证标签->摘要映射也包含在签名中。
此示例验证了指向(`sha256:1304f174557314a7ed9eddb4eab12fed12cb0cd9809e4c28f29af86979a3c870`)的摘要 `$TAG`
已被签名,**并且** `tag` 注解具有 `sign-me` 值:
```
$ cosign verify --key cosign.pub -a tag=$TAG $IMAGE_URI | jq .
{
"Critical": {
"Identity": {
"docker-reference": ""
},
"Image": {
"Docker-manifest-digest": "97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36"
},
"Type": "cosign container image signature"
},
"Optional": {
"tag": "sign-me"
}
}
```
也可以在此处添加时间戳,以实现 TUF 风格的冻结攻击防护。
### 基础镜像/层签名
同样,`cosign` 可以签名注册表中的任何内容。
您可以使用 `cosign` 签名旨在用作基础镜像的镜像,
并在生成的派生镜像中包含该来源元数据。
这可用于强制要求镜像是从授权的基础镜像构建的。
大致思路:
* OCI manifests 有一个有序的 `layer` `Descriptors` 列表,其中可以包含注解。
请参阅[此处](https://github.com/opencontainers/image-spec/blob/master/manifest.md)的
规范。
* 基础镜像是一个有序的层列表,其他层会追加到该列表,以及一个
会被更改的初始配置对象。
* 派生镜像可以自由地完全删除/破坏/重建来自其基础镜像的配置,
因此签名配置的价值有限。
* 我们可以对完整的有序基础层集进行签名,并将该签名作为注解附加到
生成的子镜像的 **最后** 一层。
此示例 manifest 代表一个从具有两个层的基础镜像构建的镜像。
添加了一个额外的层,形成最终镜像。
```
{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"size": 7023,
"digest": "sha256:b5b2b2c507a0944348e0303114d8d93aaaa081732b86451d9bce1f432a537bc7"
},
"layers": [
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 32654,
"digest": "sha256:9834876dcfb05cb167a5c24953eba58c4ac89b1adf57f28f2f9d09af107ee8f0"
},
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 16724,
"digest": "sha256:3c3a4604a545cdc127456d94e421cd355bca5b528f4a9c1905b15da2eb4a4c6b",
"annotations": {
"dev.cosign.signature.baseimage": "Ejy6ipGJjUzMDoQFePWixqPBYF0iSnIvpMWps3mlcYNSEcRRZelL7GzimKXaMjxfhy5bshNGvDT5QoUJ0tqUAg=="
}
},
{
"mediaType": "application/vnd.oci.image.layer.v1.tar+gzip",
"size": 73109,
"digest": "sha256:ec4b8955958665577945c89419d1af06b5f7636b4ac3da7f12184802ad867736"
}
],
}
```
请注意,这可以递归应用,用于多个中间基础镜像。
### 连署(Counter-Signing)
Cosign 签名(及其受保护的 payload)作为工件存储在注册表中。
这些签名对象也可以被签名,从而产生一个新的“连署”工件。
此“连署”保护签名(或签名集)**以及**引用的工件,这允许它
作为对 **签名本身** 的证明。
在我们对签名工件进行签名之前,我们首先给它一个易于记忆的名称,以便稍后找到它。
```
$ cosign sign --key cosign.key -a sig=original $IMAGE_URI_DIGEST
Enter password for private key:
Pushing signature to: dlorenc/demo:sha256-97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36.sig
$ cosign verify --key cosign.pub dlorenc/demo | jq .
{
"Critical": {
"Identity": {
"docker-reference": ""
},
"Image": {
"Docker-manifest-digest": "97fc222cee7991b5b061d4d4afdb5f3428fcb0c9054e1690313786befa1e4e36"
},
"Type": "cosign container image signature"
},
"Optional": {
"sig": "original"
}
}
```
现在给该签名一个易于记忆的名称,然后对其签名:
```
$ crane tag $(cosign triangulate $IMAGE_URI) mysignature
2021/02/15 20:22:55 dlorenc/demo:mysignature: digest: sha256:71f70e5d29bde87f988740665257c35b1c6f52dafa20fab4ba16b3b1f4c6ba0e size: 556
$ cosign sign --key cosign.key -a sig=counter dlorenc/demo:mysignature
Enter password for private key:
Pushing signature to: dlorenc/demo:sha256-71f70e5d29bde87f988740665257c35b1c6f52dafa20fab4ba16b3b1f4c6ba0e.sig
$ cosign verify --key cosign.pub dlorenc/demo:mysignature
{"Critical":{"Identity":{"docker-reference":""},"Image":{"Docker-manifest-digest":"71f70e5d29bde87f988740665257c35b1c6f52dafa20fab4ba16b3b1f4c6ba0e"},"Type":"cosign container image signature"},"Optional":{"sig":"counter"}}
```
最后,检查原始签名:
```
$ crane manifest dlorenc/demo@sha256:71f70e5d29bde87f988740665257c35b1c6f52dafa20fab4ba16b3b1f4c6ba0e
{
"schemaVersion": 2,
"config": {
"mediaType": "application/vnd.oci.image.config.v1+json",
"size": 233,
"digest": "sha256:3b25a088710d03f39be26629d22eb68cd277a01673b9cb461c4c24fbf8c81c89"
},
"layers": [
{
"mediaType": "application/vnd.oci.descriptor.v1+json",
"size": 217,
"digest": "sha256:0e79a356609f038089088ec46fd95f4649d04de989487220b1a0adbcc63fadae",
"annotations": {
"dev.sigstore.cosign/signature": "5uNZKEP9rm8zxAL0VVX7McMmyArzLqtxMTNPjPO2ns+5GJpBeXg+i9ILU+WjmGAKBCqiexTxzLC1/nkOzD4cDA=="
}
}
]
}
```
## 发布周期
我们会根据需要发布版本。补丁版本用于修复小错误。当修复了多个错误或添加了功能时,
会定期发布次版本。当出现破坏性功能时,
将发布主要版本。
## 安全
如果您发现任何安全问题,请参阅 sigstore 的[安全
流程](https://github.com/sigstore/.github/blob/main/SECURITY.md)
## GitHub Release Assets 中的 Bundle 文件
`cosign` 的 GitHub release assets 包含由 [GoReleaser](https://github.com/sigstore/cosign/blob/ac999344eb381ae91455b0a9c5c267e747608d76/.goreleaser.yml#L166) 生成的 Sigstore bundle 文件,该文件是在签名用于验证 release binaries 完整性的 cosign blob 时生成的。此文件不被 cosign 本身使用,而是提供给希望[验证 release binaries 完整性](https://docs.sigstore.dev/cosign/system_config/installation/#verifying-cosign-with-artifact-key)的用户。标签:CVE, DevSecOps, EVTX分析, EVTX分析, Fulcio, Go, KMS, Rekor, Ruby工具, Sigstore, Web截图, 上游代理, 二进制签名, 代码签名, 加密, 完整性校验, 容器安全, 容器签名, 抽象层, 数字签名, 无密钥签名, 日志审计, 漏洞扫描器, 透明日志, 镜像验证