2026年6月24日 2 分钟阅读

AI Agent 调用 API 时如何保护密钥不泄露?Cloak 零信任凭证代理实战

tinyash 0 条评论

当你给 Claude Code 或 Cursor 配置一个 Stripe 密钥让它帮忙测试支付流程时,你有没有想过一个问题:这个密钥现在在模型手里。

不只是模型——它在模型上下文里、在 API Provider 的日志里、在任何能读到模型输出的人手里。一次提示注入攻击,密钥就能被提取出来远走高飞。

问题的本质:Agent 需要密钥,但模型不该看到它

传统做法很简单:把 API 密钥放到环境变量、.env 文件或配置文件中,Agent 读取后直接使用。这在人机交互时代没问题——人是密钥的最终使用者。

但到了 AI Agent 时代,情况变了:

  • 密钥在模型上下文中:Agent 读取 .env 后,密钥明文就进了 LLM 的上下文窗口
  • 密钥在 Provider 日志中:大多数 LLM API Provider 会记录请求内容用于调试和监控
  • 密钥在提示注入的射程内:如果 Agent 访问了一个恶意网站,该网站可能通过提示注入提取上下文中的密钥
  • 密钥在工具调用结果中:Agent 调用 read_file(".env") 后,密钥以明文形式出现在工具调用参数中

这不是理论问题。通过 Agent 的提示注入提取 API 密钥已有多起实际报告案例。OpenAI、Anthropic 的安全文档也都将凭证管理列为 Agent 安全的核心关注点。

传统方案为什么不够

方案风险
环境变量 .envAgent 的 read_file 工具能直接读取,密钥进入模型上下文
手动输入每次都要人工操作,抵消了自动化的价值
短期 Token仍然需要初始凭证来生成 Token,没有消除根因
专用 Secret 管理服务 (Vault)设计用于服务器间通讯,不对接 MCP 协议

我们需要的是一个让 Agent 能使用但不看到密钥的方案——这就是零信任凭证代理的核心思路。

Cloak:本地加密保险库 + MCP 凭证代理

Cloak 是一个 Rust 编写的开源项目(Apache-2.0),核心设计只有一句话:把密钥放在 Agent 永远看不到的地方,Agent 只能通过代理请求来使用它们。

它由三个组件构成:

  1. cloak CLI:你用来添加和管理密钥的命令行工具
  2. cloakd 守护进程:在后台运行,持有解密后的密钥,执行所有特权操作
  3. cloak-mcp MCP 服务端:你的 AI 客户端(Claude Desktop、Claude Code、Cursor 等)通过 MCP 协议连接的桥接层

关键设计原则:MCP 服务端没有任何密钥的读取权限,密钥永远不离开守护进程的进程空间。 MCP 服务端只是一个”类型化的有线格式适配器”——它转发请求,但看不见密钥值。

安装与配置

macOS 和 Linux 上一条命令安装:

brew install cloakward/cloak/cloak
cloak setup

cloak setup 会自动安装并启动守护进程、初始化加密保险库,并检测你系统上已安装的 AI 客户端(Claude Desktop、Claude Code、Cursor、Windsurf、Zed、Continue.dev、Codex),自动配置 MCP 连接。

初始化保险库后,系统会生成一个 24 词的恢复种子,需要手写保存到离线位置——这是你丢失密码后恢复密钥的唯一方式。

添加密钥

cloak add OPENAI_API_KEY          # 在隐藏提示中输入密钥
cloak add STRIPE_SECRET_KEY       # 添加 Stripe 密钥
cloak list                        # 只显示名称,从不显示值

配置访问策略(默认拒绝)

Cloak 采用 default-deny 策略——每个密钥默认无法访问任何主机。需要明确授权:

cloak allow OPENAI_API_KEY api.openai.com
cloak allow STRIPE_SECRET_KEY api.stripe.com
cloak policy                      # 查看每个密钥的访问权限

这些策略即时生效,不需要重启守护进程。

实际使用效果

配置完成后,你的 Agent 就可以使用密钥了——但它只通过名称来引用,真正的密钥值从未进入模型上下文。

以下是一个真实示例。你告诉 Agent:

“test my checkout: create a $50 Stripe PaymentIntent with pm_card_visa and confirm it succeeded.”

Agent 调用 proxy_authenticated_http_request 工具,Cloak 在守护进程中附加 STRIPE_SECRET_KEY,向 Stripe API 发送请求,然后只返回结果给模型:

proxy_authenticated_http_request  →  POST https://api.stripe.com/v1/payment_intents

Status 200
{
  "id": "pi_3ThFkTKCZ65x2cgg0rzmsrj3",
  "amount": 5000,
  "amount_received": 5000,
  "currency": "usd",
  "livemode": false
}

一笔 50 美元的扣款成功执行了。但那个授权了这笔交易的 STRIPE_SECRET_KEY(可以退款所有订单并清空账户余额的凭证)从未出现在模型收到的任何数据中。

六种 MCP 工具详解

Cloak 向模型暴露了正好 6 个 MCP 工具,每个都遵循同一个不变量:没有工具返回原始存储的密钥值。

工具功能返回值
list_secret_names列出保险库中的密钥名称和元数据仅名称、种类、标签,无值
get_secret_metadata查询单个密钥的元数据创建时间、标签、版本,无值
sign_request对请求计算认证签名头计算的认证头信息
proxy_authenticated_http_request代理带认证的 HTTP 请求上游状态码、响应头和正文
mint_short_lived_token生成短期派生凭证派生凭证 + 过期时间
query_audit查询审计日志审计条目,无值

其中 proxy_authenticated_http_request 是最常用的工具——它相当于一个”可信代理”,让模型能调用需要认证的 API,但密钥本身留在受信任的守护进程中。

与传统凭证管理方案的区别

Cloak 的设计与传统的 Secret 管理服务(如 HashiCorp Vault、AWS Secrets Manager)有几个关键区别:

  1. 本地优先:不需要云服务、不需要账户、没有遥测。密钥在本地 SQLite 保险库中,使用 AEAD 加密
  2. MCP 原生:直接对接 Model Context Protocol,AI 客户端无需额外 SDK
  3. default-deny 策略:每个密钥默认无法访问任何主机,必须显式授权
  4. 不可读设计:MCP 服务端没有密钥读取能力,这是架构层面的保证

安全保障措施

Cloak 的威胁模型是诚实且有限的:

  • 保护范围:阻止长期密钥从 Agent 上下文中泄漏
  • SLSA L3 认证:发布版本经过 cosign 签名和 SLSA L3 认证
  • macOS 公证:macOS 版本经过 Apple 公证
  • 局限性:不防御被攻陷的主机、root 级别的攻击,也不能使被劫持的 Agent 变得无害(派生凭证仍然会被 Agent 使用)

总结

当你的 AI Agent 开始接触真正的 API —— Stripe、GitHub、AWS —— 密钥管理就从一个”基础设施问题”变成了”安全问题”。Cloak 用一种简洁的架构解决了这个问题:本地加密保险库存储密钥,MCP 代理作为可信中介处理认证请求,模型只通过名称引用密钥而永远看不到值。

对于安全敏感的 AI Agent 工作流,这不应该是一个可选项——它应该是默认配置。

相关链接

发表评论

你的邮箱地址不会被公开,带 * 的为必填项。