Skip to content

aws-samples/sample-agentcore-multi-tenant

Repository files navigation

AgentCore TypeScript Sample

⚠️ IMPORTANT: This is a PROOF OF CONCEPT / SAMPLE IMPLEMENTATION for demonstration and learning purposes only. DO NOT USE IN PRODUCTION without significant security hardening and enterprise-grade enhancements. This sample demonstrates architectural patterns and best practices but requires additional work for production deployment.

A comprehensive TypeScript implementation demonstrating Amazon Bedrock AgentCore with multi-tenant log analytics, showcasing advanced agentic architecture patterns with proper security isolation and identity propagation.

Overview

This project implements a sample multi-tenant log analytics system using AWS Bedrock AgentCore. It demonstrates how to build sophisticated AI agents that can access multiple tool sources while maintaining tenant isolation and security boundaries. This is intended as an educational resource and reference implementation for developers learning to build multi-tenant AI agent systems.

Key Features

  • Multi-Tenant Architecture: Complete tenant isolation using JWT claims and OpenSearch query filters
  • Dual Tool Sources: Combines simple MCP server tools with complex Gateway-based Lambda functions
  • Identity Propagation: Automatic tenant ID extraction and injection throughout the request flow
  • Production-Ready Security: Cognito authentication, JWT validation, and fine-grained access control
  • Full TypeScript Stack: Type-safe implementation across all components
  • Infrastructure as Code: Complete AWS CDK deployment with 9 integrated stacks

Architecture

╔═══════════════════════════════════════════════════════════════════════╗
║                          INTERNET AREA                                ║
╠═══════════════════════════════════════════════════════════════════════╣
║                                                                       ║
║  ┌─────────────────────────────────────────────────────────────────┐ ║
║  │                     User Application                            │ ║
║  │          (Authenticates with Cognito JWT Token)                 │ ║
║  └───────────────────────────┬─────────────────────────────────────┘ ║
║                              │ Authorization: Bearer <ID_TOKEN>      ║
║                              │ (contains custom:tenantId claim)      ║
║                              ▼                                        ║
║  ┌─────────────────────────────────────────────────────────────────┐ ║
║  │                AgentCore Runtime (Agent)                        │ ║
║  │             (HTTP Protocol, Public Network)                     │ ║
║  │  ┌────────────────────────────────────────────────────────────┐ │ ║
║  │  │ • Strands-based orchestration agent                        │ │ ║
║  │  │ • Cognito JWT authentication                               │ │ ║
║  │  │ • Extracts tenant ID from JWT token                        │ │ ║
║  │  │ • Routes to appropriate tools based on query complexity    │ │ ║
║  │  └────────────────────────────────────────────────────────────┘ │ ║
║  └─────────────┬──────────────────────────────┬────────────────────┘ ║
║                │                              │                      ║
║                │                              │                      ║
║                │                   ┌──────────▼──────────────┐       ║
║                │                   │  AgentCore Gateway      │       ║
║                │                   │  (Lambda Tools)         │       ║
║                │                   └──────────┬──────────────┘       ║
║                │                              │                      ║
║                │                   ┌──────────▼──────────────┐       ║
║                │                   │ Request Interceptor     │       ║
║                │                   │ (JWT → tenantId)        │       ║
║                │                   └──────────┬──────────────┘       ║
║                │                              │                      ║
╚════════════════╪══════════════════════════════╪══════════════════════╝
                 │                              │
