Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions strands-agentcore-apigw/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.DS_Store

# Editor / IDE
.vscode/

# Kiro (local spec/steering tooling — not part of the deployable pattern)
.kiro/

# Python
venv/
.venv/
__pycache__/
*.pyc
*.so
*.egg-info/

# Test caches (regenerated on every run)
.hypothesis/
.pytest_cache/

# AWS SAM build output
.aws-sam/

# Legacy manual-packaging artifacts (pre-SAM deploy)
*-deps/
*-package/
*.zip

# Generated at deploy time by scripts/deploy.sh (contains environment-specific
# values and the test user's password)
scripts/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
��r�6�����OT��d¯C��R�_A�j���%�:?������J5V#
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"specId": "7a64bf38-3f0c-4e54-9f72-0827b62fe6c6", "workflowType": "requirements-first", "specType": "feature"}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Requirements Document

## Introduction

This feature builds a serverless AI agent that uses AWS Bedrock AgentCore Gateway with an API Gateway target type to proxy weather API requests. The Agent Lambda uses the Strands Agents SDK with Bedrock Claude Sonnet 4.6 for natural language processing. AgentCore Gateway auto-discovers operations from the API Gateway REST API via GetExportAPI, and uses an API Key credential provider for outbound authentication. Cognito provides JWT-based user authentication. The API Gateway REST API proxies requests to WeatherAPI.com, injecting the downstream API key separately from the AgentCore-to-API-Gateway key.

Existing reusable code in `handoff/src/shared/` (models, error handling, logging, JWT utils) and `handoff/src/agent/` (handler, agent_processor, strands_client) is carried forward. The new work covers CloudFormation infrastructure, deployment scripts, and tests.

## Glossary

- **Agent_Lambda**: AWS Lambda function running the Strands Agents SDK with Bedrock Claude Sonnet 4.6 to process natural language weather queries
- **AgentCore_Gateway**: AWS Bedrock AgentCore Gateway configured with CUSTOM_JWT authorization and an API Gateway target
- **API_Gateway_REST_API**: AWS API Gateway REST API exposing weather endpoints that proxy to WeatherAPI.com
- **Credential_Provider**: AgentCore Identity credential provider (API_KEY type) that injects the x-api-key header into outbound requests from the Gateway to the API Gateway REST API
- **Cognito_User_Pool**: AWS Cognito User Pool providing JWT-based authentication for the AgentCore Gateway
- **AgentCore_API_Key**: API key managed by the Credential_Provider for authenticating AgentCore_Gateway requests to the API_Gateway_REST_API
- **WeatherAPI_Key**: API key for authenticating API_Gateway_REST_API requests to WeatherAPI.com
- **CloudFormation_Stack**: AWS CloudFormation stack defining all infrastructure resources for this feature
- **Deployment_Script**: Shell script automating the multi-step deployment process
- **Strands_SDK**: The strands-agents Python SDK used by the Agent_Lambda for agentic orchestration

## Requirements

### Requirement 1: API Gateway REST API with Weather Endpoints

**User Story:** As a developer, I want an API Gateway REST API that exposes weather endpoints proxying to WeatherAPI.com, so that AgentCore Gateway can auto-discover and invoke weather operations.

#### Acceptance Criteria

1. THE CloudFormation_Stack SHALL define an AWS::ApiGateway::RestApi resource with ApiKeySourceType set to HEADER
2. THE CloudFormation_Stack SHALL define API Gateway resources for the path `/weather/current`
3. THE CloudFormation_Stack SHALL define a GET method on the `/weather/current` resource with ApiKeyRequired set to true and AuthorizationType set to NONE
4. THE CloudFormation_Stack SHALL define an HTTP_PROXY integration on the GET method that proxies requests to `https://api.weatherapi.com/v1/current.json`
5. WHEN a request includes the query parameter `q`, THE API_Gateway_REST_API SHALL forward the `q` parameter to WeatherAPI.com
6. THE CloudFormation_Stack SHALL define the WeatherAPI_Key injection into downstream requests to WeatherAPI.com via a stage variable or mapping template
7. THE CloudFormation_Stack SHALL define an AWS::ApiGateway::Deployment resource with explicit DependsOn for every Method resource
8. THE CloudFormation_Stack SHALL define an AWS::ApiGateway::Stage resource referencing the Deployment

### Requirement 2: API Gateway API Key and Usage Plan

**User Story:** As a developer, I want API Gateway to validate API keys via a usage plan, so that only authorized callers (AgentCore Gateway) can invoke the weather endpoints.

#### Acceptance Criteria

1. THE CloudFormation_Stack SHALL define an AWS::ApiGateway::ApiKey resource that depends on the Stage resource
2. THE CloudFormation_Stack SHALL define an AWS::ApiGateway::UsagePlan resource referencing the Stage
3. THE CloudFormation_Stack SHALL define an AWS::ApiGateway::UsagePlanKey resource linking the ApiKey to the UsagePlan
4. WHEN a request to the API_Gateway_REST_API lacks a valid x-api-key header, THE API_Gateway_REST_API SHALL return a 403 Forbidden response

### Requirement 3: AgentCore Gateway with API Gateway Target

**User Story:** As a developer, I want an AgentCore Gateway configured with an API Gateway target, so that the Gateway auto-discovers weather operations and proxies tool calls through the API Gateway REST API.

#### Acceptance Criteria

1. THE CloudFormation_Stack SHALL define an AWS::BedrockAgentCore::Gateway resource with AuthorizerType set to CUSTOM_JWT
2. THE CloudFormation_Stack SHALL configure JwtConfiguration on the Gateway with Issuer, Audience, and JwksUri referencing the Cognito_User_Pool
3. THE CloudFormation_Stack SHALL define an AWS::BedrockAgentCore::GatewayTarget resource with TargetConfiguration using the ApiGateway block (not OpenApiSchema)
4. THE GatewayTarget SHALL reference the API_Gateway_REST_API by ApiId and Stage
5. THE GatewayTarget SHALL configure CredentialProviderConfigurations with CredentialProviderType set to API_KEY and a ProviderArn referencing the Credential_Provider
6. THE CloudFormation_Stack SHALL output the Gateway ID for use by the Agent_Lambda and Deployment_Script

### Requirement 4: Cognito User Pool for Authentication

**User Story:** As a developer, I want a Cognito User Pool for JWT authentication, so that users can authenticate and the AgentCore Gateway can validate their tokens.

#### Acceptance Criteria

1. THE CloudFormation_Stack SHALL define an AWS::Cognito::UserPool resource
2. THE CloudFormation_Stack SHALL define an AWS::Cognito::UserPoolClient resource with ExplicitAuthFlows including ALLOW_USER_PASSWORD_AUTH and ALLOW_REFRESH_TOKEN_AUTH
3. THE CloudFormation_Stack SHALL output the User Pool ID, Client ID, and JWKS URL for use by the Agent_Lambda and Deployment_Script

### Requirement 5: Agent Lambda Function

**User Story:** As a developer, I want a Lambda function running the Strands SDK agent, so that users can send natural language weather queries and receive AI-processed responses.

#### Acceptance Criteria

1. THE CloudFormation_Stack SHALL define an AWS::Lambda::Function resource with Runtime set to python3.12 and Architecture set to x86_64
2. THE CloudFormation_Stack SHALL configure the Agent_Lambda with a minimum timeout of 120 seconds and a minimum memory of 1024 MB
3. THE CloudFormation_Stack SHALL set environment variables on the Agent_Lambda for GATEWAY_ID, COGNITO_JWKS_URL, BEDROCK_MODEL_ID, and AWS_REGION
4. THE Agent_Lambda SHALL reuse the existing handler, agent_processor, and strands_client code from `handoff/src/agent/`
5. THE Agent_Lambda SHALL reuse the existing shared utilities from `handoff/src/shared/`

### Requirement 6: IAM Roles and Permissions

**User Story:** As a developer, I want correctly scoped IAM roles, so that each component has the minimum permissions required to function.

#### Acceptance Criteria

