Harbor RBAC 实战:db_auth 模式下非管理员用户管理项目成员的完整验证与权限模型解析
【免费下载链接】harborAn open source trusted cloud native registry project that stores, signs, and scans content.项目地址: https://gitcode.com/GitHub_Trending/ha/harbor
本文基于 Harbor 仓库自带的 RBAC 测试用例(tests/testcases/Group3-RBAC/3-01-DB-user-manage-project-members.md),完整还原"非系统管理员在本地数据库认证(db_auth)模式下管理项目成员"的验证流程:读者可以掌握 Harbor 项目角色体系(projectAdmin/maintainer/developer/guest/limitedGuest)的权限边界、成员增删改对各操作的实际生效点,以及 pull/push 权限与 UI 成员列表的一致性,并能对照源码理解这些行为背后的策略定义。
测试目的与适用前提
该用例的核心目的是:在 Harbor 使用本地数据库管理用户(auth_mode为db_auth)时,验证一个非系统管理员用户能否按预期为项目添加不同角色的成员,以及各角色能做什么、不能做什么。
原文档声明的环境前提如下,执行前必须逐项确认:
- 一个可用、正在运行的 Harbor 实例;
- Harbor 认证方式为本地数据库,即
auth_mode配置为db_auth,用户数据存于本地数据库; - 一台安装了 Docker CLI 的 Linux 主机作为客户端;
- Harbor 中至少存在三个非管理员用户(下文记为 User A、B、C)。
db_auth是 Harbor 的默认认证模式,这一点可以在源码中确认:metadatalist.go 中auth_mode元数据的DefaultValue为"db_auth",其描述为The auth mode of current system, such as "db_auth", "ldap_auth", "oidc_auth";userconfig.go 在读取不到认证模式配置时同样回退返回"db_auth"。db_auth与其他认证模式(ldap_auth、uaa_auth、oidc_auth等)的常量定义见 const.go。同组测试用例中还有 LDAP 模式下的对应用例 3-04-LDAP-user-manage-project-members.md,两者验证的是同一套 RBAC 模型在不同认证源下的表现。
执行测试时的三条硬性注意事项(原文档 NOTE 部分):
- 测试中的 User A、B、C 和项目 X 应替换为更长的、有实际含义的名称,避免与真实数据混淆;
- 必须同时使用两种浏览器(如 Chrome 与 Firefox)保证两个用户会话相互独立;
- 不要在同一浏览器的不同窗口/标签页中同时登录两个用户,否则 session 会互相覆盖,导致"User A 的会话在线"这一前提失效。
项目角色体系:测试中 guest → developer → projectAdmin 的升级路径
用例第 11、17、22 步中,User A 依次把 User B 设为 guest、developer、project admin,这正是 Harbor 项目级 RBAC 的三个典型角色。从源码 const.go 可以看到项目角色的数字常量定义:
| 常量 | 值 | 说明 |
|---|---|---|
RoleProjectAdmin | 1 | 项目管理员 |
RoleDeveloper | 2 | 开发者 |
RoleGuest | 3 | 访客 |
RoleMaintainer | 4 | 维护者 |
RoleLimitedGuest | 5 | 受限访客 |
这些角色与策略的映射集中定义在 rbac_role.go 的rolePoliciesMap中。与本文测试步骤直接相关的权限差异如下(完整的resource + action清单以源码为准):
- guest:
Repository资源仅有Read/List/Pull三项动作,没有Push;对Member资源仅有Read/List——这解释了为什么 guest 只能拉取、不能推送,且不能管理成员; - developer:在 guest 基础上为
Repository增加了Create/Update/Push,因此 developer 可以推送镜像,但仍然只能Read/List成员,不能添加或修改成员; - projectAdmin:额外拥有
Member资源的Create/Update/Delete动作(以及Self资源的Read/Update/Delete),是唯一能在项目内增删改成员的角色。
projectRBACRole.GetPolicies()会按roleID解析出角色名(projectAdmin/maintainer/developer/guest/limitedGuest),再结合NewNamespace(projectID)把策略限定在该项目的命名空间内返回。也就是说,角色的每一条策略都只在其所属项目内生效,这是"成员权限随项目隔离"的底层保证。
完整测试步骤(30 步)
以下步骤完整继承自原用例文档,按"初始状态验证 → guest 授权 → developer 升级 → projectAdmin 升级 → 移除成员"五个阶段组织。
阶段一:无成员权限时的基线验证(步骤 1–10)
- 以 User A(非管理员)登录 Harbor UI。
- 创建新项目 X,publicity 保持关闭(默认 private)。
- 验证 User A 无法修改自己在项目 X 中的角色。
- 在 Docker 客户端主机上,以 User A 执行
docker login <harbor_host>登录。 - 向项目 X 推送一个镜像。
- 在客户端退出 User A,登录 User B。
- User B 执行
docker pull拉取项目 X 的镜像——应当失败。 - User B 执行
docker push向项目 X 推送镜像——应当失败。 - 保持 User A 的 UI 会话在线,在另一台浏览器的独立会话中登录 User B。
- User B 查看 "My Projects"——不应看到项目 X。
阶段二:加入为 guest(步骤 11–16)
- 在 User A 的 UI 中,将 User B 以guest角色加入项目 X。
- 在 User B 的 UI 中确认项目 X 出现在 "My Projects",可查看成员列表和镜像列表。
- 验证 User B 无法修改项目 X 中其他成员的角色。
- 验证 User B 无法向项目 X 添加新成员。
- 在客户端,User B 再次执行
docker pull拉取项目 X 的镜像——应当成功。 - User B 执行
docker push向项目 X 推送镜像——应当失败。
阶段三:升级为 developer(步骤 17–21)
- 在 User A 的 UI 中,将 User B 更新为项目 X 的developer角色。
- 在 User B 的 UI 中确认项目 X 在 "My Projects",可查看成员和镜像。
- 验证 User B 仍无法修改其他成员的角色。
- 验证 User B 仍无法添加新成员。
- 在客户端,User B 向项目 X 推送一个新镜像——应当成功。
阶段四:升级为 project admin 并授权第三个用户(步骤 22–26)
- 在 User A 的 UI 中,将 User B 更新为项目 X 的project admin角色。
- 在 User B 的 UI 中确认项目 X 在 "My Projects",可查看成员和镜像。
- 验证 User B 现在可以添加新用户 User C 到项目 X。
- 验证 User B可以修改 User C 在项目 X 中的角色。
- 在客户端,User B 再次向项目 X 推送一个新镜像——成功。
阶段五:移除成员后验证权限即时回收(步骤 27–30)
- 在 User A 的 UI 中,将 User B 从项目 X 中移除。
- 在客户端,User B 拉取项目 X 的镜像——应当失败。
- 在客户端退出 User B,登录 User C。
- User C 拉取项目 X 的镜像——应当成功(因为 User C 是步骤 24 中被加入的成员)。
预期结果逐条对照
原文档 "Expected Outcome" 部分的完整断言:
- 步骤 3:User A 不能修改自己的角色,也不能把自己从项目 X 移除;
- 步骤 7:User B 未加入项目前,拉取镜像失败;
- 步骤 8:同上,推送镜像失败;
- 步骤 9:必须确保以另一浏览器登录 User B 时 User A 的会话仍在线;
- 步骤 10:User B 看不到项目 X;
- 步骤 12–14:按描述,guest 可查看项目、不能改成员角色、不能加新成员;
- 步骤 15:User B 加入为 guest 后可以拉取镜像;
- 步骤 16:User B 作为 guest 不能推送镜像;
- 步骤 18–20:developer 同样不能改成员角色、不能加新成员;
- 步骤 21:developer 推送镜像成功;
- 步骤 23–25:project admin 可以添加 User C、可以修改 User C 的角色;
- 步骤 28:User B 被移除后拉取失败,说明权限随成员关系即时回收;
- 步骤 30:User C 拉取成功。
源码层面的佐证与延伸
- 成员权限的来源:guest/developer/projectAdmin 对
member资源分别只有Read/List或完整的Create/Update/Delete(见 rbac_role.go),与步骤 13/14(guest 不能管理成员)、19/20(developer 不能管理成员)、24/25(projectAdmin 可以管理成员)的预期结果一一对应。 - pull/push 权限的来源:
Repository资源上的Pull/Push动作是 Registry v2 认证链路的判定依据,guest 没有Push,因此步骤 8/16 推送失败、步骤 15/21/26 依角色变化而结果不同;项目范围之外的完整资源-动作清单定义在 rbac/const.go 的ScopeProject策略集中。 - "不能修改自己角色/不能移除自己"(步骤 3):
projectAdmin角色持有Self的Read/Update/Delete策略,而 guest/developer 只有Self: Read;从源码结构看,对"自己"这一子资源的操作限制是在成员管理接口的服务层结合请求者身份进一步判定的,测试用例以行为断言方式覆盖了这一边界。 - 认证模式与用户来源:
db_auth表示用户账号直接存于 Harbor 的 PostgreSQL 数据库,因此测试中才能由 A 直接在 UI 里把 B、C(同为本地用户)加入项目;在 LDAP 等外部认证源下,对应用例(见 3-04-LDAP-user-manage-project-members.md)还需要处理用户搜索与 DN 匹配等额外问题。 - 同组用例可作对照阅读:3-02-DB-user-manage-project-publicity.md 验证项目公开性管理,3-03-DB-user-search-project-members.md 验证成员搜索,3-11-DB-admin-user-manage-project-members.md 则是系统管理员执行相同成员管理操作的版本——两者对比即可看出系统管理员与项目内 projectAdmin 在成员管理上的权限差异。
小结
这个用例的价值在于它用 30 个可复现的步骤把"成员关系变化 → 角色策略变化 → pull/push 与 UI 可见性变化"的因果链完整钉死:guest 能拉不能推、developer 能推不能管人、projectAdmin 才能增删改成员,且权限随加入/移除即时生效。执行该用例时,重点检查项是步骤 7/8/10(加入前基线)、15/16(guest 边界)、21(developer 边界)、24/25(projectAdmin 边界)和 28/30(移除后的权限回收),任何一步与预期不符,都应优先对照 rbac_role.go 中对应角色的策略清单定位是权限定义问题还是会话/登录态问题(原文档 Possible Problems 一节标注为 None,说明按上述独立会话要求执行时不应出现环境问题)。
【免费下载链接】harborAn open source trusted cloud native registry project that stores, signs, and scans content.项目地址: https://gitcode.com/GitHub_Trending/ha/harbor
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考