# ADR-0051: Cluster Authentication Overload Shield - 状态:Proposed - 日期:2026-07-19 - 关联 RFC:QL-RFC-0001 D-05、D-35、D-40、D-43、D-44、D-47、D-50 ## 上下文 ADR-0045 至 ADR-0049 已把 `/api/v3` 固定为有界 HTTP host,以及 route → Authentication → Policy → durable security audit → body → handler 的两阶段 admission。真实 bearer authentication 仍需要一次 PostgreSQL credential point lookup;攻击者不必持有合法 credential,就能用大量格式正确或错误的请求消耗连接池、审计写入和 CPU。仅靠 `maxInFlightRequests` 会在数据库工作已经开始后才体现压力,不能保护认证依赖。 QingLong 3.0 同时服务单副本、小规格集群和多副本控制面。把认证限流直接做成 PostgreSQL 或 Redis 权威配额会让滥用流量继续占用要保护的依赖,并为小集群增加新基础设施;只按 bearer/credential 限流则必须先查库,而且无法约束匿名攻击。反向代理部署还存在共享出口与伪造 forwarded header 的边界,不能默认把任意 `X-Forwarded-For` 当成身份。 ## 决策 ### 1. 在 transport admission 建立认证前资源护盾 cluster-control HTTP host 在以下检查之后启用护盾: 1. URL 有界且可解析; 2. liveness/readiness probe 已分流; 3. path 位于 `/api/v3` namespace; 4. application admission 已完成安装。 护盾在 method validation、route registry、Authentication、PostgreSQL、durable security audit 和 body 读取之前消费预算。未 ready 请求不消耗预算,probe 永不受该预算影响。通过护盾不代表认证或授权成功;它只表示本副本当前愿意为该请求支付安全 admission 成本。 ### 2. 每个副本使用双固定窗口与有界 peer 表 每个 cluster-control 进程维护: - 每 transport peer 的固定窗口预算,默认 `300 / 60s`; - 本副本全局固定窗口预算,默认 `1200 / 60s`; - 最多 `4096` 个 peer 指纹; - 每次新 peer 最多检查 `64` 个旧条目做惰性过期回收。 实现不创建 timer、后台任务、外部连接或无界集合。窗口、peer/global budget 和 peer 表均有启动配置硬上限;表已满且无法在有界扫描内回收时 fail closed。关闭 HTTP surface 时立即清空状态和指纹 key。 该状态刻意是 disposable、process-local 的 overload protection,不是跨副本安全事实、计费配额或公平调度权威。多副本总预算由部署副本数放大;需要全局业务 quota 时必须在已认证主体和 Project 上另建 durable policy,而不能把本护盾升级为隐式共享事实源。 ### 3. 只信任 socket transport peer peer key 只来自 Node TCP socket 的 `remoteAddress`。`Forwarded`、`X-Forwarded-For`、`X-Real-IP` 和任意业务 header 都不得影响首版限流;缺失、超长或含控制字符的地址进入同一个 fail-closed unknown bucket。 部署在 L4/L7 proxy 后时,所有请求可能共享 proxy peer budget。运维方可以提高 per-peer budget、依赖本副本 global budget,或降低每个 pod 的入口流量。未来若支持客户端地址传播,必须新增显式 trusted-proxy allowlist、固定 hop 解析和 spoofing contract,不能静默改变本 ADR 的信任边界。 ### 4. 内存中不保存原始 peer 地址 进程启动时生成 32-byte 随机 key,对 domain-separated transport peer 做 HMAC-SHA-256,只以指纹作为 Map key。原始地址只在单次调用栈中短暂存在,不进入 event、日志、durable audit 或 wire response;关闭时清零 key。 ### 5. 稳定 wire 与低基数观测 peer/global/capacity 超限统一返回 `429 authentication_rate_limited` 和整数秒 `Retry-After`。单调时钟异常或护盾不可用返回 `503 authentication_shield_unavailable`。护盾拒绝以及 route/Authentication/Policy/audit 等所有 pre-body 拒绝都固定关闭 HTTP/1.1 connection,避免未读取 body 或 pipeline 数据继续占用可复用 socket。响应不暴露 peer、窗口计数、credential existence 或具体部署容量。 HTTP surface 提供同步、不可改变 admission 结果的低基数 event hook,只包含: - `outcome`: `rate_limited | unavailable`; - `reason`: `peer | global | capacity | clock`。 hook 抛错会被吞掉,不能形成新的可用性依赖。transport 护盾拒绝发生在 Authentication 之前,因此不是 ADR-0049 的认证决策,也不为每个攻击请求写 PostgreSQL security audit;否则攻击者可以通过审计 INSERT 反向耗尽要保护的数据库。生产观测应把 hook 接入有界 counter,并在聚合阈值上告警。 ### 6. Profile 与配置边界 配置只进入 cluster-control Profile: - `QL3_CLUSTER_AUTH_RATE_WINDOW_MS`; - `QL3_CLUSTER_AUTH_RATE_PER_PEER`; - `QL3_CLUSTER_AUTH_RATE_GLOBAL`; - `QL3_CLUSTER_AUTH_RATE_MAX_PEERS`。 edge/standalone 不安装 cluster-control 包,也不承担该状态或 crypto/cluster 依赖。该护盾不替代 edge 本机登录、cluster-admin ceremony、人工 recovery、Worker enrollment 或业务 Project quota 各自的限流设计。 ## 被否决的替代方案 ### PostgreSQL/Redis 全局 token bucket 拒绝作为认证前护盾。匿名滥用仍会打到网络依赖和连接池,Redis 又成为小型部署的新强制依赖与可用性门禁。它可用于认证后的业务 quota,但职责不同。 ### 只按 credential、subject 或 Project 限流 拒绝作为第一层。取得这些事实需要完成 token 解析和 PostgreSQL Authentication,无法保护认证路径本身;攻击者还可以持续发送不存在的 credential ID。 ### 默认信任 `X-Forwarded-For` 拒绝。没有显式 trusted proxy 与 hop contract 时客户端可伪造无限 peer key,既绕过 per-peer budget,也耗尽 peer 表。 ### 无界 sliding window、每 peer timer 或请求日志 拒绝。它们分别引入无界时间戳集合、大量 timer 或攻击者可控的日志写放大,不适合作为控制面资源保护边界。 ## 影响 ### 正向 - 匿名攻击在 body、credential lookup、Policy 和 audit INSERT 之前被限制; - 不新增 PostgreSQL 表、Redis、timer 或跨副本一致性依赖; - 内存和每请求回收工作有硬上限,peer 原始地址不保留; - probe/readiness 和 admission drain 语义保持不变; - edge/standalone 产物依赖方向不变。 ### 代价与未完成项 - process-local 限制随副本数线性放大,不提供全局精确配额; - proxy/NAT 后多个客户端共享 peer budget,需要显式调参; - 固定窗口允许边界突发,首版以实现可审查和常数状态优先; - 管理 API、人工 recovery、Worker enrollment、异常 credential 告警和认证后 Project quota 仍需各自策略; - 需要在独立 cluster 镜像与真实入口代理下测量默认值,而不是把开发机默认值视为最终容量结论。 ## 验证 1. 单元测试覆盖 peer/global/capacity、窗口回收、时钟回退和 dispose fail-closed。 2. HTTP 测试证明未 ready 请求与 probe 不消耗预算,超限在 admission/body 前返回。 3. HTTP 测试使用不同 `X-Forwarded-For` 仍命中同一 socket peer budget。 4. 配置测试覆盖四个环境变量的默认值和硬上限。 5. Node 22/24 contract、edge/cluster dependency audit 与 GitNexus detect-changes 继续作为合并门禁。