╔════════════════╪══════════════════════════════╪══════════════════════╗
║                │      PRIVATE AREA (VPC)      │                      ║
╠════════════════╪══════════════════════════════╪══════════════════════╣
║                │                              │                      ║
║      ┌─────────▼─────────────────┐            │                      ║
║      │  MCP Server (AgentCore)   │            │                      ║
║      │  • Simple Tools           │            │                      ║
║      │    - search-logs          │            │                      ║
║      │    - get-log-stats        │            │                      ║
║      └─────────┬─────────────────┘            │                      ║
║                │                              │                      ║
║                │                   ┌──────────▼───────────────┐      ║
║                │                   │ Lambda Function (VPC)    │      ║
║                │                   │ • analyze-errors         │      ║
║                │                   │ • trace-request          │      ║
║                │                   └──────────┬───────────────┘      ║
║                │                              │                      ║
║                └──────────────┬───────────────┘                      ║
║                               │                                      ║
║                      ┌────────▼─────────┐                            ║
║                      │   OpenSearch     │                            ║
║                      │  (Tenant-Filtered)│                           ║
║                      └──────────────────┘                            ║
║                                                                      ║
╚══════════════════════════════════════════════════════════════════════╝

Technology Stack

Core Services

  • Amazon Bedrock AgentCore: Agent hosting and orchestration platform
  • Amazon Bedrock: AI model inference (Nova 2 Lite)
  • Amazon OpenSearch Service: Multi-tenant log storage and analytics
  • Amazon Cognito: User authentication with custom tenant attributes
  • AWS Lambda: Serverless compute for complex analytics tools

Development Tools

  • TypeScript 5.3+: Type-safe development across all components
  • Node.js 20+: Runtime environment
  • AWS CDK 2.170+: Infrastructure as code
  • Strands Agent SDK: Agent orchestration framework
  • Model Context Protocol (MCP): Tool integration protocol
  • Express.js: HTTP server framework
  • Zod: Runtime type validation

AWS Infrastructure

  • Amazon VPC: Network isolation for OpenSearch
  • AWS Secrets Manager: Secure credential storage
  • Amazon API Gateway: OpenSearch proxy for data seeding
  • AWS IAM: Fine-grained access control
  • Amazon CloudWatch: Logging and monitoring

Project Structure

agentcore-multi-tenant/
├── packages/
│   ├── agent/                 # Strands Agent (AgentCore Runtime)
│   │   ├── src/
│   │   │   ├── agent.ts       # Agent configuration and tool setup
│   │   │   ├── index.ts       # HTTP server and request handling
│   │   │   ├── auth.ts        # JWT token parsing and validation
│   │   │   └── types.ts       # Type definitions
│   │   ├── Dockerfile         # Container image definition
│   │   └── package.json       # Dependencies and scripts
│   │
│   ├── mcp-server/           # MCP Server (AgentCore Runtime)
│   │   ├── src/
│   │   │   ├── server.ts      # MCP tool definitions
│   │   │   ├── opensearch.ts  # Direct OpenSearch queries
│   │   │   └── index.ts       # Server initialization
│   │   ├── Dockerfile         # Container image definition
│   │   └── package.json       # Dependencies and scripts
│   │
│   ├── lambda/               # Gateway Lambda Functions
│   │   ├── src/
│   │   │   ├── analyze-errors.ts    # Error pattern analysis
│   │   │   ├── trace-request.ts     # Distributed tracing
│   │   │   ├── opensearch.ts        # OpenSearch client utilities
│   │   │   ├── types.ts             # Type definitions
│   │   │   └── index.ts             # Lambda entry point
│   │   └── package.json             # Dependencies and scripts
│   │
│   ├── opensearch-proxy/     # OpenSearch API Gateway Proxy
│   │   ├── src/
│   │   │   └── index.ts       # Proxy handler for bulk/search operations
│   │   └── package.json       # Dependencies and scripts
│   │
│   └── infrastructure/        # AWS CDK Infrastructure
│       ├── lib/
│       │   ├── vpc-stack.ts              # VPC, subnets, NAT Gateway
│       │   ├── cognito-stack.ts          # User pool, custom attributes
│       │   ├── opensearch-stack.ts       # OpenSearch domain
│       │   ├── opensearch-proxy-stack.ts # API Gateway for data seeding
│       │   ├── opensearch-config-stack.ts # Index configuration
│       │   ├── lambda-stack.ts           # Analytics Lambda functions
│       │   ├── gateway-stack.ts          # AgentCore Gateway
│       │   ├── mcp-stack.ts              # MCP Server Runtime
│       │   └── agent-stack.ts            # Agent Runtime
│       ├── bin/
│       │   └── app.ts                    # CDK app entry point
│       └── package.json                  # Dependencies and scripts
│
├── scripts/
│   ├── configure-gateway-interceptor.py  # Gateway interceptor setup
│   └── test-jwt-token.sh                # JWT token testing utility
│
├── package.json              # Root workspace configuration
├── tsconfig.json             # TypeScript configuration
└── README.md                 # This file

