In this workshop you will route requests to an AWS Bedrock AgentCore agent through Solo Agent Gateway — with no proxy, no custom code, and no AWS SDK. AgentCore's JWT authentication lets the gateway forward requests directly, using standard Kubernetes Gateway API resources.
HTTPS + Bearer JWT
┌──────────┐ ┌──────────────────┐ ┌─────────────────────┐
│ │ │ │ │ │
│ Client ├─JWT─▶│ Agent Gateway ├─────▶│ AWS Bedrock │
│ │◀─────┤ (path + host │◀─────┤ AgentCore │
│ │ │ rewrite, TLS) │ │ (validates JWT, │
│ │ │ │ │ runs agent) │
└──────────┘ └──────────────────┘ └─────────────────────┘
rate limiting,
CORS, observability
Three Kubernetes resources are all you need:
| Resource | Purpose |
|---|---|
AgentgatewayBackend |
Points to bedrock-agentcore.{region}.amazonaws.com:443 |
EnterpriseAgentgatewayPolicy |
TLS origination to the HTTPS endpoint |
HTTPRoute |
Rewrites path to /runtimes/{arn}/invocations and host header |
The client sends AgentCore's native payload format with a Bearer JWT. Agent Gateway forwards it. AgentCore validates the JWT and invokes the agent.
- An EKS cluster with Solo Enterprise Agent Gateway installed
kubectlandawsCLI tools- An AgentCore agent runtime deployed (you need the ARN)
- An OIDC provider (Auth0, Keycloak, Okta, etc.) configured as a JWT authorizer on your AgentCore agent
jqandcurlinstalled
# Your AgentCore agent ARN
export AGENT_RUNTIME_ARN="arn:aws:bedrock-agentcore:us-east-1:986112284769:runtime/rvennam_agent-tEJ8OxEBo1"
export AWS_REGION="us-east-1"
# URL-encode the ARN for use in the HTTP path
export ENCODED_ARN=$(python3 -c "from urllib.parse import quote; print(quote('${AGENT_RUNTIME_ARN}', safe=''))")
# OIDC provider details (replace with your provider)
export OIDC_ISSUER_URL="https://your-idp.example.com"
export OIDC_AUDIENCE="agentcore"
export OIDC_CLIENT_ID="your-client-id"
export OIDC_CLIENT_SECRET="your-client-secret"
# Agent Gateway details
export GATEWAY_NAME="agentgateway"
export GATEWAY_NS="enterprise-agentgateway"
# Get the gateway external address
export GW_ADDR=$(kubectl get svc -n $GATEWAY_NS $GATEWAY_NAME \
-o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}")
export GW_PORT=$(kubectl get svc -n $GATEWAY_NS $GATEWAY_NAME \
-o jsonpath="{.spec.ports[0].port}")
echo "Gateway: http://${GW_ADDR}:${GW_PORT}"Tell AgentCore to accept JWTs from your OIDC provider. AgentCore uses the provider's discovery endpoint to fetch public keys and validate tokens.
aws bedrock-agentcore update-agent-runtime \
--agent-runtime-id $(echo $AGENT_RUNTIME_ARN | awk -F'/' '{print $2}') \
--authorizer-configuration '{
"customJWTAuthorizer": {
"discoveryUrl": "'${OIDC_ISSUER_URL}'/.well-known/openid-configuration",
"allowedAudience": ["'${OIDC_AUDIENCE}'"]
}
}' \
--region $AWS_REGIONVerify:
aws bedrock-agentcore get-agent-runtime \
--agent-runtime-id $(echo $AGENT_RUNTIME_ARN | awk -F'/' '{print $2}') \
--region $AWS_REGION \
--query 'authorizerConfiguration'Apply three resources: an external backend, a TLS policy, and an HTTPRoute.
kubectl create ns agentcore
kubectl apply -f - <<EOF
---
# External backend pointing to AgentCore's HTTPS endpoint
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayBackend
metadata:
name: agentcore
namespace: agentcore
spec:
static:
host: bedrock-agentcore.${AWS_REGION}.amazonaws.com
port: 443
---
# TLS origination — Agent Gateway connects to AgentCore over HTTPS
apiVersion: enterpriseagentgateway.solo.io/v1alpha1
kind: EnterpriseAgentgatewayPolicy
metadata:
name: agentcore-tls
namespace: agentcore
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: agentcore
backend:
tls: {}
---
# Route: rewrite path to the AgentCore invocation URL, rewrite Host header
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: agentcore
namespace: agentcore
spec:
parentRefs:
- name: ${GATEWAY_NAME}
namespace: ${GATEWAY_NS}
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
- type: URLRewrite
urlRewrite:
hostname: bedrock-agentcore.${AWS_REGION}.amazonaws.com
path:
type: ReplaceFullPath
replaceFullPath: /runtimes/${ENCODED_ARN}/invocations
backendRefs:
- name: agentcore
kind: AgentgatewayBackend
group: agentgateway.dev
EOF# Backend accepted?
kubectl get agentgatewaybackend agentcore -n agentcore \
-o jsonpath='{.status.conditions[0].reason}'; echo
# HTTPRoute accepted?
kubectl get httproute agentcore -n agentcore \
-o jsonpath='{.status.parents[0].conditions[0].reason}'; echo
# TLS policy attached?
kubectl get enterpriseagentgatewaypolicy agentcore-tls -n agentcore \
-o jsonpath='{.status.ancestors[1].conditions[1].reason}'; echoAll three should show Accepted or Attached.
# Auth0 example (client credentials flow)
TOKEN=$(curl -s -X POST "${OIDC_ISSUER_URL}/oauth/token" \
-H "Content-Type: application/json" \
-d '{
"client_id": "'${OIDC_CLIENT_ID}'",
"client_secret": "'${OIDC_CLIENT_SECRET}'",
"audience": "'${OIDC_AUDIENCE}'",
"grant_type": "client_credentials"
}' | jq -r .access_token)
echo "Token: ${TOKEN:0:20}..."Keycloak client credentials flow
TOKEN=$(curl -s -X POST "${OIDC_ISSUER_URL}/protocol/openid-connect/token" \
-d "grant_type=client_credentials" \
-d "client_id=${OIDC_CLIENT_ID}" \
-d "client_secret=${OIDC_CLIENT_SECRET}" | jq -r .access_token)curl -s -X POST "http://${GW_ADDR}:${GW_PORT}/" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{
"role": "user",
"content": [{"text": "Hello from Agent Gateway!"}]
}' | jq .The request flows: curl -> Agent Gateway (rewrite + TLS) -> AgentCore (JWT validated) -> Claude
No token (expect 401):
curl -s -o /dev/null -w "HTTP %{http_code}\n" -X POST "http://${GW_ADDR}:${GW_PORT}/" \
-H "Content-Type: application/json" \
-d '{"role":"user","content":[{"text":"test"}]}'Invalid token (expect 403):
curl -s -o /dev/null -w "HTTP %{http_code}\n" -X POST "http://${GW_ADDR}:${GW_PORT}/" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer invalid.jwt.token" \
-d '{"role":"user","content":[{"text":"test"}]}'Agent Gateway policies apply to the route regardless of backend type.
# Rate limit config (in the gateway namespace)
kubectl apply -f - <<EOF
apiVersion: ratelimit.solo.io/v1alpha1
kind: RateLimitConfig
metadata:
name: agentcore-rate-limit
namespace: ${GATEWAY_NS}
spec:
raw:
descriptors:
- key: generic_key
value: counter
rateLimit:
requestsPerUnit: 3
unit: MINUTE
rateLimits:
- actions:
- genericKey:
descriptorValue: counter
type: REQUEST
EOF
# Attach to the HTTPRoute
kubectl apply -f - <<EOF
apiVersion: enterpriseagentgateway.solo.io/v1alpha1
kind: EnterpriseAgentgatewayPolicy
metadata:
name: agentcore-rate-limit
namespace: agentcore
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: agentcore
traffic:
entRateLimit:
global:
rateLimitConfigRefs:
- name: agentcore-rate-limit
namespace: ${GATEWAY_NS}
EOFTest (first 3 succeed, then 429):
for i in $(seq 1 6); do
CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST "http://${GW_ADDR}:${GW_PORT}/" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"role":"user","content":[{"text":"ping"}]}')
echo "Request $i: HTTP $CODE"
donekubectl apply -f - <<EOF
apiVersion: enterpriseagentgateway.solo.io/v1alpha1
kind: EnterpriseAgentgatewayPolicy
metadata:
name: agentcore-cors
namespace: agentcore
spec:
targetRefs:
- group: gateway.networking.k8s.io
kind: HTTPRoute
name: agentcore
traffic:
cors:
allowOrigins:
- exact: "https://your-app.example.com"
allowMethods:
- POST
- OPTIONS
allowHeaders:
- Content-Type
- Authorization
maxAge: 86400s
EOFAgent Gateway exports OTel metrics and traces for all traffic, including requests to AgentCore.
# Proxy logs
kubectl logs -n ${GATEWAY_NS} -l app.kubernetes.io/name=agentgateway -f
# Grafana (if OTel stack is deployed)
kubectl port-forward svc/grafana-prometheus-grafana -n monitoring 3000:80 &
# Open http://localhost:3000kubectl delete ns agentcore
kubectl delete ratelimitconfig agentcore-rate-limit -n ${GATEWAY_NS} 2>/dev/null| What | How |
|---|---|
| Authentication | JWT — AgentCore validates directly via customJWTAuthorizer |
| Routing | AgentgatewayBackend (external) + HTTPRoute (path/host rewrite) |
| TLS | EnterpriseAgentgatewayPolicy with backend.tls |
| Custom code | None |
| Docker image | None |
| AWS SDK / IAM | None |
| Rate limiting | RateLimitConfig + EnterpriseAgentgatewayPolicy |
| CORS | EnterpriseAgentgatewayPolicy with traffic.cors |
| Observability | Built-in OTel metrics/traces through Agent Gateway |