Skip to content

Instantly share code, notes, and snippets.

@rvennam
Created February 19, 2026 18:25
Show Gist options
  • Select an option

  • Save rvennam/f63b410e1f5492646d0ada7e94df085a to your computer and use it in GitHub Desktop.

Select an option

Save rvennam/f63b410e1f5492646d0ada7e94df085a to your computer and use it in GitHub Desktop.

Workshop: Routing to AWS AgentCore Agents Through Solo Agent Gateway

Overview

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.


Prerequisites

  • An EKS cluster with Solo Enterprise Agent Gateway installed
  • kubectl and aws CLI 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
  • jq and curl installed

Step 1: Set variables

# 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}"

Step 2: Configure JWT authentication on AgentCore

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_REGION

Verify:

aws bedrock-agentcore get-agent-runtime \
  --agent-runtime-id $(echo $AGENT_RUNTIME_ARN | awk -F'/' '{print $2}') \
  --region $AWS_REGION \
  --query 'authorizerConfiguration'

Step 3: Create the gateway route to AgentCore

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

Verify the resources

# 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}'; echo

All three should show Accepted or Attached.

Step 4: Test

Get a JWT from your OIDC provider

# 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)

Send a request (with JWT)

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

Verify auth enforcement

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"}]}'

Step 5: Enterprise policies

Agent Gateway policies apply to the route regardless of backend type.

Rate limiting

# 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}
EOF

Test (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"
done

CORS

kubectl 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
EOF

Step 6: Observability

Agent 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:3000

Cleanup

kubectl delete ns agentcore
kubectl delete ratelimitconfig agentcore-rate-limit -n ${GATEWAY_NS} 2>/dev/null

Summary

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment