Morphosis API Gateway 系统设计

统一支付平台入口、细粒度授权与多地域高可用设计

架构会诊通过,待浏览器视觉验收与业务工程团队评审
  • 文档状态:架构会诊通过,待浏览器视觉验收与业务工程团队评审
  • 版本:0.4
  • 日期:2026-07-15
  • 设计范围:WebPay Inbox、BPS、Zero Confirmation 及未来支付平台的统一 API 入口
  • 生成说明:HTML 由本文档生成,禁止单独编辑 HTML 副本。

1. 依据与结论

1.1 输入材料

本设计以正式会议摘要 正式会议摘要文件 作为已确认记录,以逐字稿 会议逐字稿文件 作为上下文佐证。逐字稿包含低置信度片段、重复语句和说话人识别误差,不能单独用于确认高风险架构事实。

  1. 会议逐字稿文件
  2. 正式会议摘要文件

当前仓库 /Users/yoshiyuki/Documents/morphosis_api_gateway 尚无业务代码或既有架构文档,因此本文中的技术选型、性能目标和运维指标均属于建议设计,不代表现网事实。

1.2 已确认业务决策

  1. API Gateway 是多个支付平台的统一入口,不是 Zero Confirmation 的专用入口。
  2. 首批纳入的平台包括 WebPay Inbox、BPS 和 Zero Confirmation,未来还需接入其他支付平台。
  3. API Key 必须表达它可访问的平台、服务和操作权限。
  4. 一个商户可以拥有多个 API Key,也可以使用多个来源 IP。
  5. API Key 与来源 IP 必须建立显式绑定;未绑定的 Key 与 IP 组合必须拒绝。
  6. 系统必须支持多个地域、多个网关实例和后端多数据库场景,并提供冗余与路由能力。
  7. Zero Confirmation 的多地域设计经验未来需要复用于 BPS。

1.3 设计结论

建议采用“全局统一控制面、区域自治数据面”的架构:

  • 控制面统一管理商户、API Key、密钥版本、IP 绑定、权限范围、路由和审计。
  • 每个地域部署无状态网关数据面与本地域配置快照及限流缓存,请求不依赖跨地域同步数据库查询。
  • API Key 授权采用默认拒绝模型,并同时满足商户归属、环境、Key 状态、Key 与 IP 绑定、路由所需权限五项条件。
  • 网关只负责认证、授权、流量治理和确定性路由,不负责在 BPS 或 Zero Confirmation 的业务数据库之间做双写。
  • 支付写请求的跨地域故障转移必须以端到端幂等和后端数据一致性为前提,不能仅靠网关重试解决。

2. 目标与非目标

2.1 目标

  1. 为所有商户 API 提供统一的公网或专线入口。
  2. 用一套平台无关的授权模型管理多平台、多服务和多操作权限。
  3. 精确校验 API Key 与来源 IP 的组合,防止同一商户的多个 Key 和多个 IP 被错误混用。
  4. 支持 Key 创建、轮换、吊销、过期、权限变更和 IP 变更的完整生命周期。
  5. 支持区域内横向扩展和多地域部署,单个网关实例或单个地域故障时具备明确的降级与恢复行为。
  6. 为安全审计、故障排查、容量规划和 SLO 提供完整可观测性。
  7. 允许未来支付平台通过配置和标准接入流程接入,而不修改核心认证逻辑。

2.2 非目标

  1. 不在网关内实现 WebPay Inbox、BPS 或 Zero Confirmation 的业务逻辑。
  2. 不由网关负责平台业务数据库复制、跨库事务或账务一致性。
  3. 不允许网关自动把一个地域的支付写请求盲目重放到另一个地域。
  4. 不把 API Key 当作商户后台用户登录凭据;后台人员应使用独立的身份系统和强认证。
  5. 本阶段不设计商户计费系统,但会产出可供计费使用的用量事件。

3. 核心原则

  1. 默认拒绝:任何缺失、未知、过期、吊销或未明确授权的请求都拒绝。
  2. 显式绑定:权限和 IP 都直接绑定到具体 API Key,不从商户级配置隐式继承。
  3. 控制面与数据面分离:管理变更可以短时不可用,但存量数据面应继续处理已知且有效的请求。
  4. 区域自治:请求热路径只访问本地域组件,不依赖跨地域数据库。
  5. 后端拥有数据一致性:网关只根据已发布的路由策略选定一个后端,不参与业务双写。
  6. 机密最小暴露:API Secret 只在创建时展示一次,服务端只保存不可逆摘要。
  7. 全链路可审计:所有控制面变更和数据面授权决策都可追溯,但日志不得记录原始 Secret、支付敏感字段或完整请求体。

4. 总体架构

下图只表达逻辑责任边界和边界之间交付的内容,不展开组件、缓存或部署拓扑。六个中性节点可以由多个组件共同实现,也可以分散部署;名称中的“中心”表示统一规则与责任归属,不表示请求必须同步调用一个集中式服务。

逻辑边界总览

%%{init: {"flowchart": {"curve": "linear", "nodeSpacing": 34, "rankSpacing": 44, "htmlLabels": true}}}%% flowchart TB subgraph CONTROL["策略与配置"] direction LR CONFIG["配置发布与运营中心<br/>管理变更 · 版本发布 · 紧急只拒绝"] -->|"路由策略快照"| ROUTING["流量路由策略中心<br/>一份策略 · 两个执行点"] end subgraph REQUEST["商户请求路径"] direction LR MERCHANT["商户系统"] --> INGRESS["统一接入层<br/>入口选择 · 边缘防护 · 可信来源"] INGRESS --> ACCESS["访问控制中心<br/>身份验证 · Key-IP · Scope"] ACCESS --> GOVERN["请求治理与执行层<br/>流量策略 · 安全门禁 · 后端调用"] GOVERN --> PLATFORM["支付平台服务<br/>WebPay Inbox · BPS · Zero Confirmation"] end ROUTING -.->|"入口地域策略"| INGRESS ROUTING -.->|"后端候选与故障转移门禁"| GOVERN CONFIG -->|"Key · IP · Scope 快照"| ACCESS CONFIG -->|"路由治理快照"| GOVERN GOVERN -.->|"数据面运行与决策事件"| OBSERVE["可观测性与审计中心<br/>关联查询 · 告警 · SLO · 合规证据"] CONFIG -.->|"变更事件与事务内审计"| OBSERVE classDef external fill:#F7F9FC,stroke:#8A9AAF,color:#18212F,stroke-width:1.5px classDef entry fill:#EAF2FF,stroke:#1264D6,color:#12345B,stroke-width:2px classDef runtime fill:#FFFFFF,stroke:#4F79A7,color:#18212F,stroke-width:1.5px classDef policy fill:#EDF8F3,stroke:#16835E,color:#124D3B,stroke-width:1.5px classDef control fill:#F2F0FF,stroke:#6657C7,color:#292057,stroke-width:1.5px class MERCHANT,PLATFORM external class INGRESS entry class ACCESS,GOVERN runtime class ROUTING,OBSERVE policy class CONFIG control style CONTROL fill:#FAF9FF,stroke:#C9C0F1,stroke-width:2px style REQUEST fill:#F8FBFF,stroke:#B8CDEA,stroke-width:2px

总览中的实线是请求或版本化快照的交付关系,虚线是策略影响或事件汇聚关系。流量路由策略中心不是请求热路径上的集中式同步服务:入口执行点选择入口地域,认证后的治理执行点选择后端并应用故障转移门禁。可观测性与审计中心不替代控制面的事务内审计写入,只负责安全汇聚、关联查询、告警与证据输出。总览不单列缓存;本地域快照是访问控制和请求治理的内部实现,来源始终是配置发布链路。

抽象节点单一职责展开位置
统一接入层把外部连接安全地送入一个合格地域,并产生可信来源上下文第 4.1 节
流量路由策略中心用一份版本化策略约束入口地域和认证后后端选择第 7.1.1 节
访问控制中心完成身份、Key-IP 与路由 Scope 判定,输出稳定的允许或拒绝语义第 5.6 节
请求治理与执行层对已授权请求应用流量、安全与调用策略,并调用一个明确后端第 6.1 节
配置发布与运营中心校验管理变更、单写持久化、发布快照并提供独立紧急拒绝通道第 10.1 节
可观测性与审计中心汇聚脱敏事件,形成关联查询、告警、SLO 和合规证据第 12.1 节

4.1 统一接入层

统一接入层包含全局流量产品、边缘防护、TLS 终止点或透传路径、地域入口和负载均衡。它只建立可信连接与来源上下文,不认证 API Key,也不授予平台权限。认证前的商户或平台提示只能缩小入口候选集。

