AWS Machine Learning Blog

Building a serverless A2A gateway for agent discovery, routing, and access control

6.9内容质量
Building a serverless A2A gateway for agent discovery, routing, and access control

TL;DR · AI 摘要

Building a serverless A2A gateway for agent discovery, routing, and access control Artificial Intelligence Building a se...

核心要点

  • 主题聚焦:Building a serverless A2A gateway for agent disc
  • 来源:AWS Machine Learning Blog,建议结合原文判断细节。
  • AI 分析暂不可用,本条为保底评分与摘要。
#AI#编程#后端#云计算#安全
打开原文

为代理发现、路由和访问控制构建无服务器A2A网关 | 人工智能

为代理发现、路由和访问控制构建无服务器A2A网关

当企业将AI代理部署到不同团队、供应商和基础设施时,管理代理间的通信正成为日益增长的运营负担。没有集中层的情况下,每个新代理集成都会增加点对点连接、独立凭证和自定义路由逻辑。团队需要耗费大量工程周期来搭建连接,而非构建代理功能。访问控制变得碎片化,没有统一位置来强制规定哪些客户端可以访问哪些代理。结果是新代理工作流的上市时间变慢,不一致的认证策略带来更高的安全风险,以及随着网络中每个新代理的添加,运营开销呈二次方增长。

网关模式通过在代理前放置单一入口点来解决这个问题,无论代理运行在Amazon Elastic Container Service(Amazon ECS)、AWS Lambda、Amazon Bedrock AgentCore Runtime、非AWS云还是混合环境中。它集中处理路由并实施细粒度权限,而无需将团队绑定到特定运行时、框架或编排层。该模式基于Agent-to-Agent(A2A)协议,该协议标准化了代理间的通信方式。没有中央编排器的情况下,20个代理的部署需要多达190个点对点连接。

在本文中,您将学习如何在AWS上构建无服务器A2A网关,通过基于路径的路由(/agents/{agentId})在单一域名下托管多个代理。标准A2A客户端无需修改即可工作。该解决方案包含三个层级:

  • 管理层:带发现和语义搜索的集中代理注册表。
  • 控制层:使用JSON网络令牌(JWT)作用域和Lambda授权器实现细粒度访问控制。
  • 执行层:单域名路由,支持OAuth后端认证和服务器发送事件(SSE)流式传输。

请继续阅读,您将部署一个通过Terraform配置的网关,A2A兼容代理可以连接到该网关。

架构

下图展示了网关的组件及请求在系统中的流动方式。

