feat: make credential changes replayable

This commit is contained in:
2026-09-18 15:29:05 +08:00
parent a7be32f661
commit bea8efa790
12 changed files with 1034 additions and 8 deletions

View File

@@ -60,7 +60,7 @@ P4/P5定时等待与后续查询轮次的实现及回归记录见[时钟报告](
1. 已补[首批可复现故障工具](reports/phase-6-fault-boundaries.md):A04“派发已提交但消息尚未送达”、W01/W13事务提交结果不明,以及W16最终回执/旧PENDING结果重放/下一轮竞争。每个切点必须有实际数据库或进程证据,不能用响应错误推断事务是否已提交,也不能用普通SIGNAL竞争替代最终查询场景。
2. 已实现[基础运行观测](api/observability.md):HTTP/WS、数据库连接池、后台批次和进程指标,以及可离线验证的告警规则;独立采集监听默认关闭,固定指标目录拒绝动态标签。仍需受理/授权/完成阶段延迟与持久吞吐、流程推进延迟、重试/核查/恢复量、待处理与到期积压、发送队列及生产采集/通知验证。
3. 补齐凭据签发、轮换、撤销及Worker/订阅安全重绑,保持最小权限、管理审计与未知回执可恢复。
3. 已补齐受保护管理环境中的固定凭据操作文件、轮换、撤销、幂等回执和脱敏管理审计;轮换保留授权绑定并要求新令牌重新建立会话,撤销允许在停用范围内执行且不改写历史记录。仍需补齐提交不明故障切点、多节点安全重绑演练、凭据最小权限配置核对和生产密钥托管/审计演练。
4. 实现保留/归档与受保护记录核对,再执行备份恢复、兼容升级和六类容量负载。未确认交付、有效幂等身份、当前/历史执行证据和未终结流程不能被普通清理破坏。生产HA及RPO/RTO继续按实际拓扑验证,不缩减为本机多进程检查。
### P3 功能范围核对

View File

@@ -2,7 +2,7 @@
- 文档版本:0.2
- 整理日期:2026-09-17
- 阶段:P0–P5平台功能已通过阶段回归;[P4/P5原范围核对](reports/phase-4-5.md)和[首批故障边界](reports/phase-6-fault-boundaries.md)保留证据边界。P6生产观测与运维、P7首版交付继续推进,尚未完成全平台生产验收,数据库保持无外键。
- 阶段:P0–P5平台功能已通过阶段回归;[P4/P5原范围核对](reports/phase-4-5.md)和[首批故障边界](reports/phase-6-fault-boundaries.md)保留证据边界。P6已补进程观测和固定操作文件凭据轮换/撤销;生产积压、阶段延迟、提交不明切点、归档备份、容量与发布交付继续推进,尚未完成全平台生产验收,数据库保持无外键。
- 适用范围:Orbit 统一平台,包含 Pulse 任务调度模块、Weave 流程编排模块与公共能力。平台面向多个业务系统复用。
## 阅读顺序

View File

@@ -19,7 +19,7 @@
| `/v1/application/resources` 查询及 `:configure` 管理 | P3 已实现跨命名空间应用配额 | [应用配额与 SDK 场景](application-resources.md) |
| 任务 `concurrency_key` 与尝试 `concurrency_token` | P3 已实现跨队列资源键互斥 | [资源键接口与 SDK 场景](keyed-concurrency.md) |
| 任务 `priority` 与节点领取池 | P3 已实现有界优先级加速、应用/队列轮转 | [优先级与公平派发](priority-and-fairness.md) |
| 凭据校验与初始化 CLI | P1 已实现 | [鉴权](authentication.md) |
| 凭据校验、初始化、固定操作文件轮换/撤销与回执重放 CLI | P1/P6 已实现;不提供公网管理路由,测试专用提交不明切点已回归 | [鉴权](authentication.md)、[凭据报告](../reports/phase-6-credentials.md) |
| `/v1/worker/connect` | P2 已实现并通过阶段验收 | [Worker 契约](worker.md)、[Schema](worker-schema.md) |
| 任务相对延迟 `delay_ms` | 已实现数据库计时、原键恢复与实际执行例子 | [任务接口](tasks.md)、[延迟示例](../examples/delayed-task.md) |
| 任务冻结策略与 Worker `retryable` | P3 安全重试已实现 | [安全重试](retries.md) |

View File

@@ -23,7 +23,53 @@ ORBIT_MYSQL_DSN 通过环境注入,命令不读取 .env。所有名称必填
资源、凭据摘要和初始化审计在一个事务中提交。交付文件先写入并同步到磁盘,成功后再提交事务。如果文件写入失败则回滚并移除文件;如果已经交付后提交无法确认,保留文件并报错,应使用其中凭据核对结果,不能直接覆盖或重复创建。
初始文件包含真实秘密,应保管在受限目录或导入秘密管理系统。运行账户与迁移/初始化账户分开;生产只通过 HTTPS 使用凭据。凭据管理 HTTP API、轮换与细粒度运维命令在后续阶段实现,当前 bootstrap 主要用于完成独立接入与开发验证。
初始文件包含真实秘密,应保管在受限目录或导入秘密管理系统。运行账户与迁移/初始化账户分开;生产只通过 HTTPS 使用凭据。
## 轮换与撤销
凭据轮换和撤销只允许在受保护的数据库管理环境执行,不提供公网管理接口。轮换保留 `credential_id`,因此订阅和 Worker 实例的授权绑定仍指向同一记录;新的 Worker 进程必须按现有进程身份规则重新连接,旧令牌不能再通过任何 API 或 WSS 认证。平台不会批量改写在途任务、交付记录或历史会话证据。
先读取脱敏状态和当前版本:
```sh
go run ./cmd/orbit-admin credential status \
--namespace-id <namespace_id> \
--credential-id <credential_id>
```
状态输出不包含令牌、秘密摘要或权限正文;`revision` 是后续变更的并发条件。
```sh
go run ./cmd/orbit-admin credential rotate \
--namespace-id <namespace_id> \
--credential-id <credential_id> \
--expected-revision 1 \
--valid-for 720h \
--reason "scheduled credential rotation" \
--output .local/rotated.credentials.json
```
命令先读取并核对版本,生成一个固定 `operation_id`、令牌和绝对到期时间,写入新的 `0600` 私有操作文件,然后提交数据库事务。文件不得已存在;提交结果不明、网络断开或数据库返回未知错误时必须保留文件,并使用同一个文件执行 `credential apply --file`,不能重新执行 `rotate` 生成第二个秘密。`--valid-for` 限定在 1 小时到 1 年。数据库只保存秘密摘要、请求摘要和脱敏回执。
```sh
go run ./cmd/orbit-admin credential apply \
--file .local/rotated.credentials.json
```
`apply` 会严格拒绝软链接、非 0600 文件、未知 JSON 字段、重复 JSON 对象和修改过的操作内容。重复应用已提交的文件只返回原回执,回执中的 `deduplicated` 为 `true`,不会重新轮换或新增审计。
发生泄露或 Worker 必须立即停用时执行撤销:
```sh
go run ./cmd/orbit-admin credential revoke \
--namespace-id <namespace_id> \
--credential-id <credential_id> \
--expected-revision 2 \
--output .local/revoke.operation.json \
--reason "incident response"
```
撤销同样先写入固定操作文件,再提交事务;提交不明时用 `credential apply --file .local/revoke.operation.json` 重试。撤销只标记凭据失效,不删除订阅、任务、交付或历史记录。即使应用或命名空间已停用,管理撤销仍可执行。重复应用同一撤销文件只返回原回执,不追加重复审计。审计主体取自 MySQL 管理连接的 `CURRENT_USER()`,审计摘要不包含秘密原文或秘密摘要。
## 凭据格式与作用域

View File

@@ -0,0 +1,30 @@
# P6:凭据操作与安全轮换
日期:2026-09-18。本文只记录管理凭据操作的已实现边界,不把凭据功能等同于 P6 全部生产验收。
## 已实现行为
- `credential status` 只返回名称、版本、到期/撤销时间和应用/命名空间启用状态,不返回秘密或 `secret_digest`。
- `credential rotate` 先读取并核对 `expected_revision`,生成一次新令牌和固定绝对到期时间,写入新的 `0600` 私有操作文件,再应用事务。
- `credential apply --file` 严格读取同一个私有操作文件。操作身份、请求摘要、凭据摘要更新、脱敏回执和管理审计在同一事务中提交;提交结果不明时重复应用同一文件只返回原回执,不重新生成秘密、不重置到期时间、不新增审计。
- 操作文件被修改、替换为不同令牌或不同原因时返回 `IDEMPOTENCY_CONFLICT`;已有成功回执不受后续凭据轮换或撤销影响。
- `credential revoke` 也使用固定操作文件,允许在应用或命名空间已停用时关闭凭据。撤销只改变凭据授权状态,不批量改写 Worker、订阅、任务、交付或历史会话记录;后续认证和控制操作会重新核对凭据状态。
- 审计主体来自提交事务所在 MySQL 连接的 `CURRENT_USER()`,不是凭据 ID 或请求自报字段。审计前后摘要不包含令牌或秘密摘要。
- 没有公网管理路由,也没有新增运行时依赖;管理 CLI 使用现有 MySQL 连接和迁移账本。
## 真实验证
以下验证使用 Go 1.27.1、darwin/arm64、Docker MySQL 8.4.10 的一次性数据库:
```sh
GO="$(cat /tmp/orbit-toolchain-path)/go" DOCKER=/usr/local/bin/docker \
sh /tmp/orbit-credential-test.sh
```
`TestIntegrationCredentialOperations` 退出 0,覆盖:初始状态、轮换后旧令牌拒绝/新令牌接受、固定操作重放、修改操作文件冲突、停用应用后撤销、重复撤销回执、审计主体和敏感字段不泄露。数据库回读确认轮换审计和撤销审计各一条,当前迁移保持零外键。
`TestIntegrationCredentialCommitFaults` 同样退出 0:使用测试专用 MySQL 包代理分别在 COMMIT 发出前断线和收到成功包后丢确认,独立连接回读版本,并用同一操作文件完成核对。BEFORE 情况回滚后重试首次提交,AFTER 情况直接返回原回执;两种情况都没有生成第二个令牌或第二条审计。该故障代理只存在于测试二进制,不进入生产进程。
随后执行标准隔离回归 `GO="$(cat /tmp/orbit-toolchain-path)/go" DOCKER=/usr/local/bin/docker sh scripts/test-mysql.sh`,退出 0。该次 root MySQL 集成组耗时 264.138 秒,包含上述两个凭据场景;流程运行器、SDK、Worker/事件进程、业务 Inbox/Outbox 和 23 个 SDK 示例均通过。另一次 CLI 专项实际构建 `orbit-admin`,在一次性 MySQL 上跑通 status、rotate、apply 首次提交、apply 重放和 revoke,且新操作文件权限为 0600。
以上证据仍不替代密钥托管演练、多节点重连演练、保留/归档、备份恢复和容量验收。