%%{init: {"flowchart": {"curve": "linear", "nodeSpacing": 34, "rankSpacing": 38, "htmlLabels": true}}}%% flowchart TB MERCHANT["商户 TLS 请求"] --> EDGE["全局边缘保护<br/>L3/L4 DDoS · 连接与速率边界"] HINT["未认证路由提示<br/>只缩小候选集 · 不授予权限"] --> SELECT["执行点 1 · 入口地域选择<br/>allowed_regions · 合规 · 地域健康"] POLICY["路由策略中心<br/>入口地域策略版本"] -.-> SELECT EDGE --> SELECT SELECT -->|"存在合格地域"| REGION["地域入口"] SELECT -->|"无合格地域"| FAIL["停止解析或返回 503<br/>由全局流量产品能力决定"] subgraph REGIONAL["合格地域内的接入处理"] direction LR REGION --> TLS["TLS 终止或透传<br/>mTLS 在实际终止点完成握手"] TLS --> WAF["L7 WAF 与协议边界<br/>方法 · Header · 路径 · 报文大小"] WAF --> SOURCE["可信来源 IP<br/>覆盖外部转发头 · 校验受信代理链"] SOURCE --> BALANCE["地域内负载均衡<br/>仅选择健康网关实例"] BALANCE --> OUTPUT["输出<br/>规范请求 + 可信来源 IP<br/>mTLS 证书上下文"] end classDef external fill:#F7F9FC,stroke:#8A9AAF,color:#18212F,stroke-width:1.5px classDef input fill:#F4F7FB,stroke:#72849A,color:#253954,stroke-width:1.5px classDef entry fill:#EAF2FF,stroke:#1264D6,color:#12345B,stroke-width:1.5px classDef reject fill:#FFF2EC,stroke:#C7582B,color:#6B2812,stroke-width:1.5px class MERCHANT external class HINT,POLICY input class EDGE,SELECT,REGION,TLS,WAF,SOURCE,BALANCE,OUTPUT entry class FAIL reject style REGIONAL fill:#F8FBFF,stroke:#B8CDEA,stroke-width:2px

输出中的 mTLS 证书上下文只是握手结果,证书与 API Key 的显式绑定要在身份认证成功后校验。外部 TLS 在 WAF 终止还是透传到网关仍是待选型事项,但无论终止位置在哪里,都必须执行凭据脱敏、证书保护和可信代理链校验。

4.2 数据面组件

  1. 流量路由策略中心(逻辑能力):统一定义入口地域和地域内后端路由策略,通过版本化快照发布到两个执行点本地评估,不引入跨地域同步数据库依赖。
  2. 全局入口、WAF 与负载均衡:入口执行点根据已发布策略和地域健康选择入口地域;WAF 与负载均衡承担 DDoS 防护、TLS 终止或透传、基础协议校验和地域内实例分发。
  3. API Gateway:完成请求规范化、认证调用、权限执行、限流、路由、超时、熔断、请求标识和响应规范化。
  4. API Key 验证服务(每个地域部署):验证 Secret 摘要、Key 状态、入口环境和 Key-IP 绑定,向网关返回已验证身份与 Scope 集合;它不决定商户能否访问某条路由。
  5. 本地域配置快照与限流缓存:保存已签名或带版本号的 Key、IP、Scope、吊销和路由快照,以及分布式限流状态。支付写入 Nonce 使用独立安全缓存,只在已允许写入故障转移的地域间同步。
  6. 服务路由层:作为认证后的第二执行点,维护地域内后端端点、健康状态、重试边界,并执行策略中心发布的跨地域故障转移门禁。

4.3 控制面组件

  1. Gateway Admin API:提供机器可调用的 Key 生命周期、Scope、IP 绑定和路由管理接口。
  2. 内部身份与审批:管理员必须通过公司身份系统登录;高风险操作采用双人审批。
  3. 统一控制面:验证配置不变量,持有单写租约,写入 PostgreSQL,并通过事务 Outbox 发布版本化变更事件。
  4. PostgreSQL:作为商户、Key、权限、绑定和路由配置的唯一事实源,采用跨地域主动与备用复制和写入围栏。
  5. 备用控制面:正常情况下不接受写入,只有旧主完成围栏并取得新 epoch 后才能接管。
  6. 消息总线:把变更推送到各地域,支持重放、消费位点和幂等消费。
  7. break-glass 只拒绝入口:控制面不可用时向各地域的 API Key 验证服务追加紧急拒绝项,永远不能扩大权限。
  8. 审计存储:记录谁在何时因何原因进行了何种变更,以及变更前后的非敏感差异。

4.4 推荐技术基线

在缺少既有技术栈约束的情况下,建议先采用以下基线进行原型验证:

  • 数据面代理:Envoy Gateway 或等价的成熟 L7 代理。
  • API Key 验证:独立的外部验证服务处理凭据摘要、Key 状态、环境与 Key-IP 绑定;网关策略执行路由可见性和 required scope,避免把验证逻辑硬编码在代理配置中。
  • 配置主库:PostgreSQL。
  • 本地域配置快照与限流:Redis 兼容集群。
  • 配置分发:Kafka 兼容消息总线与 PostgreSQL 事务 Outbox。
  • 部署平台:Kubernetes,多可用区部署并使用 Pod 反亲和规则。
  • 密钥保护:云 KMS 或等价硬件保护的密钥管理服务。

该技术基线需要在平台团队提供现有基础设施清单后做一次选型确认。逻辑架构不依赖特定厂商产品。

5. 身份、API Key 与授权模型

5.1 API Key 凭据格式

客户端通过 Authorization 请求头传递凭据,认证方案名为 ApiKey。凭据由公开 Key ID 和 256 位随机 Secret 组成。公开 Key ID 用于定位记录,Secret 用于证明持有权。

安全要求:

  1. Secret 使用密码学安全随机源生成,熵不少于 256 位。
  2. Secret 只在创建或轮换成功响应中展示一次。
  3. 服务端不保存明文 Secret;使用 KMS 保护的 Pepper 对 Secret 计算 HMAC-SHA-256 摘要,并把 pepper_version 与摘要一起保存。
  4. 摘要比较必须使用常量时间算法。
  5. 网关、WAF、APM 和应用日志必须统一脱敏 Authorization 请求头。
  6. 生产与非生产环境使用不同 Key;请求入口、Key、路由和后端端点必须属于同一环境,任何跨环境组合都拒绝。
  7. Pepper 轮换只用于新签发的 Secret 版本;旧 Pepper 在对应 Secret 版本全部失效前保持只读可用,禁止轮换时重新计算或批量作废存量摘要。

5.2 权限 Scope

权限采用三个层级的明确标识:平台、资源、操作。首批示例为:

Scope含义
webpay_inbox.payment.read查询 WebPay Inbox 支付信息
webpay_inbox.payment.submit向 WebPay Inbox 提交支付操作
bps.payment.read查询 BPS 支付信息
bps.payment.submit向 BPS 提交支付操作
zero_confirmation.payment.read查询 Zero Confirmation 支付信息
zero_confirmation.payment.submit向 Zero Confirmation 提交支付操作

实际资源和操作清单必须由各平台负责人逐项确认后发布。授权规则如下:

  1. 每条可访问路由必须声明一个明确的 required scope。
  2. API Key 必须拥有该 required scope,不能依赖前缀匹配或隐式通配权限。
  3. 新增路由在没有绑定 required scope 时不得发布。
  4. Scope 变更必须生成新配置版本并记录审计。
  5. 一个 API Key 可以显式拥有多个平台的 Scope。

5.3 API Key 与 IP 绑定

绑定粒度必须是 API Key,不是商户。一个 Key 可以绑定多个明确的 IPv4 地址、IPv6 地址或 CIDR 网段;一个 IP 只有在被显式绑定到某个 Key 后才能与该 Key 配合使用。

以同一商户拥有 Key A、Key B、IP A、IP B 为例,授权矩阵如下:

API Key来源 IP是否存在绑定结果
Key AIP A继续进行 Scope 校验
Key AIP B拒绝
Key BIP A拒绝
Key BIP B继续进行 Scope 校验

具体规则:

  1. 不允许把商户级 IP 列表自动应用到该商户的全部 Key。
  2. 同一个 IP 可以被多个 Key 使用,但每一组绑定都必须单独创建并审计。
  3. IPv4、IPv6 和 CIDR 在写入时必须规范化。默认自助配置只允许 IPv4 /32 和 IPv6 /128;IPv4 /29/31、IPv6 /64/127 必须提供业务原因并通过双人审批;IPv4 小于 /29 或 IPv6 小于 /64 一律拒绝。
  4. 数据面只信任边缘负载均衡传递的客户端 IP;来自公网请求的任意 X-Forwarded-For 值不得直接作为授权依据。
  5. 边缘层必须覆盖客户端自带的转发头,并通过受信网络或 PROXY Protocol 把原始 IP 传给网关。
  6. 无法可靠确定来源 IP 时默认拒绝,不允许退化为只校验 API Key。
  7. 商户使用动态出口 IP 或第三方 NAT 时,必须先完成固定出口或专线方案,不能通过放宽到互联网级 CIDR 解决。
  8. 同一 Key 下禁止保存重复或相互包含的网段;新绑定与现有网段重叠时,控制面必须拒绝并要求先原子替换绑定集合。

5.4 Key 生命周期

API Key 状态包括 pendingactivesuspendedrevokedexpired

  1. 创建:校验商户、环境、Scope 和 IP 绑定后生成 Key,Secret 仅展示一次。
  2. 启用:高权限生产 Key 通过审批后从 pending 进入 active
  3. 轮换:为同一逻辑 Key 创建新 Secret 版本,默认允许新旧版本并行 24 小时,之后旧版本自动失效。
  4. 暂停:用于短期风险处置,可由授权管理员恢复。
  5. 吊销:不可逆,必须在各地域快速传播。
  6. 过期:到达明确的 expires_at 后自动拒绝。

建议生产 Key 最长有效期为 180 天,并在到期前 30 天、14 天、7 天和 1 天通知责任人。该周期属于安全建议,需由安全与商户运营团队确认。

5.5 请求重放防护

静态 API Key 本质上属于 Bearer 凭据。TLS 与 Key 级 IP 绑定可以降低泄露和异地重放风险,但不能阻止在受信出口网络、TLS 终止点或日志链路中窃取凭据后的重放。

