1d85329a6a
Build and Test Quality Gate / Contract Web typecheck and build (pull_request) Successful in 9m12s
Build and Test Quality Gate / Isolated Alibaba and Tencent KMS gateway (pull_request) Failing after 4m53s
Build and Test Quality Gate / Python tests and Contract API migration (pull_request) Failing after 24m55s
Security Quality Gate / npm audit, Bandit, pip-audit, detect-secrets (pull_request) Failing after 8m42s
8.2 KiB
8.2 KiB
P1-04.9.2 实施与验收报告:双云 KMS、旧密文重包裹与故障演练
日期:2026-08-25
状态:功能、迁移、接口、管理端、自动化与超级管理员 Chrome UAT 已完成;真实企业云凭据验收属于发布门禁,不以模拟结果代替。
1. 阶段目标
- 把 P1-04.9.1 的通用 KMS Gateway 契约落实为阿里云 KMS 与腾讯云 KMS 的真实官方 SDK 适配器。
- 为旧本地 Fernet 密文建立租户级清单、异步批量重包裹、回读校验、暂停/恢复/取消/失败重试及字段级证据。
- 实施托管服务不可用故障注入,证明超时、鉴权失败或提供方不可用时不会改写凭据。
- 实施 SLO 外部升级通知的预检和显式入队演练,覆盖真实通知派发、重试与死信状态回写。
- 保持合同 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。流程为:
- 按当前租户扫描带密文的允许字段,只保存表名、记录 ID、字段名、来源后端和 SHA-256 指纹。
inventory模式只生成清单与证据,不改写数据。execute模式创建异步任务,Worker 按批次取得租约并逐字段处理。- 每个字段先解开旧 envelope,再调用当前 KMS/Vault 加密,然后立即调用当前托管解密回读。
- 回读明文使用常量时间比较;只有摘要一致且数据库旧指纹未变化时才写入新 envelope。
- 并发更新、无法恢复、外部托管错误均转为
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_jobsplaybook_secret_rewrap_itemsplaybook_operational_drills
新增接口:
GET|POST /api/v1/enterprise-playbook/governance/secret-custody/rewrap-jobsPOST /api/v1/enterprise-playbook/governance/secret-custody/rewrap-jobs/{job_id}/actionsGET|POST /api/v1/enterprise-playbook/governance/operational-drills
超级管理员 Playbook 页面新增“旧密文盘点与批量重包裹”和“托管不可用与 SLO 外部升级故障演练”。危险操作有确认门禁,列表显示任务计数、字段状态、零写入证据与外部投递状态。
4. 发布门禁
正式切换前必须在隔离预发布环境完成:
- 选择一家云厂商 overlay,配置企业自己的 endpoint、CMK、ClientKey/API 凭据、CA、服务 token 和网络白名单。
- 网关
/health返回configured=true;合同 API 托管状态返回production_ready=true。 - 执行一次
round_trip和一次持久化recovery_canary,摘要均匹配。 - 先创建
inventory并导出任务计数;抽查目标记录当前指纹与业务可用性。 - 使用小批次
execute,确认成功、失败、跳过之和等于总数;失败项不得通过手工数据库覆盖。 - 运行三种托管不可用模拟,全部应为零写入。
- 对测试通知通道先
dry_run,再显式enqueue;确认外部接收与系统投递证据一致。 - 完成全量重包裹并至少保留一个回滚窗口后,撤除旧 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
8100health=ok,Web3000HTTP 200,AI API8101保持运行;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:https://help.aliyun.com/en/kms/key-management-service/developer-reference/kms-instance-sdk-for-python/
- 阿里云 KMS SDK 用户指南:https://help.aliyun.com/en/kms/key-management-service/developer-reference/sdk-user-guide/
- 阿里云官方 Python SDK 示例:https://github.com/aliyun/alibabacloud-kms-python-sdk/blob/master/README.zh-cn.rst
- 腾讯云 KMS Python SDK:https://cloud.tencent.com/document/product/573/38366
- 腾讯云 KMS Encrypt:https://cloud.tencent.com/document/api/573/34420
- 腾讯云 KMS Decrypt:https://cloud.tencent.com/document/product/573/34429
详细发布、故障演练和回退步骤见 project-docs/playbook-cloud-kms-rewrap-fault-drill-runbook-2026-08-25.md。