Skip to content

Instantly share code, notes, and snippets.

@rvennam
Created February 13, 2026 03:39
Show Gist options
  • Select an option

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

Select an option

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

AWS Bedrock with IRSA (IAM Roles for Service Accounts)

This workshop configures Solo Enterprise Agent Gateway to access AWS Bedrock without storing AWS credentials as Kubernetes secrets. Instead, we use EKS IAM Roles for Service Accounts (IRSA) to let the agentgateway pod assume an IAM role natively.

Why IRSA?

  • No long-lived AWS access keys to manage or rotate
  • Credentials are short-lived and automatically refreshed
  • Fine-grained IAM permissions scoped to a single service account
  • Follows AWS security best practices for EKS workloads

Prerequisites

  • An EKS cluster with Solo Enterprise Agent Gateway installed
  • kubectl, aws, and eksctl CLI tools installed and configured
  • AWS IAM permissions to create roles and OIDC providers
  • Amazon Bedrock model access enabled in your region

Part 1: Environment Setup

1.1 Set Environment Variables

Update these values for your environment.

export CLUSTER_NAME="<your-eks-cluster-name>"
export AWS_REGION="us-east-1"
export NAMESPACE="enterprise-agentgateway"
export SA_NAME="agentgateway"
export ROLE_NAME="agentgateway-bedrock-irsa"

# Auto-detect account ID
export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
echo "Account ID: $ACCOUNT_ID"
echo "Cluster: $CLUSTER_NAME"
echo "Region: $AWS_REGION"

1.2 Verify Cluster Access

kubectl config current-context
kubectl get ns $NAMESPACE

1.3 Verify Bedrock Model Access

aws bedrock get-foundation-model \
  --model-identifier amazon.nova-micro-v1:0 \
  --region $AWS_REGION \
  --query 'modelDetails.{modelId:modelId,status:modelLifecycle.status}' \
  --output table

Part 2: Configure IRSA

IRSA works by:

  1. Associating the EKS cluster's OIDC issuer with AWS IAM
  2. Creating an IAM role that trusts a specific Kubernetes service account
  3. Annotating the service account with the role ARN
  4. EKS automatically injects temporary AWS credentials into the pod

2.1 Associate the EKS OIDC Provider with IAM

This registers your cluster's OIDC issuer so IAM can validate service account tokens.

eksctl utils associate-iam-oidc-provider \
  --cluster $CLUSTER_NAME \
  --approve

2.2 Get the OIDC Provider ID

export OIDC_ISSUER=$(aws eks describe-cluster \
  --name $CLUSTER_NAME \
  --query "cluster.identity.oidc.issuer" \
  --output text)

export OIDC_ID=$(echo $OIDC_ISSUER | sed 's|.*/id/||')

echo "OIDC Issuer: $OIDC_ISSUER"
echo "OIDC ID: $OIDC_ID"

2.3 Create the IAM Trust Policy

This policy allows only the agentgateway service account in the enterprise-agentgateway namespace to assume the role.

cat > /tmp/trust-policy.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/oidc.eks.${AWS_REGION}.amazonaws.com/id/${OIDC_ID}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.${AWS_REGION}.amazonaws.com/id/${OIDC_ID}:sub": "system:serviceaccount:${NAMESPACE}:${SA_NAME}",
          "oidc.eks.${AWS_REGION}.amazonaws.com/id/${OIDC_ID}:aud": "sts.amazonaws.com"
        }
      }
    }
  ]
}
EOF

cat /tmp/trust-policy.json | python3 -m json.tool

2.4 Create the IAM Role

aws iam create-role \
  --role-name $ROLE_NAME \
  --assume-role-policy-document file:///tmp/trust-policy.json \
  --description "IRSA role for agentgateway to access Amazon Bedrock" \
  --query 'Role.Arn' \
  --output text

2.5 Attach the Bedrock Access Policy

aws iam attach-role-policy \
  --role-name $ROLE_NAME \
  --policy-arn arn:aws:iam::aws:policy/AmazonBedrockFullAccess

echo "Attached policies:"
aws iam list-attached-role-policies \
  --role-name $ROLE_NAME \
  --query 'AttachedPolicies[].PolicyName' \
  --output table

Part 3: Deploy Agentgateway Resources

Now we configure agentgateway to use IRSA for Bedrock access. The key difference from secret-based auth is:

  • The AgentgatewayBackend omits policies.auth (no secret reference)
  • The EnterpriseAgentgatewayParameters annotates the data plane service account with the IAM role ARN

3.1 Create the Bedrock Backend

Note: there is no policies.auth section. This signals to agentgateway to use the pod's own AWS credentials (provided via IRSA).

cat <<EOF | kubectl apply -f -
apiVersion: agentgateway.dev/v1alpha1
kind: AgentgatewayBackend
metadata:
  name: bedrock
  namespace: $NAMESPACE
spec:
  ai:
    provider:
      bedrock:
        model: "amazon.nova-micro-v1:0"
        region: "$AWS_REGION"
EOF

# Verify the backend is accepted
kubectl get agentgatewaybackend bedrock -n $NAMESPACE \
  -o jsonpath='{.status.conditions[0].message}'

3.2 Annotate the Service Account with the IRSA Role

This patches the EnterpriseAgentgatewayParameters to add the eks.amazonaws.com/role-arn annotation to the agentgateway data plane service account. EKS will then inject AWS credentials into the pod.

export ROLE_ARN="arn:aws:iam::${ACCOUNT_ID}:role/${ROLE_NAME}"