首个只读纵向切片可以在安全团队明确接受风险后使用 TLS、API Key 与 IP 绑定。任何 payment.submit 类生产路由在开放前必须满足以下两种方案之一:

  1. 商户使用 mTLS,客户端证书与 API Key 建立显式绑定,并执行证书吊销检查。
  2. 商户使用独立的 Ed25519 私钥对请求方法、规范化路径、请求体 SHA-256、UTC 时间戳、随机 Nonce、Idempotency-Key 和 API Key ID 进行签名;网关保存公钥,允许的时钟偏差为 5 分钟,Nonce 在 10 分钟内不得重复。

请求签名私钥由商户持有,网关不得接收或保存。Nonce 状态保存在允许写入故障转移地域之间的安全缓存中;该状态不可用且后端全局幂等能力未验证时,支付写请求失败关闭。TLS 在 WAF 终止还是透传到网关属于部署决策,但无论选择哪种方式,所有终止点都必须执行凭据日志脱敏并受最小权限控制。

5.6 访问控制中心

访问控制中心是“API Key 验证服务 + API Gateway 权限策略执行”的逻辑并集,不是一个新增的单体服务。验证服务只确认凭据、状态、环境与 Key-IP 绑定,并返回身份和 Scope;网关策略再判定路由可见性与 required scope。认证完成前可以暂存路由匹配结果,但不能据此返回差异响应。

%%{init: {"flowchart": {"curve": "linear", "nodeSpacing": 34, "rankSpacing": 38, "htmlLabels": true}}}%% flowchart TB REQUEST["统一接入层输出<br/>Key ID + Secret · 可信来源 IP<br/>入口环境 · 暂存 route match"] --> PARSE["解析公开 Key ID<br/>格式错误直接进入认证拒绝"] SNAPSHOT["本地域版本化快照<br/>Key · Secret 摘要 · 状态 · 环境<br/>Key-IP · Scope · 路由"] --> LOOKUP["读取记录并合并拒绝项<br/>校验 epoch / sequence 与有效期"] BREAKGLASS["独立 break-glass 通道<br/>已验签的本地域拒绝项"] -.-> LOOKUP subgraph VERIFY["组件 1 · API Key 验证服务"] direction LR PARSE --> LOOKUP LOOKUP --> CREDENTIAL["固定顺序验证<br/>Secret 常量时间比较 → 状态与时效<br/>→ 环境 → Key-IP 绑定"] CREDENTIAL --> AUTH{"身份认证通过?"} end AUTH -->|"否"| DENY401["统一 401<br/>内部记录精确 reason_code"] AUTH -->|"是"| IDENTITY["已验证身份<br/>merchant · key · Scope 集合<br/>配置版本"] subgraph POLICY["组件 2 · API Gateway 权限策略"] direction LR AUTHORIZE["读取暂存 route match<br/>路由可见性 · required scope"] AUTHORIZE --> ALLOWED{"路由存在且 Scope 充分?"} end IDENTITY --> AUTHORIZE ALLOWED -->|"否"| DENY404["统一 404<br/>路由不存在与 Scope 不足同语义"] ALLOWED -->|"是"| OUTPUT["输出到请求治理层<br/>已授权请求 + 可信身份上下文"] classDef input fill:#F4F7FB,stroke:#72849A,color:#253954,stroke-width:1.5px classDef runtime fill:#FFFFFF,stroke:#4F79A7,color:#18212F,stroke-width:1.5px classDef policy fill:#EDF8F3,stroke:#16835E,color:#124D3B,stroke-width:1.5px classDef reject fill:#FFF2EC,stroke:#C7582B,color:#6B2812,stroke-width:1.5px class REQUEST,SNAPSHOT,BREAKGLASS input class PARSE,LOOKUP,CREDENTIAL,AUTH,IDENTITY runtime class AUTHORIZE,ALLOWED,OUTPUT policy class DENY401,DENY404 reject style VERIFY fill:#F8FBFF,stroke:#B8CDEA,stroke-width:2px style POLICY fill:#F5FBF8,stroke:#AAD8C7,stroke-width:2px

本地域快照不是独立授权板块,它由第 10.1 节的发布链路产生,并由验证服务和网关策略在地域内读取。快照过期、版本不可确认或未知 Key 均失败关闭。break-glass 拒绝项与中央配置取并集,只能收缩访问,不能恢复 Key 或扩大 Scope。

6. 请求处理流程

6.1 请求治理与执行层

请求治理与执行层只接收第 5.6 节输出的已授权请求。廉价且能够保护系统容量的检查在前,支付写请求的密码学校验在后;路由策略中心的第二执行点只有在身份、路由和请求类型都可信后才选择后端。

%%{init: {"flowchart": {"curve": "linear", "nodeSpacing": 32, "rankSpacing": 38, "htmlLabels": true}}}%% flowchart TB INPUT["已授权请求<br/>可信身份 + Scope · route · request_class"] --> RATE["分层限流<br/>来源 IP · Key · 商户 · 平台"] RATE --> IDEMPOTENCY{"写请求或路由要求幂等?"} IDEMPOTENCY -->|"是"| IDEM_CHECK["校验 Idempotency-Key 语法<br/>只透传 · 去重由后端拥有"] IDEMPOTENCY -->|"否"| WRITE_SECURITY IDEM_CHECK --> WRITE_SECURITY{"生产支付写路由?"} WRITE_SECURITY -->|"是"| PROOF["持有证明<br/>Ed25519 签名 + Nonce<br/>或认证后校验 mTLS 证书绑定"] WRITE_SECURITY -->|"否"| ROUTE PROOF --> ROUTE["执行点 2 · 后端选择<br/>健康候选 · 读取一致性门禁<br/>writer 与跨地域写入门禁"] ROUTING["流量路由策略中心<br/>后端候选与故障转移策略"] -.-> ROUTE ROUTE --> HEADERS["清除外部伪造的内部身份头<br/>注入网关签名身份上下文"] HEADERS --> CALL["调用策略<br/>超时上限 · 熔断 · 有界重试<br/>非幂等写请求不自动重试"] CALL --> PLATFORM["一个明确的支付平台后端"] PLATFORM --> RESPONSE["响应规范化<br/>稳定错误码 + request_id"] classDef input fill:#F4F7FB,stroke:#72849A,color:#253954,stroke-width:1.5px classDef runtime fill:#FFFFFF,stroke:#4F79A7,color:#18212F,stroke-width:1.5px classDef policy fill:#EDF8F3,stroke:#16835E,color:#124D3B,stroke-width:1.5px classDef external fill:#F7F9FC,stroke:#8A9AAF,color:#18212F,stroke-width:1.5px class INPUT,ROUTING input class RATE,IDEMPOTENCY,IDEM_CHECK,WRITE_SECURITY,PROOF,HEADERS,CALL,RESPONSE runtime class ROUTE policy class PLATFORM external

mTLS 握手发生在第 4.1 节所述的实际 TLS 终止点;这里只校验证书上下文是否与已认证 API Key 显式绑定。Ed25519 的 Nonce 状态不可用且后端全局幂等能力未验证时,支付写请求失败关闭。路由执行点只输出一个目标,网关不向多个业务数据库双写。

跨抽象节点的请求时序

sequenceDiagram participant M as 商户系统 participant I as 统一接入层 participant A as 访问控制中心 participant C as 本地域配置快照缓存 participant G as 请求治理与执行层 participant S as 支付平台服务 M->>I: TLS 请求与 API Key I->>I: 入口选择、DDoS、TLS、WAF、协议与可信来源 I->>A: 规范请求、可信来源 IP 与 mTLS 上下文 A->>A: 生成 request_id 并暂存路由匹配结果 A->>C: 读取版本化授权快照 C-->>A: Key 摘要、状态、绑定、Scope、版本 A->>A: 身份、Key-IP、路由可见性与 Scope 判定 alt 身份与路由授权通过 A->>G: 已授权请求与可信身份上下文 G->>G: 限流、幂等、支付写安全与后端选择 G->>S: 转发请求和受信身份上下文 S-->>G: 平台响应 G-->>I: 规范化响应 I-->>M: 返回稳定响应 else 身份或 IP 认证拒绝 A-->>I: 统一 401,不暴露具体安全配置 I-->>M: 返回 401 与 request_id else 路由不存在或 Scope 不足 A-->>I: 统一 404,不暴露路由可见性 I-->>M: 返回 404 与 request_id end

该时序图只表达抽象边界与关键依赖之间的先后关系及 401/404 分支,不重复各节点的内部检查。本地域配置快照缓存是访问控制中心的内部依赖,不是新增抽象边界。流量路由策略中心不作为同步参与者:执行点 1 已包含在统一接入层,执行点 2 已包含在请求治理与执行层。

