# P1-04.9.2 实施与验收报告:双云 KMS、旧密文重包裹与故障演练 日期:2026-08-25 状态:功能、迁移、接口、管理端、自动化与超级管理员 Chrome UAT 已完成;真实企业云凭据验收属于发布门禁,不以模拟结果代替。 ## 1. 阶段目标 1. 把 P1-04.9.1 的通用 KMS Gateway 契约落实为阿里云 KMS 与腾讯云 KMS 的真实官方 SDK 适配器。 2. 为旧本地 Fernet 密文建立租户级清单、异步批量重包裹、回读校验、暂停/恢复/取消/失败重试及字段级证据。 3. 实施托管服务不可用故障注入,证明超时、鉴权失败或提供方不可用时不会改写凭据。 4. 实施 SLO 外部升级通知的预检和显式入队演练,覆盖真实通知派发、重试与死信状态回写。 5. 保持合同 API 不持有云厂商 SDK 或 AccessKey,并避免阿里云 SDK 的加密库版本约束污染主服务。 ## 2. 架构结果 ### 2.1 隔离的双云 KMS 数据面 新增独立 `yuqei-kms-gateway` 服务。合同 API 仍只调用统一的 `/v1/encrypt` 与 `/v1/decrypt`,网关内部按部署选择: - 阿里云:KMS 实例 SDK、ClientKey、ClientKey 密码、KMS 实例 CA、专属 endpoint、`AES_GCM`、固定 AAD。 - 腾讯云:KMS API 3.0 SDK、广州等国内 region、文件注入的临时或长期 API 凭据、固定 `EncryptionContext`。 - 公共门禁:文件注入服务 Bearer token、key allowlist、4 KiB 明文上限、请求超时、错误脱敏、无重定向、生产 TLS。 - SDK 依赖隔离:独立镜像或 `.venv`;合同 API 继续使用自己的 `cryptography>=44`,不加载云 SDK。 生产 Compose 提供阿里云、腾讯云两套互斥 overlay;网关容器只读、非 root、`no-new-privileges`,凭据与 TLS 材料均为只读挂载。 ### 2.2 批量重包裹 重包裹对象覆盖企业日历源中的企业应用 secret、访问令牌、刷新令牌、增量游标,以及未过期 OAuth state 的 PKCE verifier。流程为: 1. 按当前租户扫描带密文的允许字段,只保存表名、记录 ID、字段名、来源后端和 SHA-256 指纹。 2. `inventory` 模式只生成清单与证据,不改写数据。 3. `execute` 模式创建异步任务,Worker 按批次取得租约并逐字段处理。 4. 每个字段先解开旧 envelope,再调用当前 KMS/Vault 加密,然后立即调用当前托管解密回读。 5. 回读明文使用常量时间比较;只有摘要一致且数据库旧指纹未变化时才写入新 envelope。 6. 并发更新、无法恢复、外部托管错误均转为 `skipped` 或 `failed`,不静默覆盖;任务支持暂停、恢复、取消和只重试失败项。 数据库和审计不保存重包裹明文。云厂商 CMK 的原生版本轮换由云 KMS 保持历史解密能力;本批处理专门用于把 P1-04.9.1 以前的本地 Fernet 密文迁移到当前外部托管后端,不支持在未同时配置来源适配器时跨两个外部托管后端直接搬迁。 ### 2.3 故障演练 - 托管不可用:在事务内注入 `timeout`、`authorization`、`provider_unavailable` 三种隔离故障,比较演练前后租户密文字段数量与聚合摘要;只有“写入被阻止且摘要不变”才成功。 - SLO 外部升级:`dry_run` 检查通知通道已启用、握手通过且订阅 SLO 升级事件,不产生外部副作用。 - 真实入队:需要精确确认短语 `SLO_EXTERNAL_DRILL`,只向显式选择的通道创建一条带 `drill=true` 的通知投递。 - 投递 Worker 的 `delivered`、`retry_scheduled`、`dead_letter` 会回写演练账本,演练证据与普通 SLO 事件可区分。 ## 3. 数据、接口与界面 迁移:`20260825_0063`。 新增表: - `playbook_secret_rewrap_jobs` - `playbook_secret_rewrap_items` - `playbook_operational_drills` 新增接口: - `GET|POST /api/v1/enterprise-playbook/governance/secret-custody/rewrap-jobs` - `POST /api/v1/enterprise-playbook/governance/secret-custody/rewrap-jobs/{job_id}/actions` - `GET|POST /api/v1/enterprise-playbook/governance/operational-drills` 超级管理员 Playbook 页面新增“旧密文盘点与批量重包裹”和“托管不可用与 SLO 外部升级故障演练”。危险操作有确认门禁,列表显示任务计数、字段状态、零写入证据与外部投递状态。 ## 4. 发布门禁 正式切换前必须在隔离预发布环境完成: 1. 选择一家云厂商 overlay,配置企业自己的 endpoint、CMK、ClientKey/API 凭据、CA、服务 token 和网络白名单。 2. 网关 `/health` 返回 `configured=true`;合同 API 托管状态返回 `production_ready=true`。 3. 执行一次 `round_trip` 和一次持久化 `recovery_canary`,摘要均匹配。 4. 先创建 `inventory` 并导出任务计数;抽查目标记录当前指纹与业务可用性。 5. 使用小批次 `execute`,确认成功、失败、跳过之和等于总数;失败项不得通过手工数据库覆盖。 6. 运行三种托管不可用模拟,全部应为零写入。 7. 对测试通知通道先 `dry_run`,再显式 `enqueue`;确认外部接收与系统投递证据一致。 8. 完成全量重包裹并至少保留一个回滚窗口后,撤除旧 Fernet recovery key 文件。 ## 5. 明确边界 - 当前开发机没有用户企业的阿里云 ClientKey、腾讯云 SecretId/SecretKey、CMK 或私网白名单,因此没有发起任何真实云端加解密请求。 - 自动化已在独立环境实际导入两家固定版本官方 SDK,并以假客户端验证精确请求模型、AAD/EncryptionContext、返回结构、key 校验与错误分类。 - “SDK 已接入”不等于“客户云账号已验收”;真实云往返是不可跳过的发布门禁。 - 本机没有 Docker,Compose overlay 已完成 YAML 与安全字段静态校验,镜像构建及容器健康检查需在部署节点执行。 ## 6. 验收记录 - KMS Gateway:阿里云与腾讯云官方 SDK 均可在隔离 `.venv` 导入;4/4 网关契约与错误脱敏测试通过。 - 合同后端:358 collected,354 passed,4 skipped;无失败。新增测试覆盖远程重包裹回读、租户清单、乐观锁写入、管理员取消、三类零写入故障注入和 SLO 投递死信。 - 前端:typecheck、全部 Node 测试与生产 build 通过;生成路由包含三组 P1-04.9.2 代理接口。 - OpenAPI:120 paths / 180 schemas,YAML 与所有 schema 引用可解析。 - 数据库:PostgreSQL 已升级到 `20260825_0063 (head)`。 - 服务:Contract API `8100` health=ok,Web `3000` HTTP 200,AI API `8101` 保持运行;Review 与 Playbook Governance Worker 均运行且错误日志为空。Schema check 只有本地环境既有的 anti-abuse disabled warning,其余数据库、迁移和治理检查均为 ok。 - 超级管理员 Chrome UAT:账号 `uat.legal.20260823@example.test`、工作区“Playbook 隔离 UAT”;阶段标识为 P1-04.9.2,治理数据加载失败为 0,浏览器控制台错误为 0。 - UAT 盘点:创建 `playbook-secret-rewrap-3886d259f4fb`,状态 `inventory_complete`,当前隔离租户没有需要迁移的密文字段,业务数据未改写。 - UAT 托管故障:创建 timeout 模拟,状态 `succeeded`、`write_blocked=true`、`external_side_effect=false`,页面显示“零写入”。 - UAT SLO 门禁:对已握手但停用的测试邮件通道执行 dry-run,结果按预期失败且 `external_side_effect=false`;真实发送按钮保持禁用并展示启用/握手/订阅要求,未发送外部消息。 ## 7. 官方实现依据 - 阿里云 KMS 实例 SDK for Python: - 阿里云 KMS SDK 用户指南: - 阿里云官方 Python SDK 示例: - 腾讯云 KMS Python SDK: - 腾讯云 KMS Encrypt: - 腾讯云 KMS Decrypt: 详细发布、故障演练和回退步骤见 `project-docs/playbook-cloud-kms-rewrap-fault-drill-runbook-2026-08-25.md`。