
cosign v3.1.3
容器和二进制的代码签名与透明度
cosign
使用 Sigstore 对 OCI 容器(及其他制品)进行签名!
Cosign 旨在让签名成为无形的基础设施。
Cosign 支持:
- 使用 Sigstore 公共 Fulcio 证书颁发机构和 Rekor 透明日志进行“无密钥签名”(默认)
- 硬件与 KMS 签名
- 使用 cosign 生成的加密私钥/公钥对进行签名
- 在 OCI 注册表中进行容器签名、验证与存储。
- 自带 PKI
信息
Cosign 是 sigstore 项目的一部分。
我们还使用一个 slack 频道!
点击此处获取邀请链接。
安装
有关 Homebrew、Arch、Nix、GitHub Action 和 Kubernetes 的安装,请参阅安装文档。
对于 Linux 和 macOS 二进制文件,请参见 GitHub 发布资产。
🚨 如果您正在从我们的 GCS 存储桶下载 cosign 的发布版本,请查阅 2023 年 7 月 31 日的弃用通知以获取更多信息 🚨
开发者安装
如果您有 Go 1.22+,可以设置开发环境:```shell $ git clone https://github.com/sigstore/cosign $ cd cosign $ go install ./cmd/cosign $ $(go env GOPATH)/bin/cosign
## 参与贡献
如果你有兴趣为 `cosign` 做贡献,请阅读[贡献文档](https://github.com/sigstore/cosign/blob/main/CONTRIBUTING.md)。
未来的 Cosign 开发将专注于下一个主要版本,该版本将基于 [sigstore-go](https://github.com/sigstore/sigstore-go)。维护者将专注于 sigstore-go 内的功能开发。我们感谢对 sigstore-go 的贡献,特别是关于自带密钥(bring-your-own keys)和签名方面的贡献。请参阅[问题追踪器](https://github.com/sigstore/sigstore-go/issues)以获取适合新手的问题。
Cosign 2.x 是一个稳定版本,将继续接收定期的功能更新和错误修复。范围小且规模小的 PR 最有可能被快速审查。
显著修改或破坏 API 的 PR 将不被接受。规模较大但不引入破坏性变更的 PR 可能会被接受,但优先级将低于 sigstore-go 中的 PR。
## Dockerfile
以下是如何通过 ghcr.io/sigstore/cosign/cosign 镜像在 Dockerfile 中安装和使用 cosign:```shell
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" ]
快速开始
以下展示如何:
- 使用默认基于身份的“无密钥签名”方法对容器镜像进行签名(参见文档了解更多信息)
- 验证容器镜像
- 探索更广泛的无密钥 blob 签名/验证流程,详见 Sigstore Cosign 快速入门
对容器进行签名并将签名存储在镜像仓库中
请注意,您应始终基于镜像摘要(@sha256:...)而非标签(:latest)进行签名,否则可能会签名到非预期的内容!```shell
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。
关于其他签名格式的信息和注意事项,请参阅下面的详细用法。
任何有效的负载都会以json格式打印到stdout。 请注意,这些签名负载包含容器映像的摘要,这样我们就能确保这些"分离"签名覆盖了正确的映像。```shell $ 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}
### 在气隙环境中验证容器
**注意:** 本节内容已过时。
**注意:** 大多数验证工作流需要定期向TUF仓库请求服务密钥。如果要使用公共实例对签名进行气隙验证,您需要从生产TUF仓库中获取[trusted root](https://github.com/sigstore/root-signing/blob/main/targets/trusted_root.json)文件。该文件的内容会随时更改,恕不另行通知。如果不使用TUF,您需要自行构建机制来保持您的气隙副本文件是最新的。
Cosign可以通过验证[包](https://github.com/sigstore/cosign/blob/main/specs/SIGNATURE_SPEC.md#properties)来实现完全离线验证,该包通常作为镜像清单的注解分发。只要存在此注解,就可以进行离线验证。默认情况下,无密钥签名始终包含此包注解,因此默认的`cosign sign`功能将包含离线验证所需的所有材料。
要在气隙环境中验证镜像,镜像和签名必须本地存储在文件系统中。
可以使用`cosign save`将镜像保存到本地(注意,此步骤必须有网络连接):```
cosign initialize # This will pull in the latest TUF root
cosign save $IMAGE_NAME --dir ./path/to/dir
现在,在隔离网络环境中,可以验证这个本地镜像:```shell
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 签名(cosign sign-blob 不加 --key)并根据预期的签名者身份进行验证:```shell
$ 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 项目积极支持最新版本以及 v2 系列中的最后一个版本。
#### 常见问题及解决方法
1. 验证失败,显示 `failed to verify timestamps: threshold not met for verified log entry integrated timestamps: 0 < 1`:你可能正在验证一个需要 RFC3161 时间戳支持的签名
* 升级到最新的 Cosign 或
* 对于 Cosign 2.6.x,使用 `--use-signed-timestamps`
1. 验证失败,显示 `no signatures found`:你可能正在验证一个需要 Rekor v2 透明日志支持的镜像签名
* 升级到最新的 Cosign
1. 签名失败并出现 HTTP 错误:使用 Cosign 签名依赖于多个 Sigstore 服务。如果其中任何一个服务失败,重试可能是一个有用的解决方法——也欢迎针对特定失败提交问题
#### 我是其他问题
请创建一个 [issue](https://github.com/sigstore/cosign/issues/new/choose) 或通过 [slack 频道](#info) 询问。
## 与其他工件一起使用
OCI 仓库不仅用于存储容器镜像!
`Cosign` 还包含一些用于发布通用工件的工具,包括二进制文件、脚本和配置文件,使用 OCI 协议。
本节展示如何利用这些功能构建一个易于使用、向后兼容的工件分发系统,与 Sigstore 其余部分良好集成。
有关更多信息,请参阅 [文档](https://docs.sigstore.dev/cosign/signing/other_types/)。
### Blobs
你可以使用 `cosign upload blob` 发布一个工件:```shell
$ 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 下载它:```shell $ curl -L ttl.sh/v2/$BLOB_NAME/blobs/sha256:$BLOB_SUM > artifact-fetched
摘要直接嵌入到URL中,因此他们也可以进行检查。```shell
$ cat artifact-fetched | shasum -a 256
c69d72c98b55258f9026f984e4656f0e9fd3ef024ea3fac1d7e5c7e6249f1626 -
你可以使用常规的 cosign sign 命令和标志来签名它:```shell
$ 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) 包可以上传并在OCI仓库中进行管理。
规范在[这里](https://tekton.dev/docs/pipelines/tekton-bundle-contracts/)。
这意味着它们也可以使用 `cosign` 进行签名和验证。
目前,Tekton包可以通过 [tkn cli](https://github.com/tektoncd/cli) 上传,但我们将来可能会将此支持添加到 `cosign` 中。```shell
$ 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 模块也可以存储在OCI注册表中,使用此规范。
Cosign 可以使用 cosign wasm upload 命令上传这些模块:```shell
$ 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) 模块也可以存储在 OCI 注册表中,使用此[规范](https://github.com/solo-io/bumblebee/tree/main/spec)。
下面的镜像是使用 `bee` 工具构建的。更多信息可以在[这里](https://github.com/solo-io/bumblebee/)找到。
然后,Cosign 可以对这些镜像进行签名,就像对任何其他 OCI 镜像一样。```shell
$ 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 证明
Cosign 还内置支持 in-toto 证明。 其规范定义在此处。
您可以使用以下命令从本地谓词文件创建并签名一个证明:```shell $ cosign attest --predicate --key cosign.key $IMAGE_URI_DIGEST
支持所有标准密钥管理系统。
载荷使用 DSSE 签名规范进行签名,该规范定义在[此处](https://github.com/secure-systems-lab/dsse)。
要验证:```shell
$ cosign verify-attestation --key cosign.pub $IMAGE_URI
详细用法
更多信息请参见用法文档。
基于硬件的令牌
关于如何使用 cosign 与硬件的信息,请参见硬件令牌文档。
仓库支持
cosign 使用 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媒体类型的仓库中sign镜像,可能需要使用 COSIGN_DOCKER_MEDIA_TYPES 回退到传统等效类型。例如:```shell
COSIGN_DOCKER_MEDIA_TYPES=1 cosign sign --key cosign.key legacy-registry.example.com/my/image@$DIGEST
请帮助测试并在发现问题时提交问题!
使用说明可在[问题跟踪](https://github.com/sigstore/cosign/issues/40)中找到。
## 注意事项
### 故意缺失的功能
`cosign` 仅生成 ECDSA-P256 密钥并使用 SHA256 哈希,适用于临时性无密钥签名和管理密钥签名。
密钥以 PEM 编码的 PKCS8 格式存储。
不过,你可以使用 `cosign` 以任何格式存储和检索来自任何算法的签名。
### 可能应该更改的地方
#### 载荷格式
`cosign` 仅支持 Red Hat 的 [simple signing](https://www.redhat.com/en/blog/container-image-signing) 格式用于载荷。
其格式如下:```json
{
"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 环境变量。
这将替换提供的镜像中的仓库,如下所示:```shell $ 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` 中。
注意:不同的注册表可能期望不同的“仓库”格式。
* 要使用 [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`,而不仅仅是仓库名称。例如, ```shell
$ export COSIGN_REPOSITORY=us-docker.pkg.dev/my-new-repo/demo
$ cosign sign --key cosign.key $IMAGE_URI_DIGEST
where the sha256-DIGEST will match the digest for
gcr.io/dlorenc-vmtest2/demo. Specifying just a repo like
$LOCATION-docker.pkg.dev/$PROJECT/$REPO will not work in Artifact Registry.
签名规范
cosign 的灵感来源于 minisign 和
signify 等工具。
生成的私钥以 PEM 格式存储。 密钥使用密码加密,采用 scrypt 作为密钥派生函数,并使用 nacl/secretbox 进行加密。
它们具有 PEM 头部 ENCRYPTED SIGSTORE PRIVATE KEY:```shell
-----BEGIN ENCRYPTED SIGSTORE PRIVATE KEY-----
...
-----END ENCRYPTED SIGSTORE PRIVATE KEY-----
公钥以PEM编码的标准PKIX格式存储在磁盘上,头部为`PUBLIC KEY`。```
-----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 来定位签名索引。
有关此策略的一些注意事项,请参阅竞争条件。
替代实现可以使用透明度日志、本地文件系统、单独的存储库注册表、显式的签名索引引用、新的注册表 API、grafeas 等。
签名主体
cosign 目前仅适用于作为“清单”存储在注册表中的工件。提议的机制足够灵活,可以支持对任意内容进行签名。
KMS 支持
cosign 支持使用 KMS 提供程序生成和签名密钥。目前 cosign 支持 Hashicorp Vault、AWS KMS、GCP KMS、Azure Key Vault,我们希望在将来支持更多!
其他 KMS 提供程序可作为外部插件使用,例如 OVHcloud KMS。
有关更多详细信息,请参阅 KMS 文档。
OCI 工件
使用 oras 将工件推送到注册表(在本例中为 cosign 本身!):```shell
$ 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`:```shell
$ 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:```shell
$ 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}
## FAQ
### 为什么不用 Notary v2
这很难简短回答。
这篇文章包含一些对比:
[Notary V2 和 Cosign](https://medium.com/@dlorenc/notary-v2-and-cosign-b816658f044d)
如果你找到其他对比文章,请在此处发 PR 我们会全部链接。
### 为什么不用 containers/image 签名
`containers/image` 签名与 `cosign` 很接近,我们复用了载荷格式。
`cosign` 的不同之处在于它使用 ECDSA-P256 密钥而非 PGP 进行签名,并将签名存储在 registry 中。
### 为什么不用 TUF?
我相信这个工具与 TUF 是互补的,它们可以一起使用。
我还没有尝试过,但认为我们也可以复用 registry 来存储 TUF。
## 设计需求
* 无需外部服务来存储、查询或检索签名
* 我们力求支持尽可能多的 registry
* 所有操作都应通过 registry API 完成
* 完全不需要 PGP。
* 用户必须能够找到镜像的所有签名
* 签名者可以在推送后对镜像进行签名
* 多个实体可以对一个镜像签名
* 签名镜像不会改变镜像本身
* 纯 Go 实现
## 未来想法
### Registry API 变更
我们用来在 registry 中存储数据的命名约定和读取-修改-写入更新模式有点……嗯,"hacky"。
我认为这是目前可用最好(也是唯一)的实际方案,但如果 registry API 发生更改,我们可以改进这些。
### 其他类型
`cosign` 可以签名 registry 中的任何内容。
这些示例展示了签名单个镜像,但你也可以签名多平台 `Index`,
或者任何其他类型的工件。
这包括 Helm Charts、Tekton Pipelines,以及当前使用 OCI registry 进行分发的任何其他内容。
这也意味着新的工件类型可以上传到 registry 并签名。
一种值得存储和签名的有趣类型是 TUF 仓库。
我还没有尝试过,但我相当确定 TUF 可以在其之上实现。
### 标签签名
`cosign` 签名保护了存储在 registry 中对象的摘要。
可选的 `annotations` 支持(通过 `cosign sign` 的 `-a` 标志)可用于向载荷添加额外数据,这些数据会被签名并由签名保护。
其中一个用例可能是签名标签到摘要的映射。
如果你想证明某个特定标签(或一组标签)应指向某个摘要,你可以运行类似这样的命令:```shell
$ 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
然后你可以验证,tag->digest 映射也包含在签名中,使用 -a 标志运行 cosign verify。
此示例验证了指向 (sha256:1304f174557314a7ed9eddb4eab12fed12cb0cd9809e4c28f29af86979a3c870) 的摘要 $TAG 已被签名,并且也验证了 tag 注解的值为 sign-me:```shell
$ 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清单有一个`layer` `Descriptors`的有序列表,其可包含注释。
参见[此处](https://github.com/opencontainers/image-spec/blob/master/manifest.md)的规范。
* 基础镜像是一个有序的层列表,其他层会追加到其上,同时还有一个会被修改的初始配置对象。
* 派生镜像可以自由地完全删除/销毁/重新创建来自基础镜像的配置,因此对配置进行签名提供的价值有限。
* 我们可以对完整的有序基础镜像层集合进行签名,并将该签名作为注释附加到生成的子镜像的**最后一个**层上。
该示例manifest清单表示一个从具有两层的基础镜像构建而来的镜像。
添加了一个额外的层,形成了最终镜像。```json
{
"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"
}
],
}
注意,这可以递归地应用于多个中间基础镜像。
反签名
Cosign 签名(及其受保护的有效载荷)作为工件存储在注册表中。 这些签名对象也可以被签名,从而产生一个新的“反签名”工件。 这个“反签名”保护签名(或一组签名)以及被引用的工件,从而使其能够作为对签名本身的证明。
在签署签名工件之前,我们首先给它一个容易记住的名称,以便以后找到它。```shell $ 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" } }
<!-- TODO: https://github.com/sigstore/cosign/issues/2333 -->
现在为该签名起一个易记的名称,然后对其进行签名:```shell
$ 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"}}
最后,检查原始签名:```shell $ 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发布资产中的Bundle文件
`cosign`的GitHub发布资产包含由[GoReleaser](https://github.com/sigstore/cosign/blob/ac999344eb381ae91455b0a9c5c267e747608d76/.goreleaser.yml#L166)生成的Sigstore bundle文件,同时签署了用于验证发布二进制文件完整性的cosign blob。此文件不被cosign本身使用,而是提供给希望[验证发布二进制文件完整性](https://docs.sigstore.dev/cosign/system_config/installation/#verifying-cosign-with-artifact-key)的用户。