每个请求按以下固定顺序处理:

  1. 边缘层完成 TLS、WAF 和基础协议校验,得到可信来源 IP。
  2. 网关分配全局唯一 request_id,规范化路径、方法和请求头。
  3. 网关可以暂存内部路由匹配结果,但在认证完成前不得根据该结果返回不同响应。
  4. API Key 验证服务解析公开 Key ID,取得配置快照并验证 Secret 摘要。
  5. 验证 Key 的商户归属、入口环境、状态、生效时间和过期时间。
  6. 验证来源 IP 是否与该 Key 存在显式绑定;以上任一认证步骤失败都统一返回 401
  7. 认证成功后处理路由匹配结果;路由不存在或 Key 缺少 required scope 时统一返回 404,避免路由枚举。
  8. 对可见路由执行附加策略;明确允许披露的业务策略拒绝可以返回 403
  9. 执行 Key 级和商户级限流。只有 request_class 为写入,或路由策略明确要求幂等时,网关才强制 Idempotency-Key 必填并校验长度和字符格式;网关只透传该值,不保存去重状态,内容冲突由后端平台检测并返回 409
  10. 对支付写请求执行第 5.5 节规定的 mTLS 或 Ed25519 请求签名校验。
  11. 根据商户路由分区、服务能力声明和后端健康状态选择一个目标实例。
  12. 清除外部伪造的内部身份头,写入由网关签名的商户、Key、Scope、区域和请求标识。
  13. 执行带上限的连接、请求和响应超时,不对非幂等写请求自动重试。
  14. 写入结构化访问日志、授权决策日志、指标和分布式追踪。

6.2 对外错误语义

HTTP 状态使用场景对外信息
400协议、字段或幂等键不合法返回稳定错误码和 request_id
401Key 缺失、格式错误、未知、Secret 不匹配、状态无效、环境不符或 IP 未绑定统一返回认证失败,不区分具体原因
403身份和路由均可见,但明确可披露的附加业务策略拒绝返回稳定访问拒绝码,不披露安全配置
404路由不存在,或已认证 Key 缺少该路由的 required scope两种情况使用相同响应,避免路由枚举
409后端平台判定幂等键与已有请求内容冲突网关原样传递稳定冲突错误码,不在网关保存去重状态
429商户或 Key 超过限流策略返回可安全披露的重试时间
502后端协议错误返回 request_id
503授权组件或目标服务不可用返回 request_id 和可重试标记
504后端超时返回 request_id 和可重试标记

内部日志保留精确 reason_code,但对外响应不披露 Key 是否存在、绑定了哪些 IP 或拥有哪些权限。

7. 路由与多地域设计

7.1 路由模型

每条路由配置至少包含以下信息:

  • 唯一路由标识。
  • 平台和服务标识。
  • 运行环境。
  • 允许的 HTTP 方法和规范化路径规则。
  • required scope。
  • 读取或写入类型。
  • 超时、重试、请求体上限和限流策略。
  • 首选地域、允许的故障转移地域、后端服务标识和服务能力声明。
  • 配置版本、生效时间和回滚版本。

路由发布前必须通过静态校验:路由无冲突、required scope 存在、目标服务已注册、写请求明确声明幂等策略、超时有上限。

7.1.1 流量路由策略中心决策逻辑

流量路由策略中心维护一份版本化策略,但在两个位置执行。第一执行点位于全局入口,只负责选择入口地域;第二执行点位于地域网关,在 API Key 验证和路由匹配完成后选择后端。入口阶段使用的商户或平台提示未经认证,只能缩小入口候选集,不能授予权限;进入地域后必须以已验证身份复核,不一致时重新选择合格后端或拒绝请求。

%%{init: {"flowchart": {"curve": "linear", "nodeSpacing": 34, "rankSpacing": 38, "htmlLabels": true}}}%% flowchart TB PUBLISHED["已发布策略<br/>primary_region · allowed_regions<br/>服务能力 · failover_mode"] --> CENTER["流量路由策略中心<br/>编译版本化策略与运行状态视图"] RUNTIME["运行信号<br/>地域 / 后端健康 · 复制延迟 · writer 状态"] --> CENTER HINT["未认证路由提示<br/>仅用于选入口 · 不授予权限"] --> EDGE_FILTER["执行点 1 · 入口候选过滤<br/>allowed_regions · 合规 · 地域健康"] EDGE_FILTER --> MODE{"已配置策略模式"} MODE --> FIXED["设计基线 · 固定首选<br/>不自动切换"] MODE --> FAILOVER["设计基线 · 主备<br/>仅向合格备用地域切换"] MODE --> MULTI["建议选项 · 默认关闭<br/>allowed_regions 内权重 / 就近<br/>仅无状态读取"] FIXED --> ENTRY["入口地域决定<br/>失败时停止解析或返回 503<br/>取决于全局流量产品"] FAILOVER --> ENTRY MULTI --> ENTRY ENTRY --> AUTH["地域入口<br/>API Key 验证 + 路由匹配"] AUTH --> CONTEXT["已验证商户<br/>route + request_class"] CANDIDATES["执行点 2 · 认证后候选过滤<br/>服务已部署 · 健康<br/>配置按第 10.4 节有界陈旧"] CONTEXT --> CLASS{"请求类型"} CANDIDATES --> CLASS CLASS -->|"读取"| READ_GATE["读取门禁<br/>复制延迟不超过阈值<br/>状态信号未过期"] CLASS -->|"写入"| WRITE_GATE["写入门禁<br/>当前 writer 优先<br/>跨地域需全局幂等 · 唯一约束 · 显式切主"] READ_GATE --> ELIGIBLE{"过滤后有候选?"} WRITE_GATE --> ELIGIBLE ELIGIBLE -->|"是"| DECISION["输出路由决定<br/>target · reason_code · policy_version"] ELIGIBLE -->|"否"| REJECT["失败关闭<br/>返回 503"] CENTER -.->|"入口策略与状态视图"| EDGE_FILTER CENTER -.->|"地域内策略与状态视图"| CANDIDATES classDef input fill:#F4F7FB,stroke:#72849A,color:#253954,stroke-width:1.5px classDef policy fill:#EDF8F3,stroke:#16835E,color:#124D3B,stroke-width:1.5px classDef baseline fill:#EAF2FF,stroke:#1264D6,color:#12345B,stroke-width:1.5px classDef proposed fill:#FFF7E8,stroke:#B7791F,color:#62420F,stroke-width:1.5px classDef runtime fill:#FFFFFF,stroke:#4F79A7,color:#18212F,stroke-width:1.5px classDef reject fill:#FFF2EC,stroke:#C7582B,color:#6B2812,stroke-width:1.5px class PUBLISHED,RUNTIME,HINT,CONTEXT input class CENTER,EDGE_FILTER,MODE,CANDIDATES,CLASS,ELIGIBLE policy class FIXED,FAILOVER,ENTRY,AUTH,READ_GATE,WRITE_GATE,DECISION baseline class MULTI proposed class REJECT reject

会议只确认了多地域冗余和路由能力,没有确定具体算法。固定首选与主备模式是当前设计基线;权重或就近多活属于建议选项,默认关闭,只能在商户显式允许的地域集合内用于无状态读取。执行点 1 在认证前无法可靠判断请求类型;如果写请求被送到非 writer 地域,执行点 2 仍必须选择当前 writer 或返回 503,不得产生跨地域盲写。全局流量产品、TLS 终止点和认证前路由提示机制尚未确定,因此入口失败行为与可用输入需要在选型后确认。图中的 reason_code 只写入内部决策日志与审计,不对外披露;对外错误遵循第 6.2 节。

7.2 商户地域归属

为每个商户维护显式的首选地域和可用地域列表。流量路由策略中心把策略发布到两个执行点:全局入口优先把商户请求送到首选地域,地域内网关在认证后根据商户路由分区、服务能力和请求类型选择后端。

商户地域归属不能只依赖 DNS 解析地理位置,因为商户出口、专线接入点和业务数据所在地可能不同。地域策略必须由控制面配置并审计。

7.3 区域故障转移

  1. 网关数据面按多可用区部署,单实例或单可用区故障由区域负载均衡自动摘除。
  2. 流量路由策略中心的入口执行点确认地域不可用后,只把允许故障转移的商户切换到已配置且合格的备用地域。
  3. 每个平台接入时必须声明读取一致性等级、最大允许复制延迟、复制状态信号的采集方式和信号最大有效期。读取请求只有在备用地域上报的复制延迟不超过该路由的最大允许值,且状态信号未过期时才允许自动故障转移。
  4. 支付写请求只有在后端平台提供全局幂等键、唯一约束和明确的写入主地域切换机制时才能跨地域重试。
  5. 后端未满足跨地域写入前提时,网关返回可追踪的 503,禁止同时向两个地域写入。
  6. 区域恢复后采用受控回切,先验证授权配置版本和后端复制状态,再逐步恢复流量。

7.4 后端多数据库边界

会议提到 Zero Confirmation 可能使用三个数据库,BPS 未来也可能采用相似模式。网关只保存“商户或分区应路由到哪个后端服务”的元数据,不直接持有业务分库连接,也不拆分业务 SQL。

每个平台必须自行保证:

  1. 分区映射和业务数据库拓扑的一致性。
  2. 交易写入的唯一约束和幂等语义。
  3. 跨地域复制、恢复点和恢复时间。
  4. 数据库切换完成后向网关发布新的可用服务端点或路由版本。

7.5 控制面容灾

统一控制面采用跨地域主动与备用模式,任何时刻只允许一个控制面地域写入:

  1. PostgreSQL 在主地域内同步复制,在备用地域异步复制 WAL;备用地域复制延迟目标不超过 60 秒。
  2. 控制面版本使用 (epoch, sequence) 二段版本并按字典序比较。正常提交只递增 sequence,主地域切换时先递增 epoch 再从新的 sequence 开始,禁止两个地域产生可比较但分叉的版本。
  3. 主地域提升或备用地域接管前,必须通过托管数据库围栏或共识租约确认旧主节点已失去写权限;无法完成围栏时禁止接管。
  4. 控制面实例只有持有有效单写租约时才能接受管理写入,租约过期立即失败关闭。
  5. 备用地域 WAL 应用延迟超过 60 秒时停止接受普通配置写入并告警;紧急只拒绝操作改走第 10.3 节的 break-glass 通道。
  6. 接管后先恢复未发布 Outbox 事件,再以新 epoch 发布完整配置快照;各地域拒绝旧 epoch 的任何事件。
  7. 控制面建议恢复时间目标为 30 分钟,配置恢复点目标为 1 分钟;这两个目标必须通过季度恢复演练验证。

