Skip to main content

ReBAC 与 SpiceDB 权限模型

本文解释 Aisphere IAM 中的 ReBAC 权限模型,以及如何用 SpiceDB 管理 organization / project / skill / agent / workflow / repo 等资源的访问控制。

目标是形成一套清晰边界:

  • Casdoor:负责 AuthN,管理用户、组织、组、登录和 OIDC/JWT。
  • IAM:负责权限控制面,管理关系写入、同步、审计、补偿和聚合 API。
  • SpiceDB:负责 AuthZ,保存关系图并计算权限。
  • Gateway / Kernel:负责权限执行面,在请求链路中完成 principal 注入和 CheckPermission

Aisphere ReBAC / SpiceDB 总览

1. ReBAC 是什么

ReBAC 是 Relationship-Based Access Control,即基于关系的访问控制

它不是先判断用户有没有某个全局角色,而是判断:

某个主体和某个资源之间,能不能通过关系图推导出某个业务权限。

例如:

user:u1 是 group:g_dev 的 member
group:g_dev 是 project:p1 的 editor
skill:s1 属于 project:p1

当系统检查:

user:u1 能不能 edit skill:s1 ?

SpiceDB 会沿着关系图计算:

user:u1 -> group:g_dev#member -> project:p1#editor -> skill:s1#project -> edit

如果 schema 允许从 project editor 继承到 skill edit,则返回允许。

2. ReBAC、RBAC、ABAC 的区别

模型判断依据适合场景典型问题
RBAC用户是否拥有某个角色简单后台、全局角色容易角色爆炸,难表达资源层级
ABAC用户、资源、请求上下文属性IP、时间、部门、环境等动态条件复杂资源关系难维护
ReBAC主体和资源之间的关系路径组织、项目、组、资源、分享、继承需要先设计好关系图

Aisphere 的核心对象天然具有层级和关系:

user / group / organization / project / skill / agent / workflow / repo

所以资源级授权应以 ReBAC 为主,RBAC 只保留少量平台级能力,ABAC 作为动态条件补充。

3. SpiceDB 的 4 个核心概念

3.1 Resource / Object:资源对象

Resource 是被保护的东西。在 SpiceDB 中通常称为 object。

业务资源SpiceDB object
组织organization:org_uuid
项目project:project_uuid
Skillskill:skill_uuid
Agentagent:agent_uuid
Workflowworkflow:workflow_uuid
Git Reporepo:repo_uuid
Secretsecret:secret_uuid

SpiceDB 不保存资源详情。skill:skill_001 只是权限图里的一个节点,Skill 的名称、YAML、版本、描述、状态仍然放在业务库、Git 或对象存储中。

3.2 Subject:主体

Subject 是访问资源的一方。

主体类型SpiceDB subject说明
用户user:user_uuid从 Casdoor 稳定 UUID 获取
服务账号serviceaccount:iamIAM、Hub、Gateway、同步任务等 M2M
用户组成员集合group:group_uuid#member一个组的所有成员
组织成员集合organization:org_uuid#member一个组织的所有成员

重要约束:用户主体统一使用稳定 UUID,不使用 name、email、displayName、phone。

推荐:

user:4d36f0a2-7c0d-4cb5-a84f-4c6c6fbf0c70

不推荐:

user:alice@example.com
user:alice
user:张三

3.3 Relation:关系

Relation 是写入 SpiceDB 的事实

例如:

skill:skill_001#owner@user:user_001
skill:skill_001#viewer@user:user_002
skill:skill_001#editor@group:g_dev#member

可以读作:

user_001 是 skill_001 的 owner
user_002 是 skill_001 的 viewer
g_dev 组内所有 member 都是 skill_001 的 editor

Relation 是权限图里的边。它表示已经发生或被授权的关系事实。

3.4 Permission:权限

Permission 是 schema 中定义的业务动作,通常是应用代码真正检查的内容。

例如:

definition skill {
relation owner: user
relation editor: user
relation viewer: user

permission view = viewer + editor + owner
permission edit = editor + owner
permission delete = owner
}

业务代码应该检查:

skill:skill_001#edit@user:user_001

而不是直接检查:

skill:skill_001#owner@user:user_001

原因是:

  • owner / editor / viewer 是底层关系事实。
  • view / edit / delete / manage / run / share 是业务动作。
  • 业务代码稳定检查 permission,后续只改 schema 即可调整权限策略。

4. Relation 和 Permission 的边界

这是最容易混淆的点。

类型是什么是否直接写入是否业务检查示例
Relation事实关系一般不直接查skill:s1#owner@user:u1
Permission动作能力否,由 schema 计算skill:s1#delete@user:u1

关系事实:

skill:s1#owner@user:u1

权限推导:

permission view = viewer + editor + owner
permission edit = editor + owner
permission delete = owner

检查结果:

user:u1 has skill:s1#view
user:u1 has skill:s1#edit
user:u1 has skill:s1#delete

5. SpiceDB Schema 基础

Schema 是权限图的类型系统。

一个最小 Skill schema:

definition user {}

definition skill {
relation owner: user
relation editor: user
relation viewer: user

permission view = viewer + editor + owner
permission edit = editor + owner
permission delete = owner
}

5.1 常用操作符

操作符含义示例
+并集,任意满足即可view = viewer + editor + owner
&交集,必须同时满足approve = reviewer & project->member
-排除view = viewer - banned
->关系跳转,沿资源关系继续计算view = project->view + viewer

其中 -> 是 ReBAC 建模的关键,它让权限可以沿着资源关系图继承。

6. 资源层级和权限继承

Aisphere 推荐先抽象出这条资源主线:

推荐 schema 起点:

definition user {}

definition serviceaccount {}

definition group {
relation member: user | group#member
}

definition organization {
relation admin: user | group#member | serviceaccount
relation member: user | group#member | serviceaccount

permission view = member + admin
permission manage = admin
permission create_project = admin
}

definition project {
relation org: organization

relation owner: user | group#member | serviceaccount
relation editor: user | group#member | serviceaccount
relation viewer: user | group#member | serviceaccount

permission view = viewer + editor + owner + org->view
permission edit = editor + owner
permission manage = owner + org->manage
permission create_skill = edit + manage
permission create_agent = edit + manage
permission create_workflow = edit + manage
}

definition skill {
relation project: project

relation owner: user | group#member | serviceaccount
relation editor: user | group#member | serviceaccount
relation viewer: user | group#member | serviceaccount

permission view = viewer + editor + owner + project->view
permission edit = editor + owner + project->edit
permission manage = owner + project->manage
permission delete = owner + project->manage
}
caution

permission view = project->view 会让项目可见性继承到 Skill。也就是说,能看项目的人默认能看项目下的 Skill。这个策略是否正确取决于业务语义。若 Skill 需要更细粒度隔离,则不要默认继承项目 view,只继承 manage 或显式授权。

7. 权限推导示例

关系数据:

organization:o1#admin@user:u1
project:p1#org@organization:o1
skill:s1#project@project:p1

schema:

definition organization {
relation admin: user
permission manage = admin
}

definition project {
relation org: organization
relation owner: user
permission manage = owner + org->manage
}

definition skill {
relation project: project
relation owner: user
permission manage = owner + project->manage
}

检查:

Can user:u1 manage skill:s1 ?

推导路径:

结果:

HAS_PERMISSION

原因:

user:u1 是 organization:o1 的 admin
project:p1 属于 organization:o1
skill:s1 属于 project:p1
organization admin 可以 manage project
project manage 可以 manage skill

8. Aisphere 推荐建模规范

8.1 Object type 命名

类型说明
userCasdoor 用户
serviceaccount服务账号 / M2M 主体
group用户组,可支持嵌套
organization租户根对象
project组织下的项目边界
skillSkill 资源
agentAgent 资源
workflowWorkflow 资源
repoGit 仓库资源
secret密钥资源
runtimeRuntime / Sandbox 资源

8.2 Relation 用名词

Relation 表示关系事实,推荐用名词:

owner
editor
viewer
admin
member
parent
org
project
creator
runner
approver

8.3 Permission 用动作

Permission 表示业务动作,推荐用动词或动作名:

view
edit
delete
manage
share
run
publish
clone
create_skill
create_agent
create_workflow
read_secret
write_secret

8.4 应用代码只检查 Permission

APISpiceDB Check
GET /v1/projects/{id}project:{id}#view@user:{uid}
PUT /v1/projects/{id}project:{id}#edit@user:{uid}
DELETE /v1/projects/{id}project:{id}#manage@user:{uid}
POST /v1/projects/{id}/skillsproject:{id}#create_skill@user:{uid}
GET /v1/skills/{id}skill:{id}#view@user:{uid}
PUT /v1/skills/{id}skill:{id}#edit@user:{uid}
DELETE /v1/skills/{id}skill:{id}#delete@user:{uid}
POST /v1/workflows/{id}/runworkflow:{id}#run@user:{uid}

9. 关系写入生命周期

9.1 创建组织

业务库写入:

organization {
id = org_001
name = "Aisphere"
created_by = user_001
}

SpiceDB 写入:

organization:org_001#admin@user:user_001
organization:org_001#member@user:user_001

9.2 创建项目

业务库写入:

project {
id = project_001
org_id = org_001
created_by = user_001
}

SpiceDB 写入:

project:project_001#org@organization:org_001
project:project_001#owner@user:user_001

9.3 创建 Skill

业务库写入:

skill {
id = skill_001
project_id = project_001
created_by = user_001
}

SpiceDB 写入:

skill:skill_001#project@project:project_001
skill:skill_001#owner@user:user_001

9.4 授权给用户组

组成员关系:

group:g_dev#member@user:user_002
group:g_dev#member@user:user_003

资源授权:

skill:skill_001#editor@group:g_dev#member

含义:

g_dev 组内所有成员都是 skill_001 的 editor

10. 请求链路

Kernel 侧推荐通过 protoc option 声明权限:

rpc UpdateSkill(UpdateSkillRequest) returns (Skill) {
option (google.api.http) = {
put: "/v1/skills/{id}"
body: "*"
};

option (aisphere.authz) = {
resource_type: "skill"
resource_id_field: "id"
permission: "edit"
};
}

生成代码负责:

principal := contextx.Principal(ctx)
resourceID := req.Id
CheckPermission(skill:resourceID, edit, user:principal.ID)

业务代码只关注业务逻辑,不重复手写权限判断。

11. 管理链路

建议边界:

组件职责
Casdoor用户、组织、组、登录、OIDC
IAM关系管理 API、同步 Casdoor、审计、补偿、权限聚合
SpiceDB保存 relationship,执行 Check / Lookup
Hub / Runtime / Gateway调用 IAM 或 Kernel Guard,不直接随意写 SpiceDB

12. 列表接口怎么做

GET /v1/skills 这类接口不能简单把所有资源查出来再返回,需要做权限过滤。

12.1 小规模列表:LookupResources

适合:

  • 用户可见资源数量不大。
  • 管理后台页面。
  • 授权结果比业务排序更重要。

12.2 常规分页:业务库分页 + CheckBulk

适合:

  • 常规产品列表。
  • 有明确 org_id / project_id 范围。
  • 需要按照创建时间、更新时间、名称等业务字段排序。

12.3 大规模列表:权限索引

当资源量非常大时,可以增加 materialized ACL 或搜索索引:

业务库查询 + CheckBulk 保证正确性
搜索索引 / ACL 表提升性能
SpiceDB 仍作为最终授权真源

13. 公开接口和公开资源

这两个概念必须分开。

13.1 公开接口

例如:

/healthz
/readyz
/openapi.json
/oauth2/callback
/login
/public/assets/*

这些接口不需要登录,属于 AuthN/AuthZ bypass。它们应该由 Gateway 或 Kernel route 元数据标记为 public。

13.2 公开资源

例如:

某个 Skill 公开可查看
某个 Agent 模板公开可 clone
某个 Workflow 示例公开可运行

这不是接口公开,而是资源本身授权给公共主体。

可以建模为:

definition skill {
relation public_viewer: user:*
relation owner: user
relation editor: user
relation viewer: user

permission view = public_viewer + viewer + editor + owner
}

推荐约束:

  • 默认不公开,显式设置 public 才公开。
  • 公开资源只开放 view / clone 等安全动作。
  • 不允许公开主体获得 edit / manage / delete
  • public 关系必须可审计、可撤销。

14. 一致性与 ZedToken

SpiceDB 写入关系后,会返回用于一致性控制的 token。对“写完马上读”的场景,应该把该 token 传递给后续检查,保证结果至少包含刚刚完成的写入。

典型场景:

Kernel 封装建议:

type AuthzWriteResult struct {
ZedToken string
}

type CheckOptions struct {
AtLeastAsFresh string
}

15. 删除资源时清理关系

删除资源不能只删业务库。

例如删除 Skill:

DELETE FROM skills WHERE id = skill_001

还需要删除 SpiceDB 中相关关系:

skill:skill_001#project@project:project_001
skill:skill_001#owner@user:user_001
skill:skill_001#editor@...
skill:skill_001#viewer@...

推荐流程:

如果不清理,LookupResources 可能返回业务库已经不存在的资源 ID,形成幽灵权限。

16. Caveat:条件化关系

Caveat 可以理解为:

这条关系存在,但只有在运行时上下文满足条件时才成立。

可用于:

场景示例
临时分享分享 24 小时后自动失效
IP 限制只允许内网 CIDR 访问
环境限制只允许 dev/test/prod 某个环境
Runtime 限制只允许某个 service account 执行

示意:

skill:s1#viewer@user:u2 with expires_at(timestamp = "2026-07-10T00:00:00Z")

建议前期少用 Caveat。先把核心资源关系建稳,再引入动态条件。

17. Fail Closed 原则

权限模型必须默认拒绝。

推荐:

permission view = viewer + editor + owner

不推荐:

permission view = public - blocked

原因:如果 blocked 关系写入失败,用户反而可能获得访问权限。

Aisphere 权限设计原则:

没有显式关系,就没有权限。
有权限必须能解释路径。
权限变更必须可审计。
资源删除必须清理关系。
业务代码检查 permission,不检查 relation。

18. IAM API 建议

18.1 权限检查

POST /v1/iam/permissions/check

请求:

{
"resource_type": "skill",
"resource_id": "skill_001",
"permission": "edit",
"subject_type": "user",
"subject_id": "user_001"
}

响应:

{
"allowed": true,
"decision_id": "dec_01J...",
"zed_token": "..."
}

18.2 授权

POST /v1/iam/relationships/grant

请求:

{
"resource_type": "skill",
"resource_id": "skill_001",
"relation": "editor",
"subject_type": "group",
"subject_id": "g_dev",
"subject_relation": "member"
}

写入:

skill:skill_001#editor@group:g_dev#member

18.3 撤销授权

POST /v1/iam/relationships/revoke

请求:

{
"resource_type": "skill",
"resource_id": "skill_001",
"relation": "editor",
"subject_type": "group",
"subject_id": "g_dev",
"subject_relation": "member"
}

删除:

skill:skill_001#editor@group:g_dev#member

19. Schema 变更管理

SpiceDB schema 应像数据库 migration 一样管理。

推荐目录:

spicedb/
schema/
001_init.zed
002_add_workflow.zed
003_add_repo.zed
tests/
organization_test.yaml
project_test.yaml
skill_test.yaml

流程:

注意顺序:

  1. 先部署兼容性 schema。
  2. 再部署写入新 relationship 的业务代码。
  3. 最后启用依赖新 permission 的检查逻辑。

20. 可观测性与审计

每次权限检查建议记录:

字段说明
request_id请求 ID
trace_id链路追踪 ID
decision_id权限决策 ID
principal_typeuserserviceaccount
principal_id稳定 UUID
resource_type资源类型
resource_id资源 ID
permission检查的业务动作
allowed是否允许
reason拒绝原因或推导摘要
zed_token一致性 token

拒绝日志示例:

{
"level": "warn",
"message": "permission denied",
"request_id": "req_01J...",
"decision_id": "dec_01J...",
"principal_type": "user",
"principal_id": "user_001",
"resource_type": "skill",
"resource_id": "skill_001",
"permission": "edit",
"allowed": false
}

21. 常见踩坑

21.1 把 Casdoor role 当资源权限

不推荐:

role_aihub_admin = 可以管理所有 Skill

推荐:

organization:o1#admin@user:u1
project:p1#owner@user:u1
skill:s1#editor@group:g1#member

Casdoor role 可以保留做少量平台级能力,例如是否允许进入控制台、是否为平台超级管理员。业务资源权限交给 SpiceDB。

21.2 业务代码检查 relation

不推荐:

Check skill:s1#owner@user:u1

推荐:

Check skill:s1#delete@user:u1

这样以后 delete 可以从 owner 扩展为 owner + project->manage,业务代码不需要改。

21.3 双写不一致

问题:

PG 创建 skill 成功
SpiceDB 写 owner 失败
创建者看不到自己创建的 skill

解决:

PG transaction + outbox
DTM / Saga
重试队列
补偿任务
定期一致性扫描

21.4 权限继承过大

例如:

permission view = project->view

表示能看项目的人默认能看项目下所有 Skill。这个策略必须经过业务确认。

21.5 忘记清理 relationship

删除资源必须清理关系,否则会出现幽灵权限和脏 Lookup 结果。

22. 一页速查

问题建模方式
保护什么?resource_type:resource_id
谁访问?subject_type:subject_id
写入什么事实?resource#relation@subject
检查什么动作?resource#permission@subject
用户 ID 用什么?Casdoor 稳定 UUID
资源详情放哪?业务库 / Git / S3 / PG
权限关系放哪?SpiceDB
谁写 SpiceDB?IAM 控制面和受控业务 outbox
谁执行检查?Kernel Guard / Gateway / 服务中间件
列表怎么查?LookupResources 或业务分页 + CheckBulk

最终原则:

Casdoor 管身份
IAM 管关系
SpiceDB 算权限
Kernel / Gateway 执行权限
业务代码检查 permission
关系变更必须审计和补偿

参考资料