当 AI 代理访问数据库、API 和敏感业务操作时,通过 X.509 公钥基础设施(PKI)建立加密身份成为一项关键要求。核心挑战在于证明是哪个代理发出了请求、防止代理之间的伪造,并确认每个代理仅代表已获授权的用户行事。诸如在组件之间共享 API 密钥或通过代理链传递 OAuth 令牌等传统方法,无法满足企业部署所要求的零信任需求。
多代理 AI 框架越来越多地使用模型上下文协议(MCP)将代理连接到外部工具和数据源。MCP 定义了由大语言模型(LLM)驱动的代理如何调用工具,例如数据库查询或电子邮件操作。然而,MCP 没有内置的身份验证标准。它从设计上就是不依赖特定传输方式的。这就造成了一个关键缺口:如果没有适当的身份机制,任何组件都可能冒充代理、重放被截获的凭据,或未经授权调用工具。
在这篇文章中,我们将向您展示如何结合使用 Keyfactor EJBCA 和 AWS 服务来填补这一缺口。EJBCA 是一个支持高可用性部署、REST API 自动化和在线证书状态协议(OCSP)验证的 PKI 平台。该参考架构使用四种互补的安全机制。第一,签名的请求信封为每一次代理调用提供加密的所有权证明。第二,用户签名的委托断言在不共享凭据的情况下对代理进行授权。第三,RFC 8693 受众范围限定的令牌限制了任何单个令牌泄露所造成的暴露范围。第四,实时 OCSP 吊销检查可立即将凭据变更传播到所有代理。
该解决方案使用 Amazon Bedrock 通过 AWS Strands Agents SDK进行 LLM 推理。虽然此参考架构使用数据库作为受保护资源,但相同的身份验证模式适用于任何兼容 MCP 的工具服务器。所有示例的完整源代码可在随附的 GitHub 仓库中获取。
关于 Keyfactor EJBCA
据 Keyfactor 介绍,Keyfactor 提供一个被广泛采用的机器身份管理平台,在全球拥有超过 1,500 家企业客户。这些组织遍布金融服务、医疗保健、制造业和政府部门。Keyfactor 通过证书生命周期管理、PKI 运营和机器身份治理,帮助组织建立并维护加密信任。
EJBCA Enterprise 是 Keyfactor 的证书颁发机构(CA)和 PKI 平台,专为高可用性部署和 REST API 自动化而设计。EJBCA 作为企业产品提供,通过 Web 控制台和 REST API 提供 X.509 证书签发、OCSP 验证、证书吊销列表(CRL)分发以及完整的证书生命周期管理。EJBCA 支持在本地、容器中或 Amazon Elastic Compute Cloud(Amazon EC2)上部署。
AWS 与 Keyfactor 的合作将 AWS 托管服务(Amazon Bedrock、AWS Secrets Manager、Amazon Relational Database Service(Amazon RDS))与支持证书生命周期管理、自动注册和实时吊销的 PKI 基础设施结合在一起。这种组合弥补了 AI 代理生态系统中的一个缺口。AWS 提供计算、存储和 AI 推理层,而 Keyfactor 提供将代理绑定到可验证、可吊销、短生命周期凭据的加密身份层。这一由 AWS 和 Keyfactor 工程团队协作开发的联合参考架构,展示了如何集成这些技术。您可以采用本文展示的模式应用于您自己的多代理部署。
解决方案概览
该架构实现了三个身份验证层,每一层都针对代理通信链路中不同的信任边界。这三个层使用前面介绍的四种安全机制:用于所有权证明的签名信封、用于免凭据授权的委托断言、用于限制暴露范围的受众限定令牌,以及用于实时吊销的 OCSP。这些机制跨层组合,如下表所示。
| 层 | 信任边界 | 机制 | 验证内容 |
| 1. 用户身份验证 | 用户到系统 | OAuth + X.509 证书 + 委托铸造 | 用户身份、凭据绑定 |
| 2. 代理间调用 | 代理到代理 | 签名信封(PoP + nonce + 时间戳) | 调用者身份、请求新鲜度、防重放 |
| 3. MCP 身份验证 | 代理到工具服务器 | 范围限定令牌 + 信封 + 委托 | 所有身份、授权链、OCSP |
图1展示了三个身份验证层,以及凭证如何在用户、代理和MCP工具服务器之间流动。该图说明了用户凭证(保留在登录流程中)、代理凭证(按每个代理划分作用域)以及连接两者的委托链之间的分离。
图1:面向AWS上AI代理系统的三层PKI身份验证架构
图2展示了典型用户会话期间详细的流量流程。它展示了从登录到证书颁发、代理委托、工具调用以及会话清理的身份验证步骤序列。
图 2: 从用户登录到代理委派、工具调用和会话清理的身份验证流量流程
使用的 AWS 服务
以下 AWS 服务构成了参考架构的基础。
| 服务 | 用途 |
| Amazon Bedrock | 通过 Strands Agents SDK 进行 LLM 推理 |
| Amazon RDS for MySQL | 通过 MCP 工具访问的应用程序数据库 |
| Amazon Simple Email Service (Amazon SES) | Email Agent 的邮件发送服务 |
| AWS Secrets Manager | 用于 PKCS12 包、令牌和元数据的安全存储 |
| Amazon EC2 | 托管 Keycloak IDP 和 EJBCA PKI 服务器 |
解决方案演练
以下步骤将演练架构的每个组件,从初始用户登录到会话清理。每一步都在上一步的基础上构建,建立起将人类用户连接到最终工具执行的信任链。
先决条件
- 一个活跃的 AWS 账户,并可访问 Amazon Bedrock、Amazon RDS for MySQL、Amazon SES 和 AWS Secrets Manager。
- Keycloak 26.2 或更高版本(RFC 8693 标准令牌交换所需。之前的版本使用不兼容的旧版交换方式)。
- Keyfactor EJBCA Enterprise,带 REST API V1 和已配置的 OCSP 响应器。
- EJBCA API 管理员证书(
api-admin.p12),用于 REST API 身份验证。 - Python 3.9+ 开发环境。
- 熟悉 X.509 证书、OCSP、OAuth 2.0、RSA 数字签名和 PKCS#12 密钥库。
第 1 步:用户登录、证书颁发和委派铸造
登录流程通过三种机制确立用户身份,然后在不共享用户凭据的情况下将权限委派给 AI 代理。这种分离至关重要:代理获得授权证明,但从不持有用户的私钥或全会话 OAuth 令牌。
首先,应用程序使用 OAuth 2.0 密码授权(password grant)针对 Keycloak 对用户进行身份验证,获得全会话访问令牌和刷新令牌。紧接着,应用程序执行 RFC 8693 令牌交换以获取降权(downscoped)令牌。该令牌的受众被限制为 MCP 服务器。只有这个受限的令牌被交给代理。如果它被意外泄露,也无法访问组织中的任何其他服务。
其次,应用程序在本地生成一个 RSA 2048+ 密钥对,并通过 pkcs10enroll REST API 端点向 EJBCA 提交证书签名请求(CSR)。EJBCA 对 CSR 进行签名并返回证书。应用程序将证书和私钥打包成 PKCS12 容器,并存储在 AWS Secrets Manager 中。私钥从不离开应用程序边界。它不会被发送到 EJBCA,不会与代理共享,也不会存储在文件系统上。使用相同的基于 CSR 的流程为三个代理各颁发一张证书,每个代理角色一张。
第三,用户的私钥对一个委派断言进行签名。这是一个 JSON 文档,列出了所有三个代理证书的 SHA-256 指纹,以及用户的主题名称、颁发时间和过期时间。该委派证明用户授权了这些特定的代理代表其行事。代理携带此委派,而不是用户的证书。
# RFC 8693 Token Exchange - downscope to MCP audience
downscoped_token = keycloak.token_exchange(
original_token, audience="mysql-mcp-server", scope="database:write"
)
# Client-side key generation (user key never leaves this flow)
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
csr = build_csr(private_key, f"CN={username},E={username}@org.com")
user_cert = ejbca.pkcs10enroll(csr, ca_name="UserCA")
# User signs delegation over agent cert fingerprints
delegation = mint_delegation(
username=username,
user_cert_pem=user_cert,
user_key_pem=private_key_pem,
agent_cert_pems=[orch_cert, mysql_cert, email_cert]
)
# Result: {sub, agent_fingerprints[], iat, exp, user_cert_pem, signature_b64}
第 2 步:代理间签名信封
当编排代理(orchestrator agent)将请求路由到子代理(例如 MySQL 代理或 Email 代理)时,它并不是简单地传递其证书用于身份识别,而是使用其私钥通过 RSA-PSS-SHA256对整个请求负载进行签名,包括工具名称、参数、时间戳和一个加密随机数(nonce)。由此生成的签名信封提供了持有证明(proof-of-possession)。接收代理可以验证调用方确实持有与所出示证书对应的私钥。
在处理请求之前,接收代理会对信封执行六项验证检查:
- 签名验证: 证明发送方拥有私钥(拥有证明)。
- 时间戳新鲜度: 信封必须在
ENVELOPE_MAX_AGE_SECONDS(默认 60 秒)以当前时间为准。 - Nonce 唯一性: 该
ReplayCache拒绝任何之前见过的 nonce,从而防止请求重放。 - CA 链验证: 发送方的证书必须能够链到受信任的 CA(
UserCA.pem). - 角色授权: 证书 CN 的角色后缀必须位于
ALLOWED_CALLER_ROLES中,适用于该智能体。 - OCSP 吊销检查: 通过针对 EJBCA 的实时检查确认证书未被吊销。
如果编排器需要重新发送同一提示(例如,在瞬时故障之后),它必须创建一个带有全新 nonce 的新信封。旧信封无法被重放,即使是合法发送方也不行。
# Orchestrator signs request to sub-agent
envelope = sign_envelope(
payload={"tool": "query_database", "args": {"sql": "SELECT ..."}},
cert_pem=orchestrator_cert_pem,
private_key_pem=orchestrator_key_pem
)
# envelope: {payload_b64, cert_pem, timestamp, nonce, signature_b64, alg}
# Sub-agent verifies (six checks)
verified_payload = verify_envelope(
envelope,
allowed_role="orchestrator-agent",
ca_cert_pem=ca_pem,
replay_cache=cache
)
第 3 步:MCP 服务器认证
MCP 服务器(FastMCP)是任何数据库操作运行前的最后一道信任边界。它对每次工具调用执行四项验证检查,实现纵深防御。即使某个凭据遭到未授权访问,其余检查也能阻止未授权操作。
认证流程如下:
- 令牌内省: 向 Keycloak 的
/token/introspect端点发送 POST 请求,验证令牌处于活动状态且其 audience 包含 “mcp-server”。缺少正确 audience 的完整会话令牌将被拒绝。 - 信封验证: 对智能体签署的信封进行验证,包括签名正确性、时间戳新鲜度、nonce 唯一性、CA 链信任、角色匹配(
mysql-agent)以及 OCSP 未吊销。 - 委托验证: 对用户的委托声明进行验证。签名证明用户的密钥持有者授权了此委托,调用智能体的证书指纹出现在授权列表中,并且用户的证书通过 OCSP 进行检查。
- 身份交叉检查: 令牌用户名、委托主体以及智能体证书 CN 前缀必须全部匹配。这确认了从用户到工具执行的单一一致身份链。
# MCP Server - Four validation checks
# 1. Token: must be active with correct audience
info = introspect(token)
assert info["active"] and "mcp-server" in info["aud"]
# 2. Envelope: proof-of-possession + freshness + replay + CA + role + OCSP
payload = verify_envelope(envelope, "mysql-agent", ca_pem, replay_cache)
# 3. Delegation: user authorized this agent + user cert not revoked
claims = verify_delegation(delegation, agent_cert_pem, ca_pem)
# 4. Cross-check: consistent identity chain
assert token_username == claims["sub"] == agent_cn.rsplit("_", 1)[0]
# All checks passed - execute tool
result = execute_sql(payload["args"]["sql"])
第 4 步:重放防护
每个签署的信封都携带一个唯一的 nonce,这是一个使用 Python 的 secrets 模块生成的 128 位加密随机十六进制字符串。该 ReplayCache 是一个线程安全的内存存储,它会记住每个 nonce,直到其新鲜度窗口过期(2x ENVELOPE_MAX_AGE_SECONDS)。如果同一个 nonce 出现在第二个请求中,该信封会立即被拒绝,即使其签名有效且时间戳是最新的。
时间戳验证是对 nonce 检查的补充。信封的时间戳必须在服务器当前时间的 ENVELOPE_MAX_AGE_SECONDS (默认 60 秒)范围内。这些机制共同应对四种未授权访问场景:
- 录制重放: 未授权用户捕获一个有效信封并在之后重新提交。该 nonce 已被记录。
- 延迟送达: 传输途中被拦截的信封在新鲜度窗口之后才到达。时间戳检查失败。
- 过期请求重用: 代理缓存中的旧信封被重新提交。nonce 和时间戳检查均失败。
- 预计算伪造: 未授权用户无法预测未来的 nonce 来预先签名信封。
第 5 步:客户端密钥生成
此架构的一个关键安全属性是私钥在本地生成,绝不会传输到任何外部系统。应用程序使用 Python cryptography 库生成 RSA 2048+ 密钥对。它构建一个仅包含公钥和主体信息的 CSR,并仅通过 pkcs10enroll 端点将 CSR 发送给 EJBCA。
EJBCA 验证 CSR,应用证书配置文件(7 天有效期、密钥用途约束),用 CA 密钥签名,并返回颁发的证书。应用程序随后将本地持有的私钥与返回的证书打包成 PKCS12 容器,并存储在 AWS Secrets Manager 中。
此设计提供了多个安全属性:
- 用户的私钥仅在登录时用于签署委托断言。它绝不会与代理共享。
- 每个代理的私钥仅由该代理用于签署信封。它绝不会在代理之间共享。
- EJBCA 从不查看或存储私钥。它纯粹作为证书颁发机构运作。
- 如果 Secrets Manager 遭到未授权访问,PKCS12 密码(单独存储)可提供额外一层保护。
- 密钥材料可以在下次登录时通过提交新的 CSR 重新注册来独立轮换。
第 6 步:完整注销与凭证吊销
注销会触发吊销级联,立即使所有未完成的凭证失效。该流程完成后不会留下任何仍然有效的凭证:
- 在 EJBCA 中吊销用户证书: 这会立即使所有未完成的委托失效,因为委托验证会通过 OCSP 实时检查用户的证书。
- 吊销全部三个代理证书: 这会使所有未完成的已签名信封失效,因为信封验证包含 OCSP 检查。
- 从 AWS Secrets Manager 删除所有密钥: 使用
ForceDeleteWithoutRecovery进行立即删除,且不设恢复窗口。 - 终止 Keycloak 会话: 通过会话终止端点使降权令牌失效。
吊销级联是关键的安全属性。在 PKI 层吊销单个用户证书会迅速吊销所有下游代理权限,而无需逐个吊销令牌、删除会话或联系每个代理。OCSP 提供了传播机制,并且由于每个请求都会检查 OCSP,其效果是即时的。
安全考量
此架构中的设计选择解决了若干对生产环境多代理部署至关重要的安全属性。
私钥隔离。用户的私钥仅存在于登录流程中,且仅用于签署委托。代理密钥按代理单独限定,绝不共享。任何密钥材料都不会跨越信任边界。
委托与凭据共享的对比。代理通过密码学链条(委托到代理指纹到信封签名)证明其权限,而从不持有用户凭据。如果某个代理密钥泄露,只会暴露该代理的密钥,而不是用户的。
受众限定令牌。RFC 8693 令牌交换产生的令牌仅被 MCP 服务器接受。意外泄露的降权令牌无法针对 Keycloak 管理 API、其他服务,甚至另一个 MCP 服务器实例进行身份验证。
重放防护。每请求 nonce 与 60 秒新鲜度窗口的结合确保每个请求都是单次使用且有严格时限的。 ReplayCache 是线程安全且自清理的。
故障即拒绝设计。每次验证失败都会导致立即拒绝。OCSP 不可达:拒绝。签名无效:拒绝。时间戳过期:拒绝。nonce 重放:拒绝。受众错误:拒绝。安全检查没有任何优雅降级机制。
吊销级联。吊销一个用户证书会迅速使所有委托、所有代理权限和所有未完成信封失效。这通过实时 OCSP 传播,无需单独清理凭据。
仅向前的信任链。 ALLOWED_CALLER_ROLES 映射强制确保只有 orchestrator-agent 可以调用 mysql-agent 和 email-agent。子代理之间不能互相调用,不能向上调用编排器,也不能冒充用户。
AI 治理考量
PKI 架构为此系统中的 AI 代理提供了内置的行为边界。生产环境部署应使用 Amazon Bedrock Guardrails 对代理响应实施内容过滤、话题回避和依据检查,并与本文所述的基于 PKI 的访问控制配合使用。
- 工具边界:AI 代理在严格的工具约束下运行。它只能调用预定义的 MCP 工具(
execute_sql,describe_table,list_tables)。代理无法执行任意代码或访问其证书范围之外的资源。 - 人类监督:所有代理操作都会被记录并可供审计。AWS CloudTrail 捕获 AWS API 调用,MCP 服务器记录每次经过验证的工具调用及其完整身份链(用户、代理、时间戳和操作)。
- 数据处理: 用户查询和结果保持在经过身份验证的会话边界内。受众范围的令牌将数据访问限制在特定的 MCP 服务器实例内。
- 基于证书的行为边界: 代理只能调用其持有有效证书的工具。没有
mysql-agent证书的代理无法访问数据库,无论 LLM 可能生成什么指令。
扩展架构
您可以扩展此架构以支持其他代理类型、水平扩展和多租户隔离。以下段落描述了最常见的扩展点。
- 要添加新的代理类型,您只需在
ALLOWED_CALLER_ROLES中添加一个条目。证书在登录时自动颁发,委派断言会动态包含新代理的指纹。无需更改基础设施。 - 对于水平扩展,您可以在负载均衡器后面以高可用模式部署 EJBCA 的 OCSP 响应器。AWS Secrets Manager 支持适合此工作负载的高请求速率。
ReplayCache可以由 Amazon ElastiCache 支持以用于分布式部署。 - 为了在生产环境中强化此架构,您可以通过 AWS CloudHSM 或本地 HSM 使用硬件安全模块(HSM)支持的 EJBCA 签名密钥。OCSP 响应装订可减少验证延迟,证书透明度日志提供已颁发证书的完整审计跟踪。
- 对于多租户部署,您可以创建按租户的证书颁发机构或按租户的委派机构,以实现密码学上的租户隔离。结合按租户的 AWS 账户,这可以在租户之间提供强隔离。
- 您还可以将基于 PKI 的代理身份与 AWS Identity and Access Management(IAM)角色相结合。使用 PKI 进行代理间身份验证,使用 IAM 进行 AWS 服务授权。这两个系统独立工作,提供深度防御。
清理
为避免持续产生费用,请删除在此演练过程中创建的资源:
- 删除 Amazon RDS for MySQL 实例(如果您使用脚本化设置,则删除 AWS CloudFormation 堆栈)。
- 删除 AWS Secrets Manager 中的所有密钥,包括
mcp/前缀下的用户证书和代理证书。 - 从 Amazon SES 中删除已验证的发件人电子邮件地址。
- 终止运行 Keycloak 和 EJBCA 的 Amazon EC2 实例(如果为本演示部署了这些实例)。
- 使用 EJBCA 管理控制台或 REST API 撤销并删除 EJBCA 中的所有测试证书。
- 删除 Keycloak realm(
mcp-realm)以及关联的客户端。 - 如果您使用了脚本化设置,请运行
./scripts/cleanup.sh(Linux)或./scripts/cleanup.bat(Windows)来自动执行这些步骤。
结论
在这篇文章中,我们演示了一种参考架构,它使用 X.509 PKI 与 Keyfactor EJBCA 及 AWS 服务来保护 AI 代理通信。该架构通过四种互补机制解决了多代理 AI 系统中基本的身份信任缺口:
- 签名的请求信封为每一次代理间调用提供加密的所有权证明,使未授权方伪造代理身份或重放其请求的难度显著增加。
- 用户签名的委派断言将授权与凭证共享解耦。代理无需持有用户的私钥或完整会话令牌即可证明自己有权代表用户行事。
- RFC 8693 受众范围限定的令牌将任何令牌泄露造成的暴露范围限制在单一服务边界内。
- 实时 OCSP 撤销检查确认凭证撤销在整个系统中立即生效。撤销一个用户证书即可及时终止所有下游代理的权限。
该架构与框架无关。虽然我们使用 AWS Strands Agents SDK 和 FastMCP 对其进行了演示,但相同的 PKI 模式同样适用于 LangChain、CrewAI、AutoGen 或任何其他使用工具协议的多代理框架。随着 AI 代理的激增并能够访问日益敏感的操作,代理身份基础设施从可选变为必不可少。
要开始使用此参考架构,请参阅 随附的 GitHub 代码仓库。有关所用服务的更多信息,请参阅以下资源:
- Amazon Bedrock
- Amazon Bedrock 用户指南
- Keyfactor EJBCA Enterprise
- MCP 规范
- AWS Strands Agents SDK
- Introducing Strands Agents, an Open Source AI Agents SDK(AWS 开源博客文章)