控制面故障不应中断已加载配置的数据面请求,但会暂停普通 Key 创建、轮换、Scope 变更、IP 变更和路由发布。

8. 数据模型

建议控制面使用以下关系模型。所有主键使用 UUID,所有时间使用 UTC,并在展示层转换时区。

关键字段关键约束
merchantsidexternal_refnamestatuscreated_atexternal_ref 全局唯一
api_keysidmerchant_idpublic_key_idenvironmentstatusnot_beforeexpires_atcreated_atpublic_key_id 全局唯一;商户外键不可空
api_key_secret_versionsidapi_key_idsecret_digestpepper_versionversionstatusvalid_fromvalid_until每个 Key 的 version 唯一;不保存明文 Secret;Pepper 版本外键不可空
api_key_signing_keysidapi_key_idalgorithmpublic_keystatusvalid_fromvalid_until只允许批准的非对称算法;不接收私钥
api_key_client_certificatesidapi_key_idcertificate_fingerprintissuer_refstatusvalid_fromvalid_until指纹与 Key 的绑定唯一;证书链必须来自批准的发行者
api_key_ip_bindingsidapi_key_idip_networkstatuscreated_at同一 Key 下规范化后的 ip_network 唯一;禁止重叠;执行第 5.3 节前缀限制
scopesidscope_nameplatformresourceactionstatusscope_name 全局唯一
api_key_scopesapi_key_idscope_idgranted_atgranted_byKey 与 Scope 联合唯一
routesidroute_nameenvironmentplatformmethodpath_rulerequired_scope_idservice_capability_idrequest_classpolicy_versionstatus数据库 CHECK 保证已发布路由具有 required scope、环境和服务能力声明
merchant_region_policiesmerchant_idenvironmentprimary_regionallowed_regionsfailover_modeversion每个商户和环境只有一条有效策略
service_capabilitiesidservice_nameenvironmentread_consistencymax_replication_lag_mssignal_max_age_secondssupports_global_idempotencyautomatic_read_failoverautomatic_write_failover每个服务与环境只有一条有效能力声明;能力提升需要审批
service_endpointsidservice_nameenvironmentregionendpoint_refhealth_policystatus服务、环境、地域和端点引用联合唯一
control_plane_epochsepochwriter_regionlease_idactivated_atfenced_previous_writer_at只追加;接管前必须记录旧主围栏证据
config_outboxidaggregate_typeaggregate_idconfig_epochconfig_sequenceevent_typepayloadpublished_at事件 ID 唯一;与配置写入同一事务;版本按 epoch 与 sequence 比较
admin_audit_logsidactor_idactionresource_typeresource_idbefore_digestafter_digestreasoncreated_at只追加,不允许更新和删除

IP 建议使用 PostgreSQL inet 类型。secret_digest、审计差异和 Outbox 载荷均需列级加密或磁盘加密;任何载荷都不得包含明文 Secret。

9. 管理接口

管理接口只允许从内部管理网络访问,并使用公司身份系统的短期访问令牌。建议提供以下固定资源接口:

方法与路径用途关键输入
POST /admin/v1/api-keys创建 Keymerchant_idenvironmentscopesip_bindingsexpires_atreason
GET /admin/v1/api-keys按商户、状态或环境查询 Key 元数据查询条件,不返回 Secret 或摘要
POST /admin/v1/api-key-rotations创建新 Secret 版本api_key_idoverlap_hoursreason
POST /admin/v1/api-key-signing-keys注册商户请求签名公钥api_key_idalgorithmpublic_keyvalid_untilreason
POST /admin/v1/api-key-client-certificates绑定 mTLS 客户端证书api_key_idcertificate_fingerprintissuer_refvalid_untilreason
POST /admin/v1/api-key-suspensions暂停 Keyapi_key_idreason
POST /admin/v1/api-key-revocations永久吊销 Keyapi_key_idreason
PUT /admin/v1/api-key-ip-bindings原子替换一个 Key 的 IP 绑定集合api_key_idip_bindingsexpected_versionreason
PUT /admin/v1/api-key-scopes原子替换一个 Key 的 Scope 集合api_key_idscopesexpected_versionreason
POST /admin/v1/routes/validations校验待发布路由配置完整路由配置和目标版本
POST /admin/v1/route-publications发布已校验的路由版本route_idexpected_versionreason

所有写接口必须支持幂等请求标识、乐观锁版本和操作原因。原子替换 IP 或 Scope 的响应必须返回替换前集合摘要和新版本号,供误操作审计与受控回滚使用。Secret 创建响应禁止被反向代理、APM 或审计中间件记录。

高风险操作包括生产 Key 创建、Scope 提权、扩大 IP 网段、允许跨地域写入和吊销恢复策略变更,建议要求双人审批。

10. 缓存与配置一致性

10.1 配置发布与运营中心

配置发布与运营中心有两条彼此独立的路径。普通变更走单写控制面、PostgreSQL 和 Outbox;紧急只拒绝路径使用不同网络、身份角色和硬件保护签名,在普通控制面不可用时仍可收缩访问。不可篡改审计写入属于本边界,可观测性中心只读取和关联这些记录。

%%{init: {"flowchart": {"curve": "linear", "nodeSpacing": 34, "rankSpacing": 38, "htmlLabels": true}}}%% flowchart TB subgraph STANDARD["普通配置发布 · 统一控制面单写"] direction TB ADMIN["内部管理后台 / 自动化系统"] --> ADMIN_API["Gateway Admin API<br/>内部身份 · 最小权限 · 双人审批"] ADMIN_API --> VALIDATE["配置不变量校验<br/>乐观锁 · 单写租约 · 旧主围栏"] VALIDATE --> TX["PostgreSQL 事实源<br/>同一事务写配置、审计与 Outbox<br/>(epoch, sequence)"] TX --> AUDIT["不可篡改审计存储<br/>操作者 · 审批 · 原因 · 变更摘要"] TX --> OUTBOX["事务 Outbox 与消息总线<br/>幂等发布 · 重放 · 版本对账"] OUTBOX --> ROUTE_SNAPSHOT["路由策略快照<br/>供流量路由策略中心"] OUTBOX --> ACCESS_SNAPSHOT["Key · IP · Scope 快照<br/>供访问控制中心"] OUTBOX --> GOVERN_SNAPSHOT["路由治理快照<br/>供请求治理与执行层"] end subgraph EMERGENCY["紧急只拒绝 · 独立安全通道"] direction LR SECURITY["安全事件指挥<br/>独立身份角色"] --> SIGNED["硬件签名拒绝指令<br/>只追加 Key / 商户 / IP 拒绝项"] SIGNED --> REGIONAL_DENY["各地域访问控制中心<br/>验签后与中央配置取并集"] SIGNED --> LOCAL_AUDIT["本地只追加审计副本<br/>恢复后归档到正式记录"] end classDef external fill:#F7F9FC,stroke:#8A9AAF,color:#18212F,stroke-width:1.5px classDef control fill:#F2F0FF,stroke:#6657C7,color:#292057,stroke-width:1.5px classDef output fill:#FFFFFF,stroke:#4F79A7,color:#18212F,stroke-width:1.5px classDef emergency fill:#FFF2EC,stroke:#C7582B,color:#6B2812,stroke-width:1.5px class ADMIN,SECURITY external class ADMIN_API,VALIDATE,TX,OUTBOX,AUDIT control class ROUTE_SNAPSHOT,ACCESS_SNAPSHOT,GOVERN_SNAPSHOT output class SIGNED,REGIONAL_DENY,LOCAL_AUDIT emergency style STANDARD fill:#FAF9FF,stroke:#C9C0F1,stroke-width:2px style EMERGENCY fill:#FFFAF7,stroke:#E8B69F,stroke-width:2px

普通发布流程如下:

  1. 控制面在同一 PostgreSQL 事务中更新配置和写入 Outbox 事件。
  2. 发布器把事件发送到消息总线,事件包含 (epoch, sequence) 配置版本。
  3. 各地域消费者幂等应用事件,先比较 epoch 再比较 sequence,拒绝旧版本覆盖新版本。
  4. 各地域的 API Key 验证服务维护 Redis 快照和进程内短缓存。
  5. 每个地域周期性执行全量版本对账,发现缺口后从事实源重建快照。

10.2 吊销优先级

吊销、暂停和 IP 移除属于安全事件,必须走高优先级通道,并向所有地域推送失效通知。建议目标为 99.9% 的安全变更在 10 秒内生效。

如果消息总线异常,各地域使用短周期版本轮询补偿。对于无法确认状态的新 Key 或未缓存 Key,数据面必须拒绝;不得为了可用性绕过授权。

10.3 紧急只拒绝通道

控制面或 PostgreSQL 不可用时,安全人员仍必须能够立即阻止泄露的 Key。每个地域提供独立的 break-glass 紧急封禁入口,并遵守以下约束:

  1. 入口仅允许新增对公开 Key ID、商户 ID 或来源 IP 的拒绝项,不能新增允许项、扩大权限或删除中央吊销记录。
  2. 指令使用硬件保护的内部安全签名密钥签名,各地域的 API Key 验证服务先验签再把拒绝项与中央配置做并集。
  3. 正常情况下需要两名授权安全人员审批;已声明的最高级安全事件允许事件指挥官先执行,第二名审批人必须在 15 分钟内复核。
  4. 地域本地拒绝项的初始租期为 24 小时。控制面仍不可用时,安全人员可以通过相同签名与审批流程续期;API Key 验证服务在距离到期 2 小时和 1 小时告警,且在控制面不可用、拒绝项尚未正式归档时不得因租期到期自动恢复允许。控制面恢复后必须转为正式暂停或吊销记录,未完成归档前不得提前删除。
  5. 每个地域把操作人、审批人、原因、签名摘要、接收时间和生效时间写入本地只追加审计存储。
  6. break-glass 入口与普通 Gateway Admin API 使用不同网络路径、身份角色和签名密钥,季度演练一次。

10.4 降级策略

故障行为
PostgreSQL 控制面主库不可用普通管理写入停止;数据面使用最后一次已验证快照继续服务;紧急封禁使用第 10.3 节通道
消息总线不可用控制面提交配置但标记为待发布;区域通过版本轮询补偿;发布完成前不宣告变更生效
地域 Redis 不可用API Key 验证服务使用有界的进程内快照;未知 Key 和超过快照有效期的 Key 拒绝;分布式限流降级为实例本地令牌桶,实例只能使用故障前已租用且未过期的配额份额,新实例配额为零,因此全部实例份额之和不得超过该商户或 Key 的全局配额
API Key 验证服务不可用网关认证失败关闭,返回 503,不绕过权限校验
单个后端实例不可用健康检查摘除并在同一服务池选择健康实例
整个后端地域不可用按第 7.3 节的读取与写入前提决定故障转移或返回 503

最后一次已验证快照的最大离线使用时间建议为 15 分钟。超过该时间仍无法取得新版本时,应拒绝高风险写请求;读取请求是否继续需要由各平台按风险分级确认。

11. 安全设计

  1. 外部链路最低使用 TLS 1.2,优先 TLS 1.3;内部服务间使用 mTLS。
  2. KMS 中的 Pepper 和内部签名密钥按环境、地域和用途隔离。Pepper 轮换按第 5.1 节保留旧版本,直到引用该版本的 Secret 全部失效。
  3. 管理员采用短期身份令牌和最小权限角色,不使用商户 API Key 调用管理接口。
  4. Key 创建、Scope 提权、IP 网段扩大、路由发布和跨地域写入开关变更全部审计。
  5. 网关覆盖外部传入的商户身份、权限、来源地域和内部追踪头,避免身份头伪造。
  6. 请求体大小、Header 数量、路径长度、连接数和并发数都有明确上限。
  7. 限流至少包含来源 IP、API Key、商户和平台四个维度,并支持紧急封禁。
  8. 访问日志不记录 Authorization、Cookie、支付卡数据、银行账户信息或完整请求体。
  9. 日志中的来源 IP 按敏感数据治理,限制查询权限并设置保留周期。
  10. 每季度执行 Key 权限复核,每半年执行一次跨地域故障演练和一次 API Key 泄露演练。

建议在详细设计阶段完成 STRIDE 威胁建模,重点覆盖伪造转发头、Key 枚举、Secret 泄露、缓存投毒、配置回滚、重放攻击、跨地域重复写和内部身份头伪造。

12. 可观测性与审计

12.1 可观测性与审计中心

可观测性与审计中心只接收有明确来源的事件:数据面运行与决策事件、普通控制面变更及事务内审计、break-glass 本地审计副本。它负责脱敏、关联和证据输出,不另起一套控制面审计写入链路。

%%{init: {"flowchart": {"curve": "linear", "nodeSpacing": 36, "rankSpacing": 40, "htmlLabels": true}}}%% flowchart TB DATA["数据面事件<br/>请求 · 授权决策 · 路由 · 后端健康"] --> INGEST["统一采集与缓冲<br/>事件 Schema · 背压 · 丢失检测"] CONTROL["普通控制面事件<br/>发布版本 · 传播状态 · 事务内审计"] --> INGEST EMERGENCY["break-glass 本地审计副本"] --> INGEST INGEST --> REDACT["敏感信息治理<br/>删除 Authorization 与支付字段<br/>脱敏 Key ID · 限制来源 IP 查询"] REDACT --> CORRELATE["跨域关联<br/>request_id · trace_id<br/>epoch · sequence · reason_code"] CORRELATE --> TELEMETRY["运行遥测<br/>结构化日志 · 指标 · 分布式追踪"] CORRELATE --> AUDIT_VIEW["只读审计索引与查询视图<br/>不替代事务内不可篡改审计"] TELEMETRY --> OUTCOME["输出<br/>仪表盘 · 实时告警 · SLO 测量<br/>故障证据 · 合规证据"] AUDIT_VIEW --> OUTCOME classDef input fill:#F4F7FB,stroke:#72849A,color:#253954,stroke-width:1.5px classDef process fill:#EDF8F3,stroke:#16835E,color:#124D3B,stroke-width:1.5px classDef store fill:#FFFFFF,stroke:#4F79A7,color:#18212F,stroke-width:1.5px class DATA,CONTROL,EMERGENCY input class INGEST,REDACT,CORRELATE,OUTCOME process class TELEMETRY,AUDIT_VIEW store

审计覆盖率以配置写事务为准,告警与合规查询以可观测性中心的关联结果为准。两者共享 request_id、配置版本和资源标识,但职责不重复。

12.2 核心指标

  • 请求量:按地域、平台、路由、商户和结果统计。
  • 延迟:网关总延迟、授权延迟、后端延迟,分别统计 P50、P95、P99。
  • 错误率:按 401403404429502503504 和内部 reason code 统计。
  • 授权:Key 未知、摘要失败、IP 不匹配、Scope 不足、Key 过期、Key 吊销。
  • 配置:控制面最新版本、各地域已应用版本、传播延迟、消费积压和对账差异。
  • 路由:后端健康实例数、熔断状态、重试次数和故障转移次数。
  • 安全:Key 枚举特征、异常 IP 变化、拒绝率突增和管理高风险操作。

12.3 日志与追踪字段

数据面结构化日志至少包含:timestamprequest_idtrace_idregionenvironmentroute_nameplatformmerchant_id、脱敏 Key ID、规范化来源 IP、授权结果、内部 reason code、配置 epoch、配置 sequence、HTTP 状态、请求耗时、后端耗时和失败域。

管理审计日志至少包含:操作者身份、审批人身份、资源、操作、原因、变更前后摘要、请求标识、来源系统和时间。

12.4 告警

以下事件应触发实时告警:

  1. 任一地域授权拒绝率相对过去 30 分钟基线显著上升。
  2. 区域配置版本落后控制面超过 30 秒。
  3. 安全变更传播超过 10 秒。
  4. 任一平台无健康后端或触发跨地域故障转移。
  5. 网关 P99 延迟或 5xx 比例超过 SLO。
  6. 单个 Key 在多个未绑定 IP 上连续认证失败。
  7. 高风险管理操作未完成双人审批或审计写入失败。

13. 建议 SLO 与容量原则

以下指标是设计建议,不是会议已确认承诺:

指标建议目标测量方法
地域内网关月可用性99.99%从受控外部探针使用有效测试 Key、已绑定 IP 和只读测试路由贯穿 WAF、网关与 API Key 验证服务;网关或 API Key 验证服务产生的 5xx 计失败
网关新增延迟,不含后端耗时P95 不高于 20 毫秒,P99 不高于 50 毫秒使用单调时钟计算网关总 span 减去 upstream wait span,按地域和路由聚合
普通配置传播99.9% 在 30 秒内到达所有健康地域从 PostgreSQL 提交时间到每个健康地域报告已加载相同 (epoch, sequence) 的时间
暂停、吊销和 IP 移除传播99.9% 在 10 秒内到达所有健康地域从中央提交或 break-glass 指令被接受,到各健康地域探针首次观察到拒绝的时间
单实例或单可用区故障恢复60 秒内自动摘除并恢复容量从注入故障到健康实例承接全部允许流量且错误率回到阈值内的时间
区域级网关故障恢复时间5 分钟内完成允许流量的切换从区域健康检查确认失效到备用地域连续 5 分钟满足成功率目标的时间
控制面恢复时间30 分钟内恢复单写管理能力从主地域被判定不可恢复到备用地域完成围栏、提升和首个新 epoch 写入的时间
网关配置恢复点不超过 1 分钟故障接管后核对最后确认提交与恢复后最大已恢复提交时间,丢失窗口不得超过 60 秒
控制面变更审计覆盖率100%每个成功写事务必须存在同一 request_id 的只追加审计记录
未授权请求测试拦截率100%第 14.1 节全部负向用例均被拒绝且无身份、路由和权限信息泄露

网关可用性 SLI 的分母是通过基础协议校验且到达地域入口的请求;客户端造成的 4xx 和已标记为后端失败域的 5xx 不计入网关失败,但必须另设端到端可用性 SLI。API Key 验证服务失败关闭产生的 503 属于网关失败并消耗错误预算。

按 30 天计算,99.99% 只允许约 4.32 分钟不可用。边缘入口、网关和 API Key 验证服务各自最多使用三分之一错误预算,对应各组件月可用性不低于 99.997%。Redis 不应成为每个请求的强同步依赖,进程内配置快照用于隔离其故障。该预算必须在技术选型后用实际依赖图重新计算,不能把组件 SLO 简单相乘后宣告达标。