1. THE CloudFormation_Stack SHALL define an IAM execution role for the Agent_Lambda with permissions for bedrock:InvokeModel, bedrock:InvokeModelWithResponseStream, bedrock:Converse, and bedrock:ConverseStream
2. THE CloudFormation_Stack SHALL grant the Agent_Lambda role permission to call bedrock-agentcore:GetGateway on the Gateway resource
3. THE CloudFormation_Stack SHALL define an IAM execution role for the AgentCore_Gateway with permissions for bedrock-agentcore:GetWorkloadAccessToken on the workload-identity-directory resources
4. THE CloudFormation_Stack SHALL grant the Gateway execution role bedrock-agentcore:GetResourceApiKey permission on all four required ARN patterns: token-vault/default, token-vault/default/apikeycredentialprovider/*, workload-identity-directory/default, and workload-identity-directory/default/workload-identity/{GatewayName}-*
5. THE CloudFormation_Stack SHALL grant the Gateway execution role secretsmanager:GetSecretValue permission on the bedrock-agentcore-identity secret path
6. THE CloudFormation_Stack SHALL grant the Gateway execution role apigateway:GET permission on the REST API exports resource for GetExportAPI access
7. THE CloudFormation_Stack SHALL grant the Agent_Lambda role permission to write logs to CloudWatch Logs

### Requirement 7: Deployment Script

**User Story:** As a developer, I want an automated deployment script, so that I can deploy the full stack in the correct order accounting for resources that cannot be created via CloudFormation.

#### Acceptance Criteria

1. THE Deployment_Script SHALL validate the CloudFormation template before deploying
2. THE Deployment_Script SHALL create Secrets Manager secrets for the WeatherAPI_Key and a placeholder AgentCore_API_Key before stack creation
3. THE Deployment_Script SHALL deploy the CloudFormation_Stack and wait for completion
4. THE Deployment_Script SHALL retrieve the actual API Gateway API key value from the stack after deployment
5. THE Deployment_Script SHALL update the Secrets Manager secret for the AgentCore_API_Key with the real API Gateway key value
6. THE Deployment_Script SHALL output instructions for manually creating the Credential_Provider via the AWS Console, since the Credential_Provider cannot be created via CloudFormation
7. THE Deployment_Script SHALL package the Agent_Lambda code with dependencies targeting python3.12 and x86_64 platform, preserving .dist-info directories
8. WHEN the packaged Lambda zip exceeds 50 MB, THE Deployment_Script SHALL upload the zip to S3 and update the Lambda function code from S3
9. THE Deployment_Script SHALL accept an environment name parameter to support multiple deployment environments

### Requirement 8: CloudFormation Template Structure

**User Story:** As a developer, I want a well-structured CloudFormation template, so that all resources are created with correct dependency ordering and parameterization.

#### Acceptance Criteria

1. THE CloudFormation_Stack SHALL accept parameters for EnvironmentName, WeatherApiKeySecretArn, and CredentialProviderArn
2. THE CloudFormation_Stack SHALL use the EnvironmentName parameter to namespace all resource names
3. THE CloudFormation_Stack SHALL define all resources in us-east-1 region due to BedrockAgentCore service availability
4. THE CloudFormation_Stack SHALL define Outputs for GatewayId, RestApiId, ApiKeyId, UserPoolId, UserPoolClientId, CognitoJwksUrl, AgentLambdaArn, and ApiEndpointUrl

### Requirement 9: Testing

**User Story:** As a developer, I want tests that verify the infrastructure configuration and agent integration, so that I can validate the deployment before and after going live.

#### Acceptance Criteria

1. THE test suite SHALL include unit tests that validate the CloudFormation template structure including resource types, dependency chains, and required properties
2. THE test suite SHALL include unit tests that verify the API Gateway deployment depends on all method resources
3. THE test suite SHALL include unit tests that verify the Gateway execution role includes all four required ARN patterns for GetResourceApiKey
4. THE test suite SHALL include an integration test script that authenticates via Cognito, obtains a JWT, sends a weather query to the Agent_Lambda, and validates the response contains weather data
5. THE test suite SHALL include a test that verifies the API Gateway returns 403 when called without an API key

Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Implementation Tasks

## Task 1: CloudFormation Template — API Gateway Resources
- [x] 1.1 Create `infrastructure/cloudformation-template.yaml` with Parameters (EnvironmentName, WeatherApiKeySecretArn, CredentialProviderArn)
- [x] 1.2 Define RestApi resource with `ApiKeySourceType: HEADER`
- [x] 1.3 Define WeatherResource (`/weather`) and WeatherCurrentResource (`/weather/current`) path resources
- [x] 1.4 Define GetCurrentWeatherMethod (GET, `ApiKeyRequired: true`, `AuthorizationType: NONE`) with HTTP_PROXY integration to `https://api.weatherapi.com/v1/current.json`, mapping `q` query param and injecting WeatherAPI key via `stageVariables.weatherApiKey`
- [x] 1.5 Define ApiDeployment with `DependsOn: GetCurrentWeatherMethod`
- [x] 1.6 Define ApiStage with stage variable for WeatherAPI key
- [x] 1.7 Define ApiKey (DependsOn ApiStage), UsagePlan (DependsOn ApiStage), and UsagePlanKey


**Requirements: 1, 2, 8**

## Task 2: CloudFormation Template — AgentCore, Cognito, Lambda, IAM
- [x] 2.1 Define CognitoUserPool and CognitoUserPoolClient with ALLOW_USER_PASSWORD_AUTH and ALLOW_REFRESH_TOKEN_AUTH
- [x] 2.2 Define AgentCoreGateway with `AuthorizerType: CUSTOM_JWT` and JwtConfiguration referencing Cognito
- [x] 2.3 Define WeatherAPITarget with `ApiGateway` block (not OpenApiSchema), referencing RestApi and ApiStage, with API_KEY credential provider config
- [x] 2.4 Define AgentLambdaFunction (python3.12, x86_64, 120s timeout, 1024MB memory) with environment variables (GATEWAY_ID, COGNITO_JWKS_URL, BEDROCK_MODEL_ID, AWS_REGION)
- [x] 2.5 Define AgentLambdaRole with Bedrock permissions (InvokeModel, InvokeModelWithResponseStream, Converse, ConverseStream), bedrock-agentcore:GetGateway, and CloudWatch Logs permissions
- [x] 2.6 Define GatewayExecutionRole with GetWorkloadAccessToken (2 ARN patterns), GetResourceApiKey (all 4 ARN patterns), secretsmanager:GetSecretValue on bedrock-agentcore-identity path, and apigateway:GET on REST API exports
- [x] 2.7 Define all Outputs: GatewayId, RestApiId, ApiKeyId, UserPoolId, UserPoolClientId, CognitoJwksUrl, AgentLambdaArn, ApiEndpointUrl

**Requirements: 3, 4, 5, 6, 8**

## Task 3: Copy Existing Agent Code
- [x] 3.1 Copy `handoff/src/agent/` to `src/agent/` (handler.py, agent_processor.py, strands_client.py)
- [x] 3.2 Copy `handoff/src/shared/` to `src/shared/` (models.py, logging_utils.py, error_utils.py, jwt_utils.py)
- [x] 3.3 Create `requirements.txt` with `strands-agents>=1.0.0` and `mcp>=1.0.0`

**Requirements: 5**

## Task 4: Deployment Script
- [x] 4.1 Create `scripts/deploy.sh` accepting `--environment-name`, `--weather-api-key`, `--region` (default us-east-1), `--s3-bucket` parameters
- [x] 4.2 Implement template validation step
- [x] 4.3 Implement Secrets Manager secret creation/update for WeatherAPI key and placeholder APIGW key
- [x] 4.4 Implement CloudFormation stack deploy with wait
- [x] 4.5 Implement API Gateway key retrieval and Secrets Manager update with real value
- [x] 4.6 Implement credential provider manual setup instructions output
- [x] 4.7 Implement Lambda packaging (pip install --platform manylinux2014_x86_64 --python-version 3.12, preserve .dist-info, remove .egg-info only)
- [x] 4.8 Implement Lambda deploy with S3 fallback for packages >50MB

**Requirements: 7**

## Task 5: Unit Tests — CloudFormation Template Validation
- [x] 5.1 Create `tests/unit/test_cloudformation_template.py` with pytest tests validating all API Gateway resources, dependencies, and properties
- [x] 5.2 Add tests for AgentCore Gateway, GatewayTarget (ApiGateway block, not OpenApiSchema), and Cognito resources
- [x] 5.3 Add tests for Lambda config (python3.12, x86_64, timeout >= 120, memory >= 1024, env vars)
- [x] 5.4 Add tests for IAM roles — Lambda role has all 4 Bedrock actions + GetGateway + CloudWatch Logs; Gateway role has all 4 GetResourceApiKey ARN patterns + GetWorkloadAccessToken + secretsmanager + apigateway:GET
- [x] 5.5 Add tests for template parameters and all 8 outputs

**Requirements: 9.1, 9.2, 9.3**

## Task 6: Property-Based Tests
- [ ]* 6.1 Create `tests/unit/test_properties.py` — Property 1: Deployment DependsOn includes all method logical IDs (hypothesis, 100 iterations)
- [ ]* 6.2 Property 2: Lambda role includes all 4 required Bedrock actions (hypothesis, 100 iterations)
- [ ]* 6.3 Property 3: Gateway role includes all 4 GetResourceApiKey ARN patterns (hypothesis, 100 iterations)
- [ ]* 6.4 Property 4: All named resources use EnvironmentName for namespacing (hypothesis, 100 iterations)
- [ ]* 6.5 Property 5: All 8 required outputs are defined (hypothesis, 100 iterations)

**Requirements: 9.1, 9.2, 9.3 | Design Properties: 1-5**

## Task 7: Integration Tests
- [x]* 7.1 Create `tests/integration/test_e2e.py` — API Gateway 403 test (call without API key, verify 403)
- [x]* 7.2 End-to-end agent test (Cognito auth → JWT → Agent Lambda → weather response validation)

**Requirements: 9.4, 9.5**

## Task 8: Validation Checkpoint
- [x] 8.1 Run unit tests and property-based tests: `pytest tests/unit/ -v`
- [x] 8.2 Validate CloudFormation template: `aws cloudformation validate-template --template-body file://infrastructure/cloudformation-template.yaml`
Loading