Files
pikasTech-HWLAB/docs/reference/spec-v02-openfga-authorization.md
T
2026-06-05 16:21:04 +08:00

20 KiB
Raw Blame History

v0.2 OpenFGA 授权与 Admin Access 管理规格

本文是 HWLAB v0.2 细粒度资源授权、OpenFGA 接入、管理员 Access WebUI 和同路径 CLI 的长期规格。Keycloak 只回答“用户是谁”;OpenFGA 回答“该用户能不能对该对象做该动作”;hwlab-cloud-api 仍是唯一应用层 enforcement point 和授权写入口。

本规格补充 spec-v02-auth.mdspec-user-access.md:前者定义 Keycloak/Web session/API key 到 AuthPrincipal 的认证归一;后者定义用户、session owner、HWPOD 和工具能力的业务权限口径;本文定义 OpenFGA 如何在 hwlab-v02 namespace 内以 Kubernetes 原生方式落地,并如何被 Cloud Web 与 hwlab-cli client 管理和验证。

实施跟踪 issue 必须记录 spec、GitOps、cloud-api、Cloud Web、CLI、测试、PR/CI/CD 和原入口验收进展。过程记录写 issue 评论,本文只保留稳定目标和验收口径。

在系统中的职责划分

组件 职责
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 根据用户权限注入的短期工具环境;工具凭据必须按 tool capability 独立授权。

OpenFGA 是 HWLAB 应用层授权基础设施,不是 Kubernetes RBAC、ServiceAccount、NetworkPolicy 或 Keycloak realm role 的替代。普通用户不获得 kubeconfig、内部 Service 直连、OpenFGA token 或 Keycloak admin 权限。

当前实现状态

  • 当前 v0.2 desired state 和 runtime 都包含 hwlab-openfga ClusterIP 服务、Postgres backend、migration/bootstrap 过程和 hwlab-v02-openfga SecretRef。hwlab-cloud-api/health/live 和 Admin Access summary 中只公开 mode、readiness、store/model 摘要和 degraded reason。
  • enforce 是当前正式授权口径。Admin Access 写入 OpenFGA 失败时必须 fail closed;本地 role/status、effective matrix 或 access 摘要只能作为 domain state 和可见性材料,不能在 OpenFGA 不可用时单独放行。
  • 当前授权写入口只有 cloud-api Admin Access APICloud Web Access 和 hwlab-cli client access ... 都调用同一路 API。浏览器、CLI、AgentRun runner 和普通用户都不直连 OpenFGA,也不持有 OpenFGA token。
  • tool:trans_cmd#can_use 的当前含义是允许在 agent/tool registry 中暴露受控 UniDesk passthrough 命令能力;它不改变 UniDesk route/operation 边界,不授予 Kubernetes Secret 读取、裸控制面写入、残留执行链路内部 token 或主 server SSH key。
  • hwpod/profile 修改当前仍由迁移期 POST/PUT /v1/admin/device-pods path 和 profile_editor/admin 权限控制;OpenFGA 管 relationcloud-api 管 profile authority,执行节点只执行内部受控 job。该 API path 名称是实现残留,不是当前概念命名。

Kubernetes 和 GitOps 落点

OpenFGA 固定部署在 hwlab-v02 namespace,作为稳定外部服务进入 v0.2 GitOps desired state

  • deploy/gitops/g14/runtime-v02/openfga.yaml 声明 DeploymentService、migration Job 或 init/migrate step、SecretRef 和 health/readiness。
  • deploy/gitops/g14/runtime-v02/kustomization.yaml 必须引用 openfga.yamlrender 脚本如果有 service inventory 或 artifact catalog,也必须加入 OpenFGA 的外部服务记录。
  • OpenFGA Service 只允许 ClusterIP,默认 DNS 为 hwlab-openfga.hwlab-v02.svc.cluster.local;不得配置 FRP、公网 Ingress 或 Cloud Web 直连。
  • 数据存储使用 Postgres backend;禁止 production/stable runtime 使用 memory backend。可复用 hwlab-v02-postgres 实例,但必须使用独立 database/schema/role 和独立 SecretRef,避免和 cloud-api migration ledger 混写。
  • 首次部署和版本升级必须执行 OpenFGA migratemigration 失败时 cloud-api OpenFGA readiness 必须 degraded,不能进入 enforce。
  • OpenFGA 鉴权使用 preshared key 或等价内部服务 token SecretRefSecret 值不得出现在 ConfigMap、日志、issue、trace 或 CLI 默认输出。
  • Readiness 使用 OpenFGA health endpointcloud-api /health/live 汇总 OpenFGA endpoint、store/model status、mode 和 degraded reason,但不输出 token。

