智能体面试准备(八十):智能体凭证治理与最小权限访问工程——密钥托管、临时凭证与全链路审计

智能体面试准备(八十):智能体凭证治理与最小权限访问工程------密钥托管、临时凭证与全链路审计

引言

本文是系列第 80 篇。前面讲过工具沙箱、人在回路、多租户权限,这一篇聚焦一个更细但后果极重的问题:Agent 调用外部系统时,凭证(Credential)怎么管。

这件事一旦做错,后果是灾难性的:把数据库密码写进 prompt、把长期有效的 API Key 硬编码在镜像里、Agent 被提示词注入后拿着高权限 token 删库。而面试官考察"Agent 安全"时,凭证治理是绕不开的一环------因为它最能区分"知道要加锁"和"真的做过权限体系"。

本篇讲清四件事:凭证不能出现在模型可见的任何地方、要用短期凭证、要按任务最小授权、要能追溯每一次使用。

复制代码
凭证治理总览
==================================================
          用户 / 上游系统
                 │  1. 身份认证(OIDC/OAuth)
                 ▼
        ┌─────────────────────┐
        │  凭证颁发服务 STS    │
        │  签发短期、受限凭证  │
        └──────────┬──────────┘
                   │ 2. 短期凭证(分钟级、范围受限)
                   ▼
        ┌─────────────────────┐
        │  Agent 运行时        │
        │  ┌───────────────┐  │
        │  │ 凭证代理 Proxy │  │  <- 模型永远拿不到明文
        │  └───────┬───────┘  │
        └──────────┼──────────┘
                   │ 3. 代理注入到真实调用
                   ▼
        外部系统(DB / SaaS / 内部 API)
                   │
                   ▼ 4. 审计与回溯

一、铁律:凭证绝不进模型上下文

先看反面清单,这些都是真实事故:

反模式 后果
API Key 写进 system prompt 模型可能原样输出(注入/追问即泄露)
密钥硬编码在镜像/环境变量 镜像泄漏即全量泄露,轮换要重新发版
用同一个高权限账号跑所有任务 一次越权影响全部数据
凭证长期有效(不过期) 泄露后窗口无限大
把数据库 DSN(含密码)传给 LLM 让它"自己连" 完全失控

正确做法是凭证代理(Credential Proxy):模型只发出"我要调用 X 工具"的意图,真实凭证由旁路代理注入,模型全程接触不到明文。

复制代码
# 反例:凭证进入 prompt
bad_prompt = f"用这个 key 调接口:api_key={SECRET}"   # 严禁

# 正例:Agent 只声明意图,凭证由代理注入
def invoke_tool(tool_name, args, ctx):
    cred = sts.issue(                 # 向凭证服务申请短期、限范围凭证
        tool=tool_name,
        tenant=ctx.tenant,
        ttl_seconds=300,
        scope=f"{tool_name}:read",    # 最小权限
        reason=ctx.task_id,
    )
    headers = {"Authorization": f"Bearer {cred.token}"}
    return http_call(TOOLS[tool_name].endpoint, args, headers=headers)

二、短期凭证与最小权限

凭证设计三原则:短期、最小、可撤销。

原则 做法 参数示例
短期 TTL 分钟级,用完即废 ttl=300s
最小权限 按工具+操作+资源范围授权 crm:order:read 而非 crm:*
可撤销 支持按 task_id 即时吊销 revoke(task_id)
绑定上下文 凭证绑定租户/会话/任务 换任务即失效
复制代码
class ScopedCredential:
    def __init__(self, token, scope, expires_at, task_id):
        self.token, self.scope = token, scope
        self.expires_at, self.task_id = expires_at, task_id

    def valid(self, required_scope, task_id):
        return (time.time() < self.expires_at
                and task_id == self.task_id
                and scope_allows(self.scope, required_scope))

def scope_allows(granted, required):
    """支持前缀通配的最小权限判定"""
    g, r = granted.split(":"), required.split(":")
    return len(g) == len(r) and all(a == b or a == "*" for a, b in zip(g, r))

三、按任务授权与人工升级

不同风险等级的任务,凭证获取方式不同:

风险等级 示例 授权方式
只读低风险 查询天气、检索文档 自动颁发,无需审批
有副作用 发消息、写工单 自动颁发 + 事后通知
高风险 转账、删数据、发外部邮件 人工审批后颁发,或人在回路确认
越权请求 超出该 Agent 权限范围 直接拒绝并告警

实现上给每个工具标注风险等级(注册在工具注册中心,见上篇 B79),凭证服务根据等级决定"自动发 / 需审批 / 拒绝"。风险分级 + 自动颁发 + 高风险人工升级 是标准三段式。

复制代码
RISK = {"read_only": "auto", "side_effect": "auto+notify",
        "high_risk": "require_approval"}

def issue_for(tool, ctx):
    level = TOOLS[tool].risk
    policy = RISK[level]
    if policy == "require_approval":
        if not approvals.granted(ctx.task_id, tool):
            raise PermissionError(f"{tool} 需人工审批")
    return sts.issue(tool=tool, tenant=ctx.tenant,
                     ttl_seconds=300 if level != "high_risk" else 600,
                     scope=TOOLS[tool].required_scope, reason=ctx.task_id)

四、防注入:凭证在攻防中的位置

提示词注入的真实危害不是"模型说错话",而是攻击者借模型之手调用高权限工具。凭证治理正是对抗链的关键一环:

