AgentPAM.ai

Integration · primary path

接入你已有的 IdP 与网关

这是 V1 的主接入路径:agent 经你既有的 MCP 网关访问远程/内网 MCP server,AgentPAM 作为外部 Authorization Server + PDP + 凭据 Broker 插在中间。(本地笔记本 / stdio 场景不在当前范围内,属 V2+ 长期路线图。)

你已经有 IdP(Okta / Entra)和 MCP Gateway。AgentPAM 插在两者之间,你改配置,不改代码;控制平面跑在你自有 Linux,可气隙、无出站回连。

Deployment topology

三个「我们不碰」

IdP 是你的,MCP Gateway 是你的,MCP server / API 是你的。我们只提供中间那个控制平面容器组 —— 它跑在你自有的 Linux 上,可气隙,无任何出站回连。

topology.txt横向可滚动
+-- Your own Linux environment (air-gap capable, no outbound callback) --------+
|                                                                              |
|   +------------+     OIDC federation    +------------------------------+     |
|   | Your IdP    |<----------------------| AgentPAM control plane        |     |
|   | Okta/Entra |   (consumes assertions only)  | /authorize /token  AS+STS |     |
|   +-----+------+                        | PDP  AuthZEN / COAZ       |     |
|         | human SSO (Tu)                | Credential broker  RFC 8693 |     |
|   +-----v------+   ext_authz / AS       | Audit sink                   |     |
|   | Your MCP    |<--------------------->| JWKS (independent HA)        |     |
|   | gateway    |   inject cred (Tup)    +------------------------------+     |
|   | (RS)       |                                                             |
|   +-----+------+                                                             |
|         | inject short-lived credential                                       |
|   +-----v------+                                                             |
|   | Sensitive  |  <- remote / internal, NOT a laptop                          |
|   | API/server |                                                             |
|   +------------+                                                             |
+------------------------------------------------------------------------------+
        ^ agent holds Ts (session token, DPoP, 5-15 min)
   +----+-----+
   | AI Agent |  managed workstation / VDI  (agent is on the endpoint,
   | Claude   |  but the MCP server is not)
   +----------+
你的

IdP

Okta / Entra。人类认证永远发生在这里,我们只消费断言。

你的

MCP Gateway

它是 Resource Server。我们接入它,不替换它。

你的

MCP server / API

远程或内网托管,非笔记本。凭据由 broker 注入,agent 看不到。

Connect the IdP

接入 IdP:联邦消费者,不是替代者

AgentPAM 不认证人类(宪法 C-02)。人类认证发生在你的 IdP,我们通过 OIDC 联邦信任它签发的断言。我们不存人类口令、不做 MFA。

接入步骤(你在 IdP 侧做的四件事)

  1. 把 AgentPAM 注册为一个 OIDC Relying Party(或 SAML SP),给我们 client_id / client_secret(或联邦信任)。
  2. 配置 AgentPAM 的 redirect / token 端点 —— 我们的 /callback 内网地址。
  3. 把 IdP 的 JWKSdiscovery 端点暴露给我们(内网可达即可)。
  4. 映射所需 claim(subemailgroups / roles)。
agentpam.yaml横向可滚动
identity_providers:
  - id: corp-okta
    issuer: https://corp.okta.internal          # your IdP, internal
    jwks_uri: https://corp.okta.internal/oauth2/v1/keys
    audience: agentpam                            # we are the audience
    claim_mapping:
      subject: sub
      email: email
      groups: groups

支持的 IdP 与联邦方式

IdP方式备注
OktaOIDC + ID-JAG / Cross-App Access首选。EMA(Enterprise-Managed Auth)已 stable,把同意与策略移到 IdP,无同意屏
Microsoft EntraOIDC + OBO(On-Behalf-Of)直接消费 Entra Agent ID 的 facet claim(xms_act_fct / xms_sub_fct
Google WorkspaceOIDC标准 OIDC 联邦
Keycloak / 自建OIDC + RFC 8693气隙客户常用;Keycloak 原生支持 token exchange
SAML-only 老 IdPSAML 断言 → 我们转 OIDC兜底路径
EMA / ID-JAG —— 把「用户自行连接 agent」交给 IdP这正对应八类挑战 #7。启用 EMA 后:人 SSO 到 IdP → agent 从 IdP 取得 ID-JAG(Identity Assertion JWT Authorization Grant)→ agent 用 ID-JAG(RFC 8693 token exchange)在我们这里换会话令牌 → 连接按 IdP 策略自动完成。无 OAuth 同意屏、无影子连接、单一撤销点。 我们不实现 EMA 的 IdP 侧,我们实现它的 RS/AS 侧 —— 接收 ID-JAG 并做 token exchange。Okta 首发支持,Entra 跟进。

Connect the gateway

接入网关:两条并列主路径,按型号选

DR-001 修正后:不存在「通吃」路径(我们已经撤回过那个说法)。按你的网关型号选一条。第三条是兜底。

网关接入路径你改什么
agentgateway / ContextForge / Kong EE / AWS AgentCore路径 B:我们当外部 AS一段配置指向我们
Envoy/Istio / Kong OSS / Pomerium / Obot / 有 PDP 钩子的路径 A:我们当外部 PDPext_authz / OPA 指向我们
Docker MCP Gateway / 无钩子路径 C:作为上游 MCP 代理(兜底)网关把我们当上游 server

路径 B —— 我们是网关的 Authorization Server

gateway-config.yaml · agentgateway横向可滚动
# 1) the gateway publishes protected resource metadata (RFC 9728)
#    GET /.well-known/oauth-protected-resource ->
mcpAuthentication:
  issuer: https://agentpam.customer.internal       # points at us
  audiences: [ "https://mcp.customer.internal" ]   # * MANDATORY in agentgateway
  jwksUri: https://agentpam.customer.internal/.well-known/jwks.json

# 2) upstream credential injection: the gateway exchanges for Tup, the agent never sees it
backendAuth:
  oauthTokenExchange:
    path: /token                                   # * local YAML key is 'path', NOT tokenEndpointPath
    grantType: urn:ietf:params:oauth:grant-type:token-exchange

键名按 G-04 源码核对更正(resource.proto):本地 YAML 键是 path,不是 tokenEndpointPath(后者是 xDS/proto 字段名,写进配置文件会加载失败)。audiences 在 agentgateway 里是结构性必填,缺失则配置加载失败 —— 这是安全的默认。⚠️ 注意这段 backendAuth 换取 / 注入链路是配置级理解,未对真实后端运行时验证(G-22)。

路径 A —— 我们是网关的外部 PDP(覆盖面更广)

envoy-extauthz.yaml + POST /pdp/evaluate横向可滚动
# Envoy ext_authz -> our PDP
http_filters:
- name: envoy.filters.http.ext_authz
  typed_config:
    grpc_service:
      envoy_grpc: { cluster_name: agentpam_pdp }   # points at our PDP
    with_request_body:                             # * pass body so we see MCP method/tool
      max_request_bytes: 8192
      allow_partial_message: true

--- our PDP interface (AuthZEN / COAZ-MCP compatible) ---
POST /pdp/evaluate
{
  "subject":  { "id": "u_dana", "type": "human" },        # the human
  "context":  { "agent": "agent_support_7f3a",            # agent, 2nd dimension (COAZ)
                "task": "task_88213" },
  "action":   { "name": "tools/call", "tool": "payments.refund" },
  "resource": { "server": "payments", "args": { "amount": 120 } }
}
-> 200 { "decision": true,
        "obligations": ["audit:high"],
        "headers": { "Authorization": "Bearer <Tup short-lived>" } }  # injected on allow

关键是允许 PDP 在 allow 时改写 header(凭据注入原语),并把请求体传给我们以便看到 MCP 的 method / tool。我们的 PDP 接口兼容 AuthZEN / COAZ-MCPsubject 是人,context.agent 是 agent 第二维度。

路径 C —— 兜底:作为上游 MCP 代理

网关无任何钩子时(如 Docker MCP Gateway):网关把我们配成上游 MCP server,我们在真实 server 前做策略执行代理。代价:多一跳,只看得到被路由过来的流量。优点:对你的网关零要求。对 Docker MCP Gateway 这是唯一可行路径 —— 它的 before:http: 钩子无法改 header,路径 A 也不成立。

诚实标注实测程度(G-22)只有 agentgateway 的 AS 发现握手是运行时实测过的(darwin-arm64,v1.4.0-alpha.2:一段 mcpAuthentication 即把我们发布为 AS 并发出 RFC 9728 challenge)。真正换取并注入 Tup 的 backendAuth.oauthTokenExchange 链路尚未对真实后端运行时验证(G-22),只到配置级。路径 B 干净支持的其余三家与所有路径 A 的片段同样是文档级、非运行时验证。我们不会把这些说成「已验证」,完整矩阵见 架构页

End to end

端到端时序(路径 B)

sequence-path-b.txt横向可滚动
[1] Human SSO -> your IdP -> Tu (OIDC, ~1h)
[2] agent -> AgentPAM /token  (RFC 8693)
        subject_token=Tu, actor_token=agent instance assertion
        authorization_details=[{ type: agent_task, task_id, purpose, sensitivity }]
    AgentPAM verifies Tu (against your IdP JWKS) -> issues Ts
        Ts: sub=human, act={sub: agent_instance}, cnf.jkt (DPoP), 5-15 min
[3] agent calls your MCP gateway with Ts
        gateway verifies Ts (against OUR JWKS) + audience
[4] per tools/call -> PDP decision: server / tool / parameter + monotonic narrowing
[5] allow -> gateway exchanges at AgentPAM /token for Tup (upstream cred, 60-300s)
        ** the agent never touches Tup **
[6] gateway injects Tup and calls the upstream API / MCP server
[7] AgentPAM writes the audit event (human/agent/task/tool/resource/decision/traceparent)
[8] task ends or CAEP revocation -> Ts invalidated immediately (no wait for TTL)

整条链只有委派语义,没有冒充。sub 永远是人,act 承载 agent 实例。第 5 步之后,agent 从不接触 Tup(上游凭据)。

One-day POC

一天内可完成的落地清单

#动作谁做验证
1docker load 导入 AgentPAM 容器组镜像(离线介质)你的运维docker images
2agentpam.yaml:IdP issuer / jwks、audience你的运维启动日志无错
3在 IdP 注册 AgentPAM 为 RP你的 IdP 管理员discovery 可达
4网关配置指向我们(路径 B 的 metadata + token 端点,或路径 A 的 ext_authz)你的平台团队curl .well-known/oauth-protected-resource 返回我们
5注册第一个 AgentBlueprint + AgentIdentity(含人类 sponsor)你的平台团队Portal 显示
6定义策略(server / tool / 参数 三级)你的安全团队策略生效
7跑一次 agent 调用你的开发者见下方验收

POC 验收(你当场可验证)

#检查期望
1agent 调一个允许的工具成功;上游日志见短时凭据
2agent 调被策略拒绝的工具请求不抵达上游,审计有拒绝记录
3参数超限(refund $2500 > $500)参数级拒绝
4抓 agent 会话,搜上游凭据找不到 Tup(只有 Ts)
5审计事件含人 + agent + 任务,可关联 traceparent
6标记任务完成后再调立即拒绝(即使 Ts 未到期)
7断开 AgentPAM 再重启网关(HA 测试)⚠️ 见下方「两件诚实话」—— 这是我们必须告知的耦合

Bridge, not bucket

我们是桥梁,不是篮子 —— 零常驻凭据

上一节承认了我们是高价值目标。这一节是它的架构答案:一个存下所有客户凭据的中介只是集中了风险(Salesloft Drift 正是如此塌的)。我们不做那个篮子。

不变量 BNB-0(可验证,非口号)

AgentPAM 的任何持久化存储中,都不存在可直接用于访问客户上游 API 的长期凭据明文。

四类密钥材料,各自处置 —— 诚实地说,只有前两类能做到完全的「桥」

密钥材料是什么能做到「桥」吗处置
① 上游 API 凭据客户 GitHub / DB / 云的访问凭据(Tup 的来源)✅ 能不存。 请求时从客户 vault / 云 IAM 动态取,注入后即焚
② 客户 IdP 令牌(Tu)人类 SSO 令牌✅ 能不存。 只在一次 token 交换中校验,不落库
③ 我们的签名私钥签 Ts / JWKS 的密钥❌ 必须存在某处入 HSM / KMS,硬件内生成、永不导出、只做签名
④ Secret zero我们凭以访问客户 vault 的引导凭据⚠️ 最难尽量无长期密钥:projected SA token / workload identity;裸机回退到可轮换 mTLS

三种「桥」模式 —— 我们只存「到哪儿取」的引用,从不存凭据本身

模式机制我们存了什么
A. Vault 直通客户用 HashiCorp Vault / Infisical。请求时调其动态 secret 引擎签一个短时凭据,注入,即焚什么都不存 —— 连引用都是客户 vault 的 path
B. 云 STS 交换客户用云 IAM。用 workload identity 换 STS 短时凭据(如 AWS AssumeRole 15min),注入,即焚只存一个角色 ARN 引用
C. 上游 OAuth 客户端上游是 SaaS(GitHub / Slack)。refresh token 存在客户的 vault,不在我们这里;请求时取来换 access token,注入,即焚只存 vault 引用

即使我们被完全 RCE,损害的上界

篮子(Salesloft 模式)桥(AgentPAM)
直接拿到所有客户所有上游凭据明文一堆 vault path / ARN 引用 + 无法导出的 HSM 句柄
兑现还需要无,直接用穿过 secret zero → 客户 vault 的独立策略与审计
每次兑现无痕留痕、可限速、可被客户 vault 撤销
爆炸半径所有客户(多租户 SaaS)单个客户(私有化,C-13)
客户侧应急依赖 SaaS 厂商自己轮换 vault 凭据、撤销 secret zero、停容器 —— 主动权在客户

别信我们,自己验证

这六项客户自己就能跑。第 1 和第 6 项是核心 —— 它们经验性地证明了 BNB-0:我们的存储里没有鸡蛋,凭据的生杀大权在你手里。

#验证期望
1转储我们的持久化存储(DB / 磁盘),grep 上游凭据特征(ghp_ / sk- / AKIA / DB 密码)零命中 —— 只有 path / ARN 引用
2检查 HSM / KMS 配置,确认签名私钥不可导出CKA_EXTRACTABLE=false
3断开我们到你 vault 的连接,观察 agent 调用失败 —— 证明凭据是实时取的,不是我们存的
4审计我们的出站网络(气隙下应为零)无「回家」连接(C-15)
5验证镜像签名 + SBOM签名有效、依赖可核
6撤销你 vault 里的一个凭据,立即重试 agent 调用立即失败 —— 证明我们不缓存、不留存

三处我们做不到「绝对的桥」(诚实清单)

签名私钥必须存在

Ts / JWKS 要用我们的私钥签名,这把钥匙必须存在某处 —— 我们靠 HSM 做到「存但拿不走」,不是「不存」。残余风险:签名预言机 —— RCE 后攻击者拿不到密钥,但可能诱导 HSM 合法签发恶意令牌。这靠策略侧防御(签发内容模板校验 + 限速 + 异常检测),HSM 挡不住。

Secret zero 在气隙裸机难以完全消灭

K8s 用 projected SA token、云上用 workload identity federation 都能做到无长期密钥;但气隙裸机最好情况是一个可轮换的 mTLS 客户端证书,不是零密钥。即便它泄漏,攻击者拿到的是「访问你 vault 的权限」,仍要穿过你 vault 自己的策略、审计与撤销。

内存有秒级暴露窗口

即使在桥上,凭据也会在取出→注入之间于内存出现 ≤ 秒级。缓解:注入后立即 zeroize、不进日志、不进长生命周期对象、默认不跨请求缓存(以最小暴露换一点延迟)。我们不假装这个窗口是零。

Bridge, not bucket把这三处诚实写出来,本身就是可信度的一部分。 一个声称「绝对安全、零风险」的中介,恰恰是最不该信的那一个。

Two honest disclosures

两件必须对你诚实的事

G-20 · 启动期依赖

我们不可用时,路径 B 的网关可能起不来

agentgateway 在启动时急切拉取 JWKS 且 fail-closed —— 如果那一刻 AgentPAM 不可达,网关可能起不来。缓解:JWKS 端点独立高可用部署,与策略引擎故障域隔离,并支持你侧静态托管 JWKS。这必须写进 SLA 与部署文档,我们不隐瞒。

G-21 · Envoy audience 静默失效

省略 audiences 会静默关闭校验

agentgateway 结构性强制 audiences(缺失即配置加载失败,安全)。但若你用 Envoy,省略 audiences 会静默关闭 audience 校验 —— token 可被跨受众重放。部署检查必须主动探测这一项,不能假设默认安全。

G-09 · 我们是高价值目标

控制平面持有通往所有敏感 API 的钥匙

缓解:见上方「桥不是篮子」—— 我们的持久层里没有可直接访问上游 API 的凭据明文(不变量 BNB-0)。加上根密钥入你的 KMS / HSM、单租户私有化天然隔离、审计哈希链防篡改。桥 + 私有化 = 双重收窄:爆炸半径限制在你自己的故障域内,被攻破时拿不到可离线带走的凭据库 —— 只剩一个留痕、可撤销、限单租户的活预言机(诚实边界见本节 §三处做不到绝对的桥)。