OpenFGA 官方 Helm chart 可以作为 YAML 来源,但 hwlab-v02 desired state 仍以 repo 内 GitOps render 后的 YAML 为准。任何 OpenFGA 镜像、SecretRef、Postgres URL 或 migration 变更都属于运行面/权限高风险变更,必须走 PR、CI/CD 和原入口验收。

授权模型

对象命名必须稳定、可从业务 ID 直接推导,并在日志/trace 中可脱敏展示:

对象 例子 说明
用户 user:usr_123 HWLAB users.id,不是 Keycloak sub
系统 system:hwlab 平台级 admin、access 管理和全局工具授权。
HWPOD device_pod:device-pod-71-freq 服务端 HWPOD/profile authority 对象;device_pod 是迁移期 OpenFGA object type 名称,不是当前产品概念。
Code Agent session agent_session:ags_123 会话 owner/collaborator/viewer 判定。
工具 tool:hwpodtool:unidesk_sshtool:github_prtool:trans_cmd AgentRun runner 可注入或可调用的功能能力。

目标关系模型:

model
  schema 1.1

type user

type system
  relations
    define admin: [user]
    define access_manager: admin
    define can_manage_users: admin
    define can_manage_device_pods: admin
    define can_manage_tools: admin

type device_pod
  relations
    define owner: [user]
    define viewer: [user] or owner or admin from system
    define operator: [user] or owner or admin from system
    define profile_editor: [user] or owner or admin from system
    define job_submitter: [user] or operator
    define admin: admin from system

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:hwlabadmin system:hwlab
查看 HWPOD viewer device_pod:<id>
提交 HWPOD job / 使用 hwpod operatorjob_submitter device_pod:<id>,并要求 can_use tool:hwpod
修改 HWPOD profile profile_editor device_pod:<id>admin system:hwlab
查看自己的 Code Agent session viewer agent_session:<id>
继续/取消 Code Agent session operator agent_session:<id>
注入 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。所有用户态请求按以下顺序处理:

authenticate -> AuthPrincipal -> load domain object -> openfga check -> reason check for mutating device jobs -> execute

配置项:

配置 说明
HWLAB_OPENFGA_MODE=enforce v0.2 正式运行面固定以 OpenFGA 为准;OpenFGA 不可达或写入失败时 fail closed 并返回结构化 blocker。
HWLAB_OPENFGA_API_URL 集群内 OpenFGA Service URL。
HWLAB_OPENFGA_AUTHN_TOKEN 或 SecretRef cloud-api 调 OpenFGA 的内部 token。
HWLAB_OPENFGA_STORE_ID / MODEL_ID 可由 env 注入,也可由 cloud-api bootstrap 后写入 Postgres runtime config。
HWLAB_OPENFGA_TIMEOUT_MS 单次 check/write 超时;超时必须结构化返回。

模式语义:

  • enforce 是唯一正式运行模式:HWPOD、agent session 和工具能力以 OpenFGA check 为准。OpenFGA 不可达、store/model 未就绪或 check 超时时,高风险写操作 fail closed;低风险只读可以返回 degraded blocker,不得静默放行。
  • off / shadow 不作为 v0.2 runtime 目标路径;文档、测试或 render 如再次把它们作为业务 allow source,应优先删除而不是兼容。

tuple 写入必须由 cloud-api admin API 统一完成,并和 Postgres domain state 保持事务级或可恢复一致:

  • 用户创建、禁用、角色提升/降级时同步写 userssystem:hwlab tuples。
  • HWPOD/profile 创建/更新/删除时同步迁移期 device_pods 表和相关 tuples;删除对象时清理 tuple 或标记不可用。
  • 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/HWPOD 数量和最近 mismatch 摘要。
GET /v1/admin/access/users 列出用户、role/status、Keycloak 绑定摘要、API key 数量和 effective capability 摘要。
GET /v1/admin/access/users/{userId} 返回单个用户的 HWPOD、agent session 和 tool 权限矩阵。
PATCH /v1/admin/access/users/{userId} 更新用户 role/status,并同步 OpenFGA admin tuple。
PUT /v1/admin/access/users/{userId}/device-pods/{devicePodId}/{relation} 授予 viewer/operator/profile_editor/job_submitter 等 relation。
DELETE /v1/admin/access/users/{userId}/device-pods/{devicePodId}/{relation} 撤销指定 HWPOD relationURL path 仍是迁移期实现名。
PUT /v1/admin/access/users/{userId}/tools/{toolId}/can-use 授予工具能力,例如 hwpodunidesk_sshgithub_prtrans_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 字段:modealloweddecisionSourcestoreIdmodelIdrelationobject 和 redacted actor。

Cloud Web 必须把 Admin Access 读写 API 作为同源代理路径转发给 cloud-api,包括 POST /v1/admin/access/checkPATCH /v1/admin/access/users/{userId}、HWPOD relation 的 PUT/DELETE 和 tool capability 的 PUT/DELETE。Cloud Web 不保存授权副本,也不直接访问 OpenFGA。

Admin Access WebUI

Cloud Web 新增 ActivityRail 顶层入口 Access,只对具备 access manager/admin 权限的用户显示。它不是 Keycloak 管理后台,也不放在 Settings 子页里。

页面布局:

  • 左栏:用户列表、搜索、role/status 筛选、Keycloak 绑定摘要。
  • 中栏:选中用户的权限矩阵,按 HWPODAgent SessionsToolsPlatform 分组;权限用 checkbox/toggle 表达,危险工具用显式确认。
  • 右栏:effective permission 预览、最近变更、OpenFGA mode/readiness、写入 blocker 和保存结果。

交互规则:

  • 初始加载先调用 GET /v1/admin/access/summary 和用户列表;OpenFGA degraded 时页面必须显示 blocker。
  • 修改权限时先在本地形成 pending diff;保存后逐项调用对应 PATCH/PUT/DELETE API,并刷新 effective matrix。
  • 页面不暴露 OpenFGA tuple 原文作为主要操作面;需要排障时只在详情中显示 redacted object/relation。
  • 普通用户或未登录用户访问 Access route 时显示授权 blocker 或跳登录,不渲染空管理表。

同路径 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`
`client access device-pods grant USER POD --relation viewer operator
client access device-pods revoke USER POD --relation ... DELETE /v1/admin/access/users/{userId}/device-pods/{devicePodId}/{relation};迁移期 path,业务对象是 HWPOD
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 等价验收路径。

权限变更的真实入口验收必须以 Cloud Web 同源 origin 为准。最小闭环是:client access summary 确认 openfga.mode=enforce 且 ready;对一个普通用户执行某个 HWPOD relation 的 check false -> grant -> check true -> revoke -> check false;对至少一个工具能力执行同样闭环,trans_cmd 必须覆盖;最后 users inspect 确认测试 tuple 已撤回。验收报告必须记录 baseUrl、method/path、actor、relation/object、HTTP status、OpenFGA decision 和最终 effective matrix 摘要。

AgentRun 工具能力边界

Cloud API 在创建 AgentRun command/runner 时必须按 OpenFGA 决策装配 transient env 和工具说明:

  • 用户没有 can_use tool:hwpod 时,不注入 HWLAB_API_KEYhwpod,也不在 prompt/tools 中声明 HWPOD 操作可用。
  • 用户没有目标 HWPOD 的 operator/job_submitter 时,即使拥有 tool:hwpod,具体 HWPOD job 也必须被 cloud-api 拒绝。
  • 用户没有 can_use tool:unidesk_ssh 时,不注入 UniDesk SSH client token、workspace route 或相关 alias。
  • tool:trans_cmd 只代表允许通过受控 UniDesk route 调用透传命令;它不绕过 UniDesk CLI 的 route/operation 安全边界,不允许 pod 内任意 Secret 读取或 Kubernetes 写操作。
  • GitHub issue/PR 写入能力必须单独由工具对象授权;拥有 Code Agent session 不等于拥有 GitHub 写权限。

授权残留处理

  • 授权残留指任何让用户或工具能力绕过当前 AuthPrincipal -> OpenFGA/Admin Access 判定的代码、文档、测试、render 或 runtime 路径,也包括共享用户绕过凭据、兼容写分支和只为已移除路径存在的断言。
  • 处理方式是删除或改写为当前合同,不迁移为 legacy mode、兼容表、feature flag、负向 gate 或长期分叉。快速测试应断言当前 Web session/API key/OpenFGA/Admin Access 的 allow/deny 行为,而不是保留被移除路径的名字。
  • 运行面排查可以临时扫描 source、GitOps 和 live schema 证明当前 authority 收敛;长期 SPEC 只保留当前 authority、当前入口和判定规则,不维护已移除对象清单。

测试规格

T1

阅读 docs/reference/spec-v02-openfga-authorization.md,然后检查 deploy/gitops/g14/runtime-v02 和渲染结果,确认 OpenFGA 以 ClusterIP-only 服务部署在 hwlab-v02,使用 Postgres backend、migration job/step 和 SecretRefkustomization.yaml 引用 OpenFGA 资源,且没有 FRP/Ingress 公网暴露。

T2

阅读 docs/reference/spec-v02-openfga-authorization.md,然后访问 GET /health/liveGET /v1/admin/access/summary,确认响应显示 openfga.mode、readiness、storeId/modelId 摘要和 degraded reason;响应不得包含 OpenFGA token、Postgres URL 或 Secret 值。

T3

阅读 docs/reference/spec-v02-openfga-authorization.md,然后用 admin 通过 CLI 或 WebUI 给普通用户授予某个 HWPOD 的 viewer 但不授予 operator,确认该用户可以看到 HWPOD 摘要,但提交 HWPOD job 返回 403;再授予 operator/job_submitter 后 job 可提交。

T4

阅读 docs/reference/spec-v02-openfga-authorization.md,然后撤销普通用户的 tool:hwpodtool:unidesk_ssh,创建新的 Code Agent session 并检查 trace/runner env 摘要,确认对应工具 alias/env 未注入;尝试调用时返回结构化 authorization blocker。

T5

阅读 docs/reference/spec-v02-openfga-authorization.md,然后在 enforce 运行面授予和撤销普通用户的 HWPOD relation,确认迁移期 /v1/device-pods、status、job 和 Access summary 都按 OpenFGA 结果执行;OpenFGA 写失败时 Admin Access API 必须返回结构化 5xx blocker,不能更新本地 access matrix。

T6

阅读 docs/reference/spec-v02-openfga-authorization.md,然后从浏览器打开 Access 页面,确认只有 admin/access manager 可见 ActivityRail 入口;普通用户访问 route 显示授权 blocker。保存一次权限变更后,CLI client access users inspect USER 必须看到同一 effective matrix。

T7

阅读 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 等价验收。

T8

阅读 docs/reference/spec-v02-openfga-authorization.md 和 docs/reference/spec-user-access.md,然后检查 source schema、v0.2-gitops rendered ConfigMap 和 live Postgres:确认当前授权状态能由 AuthPrincipal、users/session/API key、HWPOD profile、Admin Access API 和 OpenFGA tuple 完整表达。检查中发现其他授权 source 时,必须删除或改写到当前合同,不新增兼容分支或负向 gate。

规格的实现情况

规格项 状态 说明
OpenFGA 作为 v0.2 内部授权服务 已实现/持续约束 v0.2 runtime 以 enforce 模式运行,summary 暴露 redacted store/model 和 readinessOpenFGA 不向公网、浏览器或 CLI 暴露。
Cloud API OpenFGA client/bootstrap/check/write 已实现 Admin Access API 可 check/write tuple,响应包含 structured decision 和 redacted OpenFGA 状态。
细粒度 HWPOD / session / tool 授权 核心已实现/持续扩展 HWPOD relation 和 tool capability 统一写 OpenFGA tuple;后续 session/tool 扩展必须继续保持同一 authority。
Admin Access WebUI 部分实现/持续约束 Cloud Web Access 页面使用同一 Admin Access API;浏览器交互深测可作为专项验收,但不得新增第二条授权路径。
同路径 CLI 已实现 client access ... 走 Cloud Web 同源 path,已覆盖 summary、users、check、HWPOD relation grant/revoke 和 tool grant/revoke。
AgentRun 工具注入按用户权限过滤 部分实现/持续约束 hwpodunidesk_sshtrans_cmd、GitHub 写工具必须独立授权;runner 中的 HWLAB_API_KEY 必须映射到当前 Code Agent session owner。