When you deploy 20 agents, you face up to 190 point-to-point connections. Each agent needs credentials for every other agent it calls, separate routing logic, and custom access control. The operational burden scales quadratically.
AWS published a serverless A2A gateway pattern on July 1, 2026 that solves this with path-based routing. All agents sit behind a single domain. Standard A2A clients work without modification. The gateway handles discovery, routing, and access control using API Gateway, Lambda, and DynamoDB.
This is not a service mesh. It is not a custom protocol. It is HTTP routing with JWT scopes and a registry.
Why Path-Based Routing Matters
The pattern uses /agents/{agentId} instead of subdomains or port-based addressing. This choice has infrastructure consequences:
- Single TLS certificate covers all agents. No wildcard DNS or per-agent cert rotation.
- One API Gateway endpoint handles all traffic. No load balancer sprawl.
- Standard HTTP clients work unchanged. No custom SDKs or protocol negotiation.
Path-based routing means the gateway extracts {agentId} from the URL, looks up the backend in DynamoDB, and proxies the request. The agent does not need to know it is behind a gateway. The client does not need to know which backend hosts the agent.
Three-Layer Architecture
The gateway splits into management, control, and execution layers.
Management Layer: Agent Registry
A DynamoDB table stores agent metadata:
- Agent ID (primary key)
- Backend endpoint (ECS task, Lambda URL, Bedrock runtime)
- Semantic tags for discovery
- OAuth credentials for backend authentication
Agents register themselves at startup or via an admin API. The registry supports semantic search so agents can discover peers by capability instead of hardcoded IDs.
Control Layer: JWT Scopes and Lambda Authorizer
API Gateway uses a Lambda authorizer to validate JWTs. The token includes scopes like agent:read:agentId or agent:invoke:*. The authorizer checks:
- Token signature (Cognito or external IdP)
- Scope match against the requested agent ID
- Rate limits or IP allowlists (optional)
If the token lacks the required scope, the request fails before reaching the backend. This centralizes access control. You do not configure permissions on each agent.
Execution Layer: Proxy and SSE Streaming
API Gateway forwards the request to the backend endpoint stored in DynamoDB. The gateway:
- Adds OAuth tokens for backend authentication (retrieved from Secrets Manager)
- Preserves headers like
Content-TypeandX-Request-ID - Streams Server-Sent Events (SSE) responses back to the client without buffering
Lambda handles the routing logic. It queries DynamoDB for the backend URL, fetches OAuth credentials, and returns a proxy configuration to API Gateway.
Code Snippet: Lambda Authorizer Logic
import json
import jwt
from jwt import PyJWKClient
def lambda_handler(event, context):
token = event['authorizationToken'].replace('Bearer ', '')
# Validate JWT signature
jwks_client = PyJWKClient(JWKS_URL)
signing_key = jwks_client.get_signing_key_from_jwt(token)
decoded = jwt.decode(token, signing_key.key, algorithms=['RS256'])
# Extract requested agent ID from path
agent_id = event['methodArn'].split('/agents/')[1].split('/')[0]
# Check scope
scopes = decoded.get('scope', '').split()
required_scope = f'agent:invoke:{agent_id}'
if required_scope in scopes or 'agent:invoke:*' in scopes:
return generate_policy('Allow', event['methodArn'])
else:
return generate_policy('Deny', event['methodArn'])
def generate_policy(effect, resource):
return {
'principalId': 'user',
'policyDocument': {
'Version': '2012-10-17',
'Statement': [{
'Action': 'execute-api:Invoke',
'Effect': effect,
'Resource': resource
}]
}
}
This authorizer runs on every request. It adds 10-50ms of latency but eliminates per-agent auth configuration.
Comparison: Gateway vs. Service Mesh vs. Direct Connections
| Approach | DNS Complexity | TLS Overhead | Access Control | Latency Penalty | Operational Burden |
|---|---|---|---|---|---|
| Direct connections | High (N² entries) | High (N certs) | Per-agent config | None | Quadratic scaling |
| Service mesh | Medium (sidecar injection) | Medium (mTLS per hop) | Policy CRDs | 5-15ms per hop | Kubernetes dependency |
| Serverless gateway | Low (single domain) | Low (one cert) | Centralized JWT scopes | 10-50ms (authorizer) | DynamoDB + Lambda |
The gateway trades latency for operational simplicity. If you need sub-10ms routing, a service mesh is faster. If you want to avoid Kubernetes and sidecar injection, the serverless pattern works.
Failure Modes and Observability
The gateway introduces new failure points:
- DynamoDB throttling: If agent lookups exceed provisioned capacity, requests fail. Use on-demand billing or provision read capacity based on request rate.
- Lambda cold starts: The authorizer and routing Lambda can add 500ms on the first request. Keep functions warm with scheduled invocations or provisioned concurrency.
- Secrets Manager rate limits: Backend OAuth tokens are fetched per request. Cache tokens in Lambda memory with TTL-based refresh.
For observability, the gateway emits CloudWatch metrics:
AuthorizerLatency: Time spent validating JWTsRoutingLatency: Time spent looking up backends in DynamoDBBackendErrors: 5xx responses from agent backends
Enable API Gateway access logs to capture full request traces. Use X-Ray for distributed tracing across the gateway and agent backends.
When Standard A2A Clients Work Without Modification
The gateway is compatible with A2A clients that:
- Send
Authorization: Bearer <token>headers - Accept HTTP 307 redirects (optional, for backend failover)
- Handle SSE streams with
Content-Type: text/event-stream
Clients do not need custom SDKs. They do not need to know the backend topology. They call https://gateway.example.com/agents/order-agent/invoke and the gateway handles the rest.
This works because the gateway does not change the A2A protocol. It routes HTTP requests based on path and enforces access control with standard JWT scopes.
Deployment Shape
The full stack includes:
- API Gateway: HTTP API with JWT authorizer
- Lambda functions: Authorizer (Python 3.12) and routing proxy (Python 3.12)
- DynamoDB table: Agent registry with on-demand billing
- Secrets Manager: OAuth tokens for backend authentication
- Cognito user pool: JWT issuer for client authentication (optional, can use external IdP)
Deploy with CloudFormation or Terraform. The gateway is stateless. Scale by increasing Lambda concurrency and DynamoDB capacity.
Technical Verdict
Use this pattern when:
- You have 10+ agents and want to avoid point-to-point connections
- You need centralized access control without modifying agent code
- You want to support multiple agent runtimes (ECS, Lambda, Bedrock, external APIs)
- You can tolerate 10-50ms of gateway latency
Avoid this pattern when:
- You need sub-10ms routing (use a service mesh or direct connections)
- Your agents already run in Kubernetes (Istio or Linkerd may be simpler)
- You have fewer than 5 agents (the operational overhead is not worth it)
The serverless A2A gateway is plumbing for multi-agent systems. It does not orchestrate workflows or manage state. It routes requests and enforces permissions. If you need orchestration, layer it on top with Step Functions or a custom coordinator.