【云原生安全篇】Cosign助力Harbor验证镜像实践
目录
- 1 引言
- 2 概念
- 2.1 什么是 Cosign?
- 2.2 为什么选择 Cosign 和 Harbor?
- 3 实践: Cosign对Harbor中的镜像签名
- 3.1 环境准备
- 3.2 安装 Cosign
- 3.3 使用 Cosign 对镜像进行签名
- 3.3.1 生成密钥对
- 3.3.2 推送镜像至 Harbor
- 3.3.3 为镜像签名
- 3.3.3.1 系统添加Harbor的CA证书
- 3.3.3.2 绕过Tls验证
- 3.4 验证镜像签名
- 3.4.1 登录Harbor查看镜像
- 3.4.2 拉取镜像
- 3.4.3 验证镜像签名
- 3.5 Cosign实现离线镜像签名
- 3.5.1 选择操作:离线存储签名和发布
- 3.5.1.1 导出签名
- 3.5.1.2 导入签名并验证
- 3.5.1 选择操作:离线存储签名和发布
- 3.6 Harbor 中配置签名策略
- 3.6.1 尝试拉取未签名的镜像
- 3.7 集成 Cosign 到 DevOps 流水线
- 4 总结
- 5 参考文献:
❤️ 摘要: 随着云原生技术的普及,容器镜像的安全性越来越受到重视。镜像验证是保护软件供应链的重要环节,它确保从镜像仓库拉取的镜像未被篡改,并且来源可信。Harbor 作为广泛使用的容器镜像仓库,通过与Cosign 集成,使镜像的签名与验证变得更加便捷和安全。本文将详细介绍如何使用 Cosign 对 Harbor 中的镜像进行签名和验证,确保容器镜像在整个 DevOps 流水线中的安全性。
💯 本文关联好文:
- 《一文读懂Harbor以及部署实践攻略》
- 《一文掌握Containerd配置Harbor私有仓库》
- 《一文掌握Harbor的双向认证实践》
- 《【云原生安全篇】Trivy助力离线Harbor漏洞扫描实践》
- 《【云原生安全篇】一文掌握Harbor集成Trivy应用实践》
1 引言
随着云原生架构的广泛应用,镜像篡改、中间人攻击和镜像中毒等攻击变得越来越普遍,保护整个分发管道的安全至关重要,而未签名的容器镜像可能对系统构成威胁,因为它们可能在分发过程中被篡改或受到损害。通过在发布或分发期间自动验证真实性来应对这些攻击的系统可以帮助最大限度地降低安全风险。
目前镜像供应链的安全成为了 DevSecOps 实践中的关键环节, 在本篇文章中,我们将介绍 Cosign 与 Harbor 的结合使用,展示如何通过简单的步骤对镜像进行签名和验证,为企业的镜像管理流程提供有效的安全防护。
2 概念
2.1 什么是 Cosign?
Cosign 是由 Sigstore 项目推出的一个用于容器镜像签名和验证的开源工具。与传统的 GPG 等签名工具相比,Cosign 提供了更简洁的操作方式,并且支持无需依赖专门的密钥管理设施,通过“签名链”的方式为镜像签名,并允许验证这些签名的完整性,方便集成到现有的 DevOps 流水线中。
Cosign 的主要功能包括:
- 支持多种签名密钥存储方式(如本地文件、KMS、PKI 等)。
- 支持对容器镜像的多重签名。
- 使用开源透明日志进行记录(Rekor)。
- 不仅支持镜像签名,还可以签名其他OCI兼容的对象(如 Helm Charts、BOM 等)。
- 支持使用公钥或 Keyless 模式验证签名,确保镜像未被篡改。
- 支持多种签名格式和公钥存储选项,如 KMS(Key Management Services)、云密钥、GitHub Actions 等。
2.2 为什么选择 Cosign 和 Harbor?
将 Cosign 与 Harbor 结合使用具有以下优势:
- 提升镜像安全性:Cosign 允许为每个镜像打上唯一的签名,确保拉取的镜像来源可追溯。
- 增强自动化验证:Cosign 可以集成到 DevOps 流水线中,在镜像部署之前自动验证镜像的签名,确保未经授权的镜像无法进入生产环境。
- 简单易用:相比传统的签名工具,Cosign 的操作简单,无需复杂的配置,且支持云端密钥服务,如 Google KMS、AWS KMS 等。
- 支持OCI兼容的对象: 不仅支持镜像签名,还可以签名其他OCI兼容的对象(如 Helm Charts、BOM 等)。
3 实践: Cosign对Harbor中的镜像签名
3.1 环境准备
实验环境: Ubuntu22:04
在开始之前,需要准备以下环境:
- Harbor:安装并配置好的 Harbor 镜像仓库,版本:v2.10.3
- Docker:用于构建和推送容器镜像, 版本:27.1.2
- Cosign:安装 Cosign 工具,支持对镜像进行签名和验证。版本: v2.4.0
3.2 安装 Cosign
你可以通过以下命令快速安装 Cosign:
brew install cosign
或者通过 curl
命令下载并安装 Cosign:
curl -LO https://github.com/sigstore/cosign/releases/download/v2.4.0/cosign-linux-amd64
chmod +x cosign-linux-amd64
sudo mv cosign-linux-amd64 /usr/local/bin/cosign
3.3 使用 Cosign 对镜像进行签名
3.3.1 生成密钥对
首先,生成签名镜像所需的密钥对。Cosign 提供了生成密钥对的命令,运行以下命令来生成私钥和公钥:
cosign generate-key-pair
输入密钥密码,输出如下:
Enter password for private key:
Enter password for private key again:
Private key written to cosign.key
Public key written to cosign.pub
运行后,Cosign 会生成两个文件:cosign.key
(私钥)和 cosign.pub
(公钥)。你需要将私钥妥善保管,公钥则用于签名验证。
3.3.2 推送镜像至 Harbor
接下来,构建一个harbor.zx/hcie/curl:8.1.1
镜像并将其推送到 Harbor 仓库中。以下是一个示例:
docker push harbor.zx/hcie/curl:8.1.1
3.3.3 为镜像签名
镜像推送至 Harbor 之后,可以使用 Cosign 对镜像进行签名:
cosign sign --key cosign.key harbor.zx/hcie/curl:8.1.1
此命令会读取生成的私钥,并对镜像进行签名。签名后的信息将被记录在镜像的元数据中。
在执行命令后,出现cosign签名过程无法通过harbor的tls证书校验:
root@jenkins:~/cosign# cosign sign --key cosign.key harbor.zx/hcie/curl:8.1.1
Enter password for private key:
Error: signing [harbor.zx/hcie/harbor.zx/hcie/curl:8.1.1]: accessing image: Get "https://harbor.zx/v2/": tls: failed to verify certificate: x509: certificate signed by unknown authority
main.go:74: error during command execution: signing [harbor.zx/hcie/curl:8.1.1]: accessing image: Get "https://harbor.zx/v2/": tls: failed to verify certificate: x509: certificate signed by unknown authority
❔ 说明: 这是因为harbor镜像仓库是使用tls单向认证, 那么需要cosign验证时附带上harbor的ca证书。
解决的方式有两个:
3.3.3.1 系统添加Harbor的CA证书
- 因为Cosign 使用的是系统的 CA 证书信任库,因此你需要将 Harbor 的自签名证书也添加到系统的 CA 列表中。将harbor的ca.crt文件复制到系统的ca证书目录:
sudo cp /etc/docker/certs.d/harbor.zx/ca.crt /usr/local/share/ca-certificates/harbor.crt
- 更新和应用ca证书
sudo update-ca-certificates
输出如下:
Updating certificates in /etc/ssl/certs...
rehash: warning: skipping ca-certificates.crt,it does not contain exactly one certificate or CRL
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
再尝试cosign签名镜像
cosign sign --key cosign.key harbor.zx/hcie/curl:8.1.1
#输入私钥加密密码
Enter password for private key:
The sigstore service, hosted by sigstore a Series of LF Projects, LLC, is provided pursuant to the Hosted Project Tools Terms of Use, available at https://lfprojects.org/policies/hosted-project-tools-terms-of-use/.
Note that if your submission includes personal data associated with this signed artifact, it will be part of an immutable record.
This may include the email address associated with the account with which you authenticate your contractual Agreement.
This information will be used for signing this artifact and will be stored in public transparency logs and cannot be removed later, and is subject to the Immutable Record notice at https://lfprojects.org/policies/hosted-project-tools-immutable-records/.
By typing 'y', you attest that (1) you are not submitting the personal data of any other person; and (2) you understand and agree to the statement and the Agreement terms at the URLs listed above.
Are you sure you would like to continue? [y/N] y
tlog entry created with index: 134950833
Pushing signature to: harbor.zx/hcie/curl
最后可以看到成功签名镜像。
3.3.3.2 绕过Tls验证
cosign也提供绕过tls证书验证的方式,但是不建议真实环境这么做,命令如下
cosign sign --key cosign.key --insecure-skip-verify=true harbor.zx/hcie/curl:8.1.1
输出如下:
Enter password for private key:
WARNING: Image reference harbor.zx/hcie/curl:8.1.1 uses a tag, not a digest, to identify the image to sign.
This can lead you to sign a different image than the intended one. Please use a
digest (example.com/ubuntu@sha256:abc123...) rather than tag
(example.com/ubuntu:latest) for the input to cosign. The ability to refer to
images by tag will be removed in a future release.
The sigstore service, hosted by sigstore a Series of LF Projects, LLC, is provided pursuant to the Hosted Project Tools Terms of Use, available at https://lfprojects.org/policies/hosted-project-tools-terms-of-use/.
Note that if your submission includes personal data associated with this signed artifact, it will be part of an immutable record.
This may include the email address associated with the account with which you authenticate your contractual Agreement.
This information will be used for signing this artifact and will be stored in public transparency logs and cannot be removed later, and is subject to the Immutable Record notice at https://lfprojects.org/policies/hosted-project-tools-immutable-records/.
By typing 'y', you attest that (1) you are not submitting the personal data of any other person; and (2) you understand and agree to the statement and the Agreement terms at the URLs listed above.
Are you sure you would like to continue? [y/N] y
tlog entry created with index: 134954220
Pushing signature to: harbor.zx/hcie/curl
同样也能完成镜像签名。
3.4 验证镜像签名
完成签名后,你可以通过 Cosign 验证镜像签名的合法性。
3.4.1 登录Harbor查看镜像
登录到Harbor的管理页面,点击“项目”→选择“hcie”项目→选择“curl”镜像:
可以看到“已签名”已经打✅。
可以点击“①”看到cosign签名的附件:
点击“②”,可以复制摘要, 或者删除cosign签名的附件;
3.4.2 拉取镜像
首先,从 Harbor 仓库中拉取你签名的镜像:
docker pull harbor.zx/hcie/curl:8.1.1
3.4.3 验证镜像签名
使用以下命令验证镜像的签名是否有效:(验证镜像签名需要依赖网络环境:rekor.sigstore.dev)
cosign verify --key cosign.pub harbor.zx/hcie/curl:8.1.1
如果网络问题,可能出现:
Error: getting Rekor public keys: updating local metadata and targets: error updating to TUF remote mirror: tuf: failed to download 10.root.json: Get "https://tuf-repo-cdn.sigstore.dev/10.root.json": dial tcp: lookup tuf-repo-cdn.sigstore.dev on 127.0.0.53:53: server misbehaving
main.go:74: error during command execution: getting Rekor public keys: updating local metadata and targets: error updating to TUF remote mirror: tuf: failed to download 10.root.json: Get "https://tuf-repo-cdn.sigstore.dev/10.root.json": dial tcp: lookup tuf-repo-cdn.sigstore.dev on 127.0.0.53:53: server misbehaving
如果签名有效,Cosign 会输出相关的签名信息,确认镜像没有被篡改且来自可信来源。输出如下:
Verification for harbor.zx/hcie/curl:8.1.1 --
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
[{"critical":{"identity":{"docker-reference":"harbor.zx/hcie/curl"},"image":{"docker-manifest-digest":"sha256:5df2709c7c473c8e63d645e36fc4fe12e6a732d8c60841aaa5e5a73acf8a12f3"},"type":"cosign container image signature"},"optional":{"Bundle":{"SignedEntryTimestamp":"MEYCIQDEwyZKwgly4Hh8xWch5lGXvA1Mw5GPa9OZIJ9SAwX+swIhALicbdUkOUJbIcJ9WoIkGrSHz4fYesoEvRDsb2Cl7aiZ","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJjNjg4MjIzNTUzZDg3MTVkYWRlNmU4MDhlYWU4ZGQzNDFmMzIxODY2Y2Y0OTJiMTdlYTE3Y2QzZGEyM2E0YWE1In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUURiZU5vWkNuUEJ4YU9GbXYvV0xYSjRTalFJdG1DME5MT1AzTjF4alExK3RnSWdkQTIzUmpTUjZ3NERXOC9oSFJYUzJnZmdqaVdTcDBLMFg0MFR5OFVtSzE0PSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCUVZVSk1TVU1nUzBWWkxTMHRMUzBLVFVacmQwVjNXVWhMYjFwSmVtb3dRMEZSV1VsTGIxcEplbW93UkVGUlkwUlJaMEZGYWtsTWNrUlBSVTVSYVdaQllXazJWbTFEWWtOM01VRkVSRWd6T1FwTlRsaEZjbFZ5TURsS1QyRndiMlY0TmxoU0swOWhTazFtWlZkalJVSXhXRGgyYTNWUVltMDVRa2M0Ymt4dFYxVXdZWGwyZURGd2F5dFJQVDBLTFMwdExTMUZUa1FnVUZWQ1RFbERJRXRGV1MwdExTMHRDZz09In19fX0=","integratedTime":1727529906,"logIndex":134950833,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}},{"critical":{"identity":{"docker-reference":"harbor.zx/hcie/curl"},"image":{"docker-manifest-digest":"sha256:5df2709c7c473c8e63d645e36fc4fe12e6a732d8c60841aaa5e5a73acf8a12f3"},"type":"cosign container image signature"},"optional":{"Bundle":{"SignedEntryTimestamp":"MEUCID3dvTzK2mNadn9zV86Qb3wB9E62xvlbgxfrBCC4zt04AiEAjXmg4URN5dS6YMHY5/zq43BcycP+j40RmJgxRdhaaNA=","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJjNjg4MjIzNTUzZDg3MTVkYWRlNmU4MDhlYWU4ZGQzNDFmMzIxODY2Y2Y0OTJiMTdlYTE3Y2QzZGEyM2E0YWE1In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJSHNuVVV0RWZnczZEeWIxajB1UHNFdVdUbFJUanAyNDB3VE0rVDh5MnF0aEFpRUF1UFJUbGQzZXp6bFlHcVhEZUlRWkcyL0FSdE1qcFVncHBXSHM1Qm1qcFVBPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCUVZVSk1TVU1nUzBWWkxTMHRMUzBLVFVacmQwVjNXVWhMYjFwSmVtb3dRMEZSV1VsTGIxcEplbW93UkVGUlkwUlJaMEZGYWtsTWNrUlBSVTVSYVdaQllXazJWbTFEWWtOM01VRkVSRWd6T1FwTlRsaEZjbFZ5TURsS1QyRndiMlY0TmxoU0swOWhTazFtWlZkalJVSXhXRGgyYTNWUVltMDVRa2M0Ymt4dFYxVXdZWGwyZURGd2F5dFJQVDBLTFMwdExTMUZUa1FnVUZWQ1RFbERJRXRGV1MwdExTMHRDZz09In19fX0=","integratedTime":1727530670,"logIndex":134953908,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}},{"critical":{"identity":{"docker-reference":"harbor.zx/hcie/curl"},"image":{"docker-manifest-digest":"sha256:5df2709c7c473c8e63d645e36fc4fe12e6a732d8c60841aaa5e5a73acf8a12f3"},"type":"cosign container image signature"},"optional":{"Bundle":{"SignedEntryTimestamp":"MEQCIDmu+O2Rb/39jG/WSkY31/ufr0wNLOBQohHRj1ZXmYxtAiAFhZ5D0XNuYNMXUAqWxgJAqFJgVhseHFfZgjugHa5OEQ==","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJjNjg4MjIzNTUzZDg3MTVkYWRlNmU4MDhlYWU4ZGQzNDFmMzIxODY2Y2Y0OTJiMTdlYTE3Y2QzZGEyM2E0YWE1In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FWUNJUURHaWQwSzVVc1E2VXhNbWRpU3FreWgyT0t2WWoyRHZ2dWtXQURDVTdzZXJnSWhBUG4xQjkwdEh6MGJCSlZEc3VPZ1JOL0gxVVpjaDBOTnEwOFZueEdvK09pMiIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCUVZVSk1TVU1nUzBWWkxTMHRMUzBLVFVacmQwVjNXVWhMYjFwSmVtb3dRMEZSV1VsTGIxcEplbW93UkVGUlkwUlJaMEZGYWtsTWNrUlBSVTVSYVdaQllXazJWbTFEWWtOM01VRkVSRWd6T1FwTlRsaEZjbFZ5TURsS1QyRndiMlY0TmxoU0swOWhTazFtWlZkalJVSXhXRGgyYTNWUVltMDVRa2M0Ymt4dFYxVXdZWGwyZURGd2F5dFJQVDBLTFMwdExTMUZUa1FnVUZWQ1RFbERJRXRGV1MwdExTMHRDZz09In19fX0=","integratedTime":1727530978,"logIndex":134954220,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}}]
3.5 Cosign实现离线镜像签名
目前Cosign更建议的是使用镜像摘要作为tag来识别镜像,如下:
harbor.zx/hcie/curl@sha256:5df2709c7c473c8e63d645e36fc4fe12e6a732d8c60841aaa5e5a73acf8a12f3
签名镜像,命令如下:
cosign sign --key cosign.key harbor.zx/hcie/curl@sha256:<digest>
验证镜像,命令如下:
cosign verify --key cosign.pub --payload curl.sig harbor.zx/hcie/curl@sha256:<digest>
输出如下:
Verification for harbor.zx/hcie/curl@sha256:5df2709c7c473c8e63d645e36fc4fe12e6a732d8c60841aaa5e5a73acf8a12f3 --
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
[{"critical":{"identity":{"docker-reference":"harbor.zx/hcie/curl"},"image":{"docker-manifest-digest":"sha256:5df2709c7c473c8e63d645e36fc4fe12e6a732d8c60841aaa5e5a73acf8a12f3"},"type":"cosign container image signature"},"optional":{"Bundle":{"SignedEntryTimestamp":"MEYCIQD6prj50wo4K2jG7d543/8GiA8qKil98eztYB8oqn4RwAIhAKJ/KnKN/qvT12joC1Zok1WDTWn34+GBbHbB4U5Jd99s","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJjNjg4MjIzNTUzZDg3MTVkYWRlNmU4MDhlYWU4ZGQzNDFmMzIxODY2Y2Y0OTJiMTdlYTE3Y2QzZGEyM2E0YWE1In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUURMcHEzZk0yczlHK3VYNndLTklDdUhHU2dwc3pkYnJVVE1TN3EwQnRoVEFRSWdVbjM3Y1FXZ09FYlpzaWhKNkE0MnFXdWJHTW1jYjdxcE1lc3Y0azl1ZWRFPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCUVZVSk1TVU1nUzBWWkxTMHRMUzBLVFVacmQwVjNXVWhMYjFwSmVtb3dRMEZSV1VsTGIxcEplbW93UkVGUlkwUlJaMEZGYWtsTWNrUlBSVTVSYVdaQllXazJWbTFEWWtOM01VRkVSRWd6T1FwTlRsaEZjbFZ5TURsS1QyRndiMlY0TmxoU0swOWhTazFtWlZkalJVSXhXRGgyYTNWUVltMDVRa2M0Ymt4dFYxVXdZWGwyZURGd2F5dFJQVDBLTFMwdExTMUZUa1FnVUZWQ1RFbERJRXRGV1MwdExTMHRDZz09In19fX0=","integratedTime":1727533515,"logIndex":134956425,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}},{"critical":{"identity":{"docker-reference":"harbor.zx/hcie/curl"},"image":{"docker-manifest-digest":"sha256:5df2709c7c473c8e63d645e36fc4fe12e6a732d8c60841aaa5e5a73acf8a12f3"},"type":"cosign container image signature"},"optional":{"Bundle":{"SignedEntryTimestamp":"MEUCIHhdCw5Y9nAh/Y5XGxGPxNJ1bZ7B1pvQpQiqgAOzpsIXAiEAuOXodDmzzbQ6R6BJuO/Xf0AEq1gAVQS/9v7dO0Uiqt0=","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJjNjg4MjIzNTUzZDg3MTVkYWRlNmU4MDhlYWU4ZGQzNDFmMzIxODY2Y2Y0OTJiMTdlYTE3Y2QzZGEyM2E0YWE1In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJRnZKcXVDcmF3eTdUWXBiV1ZwQ2JVNHVaRm8zZkx5Y1NpOW5ham5Sb2JqaEFpRUEyUkdQTVoxNnRZS29sU3Q3c203R3MycGxobnJXbmJtaEF2YUpuWnl6RUVNPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCUVZVSk1TVU1nUzBWWkxTMHRMUzBLVFVacmQwVjNXVWhMYjFwSmVtb3dRMEZSV1VsTGIxcEplbW93UkVGUlkwUlJaMEZGYWtsTWNrUlBSVTVSYVdaQllXazJWbTFEWWtOM01VRkVSRWd6T1FwTlRsaEZjbFZ5TURsS1QyRndiMlY0TmxoU0swOWhTazFtWlZkalJVSXhXRGgyYTNWUVltMDVRa2M0Ymt4dFYxVXdZWGwyZURGd2F5dFJQVDBLTFMwdExTMUZUa1FnVUZWQ1RFbERJRXRGV1MwdExTMHRDZz09In19fX0=","integratedTime":1727533621,"logIndex":134956507,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}}}}]
3.5.1 选择操作:离线存储签名和发布
Cosign 通常将签名信息附加到容器镜像的 OCI
元数据中,但你也可以选择导出签名并单独管理签名文件。例如,在某些环境中,你可能希望将签名与镜像分开存储,以便在不同时间或环境中进行分发。
3.5.1.1 导出签名
使用 --output-signature
参数可以将签名导出为文件:
cosign sign --key cosign.key --output-signature curl.sig harbor.zx/hcie/curl@sha256:<digest>
3.5.1.2 导入签名并验证
在另一台机器或环境中,你可以通过以下命令导入并验证签名:
cosign verify --key cosign.pub --payload curl.sig harbor.zx/hcie/curl@sha256:<digest>
3.6 Harbor 中配置签名策略
在 Harbor 中可以配置策略(policy),要求镜像在部署或使用前必须通过签名验证,确保从可信的源获取容器镜像。Harbor 在V2.5版本中默认支持 Cosign 组件,允许配置策略来强制镜像签名的存在和验证。
在Harbor的管理页面,进入项目的配置管理。
在部署安全,勾选“Cosign”;
最后保存确认。
3.6.1 尝试拉取未签名的镜像
选择一个未签名的镜像,如Nginx:1.26.1
先删除本地镜像
root@jenkins:~/cosign# docker rmi harbor.zx/hcie/nginx:1.26.1
Untagged: harbor.zx/hcie/nginx:1.26.1
Untagged: harbor.zx/hcie/nginx@sha256:03bc8cca389b961e1f446706e83c1e565fd4426b0658a5478ad69aa737dc1570
重新拉取镜像
root@jenkins:~/cosign# docker pull !$
docker pull harbor.zx/hcie/nginx:1.26.1
Error response from daemon: unknown: The image is not signed by cosign.
可以看到策略生效,客户端无法拉取未签名的镜像,这可以从源头保证镜像的合规性。
3.7 集成 Cosign 到 DevOps 流水线
为了在企业的 CI/CD 流水线中实现自动化的镜像签名与验证,Cosign 可以轻松集成到 Jenkins、GitLab CI 等工具中。以下是一个简单的集成流程示例:
- 构建容器镜像:在 CI/CD 流程中构建容器镜像。
- 签名镜像:在推送镜像到 Harbor 之后,使用 Cosign 对镜像进行签名。
- 验证签名:在部署镜像到生产环境之前,自动化地验证镜像的签名,确保其来源可信。
💯 这种自动化流程可以大大提高镜像的安全性和可信性,确保只有经过签名验证的镜像才能被部署到生产环境中。后续也会出相关的文章进行说明。
4 总结
通过将 Cosign 与 Harbor 结合,企业可以构建一个安全的容器镜像签名和验证机制,有效防止镜像被篡改或使用不可信的镜像。希望通过本文的介绍,您能够更好地理解Cosign 如何通过提供更可靠的方法来确保容器映像的真实性和完整性,和如何在 Harbor 中使用 Cosign 进行镜像签名和验证,并将其应用到实际的开发和运维过程中,提升整体的镜像安全管理能力。
5 参考文献
[1]Cosign 官方文档
[2]Harbor 官方文档
[3]Sigstore 项目