Prerequisites

Required Software

  • Node.js: >= 20.0.0
  • npm: >= 10.0.0
  • AWS CLI: Configured with appropriate credentials
  • Docker: For building container images
  • AWS CDK CLI: Install globally with npm install -g aws-cdk

AWS Services Access

  • Amazon Bedrock (with model access for Claude or Nova)
  • Amazon Bedrock AgentCore
  • Amazon OpenSearch Service
  • Amazon Cognito
  • AWS Lambda
  • Amazon VPC
  • AWS IAM (permissions to create roles and policies)

AWS Account Requirements

  • Sufficient service quotas for VPC resources
  • Permissions to create IAM roles and policies
  • Access to create Bedrock AgentCore resources
  • Budget for ongoing AWS service costs

Installation

1. Clone the Repository

git clone git@ssh.gitlab.aws.dev:flolac/agentcore-multi-tenant.git
cd agentcore-multi-tenant

2. Install Dependencies

Install all workspace dependencies:

npm install

3. Build All Packages

Compile TypeScript code across all packages:

npm run build

This compiles:

  • Agent package
  • MCP server package
  • Lambda functions
  • Infrastructure code

Deployment

1. Bootstrap CDK (First Time Only)

If you haven't used CDK in your AWS account/region before:

cd packages/infrastructure
cdk bootstrap

2. Deploy All Stacks

Deploy the complete infrastructure:

cd packages/infrastructure
cdk deploy --all

This deploys 9 stacks in the correct order:

  1. VPC Stack
  2. Cognito Stack
  3. OpenSearch Stack
  4. OpenSearch Proxy Stack
  5. OpenSearch Config Stack
  6. Lambda Stack
  7. Gateway Stack
  8. MCP Stack
  9. Agent Stack

Deployment takes approximately 20-30 minutes due to OpenSearch domain creation.

3. Configure Gateway Interceptor

After deployment, configure the Gateway Request Interceptor:

cd scripts
python3 configure-gateway-interceptor.py

4. Create Test Users

Create users with tenant IDs:

# Get User Pool ID from CDK outputs
USER_POOL_ID=$(aws cloudformation describe-stacks \
  --stack-name AgentCoreTypescriptSample-CognitoStack \
  --query 'Stacks[0].Outputs[?OutputKey==`UserPoolId`].OutputValue' \
  --output text)

# Create user for tenant-123
aws cognito-idp admin-create-user \
  --user-pool-id "$USER_POOL_ID" \
  --username alice \
  --user-attributes \
    Name=email,Value=alice@example.com \
    Name=custom:tenantId,Value=tenant-123 \
  --temporary-password TempPass123! \
  --message-action SUPPRESS

# Create user for tenant-456
aws cognito-idp admin-create-user \
  --user-pool-id "$USER_POOL_ID" \
  --username bob \
  --user-attributes \
    Name=email,Value=bob@example.com \
    Name=custom:tenantId,Value=tenant-456 \
  --temporary-password TempPass456! \
  --message-action SUPPRESS

5. Seed Sample Data (Optional)

Use the OpenSearch proxy to seed test data:

# Get proxy endpoint from CDK outputs
PROXY_ENDPOINT=$(aws cloudformation describe-stacks \
  --stack-name AgentCoreTypescriptSample-OpenSearchProxyStack \
  --query 'Stacks[0].Outputs[?OutputKey==`ProxyEndpoint`].OutputValue' \
  --output text)

# Create sample logs for tenant-123
curl -X POST "$PROXY_ENDPOINT/logs/_bulk" \
  -H "Content-Type: application/x-ndjson" \
  --data-binary @sample-logs-tenant-123.ndjson

