159 lines
9.6 KiB
Markdown
159 lines
9.6 KiB
Markdown
# v0.2 OpenFGA 授权与 Admin Access 管理规格
|
||
|
||
本文是 HWLAB `v0.2` 细粒度资源授权、OpenFGA 接入、管理员 Access WebUI 和同路径 CLI 的长期规格。Keycloak 只回答“用户是谁”;OpenFGA 回答“该用户能不能对该对象做该动作”;`hwlab-cloud-api` 是唯一应用层 enforcement point 和授权写入口。
|
||
|
||
当前 HWPOD 快速闭环阶段只管理用户、Code Agent session 和工具能力,不为旧设备对象保留 OpenFGA type、relation、API 或 CLI。
|
||
|
||
## 在系统中的职责划分
|
||
|
||
| 组件 | 职责 |
|
||
| --- | --- |
|
||
| Keycloak | 身份认证、注册、OIDC issuer;不直接授予 HWLAB 功能权限。 |
|
||
| `hwlab-cloud-api` | `AuthPrincipal` 恢复、OpenFGA store/model bootstrap、授权 check、授权写 API、enforce 策略、AgentRun transient env 过滤和审计摘要。 |
|
||
| OpenFGA | `hwlab-v02` namespace 内部 PDP 和 relationship tuple store;只接受 cloud-api 调用,不向浏览器、CLI、AgentRun runner 或公网暴露。 |
|
||
| HWLAB v0.2 Postgres | 业务对象、用户、session、API key、access_tuples 摘要、OpenFGA store/model 指针和迁移 ledger 的 durable source。 |
|
||
| `hwlab-cloud-web` | Admin Access 页面和同源 API proxy;不直接调用 OpenFGA。 |
|
||
| `hwlab-cli client` | Web 等价非视觉授权管理入口;通过 `19666` Cloud Web 同源 path 调 cloud-api,不直连 OpenFGA。 |
|
||
| AgentRun v0.1 runner | 只消费 cloud-api 根据用户权限注入的短期工具环境;不持有跨用户共享 key、GitHub token 或 UniDesk SSH token。 |
|
||
|
||
## 授权模型
|
||
|
||
对象命名必须稳定、可从业务 ID 直接推导,并在日志/trace 中可脱敏展示:
|
||
|
||
| 对象 | 例子 | 说明 |
|
||
| --- | --- | --- |
|
||
| 用户 | `user:usr_123` | HWLAB `users.id`,不是 Keycloak `sub`。 |
|
||
| 系统 | `system:hwlab` | 平台级 admin、access 管理和全局工具授权。 |
|
||
| Code Agent session | `agent_session:ags_123` | 会话 owner/collaborator/viewer 判定。 |
|
||
| 工具 | `tool:hwpod`、`tool:unidesk_ssh`、`tool:github_pr`、`tool:trans_cmd` | AgentRun runner 可注入或可调用的功能能力。 |
|
||
|
||
目标关系模型:
|
||
|
||
```fga
|
||
model
|
||
schema 1.1
|
||
|
||
type user
|
||
|
||
type system
|
||
relations
|
||
define admin: [user]
|
||
define access_manager: admin
|
||
define can_manage_users: admin
|
||
define can_manage_tools: admin
|
||
|
||
type agent_session
|
||
relations
|
||
define owner: [user]
|
||
define viewer: [user] or owner or admin from system
|
||
define operator: [user] or owner or admin from system
|
||
define admin: admin from system
|
||
|
||
type tool
|
||
relations
|
||
define can_use: [user] or admin from system
|
||
define admin: admin from system
|
||
```
|
||
|
||
实现可以在第一版用等价模型名称和 relation 名称,但必须保持以下能力语义:
|
||
|
||
| 功能 | Check |
|
||
| --- | --- |
|
||
| 管理用户和权限 | `user:<id> access_manager system:hwlab` 或 `admin system:hwlab` |
|
||
| 查看自己的 Code Agent session | `viewer agent_session:<id>` |
|
||
| 继续/取消 Code Agent session | `operator agent_session:<id>` |
|
||
| 使用 HWPOD 工具 | `can_use tool:hwpod` |
|
||
| 注入 UniDesk SSH 透传能力 | `can_use tool:unidesk_ssh` |
|
||
| 允许 trans 透传 cmd | `can_use tool:trans_cmd`,且仍受 UniDesk route/operation 边界限制 |
|
||
| GitHub PR/issue 写操作工具 | `can_use tool:github_pr` 或更细工具对象 |
|
||
|
||
`admin/user` 仍保留为 UX 和 bootstrap 角色,但 runtime 授权必须逐步迁移到 OpenFGA check。`users.role='admin'` 必须镜像为 `system:hwlab#admin@user:<id>` tuple;降级 admin 时必须同步删除 tuple。Keycloak realm role、group、claim 不能直接变成 OpenFGA tuple,除非由 HWLAB admin API 明确写入。
|
||
|
||
## Cloud API 授权策略
|
||
|
||
`hwlab-cloud-api` 是唯一 policy enforcement point。所有用户态请求按以下顺序处理:
|
||
|
||
```text
|
||
authenticate -> AuthPrincipal -> load domain object -> openfga check -> execute
|
||
```
|
||
|
||
`enforce` 是唯一正式运行模式。OpenFGA 不可达、store/model 未就绪或 check 超时时,高风险写操作 fail closed;低风险只读可以返回 degraded blocker,不得静默放行。
|
||
|
||
tuple 写入必须由 cloud-api admin API 统一完成,并和 Postgres domain state 保持事务级或可恢复一致:
|
||
|
||
- 用户创建、禁用、角色提升/降级时同步写 `users` 和 `system:hwlab` tuples。
|
||
- Code Agent session 创建时写 `agent_session:<id>#owner@user:<owner>`;取消/归档不删除 owner tuple,便于 trace 回放。
|
||
- API key `scopes_json` 只能作为用户权限的收窄条件,不能授予超过 OpenFGA 的能力。
|
||
|
||
## Admin Access API
|
||
|
||
Cloud Web 和 CLI 只能通过 cloud-api 的 admin API 管理授权。第一版 API surface:
|
||
|
||
| 接口 | 说明 |
|
||
| --- | --- |
|
||
| `GET /v1/admin/access/summary` | 返回 mode、OpenFGA readiness、storeId/modelId、user/tool 数量和最近 mismatch 摘要。 |
|
||
| `GET /v1/admin/access/users` | 列出用户、role/status、Keycloak 绑定摘要、API key 数量和 effective capability 摘要。 |
|
||
| `GET /v1/admin/access/users/{userId}` | 返回单个用户的 agent session 和 tool 权限矩阵。 |
|
||
| `PATCH /v1/admin/access/users/{userId}` | 更新用户 `role/status`,并同步 OpenFGA admin tuple。 |
|
||
| `PUT /v1/admin/access/users/{userId}/tools/{toolId}/can-use` | 授予工具能力,例如 `hwpod`、`unidesk_ssh`、`github_pr`、`trans_cmd`。 |
|
||
| `DELETE /v1/admin/access/users/{userId}/tools/{toolId}/can-use` | 撤销工具能力。 |
|
||
| `POST /v1/admin/access/check` | 管理员调试单次 authorization check;响应必须标明 actor/object/relation/mode,但不得泄漏 token。 |
|
||
|
||
所有 write API 必须要求当前 actor 具备 `access_manager system:hwlab` 或 admin tuple;普通 `user` 不可调用。响应必须包含结构化 `authorization` 字段:`mode`、`allowed`、`decisionSource`、`storeId`、`modelId`、`relation`、`object` 和 redacted actor。
|
||
|
||
## Admin Access WebUI
|
||
|
||
Cloud Web 的 Access 页面只管理用户 role/status、Code Agent session 可见性和工具 capability。页面不暴露 OpenFGA tuple 原文作为主要操作面;需要排障时只在详情中显示 redacted object/relation。
|
||
|
||
## 同路径 CLI
|
||
|
||
`hwlab-cli client` 必须提供与 WebUI 同一 API surface 的非视觉入口,默认由 runtime namespace/lane 解析到 `19666` Cloud Web origin:
|
||
|
||
| CLI | Web/API 等价 |
|
||
| --- | --- |
|
||
| `client access summary` | `GET /v1/admin/access/summary` |
|
||
| `client access users list` | `GET /v1/admin/access/users` |
|
||
| `client access users inspect USER` | `GET /v1/admin/access/users/{userId}` |
|
||
| `client access users set-role USER --role admin|user` | `PATCH /v1/admin/access/users/{userId}` |
|
||
| `client access tools grant USER TOOL` | `PUT /v1/admin/access/users/{userId}/tools/{toolId}/can-use` |
|
||
| `client access tools revoke USER TOOL` | `DELETE /v1/admin/access/users/{userId}/tools/{toolId}/can-use` |
|
||
| `client access check --user USER --relation REL --object OBJECT` | `POST /v1/admin/access/check` |
|
||
|
||
CLI 输出必须是 JSON,包含 `runtimeEndpoint`、HTTP route、actor 摘要、mode、decision 和变更后的 effective matrix 摘要。它不能直接调用 OpenFGA API,不能手动传 OpenFGA token,不能把 `--base-url 19667` 作为 WebUI 等价验收路径。
|
||
|
||
## AgentRun 工具能力边界
|
||
|
||
Cloud API 在创建 AgentRun command/runner 时必须按 OpenFGA 决策装配 transient env 和工具说明:
|
||
|
||
- 用户没有 `can_use tool:hwpod` 时,不注入 `HWLAB_API_KEY` 给 `hwpod`,也不在 prompt/tools 中声明 HWPOD 操作可用。
|
||
- 用户没有 `can_use tool:unidesk_ssh` 时,不注入 UniDesk SSH client token、workspace route 或相关 alias。
|
||
- `tool:trans_cmd` 只代表允许通过受控 UniDesk route 调用透传命令;它不绕过 UniDesk CLI 的 route/operation 安全边界。
|
||
- GitHub issue/PR 写入能力必须单独由工具对象授权;拥有 Code Agent session 不等于拥有 GitHub 写权限。
|
||
|
||
## 测试规格
|
||
|
||
## T1
|
||
|
||
阅读 docs/reference/spec-v02-openfga-authorization.md,然后访问 `GET /health/live` 和 `GET /v1/admin/access/summary`,确认响应显示 `openfga.mode`、readiness、storeId/modelId 摘要和 degraded reason;响应不得包含 OpenFGA token、Postgres URL 或 Secret 值。
|
||
|
||
## T2
|
||
|
||
阅读 docs/reference/spec-v02-openfga-authorization.md,然后撤销普通用户的 `tool:hwpod` 或 `tool:unidesk_ssh`,创建新的 Code Agent session 并检查 trace/runner env 摘要,确认对应工具 alias/env 未注入;尝试调用时返回结构化 authorization blocker。
|
||
|
||
## T3
|
||
|
||
阅读 docs/reference/spec-v02-openfga-authorization.md,然后从浏览器打开 Access 页面,确认只有 admin/access manager 可见 ActivityRail 入口;普通用户访问 route 显示授权 blocker。
|
||
|
||
## T4
|
||
|
||
阅读 docs/reference/spec-v02-openfga-authorization.md,然后在 runtime endpoint locked 环境运行 `hwlab-cli client access summary/users/check/grant/revoke`,确认全部走 Cloud Web 同源 `19666` path,输出 JSON、route、actor、mode、decision 和 effective matrix;不手动传 OpenFGA URL/token,不直连 `19667` 作为最终 Web 等价验收。
|
||
|
||
## 规格的实现情况
|
||
|
||
| 规格项 | 状态 | 说明 |
|
||
| --- | --- | --- |
|
||
| OpenFGA 作为 v0.2 内部授权服务 | 已实现/持续约束 | v0.2 runtime 以 `enforce` 模式运行,summary 暴露 redacted store/model 和 readiness;OpenFGA 不向公网、浏览器或 CLI 暴露。 |
|
||
| Cloud API OpenFGA client/bootstrap/check/write | 已实现 | Admin Access API 可 check/write tuple,响应包含 structured decision 和 redacted OpenFGA 状态。 |
|
||
| session / tool 授权 | 核心已实现/持续扩展 | Code Agent session 和 tool capability 是当前授权来源。 |
|
||
| 同路径 CLI | 已实现 | `client access ...` 走 Cloud Web 同源 path,覆盖 summary、users、check 和 tool grant/revoke。 |
|