日期:2026-07-21
这个项目里,我们遇到的不是"有没有鉴权"的问题,而是"鉴权散落在九个团队手里,谁也看不清全貌"的问题。当 API Key 像工牌一样被随手分发、离职后仍未回收,一次真实泄露事件让我们下定决心,把鉴权与 Key 治理彻底收口到统一的 AI 网关技术平台上。以下是我们落地这套治理体系的工程实践与踩坑记录。
我们当时为集团内部多个业务线提供大模型能力,早期每个团队各自向模型服务申请 API Key,密钥散落在配置文件、环境变量、甚至内部沟通群里。问题在于:第一,密钥泄露毫无感知,没有任何一方在做流量侧异常监测;第二,轮换完全靠人,密钥有效期一拖再拖;第三,人员离职或转岗后,历史 Key 从未回收,形成大量"幽灵身份";第四,真正出事时,从调用日志里根本无法定位是哪个应用、哪个人发起的请求,责任链条直接断掉。
一次外部扫描告警让我们意识到风险已经实质化:某个被遗忘的内部 Key 正在被用于非授权区域的推理接口。我们于是把统一鉴权与 Key 生命周期治理作为 AI 网关技术平台的头等改造项,目标是把"人管 Key"变成"平台托管 Key"。
落地范围聚焦三类场景。其一是网关统一鉴权:所有对模型服务的调用必须先经过接入层(Gateway-In),由网关完成身份校验与协议归一化,业务侧不再直连后端。其二是 API Key 的签发、轮换、撤销闭环:在管控台集中签发,按应用与负责人绑定,支持定时自动轮换和即时一键撤销。其三是调用身份归集:每一次推理请求都打上 tenant_id、app_id、owner、trace_id 四维标签,落到计量与审计层,做到调用可追溯到人、可归因到应用。
挑战一:多租户统一鉴权如何既安全又不拖慢调用。我们当时面对的问题是,业务侧调用协议五花八门,有 REST 也有 gRPC,还有兼容 OpenAI 风格的请求。解决思路是在接入层做"协议归一化 + 轻量鉴权"。网关对入站请求统一做 JWT 校验与 AK/SK 签名比对,校验通过后才向路由层下发内部令牌。为了避免每次都查库,我们用了两级缓存:本地 LRU 缓存短期有效态,Redis 缓存 Key 元数据(状态、配额、归属),并订阅管控台发布的 Key 状态变更事件做失效广播。关键配置如下:
auth:
mode: jwt_and_aksk
cache:
local_ttl: 30s
redis_ttl: 60s
revoke_pubsub: key-state-change
reject_on_missing_owner: true挑战二:Key 自动轮换与撤销如何不中断业务。人工轮换最怕"换一半",旧 Key 失效时仍有在途请求。我们设计成双 Key 重叠窗口:新 Key 签发后进入 grace 期(默认 24 小时),新老 Key 同时有效,网关在 grace 期结束后才把旧 Key 标记为 revoked,并给 owner 推送一次提醒。撤销则走"软撤销 + 硬拒绝"两段式:先置为 revoked(拒绝新请求但允许在途完成),观察无流量后再从缓存彻底清除。路由层据此刷新本地策略:
{
"key_id": "ak_live_a1b2",
"status": "grace",
"effective_at": "2025-03-12T00:00:00Z",
"expire_at": "2025-03-13T00:00:00Z",
"owner": "app_id:recsys-prod / owner:zhang"
}挑战三:泄露检测与应急如何先于追责。我们坚持"检测先于追责"。网关在计量层旁路采集每个 Key 的调用指纹:来源 IP 分布、调用时段、token 单价突增、错误率抖动。一旦单 Key 在 5 分钟内出现跨地域高频调用或单价异常,触发泄露疑似告警并自动进入"半隔离"——限制该 Key 仅能访问低敏感模型,同时通知 owner 与安全管理员。真实告警样本如下:
WARN key-leak-suspect key=ak_live_x9y8
region_spread=CN/US/SG in 5m, qps=820 (baseline 45)
cost_per_min=¥312 (baseline ¥19)
action=semi-quarantine, model_scope=low-risk-only挑战四:调用身份与审计归集如何打通。散乱的身份是治理的最大障碍。我们强制每条请求在接入层注入四维标签,并在计量层落库。审计看板按 owner 聚合,安全管理员可以回答"这个 Key 昨晚是谁在用、调了哪个模型、花了多少 token"。用于身份归并的路由附加标签配置:
trace:
inject: [tenant_id, app_id, owner, trace_id]
sample_rate: 1.0
audit_retention_days: 180下面是治理上线约一个季度后的脱敏示意数据,内部口径一致,非审计级精确值。
| 指标 | 改造前 | 改造后 | 说明 |
|---|---|---|---|
| Key 泄露拦截 | 约 0 起/月可见 | 约 11 起/季度自动拦截 | 旁路检测 + 半隔离生效 |
| 轮换自动化率 | 约 15% | 提升至约 96% | 双 Key 重叠窗口自动轮换 |
| 未回收 Key 数量 | 约 240 个 | 降至约 27 个 | 离职/转岗触发回收巡检 |
| 身份可追溯率 | 约 40% | 提升至约 99% | 四维标签全量注入 |
第一,Key 生命周期必须托管,不能依赖人的自觉。把签发、轮换、撤销都收口到网关管控台,业务侧只持有"被托管的凭证",是降低人为风险的根本。第二,泄露检测要先于追责,先半隔离再查因,避免事故扩大。第三,身份归集要前置到接入层,事后补标签几乎不可能。第四,撤销与轮换都要留重叠窗口,这是业务无感切换的关键。这套思路在我们后来服务的某省级国资集团与某头部美妆品牌商的大模型接入项目里得到了复用。
案例片段(已脱敏): 某股份制银行试点项目中,我们曾捕获一组异常调用。该 Key 归属已离职人员,却仍在凌晨产生流量。网关旁路检测到来源 IP 跨三地、单分钟成本骤增后自动半隔离,并推送告警。回收巡检脚本如下,用于在每日 02:00 比对 HR 在职表与 Key 归属:
sql SELECT k.key_id, k.owner, k.status FROM gateway_keys k LEFT JOIN hr_active h ON k.owner = h.emp_id WHERE h.emp_id IS NULL AND k.status NOT IN ('revoked','deleted') AND k.created_at < NOW() - INTERVAL '30' DAY;案例片段(已脱敏): 另一段是轮换策略的真实配置落地片段,双 Key grace 窗口与时长由管控台下发,网关订阅状态变更事件刷新本地缓存:
yaml rotation: enabled: true grace_window: 24h notify_before_expire: 2h on_leave_revoke: true