Harbor 内容信任实战:Docker 客户端拉取已签名镜像(DB 模式)完整指南
【免费下载链接】harborAn open source trusted cloud native registry project that stores, signs, and scans content.项目地址: https://gitcode.com/GitHub_Trending/ha/harbor
导读
本文以 Harbor 官方内容信任(Content Trust)测试用例 9-03-DB-user-pull-signed-images.md 为骨架,系统讲解在本地数据库(DB 模式)认证环境下,普通用户如何通过 Docker 客户端启用 Docker Content Trust(DCT)并成功拉取已签名镜像的完整流程。读者将掌握DOCKER_CONTENT_TRUST与DOCKER_CONTENT_TRUST_SERVER环境变量的正确配置、自签名证书环境下 Notary 服务的信任配置、签名镜像在 Harbor Web 界面的识别方法,以及 Harbor 服务端在拉取链路上执行内容信任校验的底层原理。
背景:为什么需要"内容信任"与 Notary
Harbor 是一个开源的云原生制品仓库,支持制品的存储、签名与扫描。内容信任(Content Trust)基于 Docker 的 Notary 项目实现:当客户端启用 DCT 后,推送镜像时会同时生成签名元数据并上传至 Notary 服务(Harbor 中该服务默认监听4443端口);拉取镜像时,Docker 客户端会先向 Notary 校验镜像的签名与信任链,再决定是否拉取对应镜像内容。
在 Harbor 中,内容信任的落地分为两个层面:
- 客户端层面:由 Docker CLI 通过环境变量控制是否签名、是否校验签名;
- 服务端层面:当项目开启了"内容信任"策略后,Harbor 的 Registry 路由会在拉取镜像的请求链路上插入校验中间件,强制要求镜像存在有效签名,否则拒绝拉取。
本文聚焦第一个层面——用户主动开启 DCT 并成功拉取已签名镜像(对应测试用例 9-03)。
环境准备
依据测试用例的Environment一节,执行本流程需要满足:
- 一个正在运行且可访问的 Harbor 实例(本地数据库认证模式,即 DB 模式);
- 一台安装了 Docker CLI(Docker 客户端)的 Linux 机器;
- 一个已经存在的 Harbor 项目(文中以 project X 代指)。
补充说明:DB 模式意味着用户数据存放在 Harbor 内置的本地数据库中,与之相对的是 LDAP/AD 等外部认证模式。本测试用例 9-03 针对 DB 模式设计;对应的 LDAP 版本见 9-13-LDAP-user-pull-signed-images.md,管理员版本见 9-23-admin-pull-signed-images.md。
测试步骤详解
第 1 步:登录 Harbor Web UI
在浏览器中访问 Harbor 门户,使用具有目标项目访问权限的普通用户账号登录 UI。确保目标项目 X 已存在(可通过 9-01-DB-user-push-signed-images.md 中的流程创建项目并推送已签名镜像作为前置准备)。
第 2 步:在 Docker 客户端启用内容信任并登录
在 Docker 客户端主机上执行以下环境变量设置:
export DOCKER_CONTENT_TRUST=1 export DOCKER_CONTENT_TRUST_SERVER=https://<harbor_ip>:4443DOCKER_CONTENT_TRUST=1:通知 Docker CLI 启用内容信任模式。此模式下,docker pull在拉取镜像前会先向信任服务器查询该镜像的签名元数据,只有签名有效时才继续拉取镜像内容。DOCKER_CONTENT_TRUST_SERVER=https://<harbor_ip>:4443:显式指定信任服务器地址。Harbor 部署的 Notary 服务默认暴露在 4443 端口(HTTPS)。不设置此变量时,Docker 会按https://<registry_host>:4443的默认约定推断,但在 Harbor 场景下显式指定更稳妥。
设置完成后,登录 Harbor:
docker login <harbor_ip>按提示输入用户名与密码。若目标 Harbor 使用了非默认端口,需在<harbor_ip>后附带端口号。
自签名证书注意事项:如果 Harbor 使用自签名证书,Docker 客户端默认不会信任该证书,必须将 CA 根证书复制到以下两个位置(来自测试用例的 NOTE 说明):
# Registry 访问信任 /etc/docker/certs.d/<harbor_ip>/ # Notary 信任服务器访问信任(端口 4443) $HOME/.docker/tls/<harbor_ip>:4443/完成证书放置后重启 Docker 守护进程使其生效。这一步骤缺失时,docker login或后续的信任校验会因 TLS 证书不受信任而失败。
第 3 步:拉取已签名镜像
从项目 X 中拉取一个已签名镜像:
docker pull <harbor_ip>/project_x/signed-image:tag其中project_x应替换为实际项目名,signed-image:tag替换为实际镜像名与标签。
预期结果
根据测试用例Expected Outcome:
镜像可以被成功拉取。
即docker pull命令成功完成,本地出现该镜像。这表明:在DOCKER_CONTENT_TRUST=1下,Docker 客户端成功向 Harbor 的 Notary 服务(4443 端口)验证了镜像签名,随后从 Registry 拉取了镜像内容。
服务端原理:Harbor 如何配合签名拉取
虽然测试用例 9-03 主要验证"客户端开启 DCT 后能拉到签名镜像",但理解 Harbor 服务端的处理逻辑有助于排查问题。从源码看,Harbor 在 Registry 的 manifest 拉取链路上挂了内容信任中间件。
在 src/server/registry/route.go 中,GET与HEAD两种/*/manifests/:reference请求都挂载了contenttrust.ContentTrust()中间件:
root.NewRoute(). Method(http.MethodGet). Path("/*/manifests/:reference"). Middleware(metric.InjectOpIDMiddleware(metric.ManifestOperationID)). Middleware(repoproxy.ManifestMiddleware()). Middleware(contenttrust.ContentTrust()). Middleware(vulnerable.Middleware()). HandlerFunc(getManifest)中间件实现位于 src/server/middleware/contenttrust/contentrust.go:它根据请求中的ArtifactInfo找到对应项目,若项目开启了内容信任策略(ContentTrustEnabled()或ContentTrustCosignEnabled()),则进一步调用signatureChecking检查制品是否带有对应类型的签名 accessory;若无签名,则返回PROJECTPOLICYVIOLATION错误,拒绝拉取。
项目级策略通过项目元数据(metadata)实现,键定义在 src/pkg/project/models/pro_meta.go:
enable_content_trust(对应ProMetaEnableContentTrust):是否要求镜像具备 Notation 签名;enable_content_trust_cosign(对应ProMetaEnableContentTrustCosign):是否要求镜像具备 Cosign 签名。
对应的布尔判断实现在 src/pkg/project/models/project.go。
需要强调的是:9-03 场景下项目未必开启了上述项目级策略,拉取成功的关键在于 Docker 客户端自身开启 DCT 并成功完成签名校验。项目级策略是另一道服务端强制门禁,对应测试 9-30-Project-level-content-trust.md(启用策略后,未签名镜像将无法拉取,而签名镜像可以拉取)。
关联场景:签名镜像的完整生命周期
9-03 属于 Group9-Content-trust 测试组中"DB 模式普通用户"的子集,将其放入整个测试矩阵可以更清楚地理解内容信任的完整闭环:
| 测试用例 | 操作 | 关键预期 |
|---|---|---|
| 9-01 | 开启 DCT 后推送镜像 | 镜像被签名并推送成功,UI 显示绿色对勾 |
| 9-02 | 关闭 DCT 推送镜像 | 推送成功但无签名 |
| 9-03 | 开启 DCT 拉取已签名镜像 | 拉取成功 |
| 9-04 | 开启 DCT 拉取未签名镜像 | 拉取被拒绝 |
| 9-05 | 删除已签名镜像 | 删除成功 |
从 9-01 的Expected Outcome可以看到,签名镜像在 Harbor UI 中会以"绿色对勾"标识呈现,这是确认镜像已被签名的最直观方式。在 9-04 中,当DOCKER_CONTENT_TRUST=1时拉取未签名镜像会失败——这正是 Docker 客户端侧 DCT 校验拦截的结果,与 9-03 形成对照。
常见问题与排查思路
测试用例中Possible Problems为 None,但在真实环境中仍可能遇到以下情况:
- TLS 证书错误(
x509: certificate signed by unknown authority):自签名证书未按上文复制到/etc/docker/certs.d/<harbor_ip>/与$HOME/.docker/tls/<harbor_ip>:4443/,或复制后未重启 Docker 守护进程。 - 拉取被拒(
could not find signed tag/no valid trust data):目标镜像本身未签名(未在 DCT 开启状态下推送),请先通过 9-01 流程准备签名镜像,或在 UI 中确认镜像带绿色对勾标识。 - 项目级内容信任策略拦截:若项目在配置页面开启了"内容信任"或"Cosign 内容信任",未签名镜像即使客户端开启 DCT 也会被 Harbor 服务端中间件拒绝(返回
PROJECTPOLICYVIOLATION,错误信息为 "The image is not signed by notation/cosign")。此时需使用签名镜像,或按 9-30 的流程验证策略行为。 - 信任服务器端口不通:确认 Harbor 的 Notary 服务(4443 端口)对外可达,且
DOCKER_CONTENT_TRUST_SERVER中的 IP/FQDN 与证书中的主机名匹配。
小结
本测试用例验证了 Harbor 内容信任体系中最基础也最关键的一环:DB 模式下的普通用户能够在启用DOCKER_CONTENT_TRUST后成功拉取已签名镜像。整个过程同时涉及 Docker 客户端侧(环境变量、信任服务器、TLS 证书)与 Harbor 服务端侧(Notary 4443 端口、manifest 拉取链路中间件、项目元数据策略)。掌握 9-03 的操作流程,再配合 9-01(签名推送)、9-04(未签名拦截)与 9-30(项目级强制策略)等关联用例,即可完整落地 Harbor 的镜像签名信任体系。
相关文件索引:
- 测试用例:9-03-DB-user-pull-signed-images.md、9-01-DB-user-push-signed-images.md、9-04-DB-user-pull-unsigned-images.md、9-30-Project-level-content-trust.md
- 服务端中间件:src/server/middleware/contenttrust/contentrust.go
- 路由挂载点:src/server/registry/route.go
- 项目元数据键定义:src/pkg/project/models/pro_meta.go
- 项目策略判断:src/pkg/project/models/project.go
【免费下载链接】harborAn open source trusted cloud native registry project that stores, signs, and scans content.项目地址: https://gitcode.com/GitHub_Trending/ha/harbor
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考