复制代码
防线叠加(缺一不可)
1. 凭证不进上下文   -> 注入者无法直接套出密钥
2. 最小权限 scope   -> 即使被诱导调用,影响范围受限
3. 高风险需审批     -> 关键动作有人工闸门
4. 短期 TTL         -> 泄露窗口极小
5. 全链路审计       -> 事后可追溯、可告警

注意:不要把"模型判断安全"当作唯一闸门。模型的判断可被诱导,真正的闸门必须是策略引擎(代码级、确定性),模型只能提供建议。

五、审计与轮换

能力 说明
审计日志 每次凭证颁发与使用记录:谁、何时、工具、参数摘要、结果
异常检测 频率异常、非常规时段、跨租户访问、权限提升尝试
密钥轮换 定期自动轮换;泄露时一键吊销
最小可见 日志中脱敏,绝不记录明文凭证
复制代码
def audit_log(tool, args, ctx, result):
    log.info({
        "ts": time.time(),
        "tenant": ctx.tenant,
        "task_id": ctx.task_id,
        "tool": tool,
        "args_digest": hashlib.sha256(
            json.dumps(args, sort_keys=True).encode()).hexdigest()[:16],
        "status": "ok" if result.ok else "fail",
        # 注意:不记录明文参数与凭证
    })

六、落地检查清单

  • 凭证是否 100% 不进入模型上下文(prompt / 工具返回值 / 日志)?
  • 是否全部使用短期凭证(TTL ≤ 分钟级)?
  • 是否按"工具+操作+资源"三维最小授权?
  • 高风险工具是否有人工审批闸门,且闸门在策略层而非模型层?
  • 是否能按 task_id 即时吊销?
  • 是否所有调用都有审计,且日志脱敏?
  • 密钥是否支持自动轮换与一键吊销?

面试速答

问:Agent 调用外部 API 的密钥怎么管?

答:凭证绝不进模型上下文。用凭证代理:模型只声明调用意图,真实凭证由旁路服务按"短期 TTL + 最小 scope + 绑定 task_id"签发并注入,模型全程接触不到明文。

问:短期凭证的具体参数怎么设?

答:TTL 分钟级(如 300s),scope 按工具+操作+资源三维最小授权(如 crm:order:read 而非 crm:*),绑定 task_id 与租户,支持按 task_id 即时吊销。

问:提示词注入怎么防?

答:五层叠加------凭证不进上下文、最小权限 scope、高风险人工审批、短期 TTL、全链路审计。关键是安全闸门必须在策略层(代码确定性),不能依赖模型判断。

问:高风险操作怎么控制?

答:工具在注册中心标注风险等级,凭证服务按等级决定自动颁发/需审批/拒绝。高风险(转账、删数据、外发邮件)走人工审批或人在回路确认,审批通过才发凭证。

高频追问清单

  1. 凭证代理挂了或被绕过,怎么保证 Agent 拿不到明文?
  2. 多租户场景下凭证怎么隔离?跨租户访问怎么检测?
  3. 短期凭证 TTL 设太短导致频繁申请,性能和可用性怎么权衡?
  4. 工具返回值里意外带了密钥(如接口返回 token),怎么清洗?
  5. Agent 需要代表用户操作(on-behalf-of),OAuth 委托授权怎么设计?
  6. 高风险审批流超时未响应,任务应该阻塞、降级还是中止?
  7. 凭证审计日志本身怎么防篡改?
  8. 密钥自动轮换时,在途请求怎么处理才不中断?
  9. 如何检测"凭证被异常使用"(频率、地理、时段异常)?
  10. 本地/私有化部署没有云厂商 STS,怎么自建短期凭证服务?
相关推荐
程序猿编码5 天前
告别改源码适配模型:纯 C++ 可配置 LLM 推理引擎,全格式全结构兼容
c++·大模型·llm·推理引擎
蔡俊锋5 天前
华为昇腾 960 超节点发布:4096 卡、5500 个光引擎替 4.8 万光模块——国产算力拐点到了吗?
大模型·模型部署·ai架构·国产算力·华为昇腾
O。O蛋黄酥啊5 天前
Claude Code 记忆机制全拆解:Auto Memory 与 CLAUDE.md 双轨解析
大模型·agent·memory·claude·codex·记忆
BlackStar_L5 天前
第二章 上下文工程
大模型·llm·agent
User_芊芊君子5 天前
让 Claude Code 换上国产大脑:蓝耘元生代上 GLM-5.2 / DeepSeek / Qwen 模型横评实测
人工智能·ai·大模型
寻道码路5 天前
大模型工程化实战(十二):RAG 数据工程底座——采集到入库流水线(离线+在线双链路)
大模型·知识库·rag·ai工程化·llmops`·数据工程底座·文档采集
Web3&Basketball6 天前
CRM Agent 后训练实战:3 倍更少错误
python·架构·大模型·agent·推理
蚁小二官方6 天前
AI 安全治理框架更新|大模型训练数据合规,企业实操落地思路
大模型·数据合规·ai安全
AI模力圈6 天前
On-Policy Distillation:原理、变体与工程实现解析
大模型·强化学习·知识蒸馏
长谷深风1116 天前
根因定位:三步隔离法破解AIBadcase
人工智能·ai·大模型·retrieval·ai智能体·aiagent·aibadcase