健康地域定义为最近 30 秒持续上报数据面健康、配置版本和时钟同步状态的地域。传播 SLI 只排除已被流量路由策略中心入口执行点正式摘除的地域,不能因传播落后而把地域临时标记为不健康来规避统计。

会议材料没有提供峰值 QPS、平均请求体、响应体、连接持续时间、商户数量、API Key 数量或地域清单,因此当前不能给出可信的实例数与硬件定容。

定容前必须收集各平台最近 30 天的峰值 QPS、P95 与 P99 请求体、P95 与 P99 后端耗时、连接复用率、商户数量、每商户 Key 数量和 IP 绑定数量。压测应在 70% 目标容量下验证 SLO,并保留至少 30% 的区域内突发余量和一个可用区故障后的剩余承载能力。

14. 验证与验收

14.1 授权矩阵测试

必须覆盖以下自动化测试:

  1. 有效 Key、已绑定 IP、正确环境、拥有 required scope 时通过。
  2. 有效 Key 与同一商户的另一个未绑定 IP 组合时返回 401
  3. 同一商户的另一个 Key 与当前 IP 未绑定时返回 401
  4. Key 与 IP 已绑定但缺少 required scope 时返回 404,响应与真实不存在的路由一致。
  5. Key 未知、Secret 错误或凭据格式错误时统一返回 401
  6. Key 处于 pendingsuspendedrevokedexpired 时拒绝。
  7. 轮换窗口内新旧 Secret 都可用,窗口结束后只有新 Secret 可用。
  8. 客户端伪造 X-Forwarded-For 时不能改变授权使用的来源 IP。
  9. 路由未声明 required scope 时无法发布。
  10. 生产 Key 不能访问非生产环境,非生产 Key 不能访问生产环境。
  11. 未认证请求对存在和不存在的路由都返回相同的 401,不能枚举路由。
  12. Pepper 升级后,引用旧 Pepper 版本且仍在有效期内的 Secret 继续可验证,新 Secret 使用新 Pepper 版本。
  13. IPv4 小于 /29 或 IPv6 小于 /64 的绑定被拒绝,重叠网段不能写入。
  14. 支付写请求的签名时间戳超出 5 分钟、Nonce 在 10 分钟内重复、正文摘要不符或签名不正确时拒绝。

14.2 多地域与故障测试

  1. 停止一个网关实例,请求无感切换且无授权绕过。
  2. 停止一个可用区,区域剩余容量仍满足 SLO。
  3. 停止某一地域的 Redis,已知请求按有界快照策略处理,未知 Key 拒绝。
  4. 停止消息总线,配置标记为待发布,恢复后事件无丢失且按版本顺序收敛。
  5. 吊销一个 Key,验证所有健康地域在 10 秒目标内拒绝。
  6. 模拟整个地域不可用,只对满足策略的读取或幂等写入执行故障转移。
  7. 模拟备用地域业务数据库落后,确认网关不进行盲目跨地域写入。
  8. 恢复原地域,执行受控回切并验证配置版本和后端数据状态。
  9. 提升备用控制面前验证旧主写入已围栏;新控制面使用更高 epoch,所有地域拒绝旧 epoch 事件。
  10. 控制面与 PostgreSQL 同时不可用时,通过 break-glass 在全部健康地域封禁一个测试 Key,恢复后归档为正式吊销记录。
  11. Redis 故障后验证本地令牌桶配额总和不超过全局配额,并验证恢复时不会突发放大流量。
  12. 最后一次授权快照超过 15 分钟时,高风险写请求拒绝,读取请求遵循已批准的风险策略。
  13. 备用地域复制状态信号过期或延迟超过路由阈值时,读取请求不得自动故障转移。
  14. 旧配置版本覆盖被拒绝,429 和后端 409 语义保持稳定,IP 绑定原子替换期间不存在部分集合可见状态。

14.3 发布门禁

首个生产版本必须同时满足:

  1. 授权矩阵自动化测试通过率 100%。
  2. 安全变更传播、网关延迟和可用性达到第 13 节目标。
  3. 网关、WAF、APM 和审计日志扫描未发现明文 Secret。
  4. 完成单可用区故障演练、控制面实际接管演练、break-glass 实际封禁演练和区域级数据面桌面演练。
  5. 各首批平台负责人签署路由、required scope、幂等和故障转移策略。
  6. 安全团队完成威胁模型和渗透测试高风险项关闭。
  7. 运维团队确认仪表盘、告警、值班手册和回滚流程可用。

15. 分阶段实施计划

阶段 0:需求冻结与威胁建模

产出商户规模与流量基线、平台路由清单、Scope 清单、地域清单、后端幂等能力清单、数据合规约束和 STRIDE 威胁模型。没有这些输入,不进行生产定容。

阶段 1:单地域纵向切片

在非生产环境实现控制面最小闭环、Key 生命周期、Key 与 IP 绑定、Scope 授权、本地域配置快照、审计、限流和一条真实平台路由。建议优先以 Zero Confirmation 作为首条纵向切片,因为会议明确提到其多数据库和多地域设计将复用于 BPS。

阶段验收以真实客户端完成创建 Key、绑定 IP、授权调用、错误组合拒绝、轮换和吊销全过程为准。

阶段 2:首批平台统一接入

在非生产环境接入 WebPay Inbox、BPS 和 Zero Confirmation 经各平台负责人确认后的路由;建立每条路由的 required scope、超时、重试、幂等和限流策略;完成商户迁移、影子流量和兼容性测试。

阶段 3:多地域数据面

部署第二地域,打通配置分发、控制面围栏接管、地域版本对账、break-glass、流量路由策略中心的两个执行点、商户地域归属和只读故障转移,完成单可用区和地域级演练。首个生产网关版本只能在本阶段发布门禁全部通过后上线。

阶段 4:受控跨地域写入与平台扩展

仅对已经证明具备全局幂等、唯一约束和明确主地域切换机制的平台开放跨地域支付写入。形成标准接入模板,使未来平台通过路由、Scope、服务注册和验证清单接入。

16. 关键风险与缓解措施

风险影响缓解措施
把商户级 IP 误当成 Key 级 IP同一商户的 Key 与 IP 可被错误混用数据模型直接建立 api_key_idip_network 的绑定,授权矩阵进入发布门禁
信任客户端自带转发头可伪造来源 IP 绕过绑定边缘覆盖转发头,只信任受信代理链或 PROXY Protocol
每个请求查询中心数据库跨地域延迟和中心故障放大本地域版本化配置快照、版本化事件和周期对账
配置缓存过旧吊销或权限收缩不能及时生效高优先级失效事件、10 秒传播目标、短周期版本轮询
控制面故障时无法吊销泄露 Key攻击凭据在故障窗口内持续有效各地域 break-glass 只拒绝通道、硬件签名、本地只追加审计和季度演练
控制面双主或版本分叉区域配置无法确定新旧顺序单写围栏租约、主动与备用数据库、(epoch, sequence) 版本和接管演练
认证响应暴露 Key 或路由存在性攻击者枚举有效凭据和平台接口身份与 IP 失败统一 401,缺少 Scope 与路由不存在统一 404
网关自动重试支付写请求重复交易强制幂等键,非幂等写请求不自动重试
网关承担业务数据库双写跨库事务不一致且难以恢复网关只路由到一个明确后端,复制与切换由平台负责
单个超级 Scope 权限过大Key 泄露后横向影响多个平台按平台、资源、操作拆分 Scope,默认拒绝并定期复核
Secret 出现在日志或后台长期凭据泄露一次展示、日志头脱敏、摘要存储、泄露演练和定期轮换
Pepper 轮换导致全部存量 Key 失效商户请求大面积中断摘要记录 Pepper 版本,旧 Pepper 保留到对应 Secret 全部失效
静态 Key 被重放未授权重复读取或支付操作TLS、Key 级 IP 绑定、支付写入 mTLS 或 Ed25519 请求签名、后端全局幂等
运维配置过宽 CIDRIP 绑定失去隔离效果默认只允许单地址,较小网段双人审批,更宽网段拒绝,重叠网段禁止
多地域入口与数据地域不一致合规违规或读取陈旧数据显式商户地域策略,不仅依赖地理 DNS
业务流量未知容量和 SLO 缺少依据先收集 30 天流量基线,再压测和定容

17. 待业务与平台团队确认

以下信息在两份会议材料中没有出现,当前没有事实依据:

  1. WebPay Inbox、BPS 和 Zero Confirmation 的完整 API 路由、协议和版本。
  2. 各平台实际的读写语义、幂等能力、超时上限和重试约束。
  3. 生产地域、可用区、专线和公网入口清单。
  4. 逐字稿提及的 Zero Confirmation 三个数据库是否准确,以及其拓扑、复制方式、写入主节点和切换流程。
  5. BPS 是否已经具备多数据库或多地域能力。
  6. 商户数量、API Key 数量、每 Key IP 数量、峰值 QPS 和报文大小。
  7. 商户是否都有稳定出口 IP,是否存在共享 NAT、动态 IP 或第三方平台代理。
  8. API Key 由内部人员创建还是允许商户自助创建,以及审批责任人。
  9. 访问日志和审计日志的法定保留周期、数据驻留和隐私要求。
  10. 现有 Kubernetes、PostgreSQL、Redis、消息总线、KMS、WAF 和全局流量管理产品清单;全局流量产品将作为流量路由策略中心的入口执行点。
  11. 对外域名、证书体系和旧入口迁移兼容期。
  12. 建议 SLO、Key 有效期、24 小时轮换窗口和 15 分钟离线快照策略是否可接受。
  13. 外部 TLS 在 WAF 终止还是透传到网关,以及各终止点的日志、密钥和访问控制责任。
  14. 支付写请求采用 mTLS 还是 Ed25519 请求签名;只读接口是否接受 TLS 与 IP 绑定下的剩余重放风险。
  15. 各平台读取一致性等级、复制延迟信号来源、信号有效期和自动读取故障转移阈值。
  16. 认证前可用于入口地域选择的路由提示机制,以及提示信息的防枚举和隐私边界。
  17. 固定首选、主备故障转移和权重或就近路由分别适用于哪些商户、平台和请求类型。

