Skip to content

New serverless pattern - Strands Agent on Lambda with AgentCore Smithy Bedrock Target - #3221

Open
humem001 wants to merge 2 commits into
aws-samples:mainfrom
humem001:mjhume-feature-strands-agentcore-smithy
Open

New serverless pattern - Strands Agent on Lambda with AgentCore Smithy Bedrock Target#3221
humem001 wants to merge 2 commits into
aws-samples:mainfrom
humem001:mjhume-feature-strands-agentcore-smithy

Conversation

@humem001

@humem001 humem001 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Issue #, if available:

Description of changes:
Strands SDK agent on Lambda calls Bedrock Runtime via AgentCore Gateway using a Smithy
model target, with Cognito JWT auth and IAM role signing.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

Statement:
- Effect: Allow
Action:
- bedrock-agentcore:*

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of wild card (*) access, can you make it restricted to required actions only.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The single bedrock-agentcore:* statement was replaced with two scoped statements:

TokenVaultApiKeyAccess — grants only GetResourceApiKey on the token vault resources. This is the correct action for retrieving API keys stored in the credential provider (e.g., for OpenAI or other MCP tool integrations).
WorkloadIdentityTokenAccess — grants the three workload access token actions on the workload identity directory resources. These are the only actions the gateway execution role needs for identity/auth flows.

Resource:
- !Sub 'arn:aws:bedrock:${AWS::Region}::foundation-model/*'
- !Sub 'arn:aws:bedrock:${AWS::Region}:${AWS::AccountId}:inference-profile/*'
- '*'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wildcard (*) opens up everything. Can you make it restricted to required resources only.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the '*' resource entry

- bedrock:InvokeModelWithResponseStream
- bedrock:Converse
- bedrock:ConverseStream
Resource: '*'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wildcard (*) opens up everything. Can you make it restricted to required resources only.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Replaced Resource: '*' with the same two scoped ARN patterns used in GatewayExecutionRole

- Effect: Allow
Principal:
Service: bedrock-agentcore.amazonaws.com
Action: sts:AssumeRole

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you try adding the condition? Please test after adding. Adding these conditions to prevent the cross-service confused deputy problem

AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: bedrock-agentcore.amazonaws.com Action: sts:AssumeRole Condition: StringEquals: aws:SourceAccount: !Ref AWS::AccountId ArnLike: aws:SourceArn: !Sub 'arn:aws:bedrock-agentcore:${AWS::Region}:${AWS::AccountId}:*'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aws:SourceAccount — ensures only resources from your own account can trigger the role assumption, blocking confused deputy attacks where another account's AgentCore service tricks a role.
aws:SourceArn with ArnLike — further scopes it to only AgentCore resources within your specific account and region, so even within the same account only the AgentCore service (not some other AWS service) can assume the role.

- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: '*'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make it more restrictive? e.g.

Resource: - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${AWS::StackName}-AgentFunction:*'

Test and modify if needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

  • Effect: Allow
    Action:
    • logs:CreateLogGroup
      Resource:
    • !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${AWS::StackName}-AgentFunction'
  • Effect: Allow
    Action:
    • logs:CreateLogStream
    • logs:PutLogEvents
      Resource:
    • !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${AWS::StackName}-AgentFunction:*'

if isinstance(body, dict):
prompt = body.get("prompt", "")
elif isinstance(body, str):
import json

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move the import statement at the top of the file to maintain standard.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — import json is at line 9, in the top-level imports block. The inline import json inside the elif isinstance(body, str) branch was removed at the same time.

Transform: AWS::Serverless-2016-10-31
Description: >
AgentCore Smithy Bedrock Runtime - Serverless AI agent exposing Bedrock Runtime
operations through AWS Bedrock AgentCore Gateway using a Smithy model target.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AWS Bedrock AgentCore --> Amazon Bedrock AgentCore

Bedrock --> Amazon Bedrock

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated



def create_mcp_client(gateway_url: str, token: str) -> MCPClient:
"""Create an MCP client configured to connect to AgentCore Gateway.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AgentCore Gateway --> Amazon Bedrock AgentCore Gateway

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

Configures Claude 3 Sonnet as the LLM provider via AWS Bedrock.

Args:
model_id: Bedrock model identifier. Defaults to Claude 3 Sonnet.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the model id accordingly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all three references now correctly say Claude Sonnet 4.6:

Comment on DEFAULT_MODEL_ID
Function docstring: Configures Claude Sonnet 4.6 as the LLM provider
Args description: Defaults to Claude Sonnet 4.6

One command deploys everything:

```bash
bash scripts/deploy.sh

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy failed with the following issue:

`strands-agentcore-smithy % bash scripts/deploy.sh

Deploying stack: agentcore-smithy-bedrock in region: us-east-1

Step 1: Validating SAM template...

SAM CLI update available (1.163.0); (1.162.1 installed)
To download: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html
Template validation successful.

Step 2: Uploading Bedrock Runtime Smithy model to S3...
upload failed: ../../../../../../../tmp/bedrock-runtime-2023-09-30.json to s3://agentcore-smithy-bedrock-smithy-models/bedrock-runtime-2023-09-30.json An error occurred (AccessDenied) when calling the PutObject operation: Access Denied`

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Three things fixed:

Removed duplicate prerequisites — they were listed twice (under ## Prerequisites and ### Step 1: Prerequisites). Now a single clean list.
Added IAM permissions note — explicitly tells users they need permissions for CloudFormation, IAM, Lambda, S3, Cognito, and AgentCore. This directly addresses the AccessDenied deployment failure.
Fixed step numbering — Deploy steps now run 1→2→3 cleanly.
The AccessDenied error itself is a credentials/IAM issue in the user's AWS account — the user needs to ensure their AWS CLI credentials have the necessary S3 permissions before running the deploy script.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants