P4 Gotham
ABAC 访问控制:谁能读机密,系统说了算
权限不是"是管理员就能全看",而是按属性精细判定:RBAC 先做基础门,ABAC 再按主体 / 资源 / 动作 / 环境的属性收窄,deny 一票否决;全部高危写端点都挂了 PEP 写门,读列表 / 详情按密级行级过滤。看完这 4 个故事,你就能用评估测试台把"角色 × 资源密级 × 动作"组合出正确决策、给高危操作配拦截策略,并读懂评估 trace 里的审计留痕。
平台管理员
情报分析师
deny 一票否决
评估测试台
PEP 写门
审计 trace
共 4 个故事
能 / 不能速览
✅ 这个主题能做
- 策略 CRUD:effect(allow / deny)+ 四类属性条件(subject / resource / action / environment)+ priority + 启停
- 两层评估:RBAC 基础门先判,拒绝即短路;ABAC 按 priority 降序收窄
- deny 一票否决:任一 deny 命中即拒绝,无论其后有多少 allow
- 评估测试台:POST /access-policies/evaluate 改 roles / resource_attrs / action 看决策变化
- PEP 写门:图/入库/解析/地图/时间轴/模式/报告/视图/协同等全部受保护写端点逐条挂 PEP,deny 策略可拦截,403 ABAC_DENIED
- 评估 trace 落审计:每次评估记录命中策略 id / 快照 / 上下文,可回溯"谁被谁拒了"
⛔ 这个主题做不了
- 读列表 / 详情已按密级做行级过滤(deny 命中滤行 / 单条 404 / fail-open),数据层的 RLS 与列级 CLS 过滤串联未实现(属演进方向)
- ABAC ontology_action 资源类型未实现:R2 等价落地为"强制审计 + eventbus 桥接 + PEP 写门",未按 Foundry Action 逐动作授权
- 环境属性(时间范围 / IP 前缀)匹配引擎存在,但演示 seed 未内置这类策略
- RBAC 基础门内置规则有限:非 admin 的 delete / export / write 高危动作默认拒绝,需策略显式放行
- 无 ReBAC(关系型访问控制)与策略版本对比,属 V2
- 策略条件用属性匹配(等值 / 通配 / 数组),不支持任意布尔表达式语言
适用角色
本主题面向两个角色:
- 平台管理员(核心):维护访问策略、用评估测试台验证"角色 × 资源 × 动作"组合、查评估 trace 做审计,是策略全流程的操作者。
- 情报分析师:是被判定的一方——理解为什么自己读不了机密、哪些动作被基础门拒绝,配合管理员收敛权限。
决策者通过审计报表了解访问管控情况,不直接操作策略。
能力速览(能做什么)
策略管理
access_policies 策略表:effect(allow / deny)+ subject / resource / action / environment 四类属性条件 + priority + enabled。
两层评估
RBAC 基础门(admin 全过,非 admin 高危动作拒)→ ABAC 收窄(priority 降序评估全部启用策略),deny 一票否决。
评估测试台
POST /access-policies/evaluate:传 user_id / roles / user_attrs / resource_attrs / action,秒出 decision 与 reason。
PEP 写门
全部受保护写端点(graph / ingestion / resolution / map / timeline / patterns / reports / views / collab 等十余资源)逐条挂 PEP 走纯 ABAC 判定:deny 一票否决拦截(403 ABAC_DENIED)、默认放行。
评估留痕
每次评估落 access_decision_traces:命中策略 id + 快照 + 上下文(主体 / 资源 / 动作 / reason),满足审计要求。
属性匹配引擎
等值 / * 通配 / 数组包含 / 时间范围(HH:MM)/ IP 前缀("10.")五种匹配,四类条件全部满足才算策略命中。
调整指南(怎么调整)
- 改收窄规则:给"角色 + 资源密级"配 deny / allow 策略,priority 越大越先评估;同一主体命中多个策略时 deny 一票否决。
- 改高危动作:非 admin 的 delete / export / write 会被 RBAC 基础门默认拒绝,想放行必须显式建 allow 策略。
- 改属性匹配:环境属性支持时间范围(["08:00","20:00"])与 IP 前缀("10."),命中规则见 matchAttr 五种匹配。
- 改策略启停:策略禁用后不参与评估,适合临时放行 / 收窄的灰度验证;改完先上评估测试台测一遍再生效。
- 拦高危写操作:PEP 写门按"主体 role + 资源 type + execute 动作"三元组判定,配 deny 策略即可拦截图删除 / 合并、解析审核、报告建发删等全部受保护写端点;PEP 无命中默认放行,不会因策略缺失瘫痪业务。
- 改审计视角:traces 支持按 user_id 过滤、limit 默认 100 最大 500;把管理员关键操作的评估 trace 拉出来就是一份访问审计台账。
做得好的场景
ABAC 把"谁能看什么"变成可量化、可验证的策略,特别适合以下场景:
- 机密隔离:玄武集团节点密级是 secret,分析师角色被 deny 策略一票否决,读不了机密情报,权限不靠自觉。
- 分级放行:分析师可读内部数据(classification=internal)有独立 allow 策略,日常分析不受影响,只有机密以上被拦。
- 高危动作管控:非 admin 的导出 / 删除 / 写操作被基础门默认拒绝,重要数据不会"手滑外泄";高危写点另有 PEP 写门按 (role, resource type, action) 精确拦截。
- 审计可回溯:每次评估(含 PEP 写门判定)都落 trace,谁被拒、被哪条策略拒、决策理由是什么,全量留痕可查。
限制与不足
以下是明确的边界,使用前先知道:
- 请求级判定:ABAC 判定发生在请求入口;读列表 / 详情已按密级做行级过滤(deny 命中滤行 / 单条 404),数据层的 RLS 与列级 CLS 过滤串联尚未打通(先 ABAC 后 RLS 的理想链路属演进方向)。
- ontology_action 资源类型未实现:R2 等价落地为"强制审计 + eventbus 桥接 + PEP 写门",未按 Foundry Action 语义逐动作授权。
- 基础门内置规则有限:只对 admin 角色与 delete / export / write 前缀做了内置判定,复杂角色体系需自行扩展 RBACGate。
- 无 ReBAC:关系型访问控制(按组织树 / 项目归属推断权限)不在 MVP,策略条件用属性匹配表达。
- 条件语言受限:策略条件是"属性等值 / 通配 / 数组 / 时间 / IP",不支持任意布尔表达式(AND / OR / NOT 组合语言)。
- 环境策略未预置:时间 / IP 匹配引擎已实现但演示 seed 未内置,需管理员自建策略体验。
场景故事
故事 1
周警官以分析师身份读机密情报,被 deny 一票否决
场景:deny 一票否决
角色:情报分析师
耗时:约 3 分钟
- 背景
- 周警官是玄武集团情报组的分析师。2026 年 8 月他在图工作台上看到玄武集团节点(graph:org:xuanwu)的密级是 secret,想直接打开详情,却被系统拦下。他想搞清楚:为什么明明有权限查图,读这条"机密"却不行。
- 传统做法对比
- 以前权限靠"管理员口头告知 + 纸质审批",分析师能不能看机密全凭别人记不记得提醒,出了事互相扯皮。现在访问判定由策略自动执行,读机密直接被 deny,且评估全程留痕,谁拒的、为什么拒一查便知。
- 角色
- 情报分析师(周警官)作为被判定主体;平台管理员预置的"分析师禁读机密"策略生效。
- 操作步骤
-
- 周警官尝试打开密级为 secret 的玄武集团节点详情
- 系统在访问入口执行两层评估:RBAC 基础门通过(read 非高危动作)→ ABAC 收窄
- ABAC 按 priority 降序评估策略,命中"分析师禁读机密"(deny)
- deny 一票否决生效,请求被拒,评估结果落 trace
- 系统响应
- 在评估测试台模拟同条件也得到相同结论:
{
"decision": "deny",
"reason": "deny策略",
"matched_policy_ids": [1]
}
reason=deny策略 说明命中了一条 deny 且一票否决;matched_policy_ids=[1] 指向"分析师禁读机密"(priority=100,role=analyst 且 classification=secret 且 action=read)。
- 结果洞察
- 周警官确认这不是权限配置遗漏,而是策略主动拦截:玄武集团节点的 secret 密级 + 他的 analyst 角色 + read 动作三者同时满足 deny 条件。机密情报只有管理员与授权分析师可访问,系统替他守住这条红线。
- 调整建议
- 确实需要看机密就向管理员申请更高权限角色(如 admin);管理员可在评估测试台先验证"改角色为 admin 是否放行"再决定授权;注意"分析师可读内部数据"只覆盖 internal,不会覆盖 secret。
- 动手试一试
- 登录:admin / admin1。页面路径:ABAC 访问控制 → 评估测试台。输入内容:roles=["analyst"]、resource_attrs={"classification":"secret"}、action=read。预期结果:decision=deny、reason=deny策略、matched_policy_ids 指向"分析师禁读机密"。
- 限制提示
- deny 一票否决意味着"只要有 deny 命中,无论后面多少 allow 都拒绝";ABAC 判定是请求级的:读列表 / 详情已按密级行级过滤,数据层的 RLS / CLS 列级过滤串联属 V2;本演示中玄武集团节点是唯一 secret 密级资源。
故事 2
评估测试台:改角色、改资源、改动作,看决策怎么变
场景:评估测试台
角色:平台管理员
耗时:约 6 分钟
- 背景
- 平台管理员(老王)要为一套权限调整做验证:把周警官临时提为 admin 看是否放行机密;让分析师读 internal 资源看是否正常;再试一次"分析师导出机密"看高危动作怎么被拦。三组实验在评估测试台一次做完,避免改完策略才发现配错。
- 传统做法对比
- 以前改权限要先改数据库、再让用户登录真机点一遍,一次验证 30 分钟起步,误配还可能直接放行机密;现在评估测试台不落数据、不改权限,POST 一次几秒出决策。
- 角色
- 平台管理员(老王),在评估测试台构造多组"角色 × 资源 × 动作"组合验证。
- 操作步骤
-
- 打开评估测试台,第一组:roles=["admin"]、resource_attrs={"classification":"secret"}、action=read
- 第二组:roles=["analyst"]、resource_attrs={"classification":"internal"}、action=read
- 第三组:roles=["analyst"]、resource_attrs={"classification":"secret"}、action=export
- 逐组提交 POST /access-policies/evaluate,对比 decision 与 reason
- 系统响应
- 三组评估结果对比:
# 组1(admin 读 secret)
{ "decision": "allow", "reason": "allow策略", "matched_policy_ids": [3] }
# 组2(analyst 读 internal)
{ "decision": "allow", "reason": "allow策略", "matched_policy_ids": [2] }
# 组3(analyst 导出 secret)
{ "decision": "deny", "reason": "基础门拒绝", "matched_policy_ids": null }
组3 的 reason=基础门拒绝——导出属高危动作,非 admin 在 RBAC 基础门就被拦截,根本没走到 ABAC。
- 结果洞察
- 三组实验拼出完整权限画像:admin 读机密靠"管理员全量放行"(priority=10, action=*);分析师读内部靠"分析师可读内部数据"(priority=80);分析师导出机密被基础门短路拒绝。老王确认当前策略组合符合预期,不用动配置。
- 调整建议
- 想给分析师开放"导出 internal"这类场景,可显式建 allow 策略(基础门默认拒绝高危动作,需策略放行);想限制 admin 的敏感动作,可在 ABAC 层加 deny 覆盖;每次改策略后都先跑一轮测试台再生效。
- 动手试一试
- 登录:admin / admin1。页面路径:ABAC 访问控制 → 评估测试台。输入内容:按上面三组 roles / resource_attrs / action 依次提交。预期结果:组1 allow(管理员全量放行)、组2 allow(分析师可读内部)、组3 deny(基础门拒绝)。
- 限制提示
- 评估测试台是模拟判定,不校验 user_id 是否真实存在;RBAC 基础门只对 admin 角色与 delete / export / write 前缀有内置规则;复杂角色体系(如部门维度)需自定义 RBACGate。
故事 3
看评估 traces,理解"管理员为什么全量放行"
场景:审计留痕
角色:平台管理员
耗时:约 5 分钟
- 背景
- 月度审计时,老王要回答两个问题:周警官上周到底被哪些策略拒过?管理员访问机密为什么总是 allow?答案都藏在评估 trace(access_decision_traces)里——每次评估自动留痕,按 user_id 过滤即可回放。
- 传统做法对比
- 以前权限审计靠翻应用日志、问开发,日志格式五花八门,经常查不到"某次访问为什么被拒"。现在评估 trace 结构化落库,策略 id、快照、上下文、决策理由一次查全,审计半天变 10 分钟。
- 角色
- 平台管理员(老王),查询评估 trace 做审计回放。
- 操作步骤
-
- 进入"评估 trace"列表,按 user_id 过滤查看周警官的评估记录
- 查看每条 trace 的 decision / reason / matched_policy_ids / context
- 再过滤 admin 用户,观察 admin 读 secret 的评估记录
- 对比两条链路,确认双层收窄逻辑符合预期
- 系统响应
- GET /access-policies/traces?user_id=zhou 返回评估留痕:
[
{ "id": 101, "user_id": "zhou", "decision": "deny", "policy_ids": [1],
"context": { "roles": ["analyst"], "resource_attrs": { "classification": "secret" },
"action": "read", "reason": "deny策略" }, "decision_time": "2026-08-15T09:31:00Z" }
]
admin 的评估 trace decision=allow、reason=allow策略、policy_ids=[3](管理员全量放行)。
- 结果洞察
- 双层收窄逻辑清晰可见:admin 在 RBAC 基础门直接放行(adminRole 对全部动作过),ABAC 层再命中"管理员全量放行"(priority=10, action=*)所以 allow;分析师则因 deny 策略被收窄。管理员全量放行不是特权漏洞,而是策略明确声明,且每次放行都有 trace 可回溯。
- 调整建议
- 审计时按 user_id + decision 双条件过滤最快;trace 里的 context 含完整主体 / 资源 / 动作 / reason,可直接作为合规证据导出;如果发现某用户被意外拒绝,比对 trace 里命中的策略 id 即可定位原因。
- 动手试一试
- 登录:admin / admin1。页面路径:ABAC 访问控制 → 评估 trace。输入内容:GET /access-policies/traces?user_id=zhou。预期结果:返回该用户的评估留痕,含 decision / reason / matched_policies / context;再过滤 admin 可见 allow 记录。
- 限制提示
- traces 记录经 Evaluate / EvaluatePolicies 入口的评估:评估测试台、PEP 写门、以及读路径的受控分类过滤(classificationAllowed 判定)都会落 trace,完全不经 ABAC 判定的公开路径不产生 trace;limit 默认 100 最大 500;trace 是一次评估的快照,策略后续改动不会改写历史记录。
故事 4
PEP 写门:给"删除机密图节点"配一条 deny 策略,高危操作当场被拦
场景:PEP 写门
角色:平台管理员
耗时:约 6 分钟
- 背景
- 玄武集团节点(graph:org:xuanwu)是唯一密级 secret 的机密资源。老王作为平台管理员,担心分析师手滑把它从图上删掉。他要给图节点删除这个高危写点配一条 deny 策略,验证 PEP 写门真的能拦住。
- 传统做法对比
- 以前删错节点只能靠"删了再补 + 群公告提醒",图数据没有回收站,误删就丢。现在高危写操作(图 / 入库 / 解析 / 地图 / 时间轴 / 模式 / 报告 / 视图 / 协同等全部写端点)都挂了 PEP 写门,配一条 deny 策略就从源头堵住。
- 角色
- 平台管理员(老王)建策略;情报分析师(周警官)触发删除,被 PEP 拦截。
- 操作步骤
-
- 老王在 /gotham/access 创建 deny 策略:subject role=analyst、resource type=graph.node、action=execute:delete
- 周警官以分析师身份调 DELETE /graph/nodes/graph:org:xuanwu
- PEP 在 handler 校验参数后、调用 service 前执行 EvaluatePolicies
- 策略命中 deny → 请求 403 拦截,评估照常落 trace
- 系统响应
- 删除请求被拦:
{ "code": "ABAC_DENIED", "error": "ABAC 策略禁止该操作" }
评估 trace 落库:{ "user_id": "zhou", "decision": "deny", "reason": "deny策略",
"context": { "roles": ["analyst"], "user_attrs": { "role": "analyst" },
"resource_attrs": { "type": "graph.node" },
"action": "execute:delete" } }
管理员删同一节点则放行(命中"管理员全量放行"allow 策略,无 deny 命中),删除成功。
- 结果洞察
- PEP 写门是纯 ABAC 判定(跳过 RBAC 基础门):只有 deny 命中才拦截,allow / 无命中一律放行——所以普通分析师在没有 deny 策略时的行为不受影响,而配了策略后"删除机密节点"这条高危动作被精确拦住。拦截全程留痕,审计可说清是谁、何时、被哪条策略拒。
- 调整建议
- 拦截点覆盖全部受保护写端点:图节点 / 边(graph.node / graph.edge / graph.node.merge)、入库源(ingestion.source / graph_mapping)、解析作业与审核(resolution.job / resolution.review)、地图要素与图层(geo.feature / geo.layer)、时间轴事件、模式规则与命中(pattern.rule / pattern.hit)、报告(report)、视图(view.*)、协同项目(collab.project)等;想限哪个资源就配 resource_attrs type=<资源类型>;先禁用策略灰度验证再启用。
- 动手试一试
- 登录:admin / admin1。页面路径:/gotham/access。输入内容:创建 deny 策略 role=analyst + type=graph.node + execute:delete;再以普通分析师用户调 DELETE /graph/nodes/<id>。预期结果:分析师删除被 403 ABAC_DENIED 拦截,管理员删除正常;traces 里出现该 deny 评估记录。
- 限制提示
- PEP 默认放行(fail-open):无 deny 策略时写操作不受影响,PEP 内部评估错误也仅记日志放行;读列表 / 详情已按密级行级过滤,但数据层 RLS 与列级 CLS 过滤未实现,删除动作被拦不等于数据级过滤;ontology_action 资源类型未落地,当前按 execute:verb + resource type 判定。
常见问题
RBAC 和 ABAC 是什么关系?
这里用的是"RBAC 基础门 + ABAC 收窄"两层模型:先由 RBAC 基础门按角色判定,admin 全放、非 admin 高危动作(delete / export / write)拒绝;基础门通过后再由 ABAC 按属性收窄。基础门拒绝会短路,ABAC 只收窄已允许的访问。
deny 一票否决是什么意思?
ABAC 按 priority 降序评估全部启用策略,只要命中任意一条 deny,决策就是 deny——即使后面还有 allow 命中。它是"默认拒绝、白名单放行"安全模型的核心,防止高优先级 allow 把机密放出去。
评估 trace 会记录敏感信息吗?
trace 记录评估上下文(主体属性、资源属性、动作、reason)与命中策略 id / 快照,用于审计回放。这些是判定必须的上下文,属于审计合规要求的"评估留痕",由平台管理员查阅。
为什么演示里只有玄武集团节点是 secret?
演示 seed 把玄武集团节点(graph:org:xuanwu)的 classification 设为 secret,其余人员 / 组织 / 船舶节点都是 internal。这样正好可以演示"分析师读 secret 被拒、读 internal 放行"的分级效果。
PEP 写门和评估测试台是什么关系?
两者共用同一套 ABAC 引擎(EvaluatePolicies / evaluateABAC),入口不同:评估测试台是手动模拟判定(POST /access-policies/evaluate),PEP 写门是全部受保护业务写端点(图 / 入库 / 解析 / 地图 / 时间轴 / 模式 / 报告 / 视图 / 协同等)在 handler 里的自动判定。PEP 跳过 RBAC 基础门、仅按 deny 一票否决拦截,默认放行。
策略支持哪些属性条件?
四类:主体(subject_attrs,如 role)、资源(resource_attrs,如 classification 或 PEP 的 type=graph.node)、动作(action,如 read / * / execute:name)、环境(environment_attrs,如时间范围 / IP 前缀)。四类条件全部满足才算策略命中;匹配规则为等值 / * 通配 / 数组包含 / HH:MM 时间范围 / IP 前缀。
主题小结
一句话:ABAC 的玩法是"配策略 → 评估测试台验证 → 看 trace 审计",高危写操作另有 PEP 写门(全部受保护写端点挂载)自动拦截。核心是四件事:RBAC 基础门先判、ABAC 按属性收窄、deny 一票否决、PEP 写门守高危动作;评估全程落 trace。记住几个边界:判定是请求级的(读列表 / 详情按密级行级过滤已落地,数据层 RLS / CLS 列级过滤未实现)、ontology_action 资源类型未落地(PEP 按 execute:verb + resource type 判定)、基础门只内置 admin 与高危动作规则。会配策略、会测组合、会守写门、会读 trace,你就能把"谁能看什么、谁能删什么"管得清清楚楚。