Files
qinglong/docs/adr/ADR-0211-instance-authority-project-for-local-identity-credential.md
T

140 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-0211Local Identity/Credential 的实例 Authority Project
- 状态:Accepted
- 日期:2026-07-29
- 关联 RFCQL-RFC-0001 D-05、D-27、D-37、D-65、D-72、D-73、D-175、
D-198、D-199、D-200、D-201
- 关联 ADRADR-0028、ADR-0074、ADR-0086、ADR-0185、ADR-0208、
ADR-0209、ADR-0210
## 背景
Project RoleBinding 是 Project-scoped policyIdentity 与 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 的影响分析为 HIGH5 个 direct repository operation、
1 个 `changeCredential` execution flow;必须运行全部相关回归;
- service 测试证明 secondary Project 的 Owner 即使通过自身 Project policy,也收到
统一 denied audit
- 真实 SQLite/CLI fixture 同时创建 default 与 secondary Ownersecondary
`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 门在锁定依赖恢复后重跑。