上述事项不阻塞逻辑架构评审,但会阻塞生产定容、详细接口契约、跨地域支付写入和最终技术选型。其中第 1、2、4、8、14、15、16、17 项应在阶段 1 开始前完成确认。

18. 架构决策记录

ADR-001:统一 Gateway,平台授权保持细粒度

  • 决策:所有平台共享统一入口和授权模型,每条 Key 与每条路由保持明确 Scope。
  • 原因:满足会议提出的跨平台统一入口,同时避免一个平台的 Key 自动获得其他平台权限。
  • 后果:需要统一的路由与 Scope 注册流程,各平台不能私自绕过网关发布商户入口。

ADR-002:IP 绑定到具体 API Key

  • 决策:IP 绑定记录以 api_key_id 为外键,不使用商户级隐式白名单。
  • 原因:直接解决同一商户多个 Key 和多个 IP 被混用的问题。
  • 后果:商户新增 Key 时必须显式配置 IP;相同 IP 复用到多个 Key 时需要多条审计记录。

ADR-003:控制面集中、数据面区域自治

  • 决策:配置事实源集中管理,通过版本化事件分发到各地域的配置快照缓存,请求热路径不访问跨地域数据库。
  • 原因:兼顾统一控制、多地域低延迟与区域故障隔离。
  • 后果:必须建设可靠的配置传播、吊销失效、版本对账和有界陈旧策略。

ADR-004:网关不负责平台数据库双写

  • 决策:网关为每个请求选择一个明确后端,不直接写入多个业务数据库。
  • 原因:API Gateway 不具备解决支付业务跨库事务和数据冲突的上下文。
  • 后果:跨地域支付写入必须由平台先提供幂等、复制和主地域切换能力。

ADR-005:成熟代理与独立 API Key 验证服务分离

  • 决策:使用成熟 L7 代理处理网络与流量治理,使用独立 API Key 验证服务处理 Secret 摘要、Key 状态、环境和 Key-IP 绑定,并向网关返回 Scope 集合;网关权限策略执行路由可见性和 required scope。
  • 原因:减少自研代理风险,同时让凭据验证与路由权限决策各自保持可测试性和演进空间。
  • 后果:API Key 验证服务成为关键依赖,必须多实例部署、使用低延迟缓存并采用失败关闭策略。

ADR-006:认证失败与路由不可见性优先

  • 决策:Key、状态、环境和 IP 绑定失败统一返回 401;缺少 required scope 与路由不存在统一返回 404
  • 原因:避免利用状态码探测有效 Key、来源 IP 绑定和未授权平台路由。
  • 后果:商户只能通过 request_id 请求内部支持团队查看精确 reason code,不能从对外错误直接判断 IP 或 Scope 配置。

ADR-007:控制面采用围栏式单写容灾

  • 决策:控制面跨地域主动与备用部署,使用单写租约和 (epoch, sequence) 版本,旧主未围栏时禁止接管。
  • 原因:普通单调序号无法解决网络分区后的双主版本分叉。
  • 后果:控制面接管可能牺牲部分管理可用性,但不会让两个地域同时发布互相冲突的配置。

ADR-008:支付写请求增加持有证明

  • 决策:生产支付写路由在 API Key 与 IP 绑定之外,必须使用 mTLS 或 Ed25519 请求签名。
  • 原因:静态 Bearer Key 即使通过 TLS 传输,仍无法抵御凭据在受信网络或 TLS 终止点泄露后的重放。
  • 后果:商户需要管理客户端证书或签名私钥,网关需要证书吊销、公钥生命周期、时钟和 Nonce 状态能力。

ADR-009:业务幂等由后端平台拥有

  • 决策:网关只强制并透传 Idempotency-Key,不保存请求结果或判断内容冲突。
  • 原因:区域本地去重状态无法保证跨地域支付写入的一致性。
  • 后果:平台必须提供全局幂等和唯一约束,网关只透传后端产生的 409

19. Codex 与 Claude 架构会诊记录

19.1 审查方式

  • Codex 基于两份会议材料形成第一版设计并执行本地一致性检查。
  • Claude Code 版本为 2.1.201,请求模型与实际模型均为 claude-fable-5,effort 为 medium
  • Claude 仅使用 Read、Grep 和 Glob 读取会议材料与设计文档,没有获得写入或 Shell 权限,没有修改文件。
  • 第一轮执行对抗性架构审查,第二轮逐项验证问题闭环,第三轮只复核审查后收口的三项残余风险。

19.2 已接受并修正

  1. 认证与路由处理顺序会通过状态码暴露 Key 或路由存在性,已由 ADR-006 和第 6 节关闭。
  2. 控制面缺少跨地域容灾、单写围栏和无分叉版本,已由第 7.5 节和 ADR-007 关闭。
  3. 控制面故障时无法紧急封禁泄露 Key,已由第 10.3 节的区域只拒绝通道关闭。
  4. Pepper 轮换无法验证存量 Key,已增加 pepper_version 与旧版本保留规则。
  5. 网关与后端的幂等职责不清,已由第 6 节和 ADR-009 明确。
  6. Redis 故障时限流行为、环境隔离、CIDR 上限、SLI 测量、Bearer 重放防护、读取一致性信号和逐字稿证据强度均已补齐。
  7. 第二轮遗留的紧急拒绝续期、Redis 故障下扩缩容配额和幂等键适用范围,已在最终限定复核前收口。

19.3 已拒绝的质疑

  1. 授权组件故障时改为失败开放:拒绝。支付入口必须失败关闭,不能用可用性目标换取授权绕过。
  2. 把 Key 级 IP 绑定简化为商户级白名单:拒绝。该方案直接违背会议关于多 Key、多 IP 不得混用的要求。
  3. 由网关协调后端三个数据库写入:拒绝。跨库事务和账务一致性属于平台边界。
  4. 在缺少基础设施证据时直接锁定某一产品栈:拒绝。本文只保留可替换的推荐技术基线。

19.4 收敛结论

三轮只读审查后未发现未关闭的 blocker 或实质性矛盾。本文可以进入业务与工程评审,但状态仍是“设计建议”,不是“生产就绪”。第 17 节列出的事实缺口必须在对应实施阶段前关闭,所有建议 SLO、技术选型和故障策略必须通过真实基础设施、压测和演练验证。

第三轮仅留下两个非阻塞的详细设计事项:规定 break-glass 单次续期时长与累计续期审计口径;为 Redis 长时间故障叠加扩容时的吞吐下降编写人工处置手册。这两项不改变当前逻辑架构和交付结论。

19.5 流量路由策略中心专项会诊

  • Claude Code 版本为 2.1.201,请求模型与实际模型均为 claude-fable-5,effort 为 medium,仅使用 Read、Grep 和 Glob,没有修改文件。
  • 第一轮专项审查发现两个 blocker:入口地域选择与认证后后端选择被合并,以及认证前路由提示被误作可信身份。本文已采用“一份策略、两个执行点”关闭这两个问题。
  • 第一轮提出的入口失败语义、候选集过滤、有界陈旧、合规约束、术语一致性和建议选项标识六项实质性问题均已修正。
  • 第二轮对实际文件复核后确认没有剩余 blocker 或实质性问题,置信度为高,可以进入业务与工程评审。
  • 终审提出的两项非阻塞措辞改进已在终审后本地采纳:补充认证前误送写请求的 writer 门禁兜底,并明确 reason_code 仅用于内部日志与审计。两项调整不改变架构语义,因此未再发起外部复核。

19.6 抽象分层与节点展开专项会诊

  • 第一轮只读审查接受“8 节点总览 + 6 个抽象节点展开 + 1 张跨节点时序”的方向,并给出 8 项必须修改:入口执行点锚定、治理顺序、身份头清洗、访问控制双组件边界、break-glass 输入、审计职责拆分、总览悬空输入清理、mTLS 与 Ed25519 边界拆分。
  • 本文已逐项落实全部必须修改。静态检查确认 8 个 Mermaid 块与 HTML 中 8 个 Mermaid 容器一一对应,总览恰好 8 个节点,6 个展开小节均可定位,旧版地域相关歧义术语为零。
  • 第二轮只读复核逐项检查 10 项事实,结论为 accept,置信度为高;未发现 blocker、实质性问题、无根板块、重复责任或错误连线。
  • 第二轮提出的两项非阻塞可读性建议已在复核后本地采纳:把时序图描述改为“抽象边界与关键依赖”,并把已验证身份节点明确放在 API Key 验证服务与网关权限策略两个组件框之间。
  • 当前未取得浏览器级视觉验收证据。Chrome 自动化拒绝本地 file:// URL,Mermaid CLI 缺少指定版本的 Headless Chrome;因此本文不得把静态检查描述成真实渲染证据。该缺口不阻塞架构图信息设计评审,但阻塞 HTML 副本的对外发布,发布前必须在可用浏览器环境补齐 8 张图的渲染与截图验证。