# Create sample logs for tenant-456
curl -X POST "$PROXY_ENDPOINT/logs/_bulk" \
  -H "Content-Type: application/x-ndjson" \
  --data-binary @sample-logs-tenant-456.ndjson

Usage

1. Authenticate with Cognito

Get an ID token from Cognito:

# Get User Pool Client ID
CLIENT_ID=$(aws cloudformation describe-stacks \
  --stack-name AgentCoreTypescriptSample-CognitoStack \
  --query 'Stacks[0].Outputs[?OutputKey==`UserPoolClientId`].OutputValue' \
  --output text)

# Authenticate user
aws cognito-idp initiate-auth \
  --client-id "$CLIENT_ID" \
  --auth-flow USER_PASSWORD_AUTH \
  --auth-parameters \
    USERNAME=alice,PASSWORD=YourSecurePassword123!

# Extract IdToken from response
ID_TOKEN="<id_token_from_response>"

2. Query the Agent

Send requests to the agent:

# Get Agent URL from CDK outputs
AGENT_URL=$(aws cloudformation describe-stacks \
  --stack-name AgentCoreTypescriptSample-AgentStack \
  --query 'Stacks[0].Outputs[?OutputKey==`AgentUrl`].OutputValue' \
  --output text)

# Simple query using MCP server tools
curl -X POST "$AGENT_URL/invocations" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ID_TOKEN" \
  -d '{
    "prompt": "Show me error logs from the last hour"
  }'

# Complex analysis using Gateway tools
curl -X POST "$AGENT_URL/invocations" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ID_TOKEN" \
  -d '{
    "prompt": "Analyze error patterns and show me trends"
  }'

# Distributed tracing
curl -X POST "$AGENT_URL/invocations" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $ID_TOKEN" \
  -d '{
    "prompt": "Trace request abc-123-def-456"
  }'

3. Understanding Agent Behavior

The agent automatically selects appropriate tools:

  • Simple queries → MCP Server tools (direct OpenSearch)

    • "show me logs with error"
    • "what are the log statistics"
  • Complex analysis → Gateway Lambda tools

    • "analyze error patterns"
    • "what trends do errors show"
    • "trace request XYZ"

Identity Flow

1. User authenticates with Cognito
   ↓
2. Pre-Token Generation Lambda adds claims to ID Token:
   • custom:tenantId (from user attributes)
   • client_id (required by AgentCore)
   ↓
3. Application sends request to Agent with ID Token
   Authorization: Bearer <ID_TOKEN>
   ↓
4. AgentCore Runtime validates JWT token
   • Verifies signature
   • Checks client_id claim
   • Validates expiration
   ↓
5. Agent extracts tenant ID from JWT token
   • Parses JWT payload
   • Extracts custom:tenantId claim
   • Stores in agent state
   ↓
6. Agent invokes tools with tenant context:
   │
   ├─→ MCP Server
   │   • Authorization header propagated
   │   • Tenant ID available in context
   │   • Direct OpenSearch queries
   │
   └─→ Gateway
       • Request Interceptor Lambda triggered
       • Extracts custom:tenantId from JWT
       • Automatically injects into tool arguments
       • Lambda receives pre-filled tenant ID
   ↓
7. OpenSearch queries filtered by tenantId
   ↓
8. User sees only their tenant's data

Security Features

Authentication & Authorization

  • Cognito JWT tokens: Industry-standard authentication
  • Custom tenant attributes: Tenant ID embedded in verified tokens
  • Client ID validation: AgentCore validates token authenticity
  • Token expiration: Time-limited access tokens

Tenant Isolation

  • JWT-based tenant ID: Extracted from verified token, not user input
  • Gateway Request Interceptor: Automatic tenant ID injection
  • Query-time filtering: All OpenSearch queries include tenant filter
  • Centralized enforcement: Cannot be bypassed by agent or user

