【云原生安全篇】Notation助力Harbor镜像验证实践
目录
💯 本文关联好文:
1 引言
容器镜像的安全性一直是 DevOps 和云原生领域的热门话题,如何确保从镜像仓库中拉取的镜像未被恶意篡改,是保障供应链安全的重要环节。Harbor 作为企业常用的镜像仓库,支持集成各种安全扫描和签名验证。而Notation 则是一个用于为容器镜像提供签名和验证的工具,可以帮助用户对镜像进行安全控制。
在本文中,我们将介绍如何将 Notation 工具与 Harbor 集成,探讨镜像签名和验证的具体操作流程,以确保容器镜像的完整性和可信性。
2 概念
2.1 什么是Notary 项目
Notary 是 Docker 公司创建的一个开源项目,最初是为了支持 Docker Content Trust (DCT),以保证容器镜像的内容可信。Notary 使用了一个叫做 TUF(The Update Framework) 的协议,通过创建和管理签名,为镜像提供内容信任机制。
Notary 主要特点:
- 基于 TUF 协议:Notary 使用 TUF 协议来管理签名、密钥和信任链,确保容器镜像或其他软件制品的安全交付。
- 支持 Docker Content Trust:Notary 被 Docker 原生集成,用于 Docker 镜像签名验证。
- 集中式签名管理:使用中央服务器来存储签名信息,通常需要依赖外部服务来存储信任数据。
Notary 的挑战:
- 架构较重:由于依赖 TUF 协议和复杂的签名管理,Notary 的实现较为复杂。
- 不完全支持现代云原生标准:虽然 Notary 是 Docker 内容信任的一部分,但在 Kubernetes 和其他云原生环境中的支持相对较弱。
2.2 什么是 Notation?
Notation 是 Notary v2 计划的一部分,是 CNCF(Cloud Native Computing Foundation)推出的一个新轻量级签名工具,专用于签名 OCI 镜像和其他云原生对象而设计,旨在为云原生环境提供更加简单、现代化的签名和验证体验。它可以为 Docker 和 OCI(Open Container Initiative)镜像生成数字签名,确保拉取的镜像未被篡改,并验证镜像的发布者身份。
Notation 主要特点:
- OCI 镜像签名支持:Notation 基于 OCI (Open Container Initiative) 标准,为 OCI 格式的镜像和其他制品提供签名功能。
- 轻量级:与 Notary 相比,Notation 的架构更为简洁,签名操作和验证更易于集成到现代的 DevOps 工具链中。
- Sigstore 集成:Notation 是 Sigstore 项目的一部分,利用其去中心化的透明日志服务(如 Rekor)进行签名的记录和验证。
- 云原生友好:Notation 与 Kubernetes 等现代云原生生态系统兼容性更好,设计上更适合在容器环境中使用。
Notary 和 Notation 的关系
Notation 是 Notary v2 项目的一部分,但与原来的 Notary v1 有很大的不同。Notary v2 的目标是简化签名机制,增强云原生支持,并且降低使用 TUF 框架时的复杂性。Notation 是实现 Notary v2 目标的具体工具,它带来了以下改进:
- 去除 TUF 复杂性:Notary v2 选择了放弃 TUF,转而使用更为轻量的机制来进行签名管理,这使得 Notation 更加轻量和简洁。
- OCI 支持:相比于 Notary v1 主要针对 Docker 镜像,Notation 完全支持 OCI 格式的镜像,符合当前云原生环境的标准化要求。
- 云原生集成:Notation 通过集成 Sigstore 项目,更好地支持 Kubernetes 和云原生架构,使得签名和验证操作更符合现代 DevOps 的需求。
2.3 为什么要将 Notation 与 Harbor 结合使用?
将 Notation 与 Harbor 结合,可以为企业提供更高层次的镜像安全性。Harbor 本身支持多种镜像安全功能,如漏洞扫描、内容信任(Content Trust)和镜像签名。而 Notation 提供了更灵活的镜像签名方式,进一步增强了 Harbor 对镜像来源的控制和保护。
具体优势包括:
- 提高镜像的安全性:使用签名可以确保镜像的完整性和来源可追溯。
- 防止镜像篡改:通过验证签名,确保镜像来自可信的开发者或团队,防止使用未经授权修改的镜像。
- 供应链安全:保障容器镜像在构建、存储和使用过程中都能保持完整性,防止供应链攻击。
- 兼容 OCI 标准:Notation 支持 OCI 格式的镜像签名,符合云原生标准,便于集成和扩展。
3 实践: Notation 为Harbor的镜像签名
3.1 环境准备
在开始之前,确保已经在系统中安装好以下工具和软件:
- Harbor:已安装并运行的镜像仓库,支持容器镜像的存储和管理。版本:v2.10.3
- Docker:用于构建和推送容器镜像。 版本:27.1.2
- Notation CLI:用于对镜像进行签名和验证。版本:v1.2.0
你可以通过以下命令安装 Notation CLI:
brew install notation
或者使用 curl
下载并安装最新的 Notation 版本:
curl -LO https://github.com/notaryproject/notation/releases/download/v1.2.0/notation_1.2.0_linux_amd64.tar.gz
tar -xzf notation_1.2.0_linux_amd64.tar.gz
sudo mv notation /usr/local/bin/
3.2 使用 Notation 对镜像进行签名
签名过程的核心是生成密钥对,并将私钥用于为镜像签名。以下是具体步骤:
3.2.1 5.1 生成密钥对
首先,你需要使用 Notation 生成一对密钥。签名时会用到私钥,而公钥则用于验证签名。
notation cert generate-test --default "zx.test.com"
该命令会生成一个自签名证书用于签名,并且该证书可以用来验证签名的镜像,输出如下:
generating RSA Key with 2048 bits
generated certificate expiring on 2024-09-30T03:40:15Z
wrote key: /root/.config/notation/localkeys/zx.test.com.key
wrote certificate: /root/.config/notation/localkeys/zx.test.com.crt
Successfully added zx.test.com.crt to named store zx.test.com of type ca
zx.test.com: added to the key list
zx.test.com: mark as default signing key
3.2.2 添加自签名CA到系统认可CA库
- 因为Notation 使用的是系统的 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.
3.2.3 签名镜像
接下来,使用 Notation 对已推送到 Harbor 的镜像进行签名:
notation sign harbor.zx/hcie/nginx:1.26.1
此命令将对指定的镜像进行签名,并且签名信息将会关联到该镜像中, 输出如下:
Warning: Always sign the artifact using digest(@sha256:...) rather than a tag(:1.26.1) because tags are mutable and a tag reference can point to a different artifact than the one signed.
Successfully signed harbor.zx/hcie/nginx@sha256:03bc8cca389b961e1f446706e83c1e565fd4426b0658a5478ad69aa737dc1570
如果是http的harbor环境,可以使用以下命令:
notation sign -u test -p teset@12345 --plain_http harbor.zx/hcie/nginx:1.26.1
查看镜像签名
notation list harbor.zx/hcie/nginx:1.26.1
输出如下:
Warning: Always list the artifact using digest(@sha256:...) rather than a tag(:1.26.1) because resolved digest may not point to the same signed artifact, as tags are mutable.
harbor.zx/hcie/nginx@sha256:03bc8cca389b961e1f446706e83c1e565fd4426b0658a5478ad69aa737dc1570
└── application/vnd.cncf.notary.signature
└── sha256:3c312ea3b275992215838f65b55b837a251eaef5062846a70bdf567dabfbe314
你也可以登录harbor的管理后台看harbor.zx/hcie/nginx:1.26.1
的信息
3.2.4 使用镜像摘要作为tag名称
官方推荐是使用镜像摘要作为tag名称,对镜像进行签名
镜像摘要可以通过harbor的页面查询,也可以通过命令查询:
docker inspect --format='{{index .RepoDigests 0}}' harbor.zx/hcie/nginx:1.26.1
输出如下:
harbor.zx/hcie/nginx@sha256:03bc8cca389b961e1f446706e83c1e565fd4426b0658a5478ad69aa737dc1570
对镜像签名
notation sign harbor.zx/hcie/nginx@sha256:03bc8cca389b961e1f446706e83c1e565fd4426b0658a5478ad69aa737dc1570
输出如下:
Successfully signed harbor.zx/hcie/nginx@sha256:03bc8cca389b961e1f446706e83c1e565fd4426b0658a5478ad69aa737dc1570
3.3 在 Harbor 中验证镜像签名
完成镜像签名后,我们可以通过 Notation 验证镜像签名是否有效,确保镜像未被篡改。
3.3.1 拉取镜像
首先,尝试拉取带有签名的镜像:
docker pull your-registry.com/project-name/image:tag
3.3.2 创建信任策略
要验证容器映像,请配置信任策略以指定对构件进行签名的可信身份以及要使用的签名验证级别。有关更多详细信息,请参阅信任策略规范。
- 参考官网案例,创建trustpolicy.json
cat <<EOF > ./trustpolicy.json
{
"version": "1.0",
"trustPolicies": [
{
"name": "harbor-images",
"registryScopes": [ "*" ],
"signatureVerification": {
"level" : "strict"
},
"trustStores": [ "ca:zx.test.com" ],
"trustedIdentities": [
"*"
]
}
]
}
EOF
上述 JSON 创建了一个名为 wabbit-networks-images
的信任策略。
-
registryScopes
设置为*
,这会将策略应用于任何镜像仓库的所有工件。 signatureVerification
设置为strict
,这将检查所有验证,任何失败都将使签名验证失败。- 此策略使用在上一步中创建的
ca
类型的zx.test.com
信任存储。
- 使用
notation policy import
从 JSON 文件导入信任策略配置。例如:
notation policy import ./trustpolicy.json
输出如下:
Trust policy configuration imported successfully.
- 使用
notation policy show
查看应用的策略配置。例如:
notation policy show
输出如下:
{
"version": "1.0",
"trustPolicies": [
{
"name": "harbor-images",
"registryScopes": [ "*" ],
"signatureVerification": {
"level" : "strict"
},
"trustStores": [ "ca:zx.test.com" ],
"trustedIdentities": [
"*"
]
}
]
}
3.3.3 验证签名
接下来,使用 Notation 验证镜像的签名:
notation verify harbor.zx/hcie/nginx:1.26.1
如果镜像签名验证不成功,可能返回
Warning: Always verify the artifact using digest(@sha256:...) rather than a tag(:1.26.1) because resolved digest may not point to the same signed artifact, as tags are mutable.
Error: signature verification failed: unable to retrieve digital signature with digest "sha256:3c312ea3b275992215838f65b55b837a251eaef5062846a70bdf567dabfbe314" associated with "harbor.zx/hcie/nginx@sha256:03bc8cca389b961e1f446706e83c1e565fd4426b0658a5478ad69aa737dc1570" from the Repository, error : GET "https://harbor.zx/v2/hcie/nginx/manifests/sha256:3c312ea3b275992215838f65b55b837a251eaef5062846a70bdf567dabfbe314": mismatch Content-Length
如果镜像签名有效,Notation 会返回验证成功的信息,表示镜像的完整性和可信度得到保障。
3.4 Harbor 中配置签名策略
在 Harbor 中可以配置策略(policy),要求镜像在部署或使用前必须通过签名验证,确保从可信的源获取容器镜像。
在Harbor的管理页面,进入项目的配置管理。
在部署安全,勾选“Notation”;
最后保存确认。
3.4.1 尝试拉取未签名的镜像
选择一个未签名的镜像,如dnstool:latest
先删除本地镜像
docker rmi harbor.zx/hcie/dnstool
重新拉取镜像
docker pull harbor.zx/hcie/dnstool
输出如下:
Using default tag: latest
Error response from daemon: unknown: The image is not signed by notation.
可以看到策略生效,客户端无法拉取未签名的镜像,这可以从源头保证镜像的合规性。
4 集成到 DevOps 流水线
在实际生产环境中,签名和验证镜像是 CI/CD 流水线中的重要环节。可以将 Notation 的签名和验证过程集成到你的 DevOps 流水线中,以确保镜像在部署前已通过安全验证。
以下是一个示例流程:
- 构建镜像:在 CI/CD 中构建容器镜像并推送至 Harbor 仓库。
- 签名镜像:在推送镜像后,使用 Notation 对镜像进行签名。
- 验证镜像:在部署到生产环境之前,通过 Notation 验证镜像签名,确保镜像未被篡改。
5 总结
在容器化应用广泛采用的今天,镜像的安全性是企业不能忽视的环节。使用 Notation 签名和验证容器镜像,不仅符合 DevOps 的自动化理念,也能帮助企业在容器镜像管理中实现更高的安全性。希望本文能帮助您在生产环境中更好地保护您的容器镜像。