
Harbor 项目公开性实战指南DB 模式下非管理员创建项目与公共/私有项目权限验证【免费下载链接】harborAn open source trusted cloud native registry project that stores, signs, and scans content.项目地址: https://gitcode.com/GitHub_Trending/ha/harbor本篇技术指南围绕 Harbor 测试用例 2-01-DB-user-create-project.md 展开深入讲解在本地数据库认证DB 模式auth_modedb_auth下非管理员用户如何创建项目、公开项目Public与私有项目Private的可见性差异以及通过 Docker CLI 完成登录、推送与拉取镜像的完整验证链路。读完本文你将掌握 Harbor 项目公开性元数据metadata.public的底层实现、项目创建权限限制配置project_creation_restriction的作用以及公共项目列表过滤的源码级原理可直接复现该测试场景并迁移到生产环境的项目权限规划中。一、测试场景概览验证什么、为什么重要该用例是 Harbor 镜像管理测试组Group2-image-management的第一个用例编号 2-01属于DB 模式DB Mode系列。它要验证的核心命题是当 Harbor 使用本地数据库管理用户auth_modedb_auth时普通非管理员用户是否能够创建项目以及项目公开性publicity切换后其他非管理员用户能否在公共项目列表中看到该项目并能否拉取其镜像。这一命题直接关系到多租户场景下项目隔离与共享的基本体验。配套用例还包括 2-02-DB-user-push-multiple-images.md同一项目推送多镜像、2-03-DB-user-push-multiple-projects.md多项目推送、2-04-DB-user-view-projects.md查看项目等本用例是其中验证项目创建与公开性语义的基础。二、测试环境与前置条件原用例对环境的要求如下这也是复现实验的最低门槛Harbor 实例已启动并可用运行中的核心服务、Registry、数据库组件齐全认证模式为本地数据库auth_mode设置为db_auth用户数据存储在 Harbor 本地数据库中即用户由 Harbor 自行管理不依赖 LDAP/OIDC 等外部认证源一台安装了 Docker CLI 的 Linux 主机作为 Docker 客户端用于docker login/docker push/docker pullHarbor 中至少存在两个非管理员用户下文记为用户 A 和用户 B。原用例特别注明示例中的用户 A、B 以及项目 X、Y 应替换为更长、更有实际含义的名称便于在真实环境与日志中区分避免使用单字母命名造成混淆。三、逐步测试流程完整复现 12 个步骤以下步骤完整继承原用例并结合 Harbor Web 界面Portal与 Docker CLI 的实际操作展开说明。角色设定用户 A、B 均为非管理员项目 X 与项目 Y 为待创建项目。3.1 用户 A 创建两个公开性不同的项目以用户 A非管理员身份登录 Harbor UI。使用浏览器访问 Harbor Portal输入用户 A 的凭据完成登录。创建项目 X公开性publicity保持关闭默认。在项目创建界面中项目访问级别默认即为私有Private。从源码实现看创建项目时若未显式指定公开性服务端会将其置为false见下文源码解析因此默认关闭即默认创建私有项目。再创建项目 Y公开性publicity设为开启Public。在创建界面勾选公开访问级别使项目 Y 对未登录用户及其他用户可见。3.2 用户 B 从另一个浏览器验证公共项目列表保持用户 A 处于登录状态在另一个浏览器中或隐身窗口以用户 B非管理员登录 Harbor UI。用户 B 查看自己的公共项目Public Projects列表预期结果项目Y公开出现在列表中项目X私有不出现在列表中。这一步验证了公共项目对全体用户可见、私有项目对外部用户不可见的基本隔离语义。3.3 切换公开性后重新验证用户 A 在项目中修改公开性将项目 X 的公开性改为开启Public将项目 Y 的公开性改为关闭Private。用户 B 刷新公共项目列表预期结果项目X现已公开出现在列表中项目Y现已私有不再出现在列表中。这一步验证了公开性切换是即时生效的公共项目列表会随项目公开性变化实时刷新。3.4 Docker CLI 侧的推送与拉取验证在 Docker 客户端主机上使用docker login harbor_host以用户 A 身份登录 Harbor。其中harbor_host替换为 Harbor 实际地址含端口如reg.example.com:443。用户 A 分别向项目 X 和项目 Y 推送镜像# 先为本地镜像打上指向项目 X 的标签 docker tag local-image:tag harbor_host/x/local-image:tag docker push harbor_host/x/local-image:tag # 再打上指向项目 Y 的标签并推送 docker tag local-image:tag harbor_host/y/local-image:tag docker push harbor_host/y/local-image:tag用户 A 在浏览器中确认两个镜像均已成功推送到项目 X 和项目 Y 的仓库列表。在 Docker 客户端主机上使用docker login harbor_host以用户 B 身份登录同一主机或另一台均可。用户 B 尝试拉取项目 X 与项目 Y 中的镜像docker pull harbor_host/x/local-image:tag docker pull harbor_host/y/local-image:tag3.5 预期结果汇总步骤操作预期结果Step 5用户 B 查看公共项目列表项目 Y 在列表中项目 X 不在列表中Step 7切换公开性后刷新列表项目 X 在列表中项目 Y 不在列表中Step 9、10用户 A 推送镜像镜像成功推送到项目 X 和项目 YUI 可见Step 11、12用户 B 拉取镜像项目 X 的镜像可拉取项目 Y 的镜像不可拉取其中 Step 12 的判定需要特别注意此时项目 X 已切换为公开因此用户 B 可以匿名拉取其镜像项目 Y 已切换为私有用户 B 并非其成员因此拉取会被拒绝。这正是公开性Public/Private在镜像分发层面的最终体现。四、源码级原理一项目公开性如何存储与判定原用例中的公开性publicity在 Harbor 源码中对应项目元数据键public。4.1 元数据键与模型定义在项目模型 src/pkg/project/models/pro_meta.go 中定义了元数据常量ProMetaPublic public而项目实体 src/pkg/project/models/project.go 中同时定义了语义常量const ( // ProjectTable is the table name for project ProjectTable project // ProjectPublic means project is public ProjectPublic public // ProjectPrivate means project is private ProjectPrivate private )可见公开/私有并非project主表的独立列而是存放在项目的metadata元数据 Map中。项目实体的Metadata map[string]string字段承载这些键值对。4.2 公开性判定逻辑IsPublic()src/pkg/project/models/project.go 提供了判定方法// IsPublic ... func (p *Project) IsPublic() bool { public, exist : p.GetMetadata(ProMetaPublic) if !exist { return false } return isTrue(public) }关键语义只要public元数据不存在从未设置一律按私有false处理。这与 UI 创建项目时公开性默认关闭的行为完全一致。4.3 创建与更新时的服务端校验在项目 API 处理器 src/server/v2.0/handler/project.go 中CreateProject对public元数据做了三段式处理// accept the public property to make replication work well with old versions(1.2.0) if req.Public ! nil req.Metadata.Public { req.Metadata.Public strconv.FormatBool(*req.Public) } // populate public metadata as false if it isnt set if req.Metadata.Public { req.Metadata.Public strconv.FormatBool(false) } // validate metadata.public value, should only be true or false if p : req.Metadata.Public; p ! { if p ! true p ! false { return a.SendError(ctx, errors.BadRequestError(nil).WithMessagef(metadata.public should only be true or false, but got: %s, p)) } }这段代码说明三件事向后兼容兼容旧版本≤1.2.0复制replication请求中携带顶层public字段的写法将其转换为元数据形式默认值兜底未设置时强制填充为false从服务端保证了默认私有入参校验public只能取字符串true或false非法值直接返回 400 Bad Request。更新项目时UpdateProject见 src/server/v2.0/handler/project.go处理器同样将请求中的元数据通过JSONCopy合并进项目实体从而允许项目所有者切换公开性。五、源码级原理二非管理员为何能创建项目原用例成立的前提是非管理员可以创建项目。这在 Harbor 中由一个系统配置项控制project_creation_restriction项目创建限制。5.1 配置取值与默认行为系统配置键定义在 src/common/const.go可取值为配置值常量含义everyoneProCrtRestrEveryone所有用户均可创建项目默认adminonlyProCrtRestrAdmOnly仅系统管理员可创建项目src/common/const.go 中的定义ProCrtRestrEveryone everyone ProCrtRestrAdmOnly adminonly判断逻辑位于 src/lib/config/userconfig.go// OnlyAdminCreateProject returns the flag to restrict that only sys admin can create project func OnlyAdminCreateProject(ctx context.Context) (bool, error) { return DefaultMgr().Get(ctx, common.ProjectCreationRestriction).GetString() common.ProCrtRestrAdmOnly, nil }5.2 CreateProject 的权限检查链CreateProject 的权限检查顺序为if err : a.RequireAuthenticated(ctx); err ! nil { ... } onlyAdmin, err : config.OnlyAdminCreateProject(ctx) ... if onlyAdmin !(a.isSysAdmin(ctx, rbac.ActionCreate) || secCtx.IsSolutionUser()) { log.Errorf(Only sys admin can create project) return a.SendError(ctx, errors.ForbiddenError(nil).WithMessage(Only system admin can create project)) }即在默认配置everyone下任何已通过认证authenticated的非管理员用户都可以创建项目只有管理员在系统配置中将project_creation_restriction切换为adminonly后非管理员才会收到 403 Forbidden。原用例的 Step 1/2 正是基于默认配置展开的。此外创建项目的所有者Owner被设定为发起请求的用户本人见 src/server/v2.0/handler/project.go通过userCtl.GetByName查询当前用户名对应的用户 ID 作为OwnerID。六、源码级原理三公共项目列表如何过滤原用例 Step 5、7 的核心是用户 B 的公共项目列表中能看到公开项目、看不到私有项目。这一行为在ListProjects处理器中实现。6.1 非管理员视角公共项目 自己参与的项目src/server/v2.0/handler/project.go 中对已认证但非系统管理员的请求查询被改写为本人成员身份 公共项目if ok secCtx.IsAuthenticated() { if !a.isSysAdmin(ctx, rbac.ActionList) !secCtx.IsSolutionUser() { // authenticated but not system admin or solution user, // return public projects and projects that the user is member of if l, ok : secCtx.(*local.SecurityContext); ok { currentUser : l.User() member : project.MemberQuery{ UserID: currentUser.UserID, GroupIDs: currentUser.GroupIDs, } // not filter by public or filter by the public with true, // so also return public projects for the member if public, ok : query.Keywords[public]; !ok || lib.ToBool(public) { member.WithPublic true } query.Keywords[member] member } ... } }MemberQuery.WithPublic字段在 src/pkg/project/models/member.go 中定义为WithPublic bool // include the public projects for the member表示在按成员查询时同时包含公共项目。当用户未指定public过滤条件或显式请求publictrue时WithPublictrue结果 本人参与的项目 全部公共项目这正是用户 B 能看到公开的项目 Y、却看不到私有的项目 X 的根源项目 X 既非公共项目用户 B 也不是其成员。6.2 匿名视角与私有查询的兜底同一处理器还处理了其他视角src/server/v2.0/handler/project.go} else { if params.Public ! nil !*params.Public { // anonymous want to query private projects return empty projects directly return operation.NewListProjectsOK().WithXTotalCount(0).WithPayload([]*models.Project{}) } // force to return public projects for anonymous query.Keywords[public] true }匿名用户只能看到公共项目若匿名用户显式请求私有项目列表则直接返回空结果。公共项目因此具备了无需登录即可拉取镜像的能力这正是 Step 12 中用户 B 能拉取公开项目 X 镜像的原因之一实际拉取时还受 Registry 的匿名访问策略支持。6.3 DAO 层的支撑验证在 src/pkg/project/dao/dao_test.go 中提供了TestListByPublic测试对按公开性过滤的查询逻辑进行了覆盖其中 dao_test.go 展示了组合查询的典型用法projects, err : suite.dao.List(orm.Context(), q.New(q.KeyWords{member: models.MemberQuery{UserID: 1, Role: common.RoleGuest, WithPublic: true}}))即以用户 ID 角色 包含公共项目为关键词组合查询与ListProjects处理器的行为一一对应。七、实操要点与边界条件7.1 Docker 客户端连通性前提docker login/push/pull依赖 Harbor 对外暴露的 Registry 端口通常是 HTTPS 443 或配置的其他端口且客户端需信任 Harbor 的 CA 证书自签名证书场景需将 Harbor 根证书加入 Docker 客户端的信任链。本用例默认环境已具备这些前提。7.2 命名建议原用例明确要求将用户 A/B 与项目 X/Y 替换为有意义的名称。建议在实测中用户alice、bob项目alice-private-repo、alice-public-repo镜像使用nginx:latest、busybox:latest等轻量公共镜像打标。7.3 判定要点重述UI 侧公共项目列表 公开项目 本人参与的项目私有且未参与的项目不出现Registry 侧公开项目允许非成员拉取私有项目仅成员含项目内角色可拉取切换即时性公开性切换无需重启 Harbor刷新页面即可看到列表变化。7.4 与 LDAP 模式的对照同目录下还有 2-11-LDAP-user-create-project.md 等 LDAP 系列用例2-11 至 2-16。两者验证的功能矩阵完全一致创建项目、推多镜像、推多项目、查看项目、删镜像、删项目唯一区别是用户来源LDAP 模式下用户由外部目录服务管理。本文的源码原理对两种模式同样适用因为项目创建、公开性与成员关系的处理逻辑与认证来源无关。八、总结通过完整复现 2-01-DB-user-create-project.md 的 12 个步骤我们验证了 Harbor 在 DB 模式下的一条完整权限链路创建默认配置下任何已认证用户均可创建项目project_creation_restrictioneveryone公开性项目通过元数据metadata.publictrue/false表达公开/私有未设置时服务端强制为私有可见性非管理员的项目列表 本人参与的项目 公共项目MemberQuery.WithPublic私有项目对其他用户完全不可见镜像访问公开项目支持非成员拉取私有项目仅成员可拉取。这套机制构成了 Harbor 多租户场景下共享与隔离的基石无论是搭建内部镜像仓库还是对外提供公共镜像服务理解metadata.public与project_creation_restriction的实现细节都能帮助你更精准地规划项目权限策略。【免费下载链接】harborAn open source trusted cloud native registry project that stores, signs, and scans content.项目地址: https://gitcode.com/GitHub_Trending/ha/harbor创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考