Network Security

  • VPC isolation: OpenSearch in private subnets
  • Security groups: Restricted network access
  • HTTPS enforcement: All traffic encrypted in transit
  • Private connectivity: No direct internet access to data stores

Access Control

  • Fine-grained IAM: Least-privilege service roles
  • Resource-level permissions: Scoped to specific resources
  • Audit trails: CloudWatch Logs for all operations
  • Secrets management: Credentials in AWS Secrets Manager

Development

Local Development

Each package can be developed independently:

# Agent package
cd packages/agent
npm run dev

# MCP Server package
cd packages/mcp-server
npm run dev

# Lambda package (unit tests)
cd packages/lambda
npm test

# Infrastructure (synth only)
cd packages/infrastructure
npm run synth

Testing

# Run all tests
npm test

# Test specific package
cd packages/lambda
npm test

# Test JWT token extraction
cd scripts
./test-jwt-token.sh

Adding New Tools

MCP Server Tool

Edit /packages/mcp-server/src/server.ts:

mcpServer.registerTool(
  'my-new-tool',
  {
    title: 'My New Tool',
    description: 'Tool description',
    inputSchema: {
      param1: z.string().describe('Parameter description'),
    },
  },
  async ({ param1 }, context) => {
    // Tool implementation
    return {
      content: [{ type: 'text', text: 'Result' }],
    };
  }
);

Gateway Lambda Tool

  1. Create handler in /packages/lambda/src/my-tool.ts
  2. Update /packages/infrastructure/lib/gateway-stack.ts to add tool definition
  3. Redeploy: cdk deploy GatewayStack

Cost Considerations

This sample creates AWS resources that incur costs:

  • AgentCore Runtime: Per-hour instance costs
  • OpenSearch domain: t3.small.search instance ($0.036/hour)
  • NAT Gateway: $0.045/hour + data transfer
  • Lambda invocations: Per-request and duration
  • Bedrock model usage: Per-token pricing
  • VPC resources: Negligible costs
  • CloudWatch Logs: Log storage and ingestion

Estimated monthly cost: $50-100 for development/testing workloads

See AWS Pricing for detailed information.

Cleanup

Remove all deployed resources:

cd packages/infrastructure
cdk destroy --all

This removes:

  • All CloudFormation stacks
  • OpenSearch domain (data is deleted)
  • Lambda functions
  • AgentCore resources
  • VPC and networking resources
  • Cognito User Pool

Note: Some resources like CloudWatch Logs may persist and incur minimal costs.

Troubleshooting

Agent returns 401 Unauthorized

  • Verify JWT token is valid and not expired
  • Ensure token includes custom:tenantId claim
  • Check user has custom:tenantId attribute set in Cognito
  • Use ID Token, not Access Token

Agent returns empty results

  • Verify sample data was seeded for the correct tenant ID
  • Check OpenSearch index exists
  • Review Lambda CloudWatch Logs for errors

OpenSearch connection errors

  • Verify Lambda is in VPC with OpenSearch security group
  • Check security group allows inbound traffic from Lambda
  • Verify OpenSearch domain is active and healthy

Gateway Interceptor not working

  • Run scripts/configure-gateway-interceptor.py
  • Verify Lambda has correct permissions
  • Check CloudWatch Logs for interceptor Lambda

Deployment failures

  • Verify AWS CLI credentials are configured
  • Check CDK bootstrap completed successfully
  • Ensure service quotas are sufficient
  • Review CloudFormation events for specific errors

Documentation

References

Contributing

This is a sample project for demonstration and educational purposes. Contributions that improve the sample implementation or documentation are welcome:

  1. Bug fixes and improvements to demonstration code
  2. Documentation enhancements and clarifications
  3. Additional example tools or use cases
  4. Testing improvements and scenarios

License

MIT License - See LICENSE file for details.

Support

For issues or questions:

  • Review TESTING.md for testing scenarios
  • Check AWS service health dashboard
  • Review CloudWatch Logs for errors
  • Contact AWS Support for service-specific issues

About

AWS Bedrock Agentcore sample illustrating multi tenancy

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors