2. GitLab权限模型总览
GitLab 的权限体系并不是一张“用户—项目”的简单对照表,而是一棵由命名空间(Namespace)组织起来的树。理解这棵树,是后续做最小权限设计、审计越权风险、排查“为什么他能看到这个项目”的前提。本节先把六个核心对象摆到同一张图上:用户(User)、群组(Group)、子群组(Subgroup)、项目(Project)、角色(Role)、成员关系(Membership),再说明它们之间如何继承。
一、六个核心对象各自是什么
用户是权限的最终承载者,可以是真人账号,也可以是机器人账号(如 CI/CD 用的 Project Access Token 对应的 Bot User)。用户本身不直接拥有权限,权限来自“它在某个命名空间或项目上被授予的成员关系”。
群组是顶层命名空间,也是权限继承的起点。它既是项目的容器,也是成员管理的边界。一个群组可以包含项目,也可以包含子群组。
子群组是群组内部的命名空间,可以多层嵌套,例如 rd-platform/backend/payment。子群组的意义在于:它让“部门—团队—业务线”的组织结构可以直接映射为权限边界,而不必为每个项目单独维护成员。
项目是代码、Issue、CI/CD、制品等资源的实际载体,也是权限判定的最小单元。项目一定归属于某个群组或某个用户命名空间。
角色决定“能做什么”。GitLab 默认提供五个层级:Guest、Reporter、Developer、Maintainer、Owner。它们不是并列的标签,而是能力递增的阶梯。
成员关系是“谁在哪个对象上拥有什么角色”的记录。它把用户、角色、命名空间/项目三者绑定在一起,是权限计算的输入。
二、继承机制:权限沿命名空间树向下流动
GitLab 的继承规则可以概括为一句话:在群组或子群组上添加成员,该成员会自动获得其下所有子群组和项目的对应权限。也就是说,权限是“向下继承”的,而不是“向上汇总”的。
举例说明:假设组织结构为 rd-platform(顶层群组)→ backend(子群组)→ payment(子群组)→ payment-api(项目)。如果把张三加入 backend 子群组并授予 Developer,那么张三会自动对 payment 子群组和 payment-api 项目拥有 Developer 权限,无需再单独添加。反过来,如果只把张三加入 payment-api 项目,他对 backend 群组本身没有任何权限,也看不到同级的其他项目。
继承还带来两个重要推论。第一,角色只能被继承,不能被“降级覆盖”:如果张三在 backend 是 Developer,在 payment-api 项目上又被单独授予 Reporter,GitLab 会取两者中更高的权限,即 Developer。第二,Owner 角色只存在于群组层级,项目层级最高是 Maintainer;因此“项目 Owner”这个说法在 GitLab 中并不成立。
三、角色能力阶梯与典型使用场景
下表给出五个默认角色在项目层面的关键能力差异,便于做权限分配时快速对照。表中“✓”表示具备,“—”表示不具备,实际能力会随 GitLab 版本略有差异,应以当前实例的官方文档为准。
| 能力 | Guest | Reporter | Developer | Maintainer | Owner |
|---|---|---|---|---|---|
| 查看项目与代码 | — | ✓ | ✓ | ✓ | ✓ |
| 查看 Issue / 看板 | ✓ | ✓ | ✓ | ✓ | ✓ |
| 克隆代码 | — | ✓ | ✓ | ✓ | ✓ |
| 推送分支 | — | — | ✓ | ✓ | ✓ |
| 触发流水线 | — | — | ✓ | ✓ | ✓ |
| 管理保护分支 | — | — | — | ✓ | ✓ |
| 管理项目成员 | — | — | — | ✓ | ✓ |
| 删除项目 | — | — | — | — | ✓ |
典型分配思路是:外包或跨团队只读人员给 Reporter;日常开发给 Developer;负责合并、保护分支和 CI 变量管理的技术负责人给 Maintainer;群组级治理、成员管理和项目生命周期决策由 Owner 承担。Guest 主要用于需要看 Issue 但不看代码的场景,例如产品经理或外部需求方。
四、成员关系的作用域与“直接成员 / 继承成员”
在 GitLab 的成员页面中,同一个用户可能同时以两种身份出现:直接成员(Direct Member)和继承成员(Inherited Member)。直接成员是在当前对象上显式添加的;继承成员是从上层群组或子群组继承下来的。排查权限问题时,第一步就是确认用户到底是哪一类成员、来源是哪个命名空间。
此外,成员关系还有“到期时间”和“访问级别”两个属性。到期时间用于临时授权,例如给外部审计人员开放 7 天 Reporter;到期后成员关系自动失效,无需人工清理。访问级别则对应角色,可在成员页面直接调整。
五、一张图看清整体结构
下面的 SVG 用一棵命名空间树把上述对象和继承方向画在一起:左侧是用户,中间是群组/子群组/项目构成的层级,右侧是角色与成员关系。箭头方向表示权限继承的流动方向,从群组向下流向子群组和项目。
六、实践中的三个判断要点
第一,先定边界,再定角色。不要一上来就给人加 Developer,而应先问“这个人属于哪个团队、应该在哪一层命名空间上被授权”。如果一个人只负责一个项目,就加到项目;如果负责整条业务线,就加到对应子群组。授权层级越高,影响面越大,越需要谨慎。
第二,用子群组替代“逐项目加人”。当同一批人需要访问多个项目时,逐个项目添加成员会产生大量重复记录,且人员变动时容易漏删。正确做法是把这些项目收拢到同一个子群组下,在子群组上统一授权,人员进出只改一处。
第三,排查权限时先看继承来源。如果某用户对项目有权限但项目成员列表里找不到他,大概率是从上层群组继承而来。此时应逐级向上检查群组和子群组的成员列表,确认授权层级和角色,而不是在项目层面反复增删。
掌握这套结构后,后续的保护分支、审批规则、CI/CD 变量、审计日志等治理手段,都可以落到“在哪个命名空间、给哪个角色、授予什么能力”这三个坐标上,权限设计也就从零散配置变成了可推理、可审计的工程问题。