Amazon API Gateway(REST API)作为单一入口点。架构使用REST API是因为REST API支持响应流式传输。基于SSE的实时代理响应需要流式传输。Lambda授权器检查JWT作用域并生成AWS Identity and Access Management(IAM)策略,允许访问特定代理路径(/agents/agent-a/*)并拒绝其他访问。

Lambda函数实现网关逻辑:

  • 授权器:验证JWT并根据作用域到代理的映射生成IAM策略。
  • 注册表:列出调用者可访问的代理,URL重写为指向网关。
  • 搜索:使用Amazon Bedrock中的Amazon Titan Text Embeddings进行语义代理发现。
  • 代理:通过OAuth认证将请求路由到后端代理,通过Lambda Web Adapter支持SSE流式传输。
  • 管理:代理注册和生命周期管理。

Amazon DynamoDB存储三个表。代理注册表将代理ID映射到后端URL、认证配置和缓存的代理卡片。权限表将JWT作用域映射到允许的代理。速率限制计数器表统计每分钟请求数。

Amazon Cognito 使用 OAuth 2.0 客户端凭证流程处理身份验证。令牌中的范围决定了调用者可以访问哪些代理。当客户端进行身份验证时,会收到包含 billing:read 或 support:write 等范围的 JWT。授权器会在权限表中查找这些范围,以确定客户端可以访问哪些代理。

AWS Secrets Manager 存储后端凭证。当 Proxy Lambda 需要与后端代理进行身份验证时,它会通过 Amazon 资源名称 (ARN) 获取 OAuth 客户端密钥。密钥不会存储在 DynamoDB 中。

对于语义搜索,代理描述使用 Amazon Titan 文本嵌入进行编码并存储在 Amazon S3 向量存储中。这使客户端可以通过自然语言查询而不是精确名称匹配来发现代理。

网关设计

A2A 原生端点遵循 A2A 协议规范并路由到后端代理。网关支持规范中定义的两种协议绑定。JSON-RPC 为每个代理使用单个端点,请求体中包含方法:

  • GET /agents/{agentId}/.well-known/agent-card.json – 获取代理能力。
  • POST /agents/{agentId} 附带 {"method": "SendMessage", ...}(用于缓冲响应)。
  • POST /agents/{agentId} 附带 {"method": "SendStreamingMessage", ...}(用于 SSE 流式传输)。

对于偏好 RESTful URL 的客户端,还支持 HTTP+JSON/REST 绑定。

这些端点完全符合 A2A 协议规范。客户端指向网关 URL 而不是单个后端 URL。然而,A2A 原生端点本身无法解决管理问题。客户端仍然需要一种方式来发现可用代理、按能力搜索代理以及管理代理生命周期。

网关端点提供这一层功能:

  • GET /agents – 列出调用者可访问的代理。
  • POST /search – 语义搜索代理。
  • POST /admin/agents/register – 注册新后端代理。
  • POST /admin/agents/{agentId}/sync – 刷新缓存的代理卡片。
  • POST /admin/agents/{agentId}/status – 启用或停用代理。

每个请求遵循相同路径。客户端在 Authorization 请求头中发送包含 JWT 的请求。API Gateway 调用 Lambda 授权器,授权器验证 JWT 并在权限表中查找调用者的范围。授权器返回允许或拒绝访问特定代理的 IAM 策略。如果允许,请求将路由到相应 Lambda:Proxy 处理 A2A 流量,Registry 处理代理发现,Search 处理语义查询,Admin 处理管理操作。对于 A2A 请求,Proxy Lambda 使用 OAuth 与后端身份验证并转发请求。未授权的请求在 API Gateway 被拒绝,不会到达后端 Lambda。

三层模型

随着代理部署规模扩大,团队需要了解可用资源情况。管理层提供集中式注册表,代理按其能力、后端 URL 和状态进行分类。新代理部署时,只需在网关注册一次即可被授权客户端立即发现。注册表还会缓存代理卡片,使客户端无需单独从每个后端获取能力信息。缓存卡片的 URL 会被重写为通过网关的路径,因此客户端与单一网关域名交互,而不是发现后端 URL。对于更大规模部署,语义搜索使客户端可以通过描述需求而非精确名称来查找代理。

在企业环境中,并非每个客户端都应访问每个代理。控制层基于 JWT 范围实施细粒度权限控制。当客户端进行身份验证时,其令牌包含类似 billing:read 或 support:admin 的范围。Lambda 授权器将这些范围映射到权限表中的特定代理,并生成 IAM 策略,在 API Gateway 层实现访问允许或拒绝。未经授权的请求不会到达后端 Lambda。此外,代理层按用户和代理实施速率限制。代理通过带有自动生存时间(TTL)的原子 DynamoDB 计数器跟踪请求次数,当客户端超出配额时会返回带 Retry-After 头的 429 响应。权限和速率限制由中心管理:要授予权限、撤销访问或调整配额,只需更新权限表,而无需修改每个代理。

执行层负责处理请求到后端代理的实际路由。客户端连接到单个域名,网关根据路径路由到相应的后端。这简化了网络配置:无需向每个代理开放连接,客户端只需访问网关即可。代理 Lambda 处理与后端的 OAuth 认证,因此客户端无需管理后端凭证。它从 Secrets Manager 获取密钥,获取访问令牌,并透明地转发请求。对于实时用例,代理支持 SSE 流式传输,允许代理在生成时逐步将响应发送回客户端。

部署解决方案

网关完全通过 Terraform 部署。首先确认您具备以下条件。

先决条件

  • Terraform >= 1.5.0
  • Python 3.12
  • 已配置有效凭证的 AWS 命令行界面(AWS CLI)
  • Docker(用于构建代理 Lambda 容器)
  • 用于 Terraform 状态的 Amazon Simple Storage Service(Amazon S3)存储桶(可选,用于远程状态)

网关代码可在 aws-samples GitHub 仓库获取。

克隆仓库并配置变量:

code
cp terraform/terraform.tfvars.example terraform/terraform.tfvars

编辑 terraform/terraform.tfvars 文件,设置您的区域和命名偏好:

code
aws_region = "us-east-1"
project_name = "a2a-gateway"
environment = "poc"

构建 Lambda 包并部署:

code
./scripts/build_lambda_package.sh
cd terraform
terraform init
terraform plan
terraform apply

Terraform 一次性创建所有资源:DynamoDB 表、Cognito 用户池、Amazon Elastic Container Registry(Amazon ECR)仓库、Lambda 函数、API Gateway 和 IAM 角色。Terraform 在部署过程中会构建并推送代理 Lambda 容器。

测试解决方案

从 Terraform 输出中获取网关凭证:

code
GATEWAY_URL=$(terraform output -raw api_gateway_url)
TOKEN_ENDPOINT=$(terraform output -raw cognito_token_endpoint)
CLIENT_ID=$(terraform output -raw cognito_client_id)
CLIENT_SECRET=$(terraform output -raw cognito_client_secret)
PERMISSIONS_TABLE=$(terraform output -raw permissions_table_name)

获取 JWT:

code
TOKEN_RESPONSE=$(curl -s -X POST "$TOKEN_ENDPOINT" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET")
export JWT=$(echo $TOKEN_RESPONSE | jq -r .access_token)

该仓库在 examples/ 目录中包含可部署的 A2A 示例代理:天气代理和计算器代理。它们可以通过各自的 Terraform 配置进行部署。可选地,使用以下命令部署它们:

code
# 在部署示例代理后,从 examples/terraform 目录
WEATHER_BACKEND=$(terraform output -raw weather_agent_backend_url)
WEATHER_CARD=$(terraform output -raw weather_agent_card_url)
AGENT_TOKEN_ENDPOINT=$(terraform output -raw cognito_token_endpoint)
AGENT_CLIENT_ID=$(terraform output -raw cognito_client_id)
AGENT_CLIENT_SECRET=$(terraform output -raw cognito_client_secret)

然后使用网关注册代理(使用之前捕获的 $GATEWAY_URL 和 $JWT):

code
curl -X POST "$GATEWAY_URL/admin/agents/register" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "agentId": "weather-agent",
    "name": "Weather Agent",
    "backendUrl": "'"$WEATHER_BACKEND"'",
    "agentCardUrl": "'"$WEATHER_CARD"'",
    "authConfig": {
      "type": "oauth2_client_credentials",
      "tokenUrl": "'"$AGENT_TOKEN_ENDPOINT"'",
      "clientId": "'"$AGENT_CLIENT_ID"'",
      "clientSecret": "'"$AGENT_CLIENT_SECRET"'",
      "scopes": ["a2a-gateway/weather:read"]
    }
  }'

网关实施细粒度访问控制。每个 OAuth 范围必须在 DynamoDB 权限表中显式授予对特定代理的访问权限。

更新权限以允许您的范围访问已注册的代理:

code
aws dynamodb put-item \
  --table-name "$PERMISSIONS_TABLE" \
  --item '{
    "scope": {"S": "gateway:admin"},
    "allowedAgents": {"L": [{"S": "weather-agent"}]},
    "description": {"S": "Admin scope with access to weather agent"}
  }'

发现已注册的代理并通过网关发送消息:

code
curl "$GATEWAY_URL/agents" -H "Authorization: Bearer $JWT"

curl -X POST "$GATEWAY_URL/agents/weather-agent/message:send" \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "message": {
      "messageId": "msg-001",
      "role": "user",
      "parts": [{"text": "What is the weather in New York"}]
    }
  }'

清理

要清理解决方案,请从 /terraform 文件夹运行 terraform destroy。Terraform 会要求您确认是否删除资源。

code
terraform destroy

安全注意事项

此网关是参考实现。在投入生产环境之前,请根据组织的安全要求审查以下需要加强的领域。

后端信任模型

网关基于认证后信任模型运行。在后端代理注册且 OAuth 凭据验证后,网关会直接将响应代理到客户端而不会进行内容检查。A2A 消息在代理过程中不会被修改,因此后端代理需自行实现提示注入防御和输入验证。在生产环境中,应为代理注册实施审批流程,由管理员在代理可访问之前审核后端代理。将此流程与持续集成和持续交付(CI/CD)管道集成,使代理的审核作为部署过程的一部分,而非部署之后。

速率限制和配额

网关在代理层实施针对每个用户和每个代理的速率限制。每个请求都会在DynamoDB中根据用户、代理和分钟窗口增加一个原子计数器。当客户端超出配额时,代理会返回429状态码并包含重试时间头,请求不会到达后端。计数器通过DynamoDB的TTL功能自动过期,因此无需清理开销。限流规则与权限表中的访问控制一起配置,可以设置为默认每分钟请求数或按代理覆盖,为管理员提供细粒度的使用控制。

私有部署

对于需要私有基础设施的环境,网关支持可选的Amazon虚拟私有云(Amazon VPC)部署模式。启用此模式后,Lambda函数将在私有子网内运行。API网关切换为仅限VPC内部访问的私有端点。VPC端点处理到AWS服务的流量而无需经过互联网。

网关支持创建新VPC或使用现有VPC。要部署到现有VPC,请在terraform.tfvars中提供以下信息:

code
enable_private_deployment = true
existing_vpc_id = "vpc-0123456789abcdef0"
existing_subnet_ids = ["subnet-aaa", "subnet-bbb", "subnet-ccc"]
existing_route_table_ids = ["rtb-aaa"]
existing_lambda_security_group_id = "sg-aaa"
existing_vpc_endpoint_security_group_id = "sg-bbb"

请注意,此模式使网关基础设施私有化,但您的VPC仍需要通过NAT网关或AWS Transit Gateway路由到共享出站VPC来实现与Cognito或其他外部身份提供商的OAuth令牌交换。AWS服务流量(DynamoDB、Amazon S3、Secrets Manager、S3 Vectors)通过VPC端点保持私有。只有OAuth令牌交换需要出站连接。如果需要使用Amazon Bedrock进行语义搜索,请将enable_bedrock_endpoint设置为true以添加Amazon Bedrock Runtime VPC端点。

对于在本地或其它云环境中运行的代理,私有网关可通过AWS Direct Connect或AWS Interconnect(预览版)访问。这使网关能够跨不同环境管理代理而无需暴露流量到公共互联网。

A2A服务器认证

网关使用OAuth 2.0客户端凭证流程与后端代理进行认证。每个已注册代理包含其令牌URL和凭证,代理Lambda函数会透明地处理令牌获取。这意味着无论后端代理运行在哪里,都必须启用OAuth认证进行部署。

当使用Amazon Bedrock AgentCore Runtime时,一个关键细节:配置customJWTAuthorizer时应将allowedClients设置为您的Cognito客户端ID,而不是allowedAudience。Cognito客户端凭证令牌包含client_id声明但不包含标准JWT aud声明。allowedAudience参数会验证aud声明并对Cognito机器到机器(M2M)令牌返回401未授权。使用allowedClients验证client_id,这正是Cognito令牌提供的字段。有关完整的认证选项,请参见AgentCore A2A协议合同。

结论

随着组织从少量代理扩展到数十甚至数百个,运营挑战的重点也从构建单个代理转向管理它们之间的连接。点对点集成无法扩展。团队不应需要了解每个代理的位置、为每个代理管理单独的凭证,或从零开始构建自己的发现和访问控制机制。

该网关为您提供了一个统一的注册代理、控制访问权限和路由流量的场所。由于其在协议层面运行,它能够跨不同环境管理代理:AWS 服务、第三方云平台、本地基础设施或混合环境。支持 A2A 协议的后端均可使用。只需将代理的 URL 和 OAuth 凭证进行注册,网关即可处理其余工作。底层运行时环境无关紧要。新代理在注册的瞬间即可被发现,访问控制和速率限制也通过中心化方式管理,而非分散在各个后端。

A2A 协议规范了代理之间通信的标准方式。网关则规范了组织管理这种通信的方式。完整源代码可在 aws-samples 仓库中获取。

关于作者

'"`