mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
140 lines
6.0 KiB
Markdown
140 lines
6.0 KiB
Markdown
# ADR-0211:Local Identity/Credential 的实例 Authority Project
|
||
|
||
- 状态:Accepted
|
||
- 日期:2026-07-29
|
||
- 关联 RFC:QL-RFC-0001 D-05、D-27、D-37、D-65、D-72、D-73、D-175、
|
||
D-198、D-199、D-200、D-201
|
||
- 关联 ADR:ADR-0028、ADR-0074、ADR-0086、ADR-0185、ADR-0208、
|
||
ADR-0209、ADR-0210
|
||
|
||
## 背景
|
||
|
||
Project RoleBinding 是 Project-scoped policy;Identity 与 API credential 则没有
|
||
`project_id`,是实例级全局安全对象。ADR-0209/0210 最初要求调用者是请求 Project
|
||
的 Owner,但未证明该 Project 对全局 Identity/Credential 拥有 authority。
|
||
|
||
当实例包含多个 Project 时,这会允许 Project A 的 Owner:
|
||
|
||
- 禁用也被 Project B 使用的全局 Identity;
|
||
- 撤销或轮换该 Identity 的 API credential;
|
||
- 查询任意已知 credential ID 的状态和时间窗;
|
||
- 通过直接调用 authorized repository 绕过只放在 CLI/service 的限制。
|
||
|
||
Project 内 `project.manage` 不能隐式等同于实例 root credential issuer。
|
||
|
||
## 决策
|
||
|
||
### 1. 实例 Authority 锚定首个成功 Owner bootstrap claim
|
||
|
||
Local Identity/Credential authority Project 定义为:
|
||
|
||
1. 在 `QingLong3LocalOwnerBootstrapChallenges` 中选择
|
||
`consumed_at_ms IS NOT NULL` 的全库最早记录;
|
||
2. 以 `consumed_at_ms ASC, project_id ASC, version ASC` 提供确定性排序;
|
||
3. 该记录的 `project_id` 是实例 authority Project。
|
||
|
||
成功 claim 是已有的 durable、append-once bootstrap 事实,不随后续 RoleBinding
|
||
grant/revoke 或当前 Owner 人员变化。challenge delivery acknowledgement GC 不删除
|
||
challenge source,因此 anchor 可恢复。
|
||
|
||
为兼容在该协议前创建或通过 adoption/manual fixture 建立的数据库,仅当全库没有任何
|
||
consumed bootstrap challenge 时,若迁移内建 `default` Project 存在,则将其作为
|
||
fallback authority。存在任一 consumed challenge 后禁止回退。
|
||
|
||
### 2. 服务层先验证 Project Owner,再验证实例 authority
|
||
|
||
local-admin 的顺序固定为:
|
||
|
||
1. 对 command 指定 Project 请求 Owner-only `project.manage`;
|
||
2. deny/approval/unavailable 按既有低敏语义审计;
|
||
3. 解析实例 authority Project;
|
||
4. 若不匹配,写 `denied` +
|
||
`instance_authority_project_required` audit;
|
||
5. 只有匹配后才能解析 replay、Identity 或 credential 状态。
|
||
|
||
这样 foreign Project Owner 不能利用 found/not-found、version conflict 或 replay
|
||
差异枚举全局对象。
|
||
|
||
### 3. SQLite 最终事务必须重复 authority fence
|
||
|
||
服务层不是最终 authority。所有以下 repository operation 在 `BEGIN IMMEDIATE`
|
||
取得写锁并复验当前认证 credential 后,必须重新解析 authority anchor:
|
||
|
||
- `inspectAuthorizedIdentity`;
|
||
- `appendAuthorizedIdentity`;
|
||
- `inspectAuthorizedCredential`;
|
||
- `appendAuthorizedCredential`;
|
||
- `appendAuthorizedDeliveryAcknowledgement`。
|
||
|
||
只有 `authorization.projectId` 等于 anchor,才继续验证 Project version、actor 最新
|
||
Owner RoleBinding 和领域 CAS。否则抛出统一 authorization fence conflict 并回滚。
|
||
因此 direct repository 调用和 authorization→transaction 间的 anchor 漂移都失败
|
||
关闭。
|
||
|
||
### 4. 不改变 Project Policy 产品边界
|
||
|
||
`ql3-policy` 仍管理各 Project 自己的 RoleBinding。授予 secondary Project Owner
|
||
只授予该 Project 的业务权限,不授予全局 Identity/Credential issuer 权限。
|
||
|
||
本决策不增加数据库迁移、第 23 个 package、第三方依赖、daemon、timer、watcher、
|
||
listener 或远程 API。Cluster 继续使用独立 PostgreSQL/RBAC authority。
|
||
|
||
## 替代方案
|
||
|
||
### 任意 Project Owner 都可管理全局 Identity
|
||
|
||
拒绝。Project RBAC 与实例 credential issuer 的作用域不同,会形成横向越权。
|
||
|
||
### 永久硬编码 `default`
|
||
|
||
拒绝作为唯一规则。它能兼容当前默认部署,却会否定合法地在其他 Project 完成首次
|
||
Owner bootstrap 的数据库。
|
||
|
||
### 选择“当前拥有最多权限的 Owner”或最新 Owner
|
||
|
||
拒绝。authority 会随日常 RoleBinding 变更漂移,产生静默 takeover,并使旧 command
|
||
不可重放。
|
||
|
||
### 新增 InstanceRole/GlobalRole 表
|
||
|
||
暂不采用。首个 Owner claim 已提供足够的不可变实例根事实;新增全局 RBAC 需要独立
|
||
迁移、恢复和管理 ceremony,超出当前最小修复。
|
||
|
||
### 只在 CLI 校验 authority Project
|
||
|
||
拒绝。local-admin 或 repository 仍可被其他 adapter 直接调用,无法形成 authority
|
||
边界。
|
||
|
||
## 影响
|
||
|
||
正向影响:
|
||
|
||
- secondary Project Owner 无法修改、查询或确认全局 credential delivery;
|
||
- authority 不随 Project Owner 交接漂移;
|
||
- 自定义首次 bootstrap Project 可被识别;
|
||
- 旧库在没有 claim 事实时继续使用既有 `default` 行;
|
||
- 低配设备只增加每次管理命令的两个有界索引查询,无常驻成本。
|
||
|
||
代价与限制:
|
||
|
||
- 多 Project 部署的 Identity/Credential 管理必须由 authority Project Owner 发起;
|
||
- 当前没有受审的 authority Project 转移 ceremony;
|
||
- fallback 数据库应在后续 adoption evidence 中明确标记“无 bootstrap anchor”;
|
||
- InstanceRole 若未来引入,必须用新 ADR supersede 本决策。
|
||
|
||
## 验证
|
||
|
||
- GitNexus 对最终事务 helper 的影响分析为 HIGH:5 个 direct repository operation、
|
||
1 个 `changeCredential` execution flow;必须运行全部相关回归;
|
||
- service 测试证明 secondary Project 的 Owner 即使通过自身 Project policy,也收到
|
||
统一 denied audit;
|
||
- 真实 SQLite/CLI fixture 同时创建 default 与 secondary Owner,secondary
|
||
`credential.inspect` 必须被拒绝;
|
||
- 直接以 secondary Project Owner fence 调用 authorized SQLite repository,必须在
|
||
transaction 内抛出 authorization fence conflict;
|
||
- default authority 的 register → inspect → issue → exact replay → acknowledge →
|
||
revoke → disable 流程保持通过;
|
||
- strict targeted TypeScript、local image/dependency audit 与 GitNexus
|
||
`detect_changes` 必须重跑;
|
||
- 完整 workspace、artifact/RSS 和 PostgreSQL HA 门在锁定依赖恢复后重跑。
|