kubectl patch enterpriseagentgatewayparameters agentgateway-params \
  -n $NAMESPACE \
  --type merge \
  -p '{
    "spec": {
      "serviceAccount": {
        "metadata": {
          "annotations": {
            "eks.amazonaws.com/role-arn": "'$ROLE_ARN'"
          }
        }
      }
    }
  }'

# Verify annotation on service account
kubectl get sa $SA_NAME -n $NAMESPACE \
  -o jsonpath='{.metadata.annotations}' | python3 -m json.tool

3.3 Create the HTTP Route

Route traffic through the agentgateway to the Bedrock backend.

cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: bedrock
  namespace: $NAMESPACE
spec:
  parentRefs:
    - name: agentgateway
      namespace: $NAMESPACE
  rules:
  - backendRefs:
    - name: bedrock
      namespace: $NAMESPACE
      group: agentgateway.dev
      kind: AgentgatewayBackend
EOF

# Verify the route is accepted
kubectl get httproute bedrock -n $NAMESPACE \
  -o jsonpath='{.status.parents[0].conditions[0].reason}'

3.4 Restart the Agentgateway Deployment

The pods need to be restarted so the EKS mutating webhook can inject the IRSA projected token and environment variables.

kubectl rollout restart deployment agentgateway -n $NAMESPACE
kubectl rollout status deployment agentgateway -n $NAMESPACE --timeout=120s

Part 4: Verify IRSA Injection

Confirm that the EKS webhook injected the correct environment variables and projected token volume into the agentgateway pod.

POD=$(kubectl get pods -n $NAMESPACE \
  -l app.kubernetes.io/name=agentgateway \
  -o jsonpath='{.items[0].metadata.name}')

echo "Pod: $POD"
echo ""
echo "=== IRSA Environment Variables ==="
kubectl get pod $POD -n $NAMESPACE \
  -o jsonpath='{range .spec.containers[0].env[*]}{.name}={.value}{"\n"}{end}' \
  | grep -E "AWS_ROLE_ARN|AWS_WEB_IDENTITY_TOKEN_FILE|AWS_REGION"

echo ""
echo "=== Projected Token Volume ==="
kubectl get pod $POD -n $NAMESPACE \
  -o jsonpath='{.spec.volumes[?(@.name=="aws-iam-token")]}' | python3 -m json.tool

You should see:

  • AWS_ROLE_ARN set to your IAM role ARN
  • AWS_WEB_IDENTITY_TOKEN_FILE set to /var/run/secrets/eks.amazonaws.com/serviceaccount/token
  • A projected volume named aws-iam-token with audience sts.amazonaws.com

Part 5: Test Bedrock Access

Send a chat completion request through the agentgateway to verify end-to-end connectivity with Bedrock using IRSA credentials.

5.1 Get the Gateway Address

export GATEWAY_IP=$(kubectl get svc agentgateway -n $NAMESPACE \
  -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
export GATEWAY_PORT=8080

# If no external LB, fall back to port-forward
if [ -z "$GATEWAY_IP" ]; then
  echo "No external LB found. Using port-forward..."
  kubectl port-forward -n $NAMESPACE svc/agentgateway 18080:8080 &
  sleep 2
  export GATEWAY_IP="localhost"
  export GATEWAY_PORT=18080
fi

echo "Gateway: http://${GATEWAY_IP}:${GATEWAY_PORT}"

5.2 Send a Chat Completion Request

curl -s -X POST "http://${GATEWAY_IP}:${GATEWAY_PORT}/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "bedrock/amazon.nova-micro-v1:0",
    "messages": [
      {"role": "user", "content": "Say hello in one sentence."}
    ]
  }' | python3 -m json.tool

You should see a successful JSON response with:

  • model: amazon.nova-micro-v1:0
  • choices[0].message.content: A greeting from the model
  • usage: Token counts for the request

5.3 Test with a More Complex Prompt

curl -s -X POST "http://${GATEWAY_IP}:${GATEWAY_PORT}/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "bedrock/amazon.nova-micro-v1:0",
    "messages": [
      {"role": "system", "content": "You are a helpful assistant. Be concise."},
      {"role": "user", "content": "What are 3 benefits of using IRSA over static AWS credentials?"}
    ]
  }' | python3 -m json.tool

Part 6: Cleanup

To remove the resources created in this workshop:

# Remove Kubernetes resources
kubectl delete httproute bedrock -n $NAMESPACE
kubectl delete agentgatewaybackend bedrock -n $NAMESPACE

# Remove IRSA annotation from service account
kubectl patch enterpriseagentgatewayparameters agentgateway-params \
  -n $NAMESPACE \
  --type json \
  -p '[{"op": "remove", "path": "/spec/serviceAccount"}]'

# Restart pods to drop IRSA credentials
kubectl rollout restart deployment agentgateway -n $NAMESPACE

# Remove AWS resources
aws iam detach-role-policy \
  --role-name $ROLE_NAME \
  --policy-arn arn:aws:iam::aws:policy/AmazonBedrockFullAccess
aws iam delete-role --role-name $ROLE_NAME

echo "Cleanup complete."

Summary

In this workshop you:

  1. Associated the EKS OIDC provider with AWS IAM to enable workload identity federation
  2. Created an IAM role with a trust policy scoped to the agentgateway service account and attached Bedrock permissions
  3. Deployed an AgentgatewayBackend for Bedrock without any secret references, relying on IRSA for authentication
  4. Annotated the service account via EnterpriseAgentgatewayParameters so EKS injects temporary credentials
  5. Verified that the pod received IRSA credentials and successfully called Bedrock

Key Takeaways

Approach Credentials Rotation Scope
Secret-based Static access key in K8s Secret Manual Any pod with secret access
IRSA Temporary STS credentials Automatic Single service account

IRSA is the recommended approach for production EKS deployments accessing AWS services.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment