mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
149 lines
6.6 KiB
Markdown
149 lines
6.6 KiB
Markdown
# ADR-0208:强认证 Local Project Role Policy CLI 与防锁死交接
|
||
|
||
- 状态:Accepted
|
||
- 日期:2026-07-29
|
||
- 关联 RFC:QL-RFC-0001 D-05、D-27、D-37、D-65、D-72、D-73、D-175、
|
||
D-197、D-198
|
||
- 关联 ADR:ADR-0028、ADR-0074、ADR-0086、ADR-0185、ADR-0193、ADR-0207
|
||
|
||
## 背景
|
||
|
||
Fresh Setup 与首 Owner ceremony 已创建 `default` Project 和首个 Owner,
|
||
ADR-0207 也让 Secret 管理具备正式 CLI。但 Project RoleBinding 仍只有 repository
|
||
和 Policy Engine,没有强认证产品入口。部署者不能把 viewer/operator/admin 权限
|
||
交给另一个已登记主体,也不能以受支持方式交接 Owner。
|
||
|
||
直接把 `ProjectPolicyRepository.append()` 暴露给 CLI 不可接受:
|
||
|
||
- 它不验证 actor 的 `project.manage`;
|
||
- RoleBinding、allowed audit 和 credential/Policy fence 不在同一事务;
|
||
- admin 持有 `policy.manage`,若产品误用该 permission,可把自己提升为 owner;
|
||
- 只数 Owner binding 会允许把 Owner 交给没有 active credential 的 User,随后撤销
|
||
原 Owner,形成不可恢复的假交接。
|
||
|
||
## 决策
|
||
|
||
### 1. 复用现有四个 package,不新增 importer
|
||
|
||
- `@qinglong/runtime-core/local-project-policy-administration` 只定义原子 repository
|
||
contract 和低敏错误;
|
||
- `@qinglong/local-sqlite/project-policy-administration` 是一次命令、一个连接的短生命
|
||
周期 composition;
|
||
- `@qinglong/local-admin/project-policy-administration` 拥有认证后领域服务;
|
||
- `@qinglong/local-owner-cli/project-policy-command` 和 `ql3-policy` 提供私有 command
|
||
file 产品入口。
|
||
|
||
workspace 继续是 22 个 package。常驻 `local-application`、Profile、Worker 和
|
||
Cluster 均不能导入两个 mutation authority。依赖审计只允许 exact
|
||
`projectPolicyCommand.ts` 使用它们。
|
||
|
||
### 2. v1 只管理既有 Project 的 RoleBinding
|
||
|
||
开放两个 operation:
|
||
|
||
- `policy.role-binding.put`:创建或更新 active binding;
|
||
- `policy.role-binding.revoke`:追加 revoked binding。
|
||
|
||
两者都要求 target、expected current version、UUIDv4 mutation、request ID 和独立
|
||
failure-audit UUID。成功只返回 Project、target、version、state、可选 role 和
|
||
`inserted|existing`,不返回 credential、token、pepper、路径或内部 Policy 细节。
|
||
|
||
本切片不创建/归档 Project,不注册 Identity,不签发 credential,不提供远程 HTTP
|
||
入口,也不把常规 `ProjectPolicyRepository.append()` 变成产品 API。
|
||
|
||
### 3. 只有当前强认证 Owner 可以修改 RoleBinding
|
||
|
||
CLI 使用现有 private `0600` command file、Owner credential presentation、
|
||
pepper provenance 和 POSIX proof 建立 `local_console` Principal。服务固定请求
|
||
`project.manage`,不能改为 `policy.manage`:
|
||
|
||
- owner 允许;
|
||
- admin/operator/viewer 拒绝;
|
||
- admin 不能借管理 RoleBinding 把自己升级为 owner;
|
||
- deny/approval/unavailable 先写低敏 audit,再返回固定错误。
|
||
|
||
### 4. 最终写事务内复验三重 fence
|
||
|
||
SQLite 在 `BEGIN IMMEDIATE` 已取得写锁后按顺序复验:
|
||
|
||
1. authenticated credential version/state、User status、有效期、pepper state 与
|
||
material digest;
|
||
2. Project active/version;
|
||
3. actor 最新 RoleBinding version/state/owner role;
|
||
4. target RoleBinding expected version 与 mutation replay;
|
||
5. Owner 连续性。
|
||
|
||
随后 RoleBinding revision 与 allowed security audit 在同一事务插入。任何 fence、
|
||
版本、mutation、audit 或约束失败都回滚。相同 mutation 的语义重放返回
|
||
`existing`;时间戳不参与 response-loss 的语义相等判断。
|
||
|
||
### 5. Owner 交接必须同时防止“最后一个 Owner”和“不可登录 Owner”
|
||
|
||
- active owner 只能授予 `user` subject;
|
||
- owner grant 在同一事务确认目标 Identity active,并至少存在一条当前有效的 active
|
||
API credential、pepper binding 和 active/retired pepper catalog;
|
||
- 撤销或降级当前 active User owner 前,必须仍有另一条最新 active User owner
|
||
binding;
|
||
- 因此正确流程是先为目标 User 完成 Identity/credential ceremony,再 grant owner,
|
||
用目标 credential 验证登录,最后 revoke 原 owner。
|
||
|
||
这不证明目标 credential 的外部 presentation file 仍在;operator 仍必须在交接前
|
||
用目标身份完成一次真实认证。
|
||
|
||
## 低配路由器与集群影响
|
||
|
||
- 管理命令仅人工调用时加载,结束后关闭单 SQLite authority;
|
||
- 不新增 migration、表、daemon、timer、watcher、listener、socket 或第三方依赖;
|
||
- Edge/Standalone 常驻 artifact closure 不导入 local-admin policy service 或 Owner
|
||
CLI;
|
||
- Cluster 继续使用独立 PostgreSQL/RBAC/管理 host 设计,不能复用本地文件
|
||
credential CLI。
|
||
|
||
## 不采用方案
|
||
|
||
### 暴露常规 `ProjectPolicyRepository.append`
|
||
|
||
缺少 actor Policy、credential fence 和同事务 audit,且会扩大任意 caller 的写权限。
|
||
|
||
### 使用 `policy.manage`
|
||
|
||
admin 本来拥有该 permission;允许其签发 owner 会形成直接提权路径。产品固定使用
|
||
owner-only `project.manage`。
|
||
|
||
### 只禁止删除最后一行 Owner
|
||
|
||
RoleBinding 是 append-only,必须检查每个 subject 的最新 revision;历史 owner 行
|
||
不能计入当前 owner 数。
|
||
|
||
### 只检查第二个 Owner binding
|
||
|
||
无 active Identity/credential 的 Owner 不能接管系统。将其计入连续性会制造锁死。
|
||
|
||
## 验收证据
|
||
|
||
- `ql3-policy` 真实 SQLite/CLI 专项 6/6:
|
||
- grant、exact replay、role update、revoke;
|
||
- admin 自提升拒绝;
|
||
- 最后一个 active User owner 撤销拒绝;
|
||
- 无 active credential 的 owner target 拒绝;
|
||
- 有 credential 的 owner handover 后允许撤销原 owner;
|
||
- credential 在预检后 revoke 时事务回滚。
|
||
- dependency/source boundary 34/34,包含 mutation authority 的 exact-file 正负向
|
||
契约;
|
||
- runtime-core contract、SQLite repository、local-admin service 和 Owner CLI 的
|
||
strict targeted TypeScript 编译通过;
|
||
- workspace 仍为 22 package,无新增 dependency 或 migration。
|
||
|
||
完整 workspace build、artifact 预算和 PostgreSQL HA 门仍需在锁定依赖恢复后重跑;
|
||
不能用本专项门替代。
|
||
|
||
## 后续
|
||
|
||
- Identity register/disable 与 credential issue/rotate/revoke 的本机产品入口;
|
||
- Project lifecycle/query 已由 ADR-0212/0213 完成,RoleBinding current query 已由
|
||
ADR-0214 完成;仍需 rename、authority transfer 与 RoleBinding history query;
|
||
- bounded local audit query 已由 ADR-0215 完成;仍需 export/retention/signing/alert;
|
||
- RoleBinding change approval/break-glass 和恢复流程;
|
||
- Cluster PostgreSQL 对等管理 transport;
|
||
- 固定 Edge 设备上的 CLI RSS、闪存写入和断电恢复证据。
|