大模型应用通常先从一个环境变量开始:OPENAI_API_KEY、云厂商访问密钥,或者某个模型平台的项目级 Token。原型阶段这样做很快,但进入多环境、多租户和多供应商架构后,长期静态密钥会带来三个致命问题。
为什么 LLM API Key 会成为生产系统的薄弱点
第一,凭证生命周期远长于一次推理请求。 密钥一旦出现在代码仓库、客户端、日志、CI 变量导出或故障排查包中,攻击者可能持续调用模型,直到团队发现异常并主动撤销。
第二,身份与调用主体脱节。 多个服务共享同一个 Key 后,供应商只能看到”这个 Key 调用了模型”,无法可靠区分是哪个工作负载、哪个租户或哪次发布产生的请求。
第三,密钥泄漏会直接转化为费用和可用性风险。 攻击者不需要进入核心数据库,只要拿到模型凭证,就可能消耗配额、触发账单、挤占速率限制,并造成正常业务被限流。
OpenAI 的官方安全建议明确要求不要把 API Key 部署到浏览器或移动端、不要提交到代码仓库,并建议使用 Key Management Service、监控用量、及时轮换以及配置 IP allowlist。对于支持云身份的模型服务,则应进一步减少长期密钥的存在时间。
核心原则:把”密钥”改造成”可验证的工作负载身份”
生产级凭证体系不应让每个业务服务自行保存供应商密钥,而应拆成四个层次:
- 工作负载身份:运行中的 Pod、VM、函数或作业拥有可验证的机器身份。
- 令牌交换或临时凭证:身份系统根据目标资源、作用域和策略签发短期令牌。
- 模型调用授权:模型平台只允许指定主体调用指定模型、区域或部署。
- 审计与撤销:记录主体、目标资源和授权结果,但不记录令牌本身。
可以把调用链抽象为:
Workload Identity
|
v
Identity Provider / STS
|
v
Short-lived Credential
|
v
LLM Endpoint with Least Privilege
这里的关键不是把静态 Key 换成另一个更复杂的静态 Secret,而是让凭证具备三个属性:短生命周期、目标受限、主体可追踪。
OAuth 2.0 Token Exchange 的 RFC 8693 定义了通过 Security Token Service 交换安全令牌的标准机制。客户端可以声明目标 resource、audience 和 scope,由授权服务器签发适用于下游服务的令牌。这类机制正是跨云工作负载身份和短期访问令牌的基础。
三种生产落地模式
模式一:模型平台原生支持工作负载身份
这是优先级最高的方案,因为应用进程不需要接触长期供应商密钥。
Azure OpenAI 可使用 Microsoft Entra ID 和 Managed Identity。运行在 Azure VM、函数、容器或其他支持资源上的应用,可以通过 DefaultAzureCredential 获取 Entra Token,通过 RBAC 控制对 Azure OpenAI 资源的访问。
from azure.identity import DefaultAzureCredential, get_bearer_token_provider
credential = DefaultAzureCredential()
token_provider = get_bearer_token_provider(
credential,
"https://ai.azure.com/.default",
)
# 将 token_provider 交给支持 Entra ID 的 Azure OpenAI 客户端。
# 应用代码不保存长期 API Key。
Amazon Bedrock 与 IAM 集成,支持身份策略、资源、条件键、ABAC 和临时凭证。运行在 EC2、ECS、EKS 或 Lambda 上的应用应使用 IAM Role,让 AWS SDK 通过默认凭证链获取动态临时凭证,而不是在配置中写入长期 Access Key。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": "arn:aws:bedrock:REGION::foundation-model/MODEL_ID"
}
]
}
实际部署时应根据所用模型、推理配置和 AWS 文档确认可使用的资源 ARN,不要为了省事直接授权所有 Bedrock 操作。
Vertex AI 可通过 Google Cloud Workload Identity Federation,让 AWS、Azure、Kubernetes、GitHub Actions 或自建 OIDC 工作负载以联合身份访问 Google Cloud,而不是分发 Service Account Key。Google 的 STS 会验证外部身份并签发联合令牌,随后可获得短期 OAuth 2.0 Access Token。
模式二:供应商只支持 API Key,由凭证代理集中托管
并非所有 LLM SaaS 都提供工作负载身份或短期令牌。此时不能宣称”无密钥”,但可以把风险压缩到一个受控边界内。
推荐结构是:
Business Service -> Internal LLM Gateway -> Secret Manager / KMS -> External LLM API
业务服务只使用内部服务身份访问 LLM Gateway。Gateway 根据租户、环境和目标供应商选择凭证,并在服务端附加外部 API Key。原始 Key 不返回给业务服务,也不进入浏览器、移动端或日志。
凭证至少按以下维度隔离:
| 隔离维度 | 说明 |
|---|---|
| 环境 | 生产、预发布和开发环境分别使用不同凭证 |
| 租户 | 高风险或高消费租户使用独立项目或独立 Key |
| 工作负载类型 | 交互请求、离线 Batch 和评测作业使用不同凭证 |
| 访问控制 | 只允许 Gateway 身份读取指定 Secret,禁止列出全部 Secret |
模式三:多云环境通过联合身份交换短期凭证
如果工作负载运行在一朵云,而模型服务位于另一朵云,不应把目标云的长期密钥复制到源云。更稳妥的做法是建立 OIDC 或其他联合信任关系:
- 源环境为工作负载签发可验证的身份 Token。
- 目标云 STS 验证 Issuer、Audience、Subject 和声明条件。
- STS 只签发访问特定模型资源的短期 Token。
- 应用通过 SDK 自动刷新,不落盘长期密钥。
Google Workload Identity Federation 明确支持 AWS、Azure、Kubernetes、GitHub、GitLab 和其他 OIDC/SAML 身份源;AWS STS 也支持 OIDC Federation 和临时安全凭证。
凭证缓存不是普通缓存
短期令牌不能每次请求都重新获取,否则身份服务会成为延迟和可用性瓶颈;但也不能像普通配置一样长期缓存。
建议为凭证缓存定义独立键:
type CredentialCacheKey = {
provider: string;
tenantScope: string;
environment: "dev" | "staging" | "prod";
audience: string;
scopes: string[];
principal: string;
};
缓存刷新应满足以下规则:
- 使用
expires_at - safety_margin作为刷新时间,而不是等到令牌真正过期。 - 加入随机抖动,避免大批实例在同一秒刷新。
- 使用 singleflight 或分布式锁合并同一个缓存键的刷新请求。
- 新令牌获取失败时,仅在旧令牌仍有效且权限完全一致时短暂复用。
- 认证失败不能无限重试,避免把权限配置错误放大成 STS 风暴。
- 不允许跨租户复用包含租户约束的凭证。
最小权限要落到模型资源和调用动作
只做到”身份认证成功”还不够。真正的风险边界取决于身份可以调用什么。
按环境隔离
开发身份不应拥有生产模型权限。生产身份也不应读取开发团队的全部供应商凭证。云账号、项目、订阅或资源组应与环境边界一致。
按动作隔离
推理服务通常只需要模型调用权限,不需要创建模型、修改部署、管理知识库或调整 IAM。在线推理和平台管理应使用不同身份。
按模型与区域隔离
允许调用通用低成本模型,不代表可以调用高成本模型、实验模型或其他区域的端点。供应商支持资源级权限时,应把授权范围收缩到实际模型或部署。
按租户隔离
租户不能直接提交 credential_id、任意 Base URL 或供应商项目 ID。Gateway 应根据可信租户上下文映射凭证和模型策略,避免客户端通过参数切换到其他租户的凭证。
静态 Key 无法消除时,如何安全轮换
轮换不应是”覆盖环境变量然后重启所有服务”,这容易造成瞬时认证失败,也无法确认旧 Key 是否仍在被使用。
更稳妥的流程是:
- 创建新 Key,并保持旧 Key 暂时可用。
- 将新 Key 写入 Secret Manager 的新版本。
- 让 Gateway 支持版本化读取,并先在少量实例启用新版本。
- 检查认证错误、调用量和供应商账单归属。
- 全量切换后,观察旧 Key 是否仍有请求。
- 撤销旧 Key,并验证没有隐藏消费者。
- 将泄漏演练、应急撤销和调用方清单纳入定期检查。
静态 Key 回退必须是显式策略。当工作负载身份故障时,系统不应悄悄切换到一个权限更大的通用 Key。确需回退时,应限制持续时间、模型范围和调用预算,并产生高优先级告警。
审计日志应该记录什么
凭证治理的日志目标是回答”谁以什么身份访问了哪个模型”,而不是记录秘密。
建议记录:
| 字段 | 说明 |
|---|---|
| provider, model_resource, region | 目标模型信息 |
| credential_source | managed_identity、sts、wif、secret_manager |
| 工作负载主体 | 主体标识或其不可逆哈希 |
| 租户、环境、发布版本 | 业务上下文 |
| Token 剩余有效期区间 | 不含 Token 内容 |
| 授权结果、错误类别 | 策略命中原因 |
| 成本关联 ID | Token 用量追踪 |
禁止记录:
- Authorization Header
- API Key、Access Token、Refresh Token
- Secret Manager 返回值
- 包含凭证的完整异常对象
- 为排障临时打印的 SDK 配置
需要重点告警的事件包括:静态 Key 使用比例突然上升、某身份开始访问新模型或新区域、认证失败集中爆发、过期令牌被重复使用、同一凭证从异常网络来源出现,以及模型费用与正常基线明显偏离。
常见误区
误区一:放进 Secret Manager 就等于没有静态密钥。 Secret Manager 解决的是存储、访问控制和轮换问题,Key 本身仍是长期凭证。应继续限制读取主体、网络出口、使用范围和轮换周期。
误区二:所有服务共享一个组织级 Key 更方便。 共享 Key 会扩大爆炸半径,并破坏费用归属和调用方追踪。至少应按环境、工作负载和风险级别拆分。
误区三:令牌越短越安全,直接设置极短有效期。 过短的令牌会增加 STS 压力,并在网络抖动时制造大量认证失败。有效期、刷新余量、缓存和故障恢复必须一起设计。
误区四:认证失败就自动回退到管理员 Key。 这会把最小权限故障升级为高权限访问。回退凭证必须权限更小、预算更低、时间更短,并经过显式审批。
误区五:只关注密钥,不限制模型资源。 一个安全保存但拥有全模型、全区域和管理权限的 Key,仍然是高风险凭证。最小权限和资源边界与秘密存储同等重要。
上线检查清单
- 浏览器、移动端和桌面客户端不包含供应商 API Key。
- 代码仓库、镜像层、CI 日志和构建产物已完成凭证扫描。
- Azure、AWS、Google Cloud 场景优先采用 Managed Identity、IAM Role 或 Workload Identity Federation。
- SaaS API Key 仅由后端 Gateway 和 Secret Manager 接触。
- 开发、预发布、生产环境的身份和凭证完全隔离。
- 权限已限制到实际调用动作、模型和区域。
- 短期令牌缓存包含安全余量、抖动和 singleflight。
- 静态 Key 回退是显式、限时、限预算策略。
- 日志不包含任何 Authorization Header 或秘密值。
- 已建立认证错误、静态 Key 使用率和异常费用告警。
- 轮换流程经过双 Key 切换与旧 Key 撤销演练。
- 应急手册能够在分钟级完成凭证冻结和调用方定位。
适用场景
这套方案尤其适合:
- 同时调用 Azure OpenAI、Bedrock、Vertex AI 和直接 SaaS API 的多供应商平台。
- 多租户 SaaS,需要限制不同客户可用模型、预算与区域。
- Kubernetes、Serverless 和频繁扩缩容的推理网关。
- CI/CD、离线评测与 Batch 推理任务。
- 对密钥泄漏、异常账单和审计追踪有严格要求的企业系统。
小型内部原型可以先使用环境变量,但只要进入真实用户、生产数据或自动付费环境,就应规划向 Secret Manager、工作负载身份和短期凭证迁移。
参考资料
- OpenAI, Best Practices for API Key Safety
- Microsoft, Azure OpenAI with Microsoft Entra ID authentication
- Microsoft, Managed identities for Azure resources
- AWS, How Amazon Bedrock works with IAM
- AWS, Temporary security credentials in IAM
- Google Cloud, Workload Identity Federation
- IETF RFC 8693, OAuth 2.0 Token Exchange