From 7a31f49b4e12451f1ae5b33c1683648cba9e864c Mon Sep 17 00:00:00 2001 From: Alexa Perlov Date: Fri, 14 Nov 2025 12:11:39 -0800 Subject: [PATCH 1/2] feat: gateway targets --- .header.md | 154 ++++++++++++++++++++++++ README.md | 170 +++++++++++++++++++++++++++ examples/gateway-example/.header.md | 31 +++-- examples/gateway-example/README.md | 34 ++++-- examples/gateway-example/main.tf | 67 ++++++++++- examples/gateway-example/outputs.tf | 16 +++ gateway.tf | 46 +++++++- gateway_target.tf | 175 ++++++++++++++++++++++++++++ outputs.tf | 39 +++++++ variables.tf | 158 +++++++++++++++++++++++++ workload_identity.tf | 21 ++++ 11 files changed, 890 insertions(+), 21 deletions(-) create mode 100644 gateway_target.tf create mode 100644 workload_identity.tf diff --git a/.header.md b/.header.md index a52bae2..1b0d300 100644 --- a/.header.md +++ b/.header.md @@ -477,6 +477,160 @@ module "agentcore" { } ``` +### AgentCore Gateway Target + +The Amazon Bedrock AgentCore Gateway Target enables you to define the endpoints and configurations that a gateway can invoke, such as Lambda functions or MCP servers. Gateway targets allow agents to interact with external services through the Model Context Protocol (MCP). + +```hcl +module "agentcore" { + source = "aws-ia/agentcore/aws" + version = "0.0.2" + + # First, create a gateway + create_gateway = true + gateway_name = "MyGateway" + + # Then create a gateway target for Lambda + create_gateway_target = true + gateway_target_name = "MyLambdaTarget" + gateway_target_description = "Lambda function target for processing requests" + + # Use the gateway's IAM role for authentication + gateway_target_credential_provider_type = "GATEWAY_IAM_ROLE" + + # Configure the Lambda target + gateway_target_type = "LAMBDA" + gateway_target_lambda_config = { + lambda_arn = "arn:aws:lambda:us-east-1:123456789012:function:my-function" + tool_schema_type = "INLINE" + inline_schema = { + name = "process_request" + description = "Process incoming requests" + + input_schema = { + type = "object" + description = "Request processing schema" + properties = [ + { + name = "message" + type = "string" + description = "Message to process" + required = true + }, + { + name = "options" + type = "object" + nested_properties = [ + { + name = "priority" + type = "string" + } + ] + } + ] + } + + output_schema = { + type = "object" + properties = [ + { + name = "status" + type = "string" + required = true + }, + { + name = "result" + type = "string" + } + ] + } + } + } +} +``` + +#### Gateway Target with API Key Authentication + +```hcl +module "agentcore" { + source = "aws-ia/agentcore/aws" + version = "0.0.2" + + # Create a gateway target with API Key authentication + create_gateway_target = true + gateway_target_name = "ApiKeyTarget" + gateway_target_gateway_id = "your-gateway-id" # If using existing gateway + + gateway_target_credential_provider_type = "API_KEY" + gateway_target_api_key_config = { + provider_arn = "arn:aws:iam::123456789012:oidc-provider/example.com" + credential_location = "HEADER" + credential_parameter_name = "X-API-Key" + credential_prefix = "Bearer" + } + + # Configure Lambda target + gateway_target_type = "LAMBDA" + gateway_target_lambda_config = { + lambda_arn = "arn:aws:lambda:us-east-1:123456789012:function:api-function" + tool_schema_type = "INLINE" + inline_schema = { + name = "api_tool" + description = "External API integration tool" + + input_schema = { + type = "string" + description = "Simple string input for API calls" + } + } + } +} +``` + +#### Gateway Target with MCP Server + +```hcl +module "agentcore" { + source = "aws-ia/agentcore/aws" + version = "0.0.2" + + # Create a gateway target for an MCP server + create_gateway_target = true + gateway_target_name = "MCPServerTarget" + + # Configure MCP Server target + gateway_target_type = "MCP_SERVER" + gateway_target_mcp_server_config = { + endpoint = "https://mcp-server.example.com" + } +} +``` + +### AgentCore Workload Identity + +The Amazon Bedrock AgentCore Workload Identity enables you to manage identity configurations for resources such as AgentCore runtime and AgentCore gateway. Workload identities provide secure access management and OAuth2 integration capabilities for your Bedrock AI applications. + +```hcl +module "agentcore" { + source = "aws-ia/agentcore/aws" + version = "0.0.2" + + # Enable Workload Identity + create_workload_identity = true + workload_identity_name = "MyWorkloadIdentity" + workload_identity_allowed_resource_oauth_2_return_urls = [ + "https://example.com/oauth2/callback", + "https://api.example.com/auth/callback" + ] + + # Optional: Add tags + workload_identity_tags = { + Environment = "production" + Project = "ai-assistants" + } +} +``` + ### AgentCore Code Interpreter Custom The Amazon Bedrock AgentCore Code Interpreter enables AI agents to write and execute code securely in sandbox environments, enhancing their accuracy and expanding their ability to solve complex end-to-end tasks. This is critical in Agentic AI applications where the agents may execute arbitrary code that can lead to data compromise or security risks. The AgentCore Code Interpreter tool provides secure code execution, which helps you avoid running into these issues. diff --git a/README.md b/README.md index c80d757..965f664 100644 --- a/README.md +++ b/README.md @@ -478,6 +478,153 @@ module "agentcore" { } ``` +### AgentCore Gateway Target + +The Amazon Bedrock AgentCore Gateway Target enables you to define the endpoints and configurations that a gateway can invoke, such as Lambda functions or MCP servers. Gateway targets allow agents to interact with external services through the Model Context Protocol (MCP). + +```hcl +module "agentcore" { + source = "aws-ia/agentcore/aws" + version = "0.0.2" + + # First, create a gateway + create_gateway = true + gateway_name = "MyGateway" + # Then create a gateway target for Lambda + create_gateway_target = true + gateway_target_name = "MyLambdaTarget" + gateway_target_description = "Lambda function target for processing requests" + # Use the gateway's IAM role for authentication + gateway_target_credential_provider_type = "GATEWAY_IAM_ROLE" + # Configure the Lambda target + gateway_target_type = "LAMBDA" + gateway_target_lambda_config = { + lambda_arn = "arn:aws:lambda:us-east-1:123456789012:function:my-function" + tool_schema_type = "INLINE" + inline_schema = { + name = "process_request" + description = "Process incoming requests" + + input_schema = { + type = "object" + description = "Request processing schema" + properties = [ + { + name = "message" + type = "string" + description = "Message to process" + required = true + }, + { + name = "options" + type = "object" + nested_properties = [ + { + name = "priority" + type = "string" + } + ] + } + ] + } + + output_schema = { + type = "object" + properties = [ + { + name = "status" + type = "string" + required = true + }, + { + name = "result" + type = "string" + } + ] + } + } + } +} +``` + +#### Gateway Target with API Key Authentication + +```hcl +module "agentcore" { + source = "aws-ia/agentcore/aws" + version = "0.0.2" + + # Create a gateway target with API Key authentication + create_gateway_target = true + gateway_target_name = "ApiKeyTarget" + gateway_target_gateway_id = "your-gateway-id" # If using existing gateway + gateway_target_credential_provider_type = "API_KEY" + gateway_target_api_key_config = { + provider_arn = "arn:aws:iam::123456789012:oidc-provider/example.com" + credential_location = "HEADER" + credential_parameter_name = "X-API-Key" + credential_prefix = "Bearer" + } + # Configure Lambda target + gateway_target_type = "LAMBDA" + gateway_target_lambda_config = { + lambda_arn = "arn:aws:lambda:us-east-1:123456789012:function:api-function" + tool_schema_type = "INLINE" + inline_schema = { + name = "api_tool" + description = "External API integration tool" + + input_schema = { + type = "string" + description = "Simple string input for API calls" + } + } + } +} +``` + +#### Gateway Target with MCP Server + +```hcl +module "agentcore" { + source = "aws-ia/agentcore/aws" + version = "0.0.2" + + # Create a gateway target for an MCP server + create_gateway_target = true + gateway_target_name = "MCPServerTarget" + # Configure MCP Server target + gateway_target_type = "MCP_SERVER" + gateway_target_mcp_server_config = { + endpoint = "https://mcp-server.example.com" + } +} +``` + +### AgentCore Workload Identity + +The Amazon Bedrock AgentCore Workload Identity enables you to manage identity configurations for resources such as AgentCore runtime and AgentCore gateway. Workload identities provide secure access management and OAuth2 integration capabilities for your Bedrock AI applications. + +```hcl +module "agentcore" { + source = "aws-ia/agentcore/aws" + version = "0.0.2" + + # Enable Workload Identity + create_workload_identity = true + workload_identity_name = "MyWorkloadIdentity" + workload_identity_allowed_resource_oauth_2_return_urls = [ + "https://example.com/oauth2/callback", + "https://api.example.com/auth/callback" + ] + # Optional: Add tags + workload_identity_tags = { + Environment = "production" + Project = "ai-assistants" + } +} +``` + ### AgentCore Code Interpreter Custom The Amazon Bedrock AgentCore Code Interpreter enables AI agents to write and execute code securely in sandbox environments, enhancing their accuracy and expanding their ability to solve complex end-to-end tasks. This is critical in Agentic AI applications where the agents may execute arbitrary code that can lead to data compromise or security risks. The AgentCore Code Interpreter tool provides secure code execution, which helps you avoid running into these issues. @@ -660,6 +807,7 @@ No modules. | Name | Type | |------|------| +| [aws_bedrockagentcore_gateway_target.gateway_target](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/bedrockagentcore_gateway_target) | resource | | [aws_cognito_user.admin](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_user) | resource | | [aws_cognito_user_pool.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_user_pool) | resource | | [aws_cognito_user_pool_client.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cognito_user_pool_client) | resource | @@ -686,6 +834,7 @@ No modules. | [awscc_bedrockagentcore_memory.agent_memory](https://registry.terraform.io/providers/hashicorp/awscc/latest/docs/resources/bedrockagentcore_memory) | resource | | [awscc_bedrockagentcore_runtime.agent_runtime](https://registry.terraform.io/providers/hashicorp/awscc/latest/docs/resources/bedrockagentcore_runtime) | resource | | [awscc_bedrockagentcore_runtime_endpoint.agent_runtime_endpoint](https://registry.terraform.io/providers/hashicorp/awscc/latest/docs/resources/bedrockagentcore_runtime_endpoint) | resource | +| [awscc_bedrockagentcore_workload_identity.workload_identity](https://registry.terraform.io/providers/hashicorp/awscc/latest/docs/resources/bedrockagentcore_workload_identity) | resource | | [random_password.password](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password) | resource | | [random_string.solution_prefix](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | | [time_sleep.browser_iam_role_propagation](https://registry.terraform.io/providers/hashicorp/time/latest/docs/resources/sleep) | resource | @@ -720,9 +869,11 @@ No modules. | [create\_browser](#input\_create\_browser) | Whether or not to create an agent core browser custom. | `bool` | `false` | no | | [create\_code\_interpreter](#input\_create\_code\_interpreter) | Whether or not to create an agent core code interpreter custom. | `bool` | `false` | no | | [create\_gateway](#input\_create\_gateway) | Whether or not to create an agent core gateway. | `bool` | `false` | no | +| [create\_gateway\_target](#input\_create\_gateway\_target) | Whether or not to create a Bedrock agent core gateway target. | `bool` | `false` | no | | [create\_memory](#input\_create\_memory) | Whether or not to create an agent core memory. | `bool` | `false` | no | | [create\_runtime](#input\_create\_runtime) | Whether or not to create an agent core runtime. | `bool` | `false` | no | | [create\_runtime\_endpoint](#input\_create\_runtime\_endpoint) | Whether or not to create an agent core runtime endpoint. | `bool` | `false` | no | +| [create\_workload\_identity](#input\_create\_workload\_identity) | Whether or not to create a Bedrock agent core workload identity. | `bool` | `false` | no | | [enable\_apikey\_outbound\_auth](#input\_enable\_apikey\_outbound\_auth) | Whether to enable outbound authorization with an API key for the gateway. | `bool` | `false` | no | | [enable\_oauth\_outbound\_auth](#input\_enable\_oauth\_outbound\_auth) | Whether to enable outbound authorization with an OAuth client for the gateway. | `bool` | `false` | no | | [gateway\_allow\_create\_permissions](#input\_gateway\_allow\_create\_permissions) | Whether to allow create permissions for the gateway. | `bool` | `true` | no | @@ -739,6 +890,15 @@ No modules. | [gateway\_protocol\_type](#input\_gateway\_protocol\_type) | The protocol type for the gateway. Valid value: MCP. | `string` | `"MCP"` | no | | [gateway\_role\_arn](#input\_gateway\_role\_arn) | Optional external IAM role ARN for the Bedrock agent core gateway. If empty, the module will create one internally. | `string` | `null` | no | | [gateway\_tags](#input\_gateway\_tags) | A map of tag keys and values for the agent core gateway. | `map(string)` | `null` | no | +| [gateway\_target\_api\_key\_config](#input\_gateway\_target\_api\_key\_config) | Configuration for API key authentication for the gateway target. |
object({
provider_arn = string
credential_location = optional(string)
credential_parameter_name = optional(string)
credential_prefix = optional(string)
})
| `null` | no | +| [gateway\_target\_credential\_provider\_type](#input\_gateway\_target\_credential\_provider\_type) | Type of credential provider to use for the gateway target. Valid values: GATEWAY\_IAM\_ROLE, API\_KEY, OAUTH. | `string` | `"GATEWAY_IAM_ROLE"` | no | +| [gateway\_target\_description](#input\_gateway\_target\_description) | Description of the gateway target. | `string` | `null` | no | +| [gateway\_target\_gateway\_id](#input\_gateway\_target\_gateway\_id) | Identifier of the gateway that this target belongs to. If not provided, it will use the ID of the gateway created by this module. | `string` | `null` | no | +| [gateway\_target\_lambda\_config](#input\_gateway\_target\_lambda\_config) | Configuration for Lambda function target. |
object({
lambda_arn = string
tool_schema_type = string # INLINE or S3
inline_schema = optional(object({
name = string
description = string
input_schema = object({
type = string
description = optional(string)
properties = optional(list(object({
name = string
type = string
description = optional(string)
required = optional(bool, false)
nested_properties = optional(list(object({
name = string
type = string
description = optional(string)
required = optional(bool)
})))
items = optional(object({
type = string
description = optional(string)
}))
})))
items = optional(object({
type = string
description = optional(string)
}))
})
output_schema = optional(object({
type = string
description = optional(string)
properties = optional(list(object({
name = string
type = string
description = optional(string)
required = optional(bool)
})))
items = optional(object({
type = string
description = optional(string)
}))
}))
}))
s3_schema = optional(object({
uri = string
bucket_owner_account_id = optional(string)
}))
})
| `null` | no | +| [gateway\_target\_mcp\_server\_config](#input\_gateway\_target\_mcp\_server\_config) | Configuration for MCP server target. |
object({
endpoint = string
})
| `null` | no | +| [gateway\_target\_name](#input\_gateway\_target\_name) | The name of the gateway target. | `string` | `"TerraformBedrockAgentCoreGatewayTarget"` | no | +| [gateway\_target\_oauth\_config](#input\_gateway\_target\_oauth\_config) | Configuration for OAuth authentication for the gateway target. |
object({
provider_arn = string
scopes = optional(list(string))
custom_parameters = optional(map(string))
})
| `null` | no | +| [gateway\_target\_type](#input\_gateway\_target\_type) | Type of target to create. Valid values: LAMBDA, MCP\_SERVER. | `string` | `"LAMBDA"` | no | | [memory\_description](#input\_memory\_description) | Description of the agent core memory. | `string` | `null` | no | | [memory\_encryption\_key\_arn](#input\_memory\_encryption\_key\_arn) | The ARN of the KMS key used to encrypt the memory. | `string` | `null` | no | | [memory\_event\_expiry\_duration](#input\_memory\_event\_expiry\_duration) | Duration in days until memory events expire. | `number` | `90` | no | @@ -774,6 +934,9 @@ No modules. | [user\_pool\_refresh\_token\_validity\_days](#input\_user\_pool\_refresh\_token\_validity\_days) | Number of days that refresh tokens are valid for. | `number` | `30` | no | | [user\_pool\_tags](#input\_user\_pool\_tags) | A map of tag keys and values for the Cognito User Pool. | `map(string)` | `null` | no | | [user\_pool\_token\_validity\_hours](#input\_user\_pool\_token\_validity\_hours) | Number of hours that ID and access tokens are valid for. | `number` | `24` | no | +| [workload\_identity\_allowed\_resource\_oauth\_2\_return\_urls](#input\_workload\_identity\_allowed\_resource\_oauth\_2\_return\_urls) | The list of allowed OAuth2 return URLs for resources associated with this workload identity. | `list(string)` | `null` | no | +| [workload\_identity\_name](#input\_workload\_identity\_name) | The name of the workload identity. | `string` | `"TerraformBedrockAgentCoreWorkloadIdentity"` | no | +| [workload\_identity\_tags](#input\_workload\_identity\_tags) | A map of tag keys and values for the workload identity. | `map(string)` | `null` | no | ## Outputs @@ -848,6 +1011,9 @@ No modules. | [cognito\_domain](#output\_cognito\_domain) | Domain of the Cognito User Pool | | [gateway\_role\_arn](#output\_gateway\_role\_arn) | ARN of the IAM role created for the Bedrock AgentCore Gateway | | [gateway\_role\_name](#output\_gateway\_role\_name) | Name of the IAM role created for the Bedrock AgentCore Gateway | +| [gateway\_target\_gateway\_id](#output\_gateway\_target\_gateway\_id) | ID of the gateway that this target belongs to | +| [gateway\_target\_id](#output\_gateway\_target\_id) | ID of the created Bedrock AgentCore Gateway Target | +| [gateway\_target\_name](#output\_gateway\_target\_name) | Name of the created Bedrock AgentCore Gateway Target | | [memory\_admin\_permissions](#output\_memory\_admin\_permissions) | IAM permissions for memory administration operations | | [memory\_admin\_policy](#output\_memory\_admin\_policy) | Policy document for granting control plane admin permissions | | [memory\_delete\_permissions](#output\_memory\_delete\_permissions) | Combined IAM permissions for deleting from both Short-Term Memory (STM) and Long-Term Memory (LTM) | @@ -876,4 +1042,8 @@ No modules. | [user\_pool\_endpoint](#output\_user\_pool\_endpoint) | Endpoint of the Cognito User Pool created as JWT authentication fallback | | [user\_pool\_id](#output\_user\_pool\_id) | ID of the Cognito User Pool created as JWT authentication fallback | | [using\_cognito\_fallback](#output\_using\_cognito\_fallback) | Whether the module is using a Cognito User Pool as fallback for JWT authentication | +| [workload\_identity\_arn](#output\_workload\_identity\_arn) | ARN of the created Bedrock AgentCore Workload Identity | +| [workload\_identity\_created\_time](#output\_workload\_identity\_created\_time) | Creation timestamp of the created Bedrock AgentCore Workload Identity | +| [workload\_identity\_id](#output\_workload\_identity\_id) | ID of the created Bedrock AgentCore Workload Identity | +| [workload\_identity\_last\_updated\_time](#output\_workload\_identity\_last\_updated\_time) | Last update timestamp of the created Bedrock AgentCore Workload Identity | \ No newline at end of file diff --git a/examples/gateway-example/.header.md b/examples/gateway-example/.header.md index ec99660..3752cee 100644 --- a/examples/gateway-example/.header.md +++ b/examples/gateway-example/.header.md @@ -1,6 +1,6 @@ -# Bedrock AgentCore Gateway Example +# Bedrock AgentCore Gateway and Gateway Target Example -This example demonstrates how to create an AWS Bedrock AgentCore Gateway that can connect to a Lambda function target. +This example demonstrates how to create an AWS Bedrock AgentCore Gateway and configure a Gateway Target that connects to a Lambda function. ## Overview @@ -8,7 +8,7 @@ This example: 1. Creates a simple Lambda function that will serve as a gateway target 2. Sets up a Bedrock AgentCore Gateway with proper IAM permissions -3. Configures the gateway to connect to the Lambda function +3. Creates a Gateway Target that connects the gateway to the Lambda function with a defined schema The AWS Bedrock AgentCore Gateway enables generative AI clients to send requests to your service implementations. This example focuses on setting up a gateway with Lambda function integration. @@ -38,15 +38,23 @@ terraform plan terraform apply ``` -### 4. Connect the Lambda function as a target (Console required) +### 4. Test the Gateway Target -After the gateway is created, you'll need to use the AWS Console or AWS CLI to create a gateway target, as the Terraform resource for gateway targets is not currently available: +After the gateway and gateway target are created, you can test them: 1. Go to the AWS Bedrock console -2. Navigate to "Agents" section and select "Agent Core" -3. Select "Gateways" and click on your newly created gateway -4. In the "Targets" tab, click "Create target" -5. Configure the target to point to the Lambda function created by this example +2. Navigate to "AgentCore" section and select "Gateways" +3. Select your newly created gateway +4. In the "Targets" tab, you should see your Lambda function target already configured +5. You can test the target using the AWS CLI: + +```bash +aws bedrock-agent-runtime invoke-gateway \ + --gateway-id \ + --target-name example-lambda-target \ + --body '{"query": "test query", "options": {"detailed": true}}' \ + --region +``` ### 5. Cleanup @@ -61,11 +69,13 @@ This example creates: - AWS Lambda function that returns a simple JSON response - IAM role and policy for the Lambda function - Bedrock AgentCore Gateway with proper IAM permissions +- Gateway Target configured to use the Lambda function - IAM role and policy for the Gateway to invoke the Lambda function ## Notes - The gateway's protocol type is set to MCP (Model Context Protocol) +- For tool schemas stored in S3, the gateway IAM role will automatically include necessary S3 permissions ## Outputs @@ -79,3 +89,6 @@ This example creates: | agent_gateway_url | URL of the created Bedrock AgentCore Gateway | | gateway_role_arn | ARN of the IAM role created for the Bedrock AgentCore Gateway | | gateway_role_name | Name of the IAM role created for the Bedrock AgentCore Gateway | +| gateway_target_id | ID of the created Bedrock AgentCore Gateway Target | +| gateway_target_name | Name of the created Bedrock AgentCore Gateway Target | +| gateway_target_gateway_id | ID of the gateway that the target belongs to | diff --git a/examples/gateway-example/README.md b/examples/gateway-example/README.md index 440be64..4d4171d 100644 --- a/examples/gateway-example/README.md +++ b/examples/gateway-example/README.md @@ -1,7 +1,7 @@ -# Bedrock AgentCore Gateway Example +# Bedrock AgentCore Gateway and Gateway Target Example -This example demonstrates how to create an AWS Bedrock AgentCore Gateway that can connect to a Lambda function target. +This example demonstrates how to create an AWS Bedrock AgentCore Gateway and configure a Gateway Target that connects to a Lambda function. ## Overview @@ -9,7 +9,7 @@ This example: 1. Creates a simple Lambda function that will serve as a gateway target 2. Sets up a Bedrock AgentCore Gateway with proper IAM permissions -3. Configures the gateway to connect to the Lambda function +3. Creates a Gateway Target that connects the gateway to the Lambda function with a defined schema The AWS Bedrock AgentCore Gateway enables generative AI clients to send requests to your service implementations. This example focuses on setting up a gateway with Lambda function integration. @@ -39,15 +39,23 @@ terraform plan terraform apply ``` -### 4. Connect the Lambda function as a target (Console required) +### 4. Test the Gateway Target -After the gateway is created, you'll need to use the AWS Console or AWS CLI to create a gateway target, as the Terraform resource for gateway targets is not currently available: +After the gateway and gateway target are created, you can test them: 1. Go to the AWS Bedrock console -2. Navigate to "Agents" section and select "Agent Core" -3. Select "Gateways" and click on your newly created gateway -4. In the "Targets" tab, click "Create target" -5. Configure the target to point to the Lambda function created by this example +2. Navigate to "AgentCore" section and select "Gateways" +3. Select your newly created gateway +4. In the "Targets" tab, you should see your Lambda function target already configured +5. You can test the target using the AWS CLI: + +```bash +aws bedrock-agent-runtime invoke-gateway \ + --gateway-id \ + --target-name example-lambda-target \ + --body '{"query": "test query", "options": {"detailed": true}}' \ + --region +``` ### 5. Cleanup @@ -62,11 +70,13 @@ This example creates: - AWS Lambda function that returns a simple JSON response - IAM role and policy for the Lambda function - Bedrock AgentCore Gateway with proper IAM permissions +- Gateway Target configured to use the Lambda function - IAM role and policy for the Gateway to invoke the Lambda function ## Notes - The gateway's protocol type is set to MCP (Model Context Protocol) +- For tool schemas stored in S3, the gateway IAM role will automatically include necessary S3 permissions ## Outputs @@ -80,6 +90,9 @@ This example creates: | agent\_gateway\_url | URL of the created Bedrock AgentCore Gateway | | gateway\_role\_arn | ARN of the IAM role created for the Bedrock AgentCore Gateway | | gateway\_role\_name | Name of the IAM role created for the Bedrock AgentCore Gateway | +| gateway\_target\_id | ID of the created Bedrock AgentCore Gateway Target | +| gateway\_target\_name | Name of the created Bedrock AgentCore Gateway Target | +| gateway\_target\_gateway\_id | ID of the gateway that the target belongs to | ## Requirements @@ -131,6 +144,9 @@ No inputs. | [agent\_gateway\_workload\_identity\_details](#output\_agent\_gateway\_workload\_identity\_details) | Workload identity details of the created Bedrock AgentCore Gateway | | [gateway\_role\_arn](#output\_gateway\_role\_arn) | ARN of the IAM role created for the Bedrock AgentCore Gateway | | [gateway\_role\_name](#output\_gateway\_role\_name) | Name of the IAM role created for the Bedrock AgentCore Gateway | +| [gateway\_target\_gateway\_id](#output\_gateway\_target\_gateway\_id) | ID of the gateway that the target belongs to | +| [gateway\_target\_id](#output\_gateway\_target\_id) | ID of the created Bedrock AgentCore Gateway Target | +| [gateway\_target\_name](#output\_gateway\_target\_name) | Name of the created Bedrock AgentCore Gateway Target | | [lambda\_function\_arn](#output\_lambda\_function\_arn) | ARN of the Lambda function created as a gateway target | | [lambda\_function\_name](#output\_lambda\_function\_name) | Name of the Lambda function created as a gateway target | \ No newline at end of file diff --git a/examples/gateway-example/main.tf b/examples/gateway-example/main.tf index 6557561..7d32653 100644 --- a/examples/gateway-example/main.tf +++ b/examples/gateway-example/main.tf @@ -99,6 +99,70 @@ module "bedrock_agent_gateway" { # Provide Lambda function ARNs that the gateway can invoke gateway_lambda_function_arns = [aws_lambda_function.example_function.arn] + # Enable and configure a gateway target using the Lambda function + create_gateway_target = true + gateway_target_name = "example-lambda-target" + gateway_target_description = "Example Lambda function target" + gateway_target_credential_provider_type = "GATEWAY_IAM_ROLE" + + gateway_target_type = "LAMBDA" + gateway_target_lambda_config = { + lambda_arn = aws_lambda_function.example_function.arn + tool_schema_type = "INLINE" + inline_schema = { + name = "example_tool" + description = "Example tool to demonstrate gateway targets" + + input_schema = { + type = "object" + description = "Input schema for the example tool" + properties = [ + { + name = "query" + type = "string" + description = "Query to process" + required = true + }, + { + name = "options" + type = "object" + nested_properties = [ + { + name = "detailed" + type = "boolean" + description = "Whether to return detailed results" + } + ] + } + ] + } + + output_schema = { + type = "object" + description = "Output schema for the example tool" + properties = [ + { + name = "result" + type = "string" + description = "Processing result" + required = true + }, + { + name = "metadata" + type = "object" + properties = [ + { + name = "timestamp" + type = "string" + description = "Timestamp of the response" + } + ] + } + ] + } + } + } + # Tags gateway_tags = { Environment = "example" @@ -106,5 +170,4 @@ module "bedrock_agent_gateway" { } } -# Note: Gateway targets are created through the AWS console or AWS CLI -# The awscc_bedrockagentcore_gateway_target resource is not currently available +# Now the gateway target is created using the module's aws_bedrockagentcore_gateway_target resource diff --git a/examples/gateway-example/outputs.tf b/examples/gateway-example/outputs.tf index ca57171..16016b5 100644 --- a/examples/gateway-example/outputs.tf +++ b/examples/gateway-example/outputs.tf @@ -44,3 +44,19 @@ output "gateway_role_name" { description = "Name of the IAM role created for the Bedrock AgentCore Gateway" value = module.bedrock_agent_gateway.gateway_role_name } + +# Bedrock Agent Core Gateway Target Outputs +output "gateway_target_id" { + description = "ID of the created Bedrock AgentCore Gateway Target" + value = module.bedrock_agent_gateway.gateway_target_id +} + +output "gateway_target_name" { + description = "Name of the created Bedrock AgentCore Gateway Target" + value = module.bedrock_agent_gateway.gateway_target_name +} + +output "gateway_target_gateway_id" { + description = "ID of the gateway that the target belongs to" + value = module.bedrock_agent_gateway.gateway_target_gateway_id +} diff --git a/gateway.tf b/gateway.tf index b351dae..d18c91d 100644 --- a/gateway.tf +++ b/gateway.tf @@ -28,6 +28,9 @@ locals { # Lambda function access has_lambda_targets = length(var.gateway_lambda_function_arns) > 0 + + # Gateway target access - needed for gateway targets created by this module + has_gateway_targets = local.create_gateway && var.create_gateway_target } resource "awscc_bedrockagentcore_gateway" "agent_gateway" { @@ -212,6 +215,47 @@ resource "aws_iam_role_policy" "gateway_role_policy" { ] Resource = var.gateway_lambda_function_arns } - ] : []) + ] : [], + # Additional permissions needed for gateway targets if they're created by this module + local.has_gateway_targets ? [ + { + Sid = "GatewayTargetOperations" + Effect = "Allow" + Action = [ + "bedrock-agentcore:CreateGatewayTarget", + "bedrock-agentcore:DeleteGatewayTarget", + "bedrock-agentcore:GetGatewayTarget", + "bedrock-agentcore:UpdateGatewayTarget", + "bedrock-agentcore:ListGatewayTargets" + ] + Resource = [ + "arn:aws:bedrock-agentcore:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:gateway/*" + ] + }, + # Additional permissions for Lambda targets if using LAMBDA target type with gateway_target + var.gateway_target_type == "LAMBDA" && var.gateway_target_lambda_config != null ? { + Sid = "GatewayTargetLambdaInvoke" + Effect = "Allow" + Action = [ + "lambda:InvokeFunction" + ] + Resource = [var.gateway_target_lambda_config.lambda_arn] + } : null, + # Add S3 permissions for tool schemas stored in S3 + (var.gateway_target_type == "LAMBDA" && + var.gateway_target_lambda_config != null && + var.gateway_target_lambda_config.tool_schema_type == "S3" && + var.gateway_target_lambda_config.s3_schema != null) ? { + Sid = "GatewayTargetS3Access" + Effect = "Allow" + Action = [ + "s3:GetObject", + "s3:GetObjectVersion" + ] + Resource = [ + "arn:aws:s3:::${split("/", replace(var.gateway_target_lambda_config.s3_schema.uri, "s3://", ""))[0]}/*" + ] + } : null + ] : []) }) } diff --git a/gateway_target.tf b/gateway_target.tf new file mode 100644 index 0000000..57343d2 --- /dev/null +++ b/gateway_target.tf @@ -0,0 +1,175 @@ +# – Bedrock Agent Core Gateway Target – + +locals { + create_gateway_target = var.create_gateway_target +} + +resource "aws_bedrockagentcore_gateway_target" "gateway_target" { + count = local.create_gateway_target ? 1 : 0 + + name = "${random_string.solution_prefix.result}-${var.gateway_target_name}" + gateway_identifier = var.gateway_target_gateway_id != null ? var.gateway_target_gateway_id : try(awscc_bedrockagentcore_gateway.agent_gateway[0].gateway_identifier, null) + description = var.gateway_target_description + + # Make sure the gateway and IAM role are created first + depends_on = [ + awscc_bedrockagentcore_gateway.agent_gateway, + aws_iam_role_policy.gateway_role_policy + ] + + # Credential provider configuration + dynamic "credential_provider_configuration" { + for_each = var.gateway_target_credential_provider_type != null ? [1] : [] + + content { + dynamic "gateway_iam_role" { + for_each = var.gateway_target_credential_provider_type == "GATEWAY_IAM_ROLE" ? [1] : [] + content {} + } + + dynamic "api_key" { + for_each = var.gateway_target_credential_provider_type == "API_KEY" && var.gateway_target_api_key_config != null ? [1] : [] + + content { + provider_arn = var.gateway_target_api_key_config.provider_arn + credential_location = var.gateway_target_api_key_config.credential_location + credential_parameter_name = var.gateway_target_api_key_config.credential_parameter_name + credential_prefix = var.gateway_target_api_key_config.credential_prefix + } + } + + dynamic "oauth" { + for_each = var.gateway_target_credential_provider_type == "OAUTH" && var.gateway_target_oauth_config != null ? [1] : [] + + content { + provider_arn = var.gateway_target_oauth_config.provider_arn + scopes = var.gateway_target_oauth_config.scopes + custom_parameters = var.gateway_target_oauth_config.custom_parameters + } + } + } + } + + # Target configuration + target_configuration { + mcp { + dynamic "lambda" { + for_each = var.gateway_target_type == "LAMBDA" && var.gateway_target_lambda_config != null ? [1] : [] + + content { + lambda_arn = var.gateway_target_lambda_config.lambda_arn + + tool_schema { + dynamic "inline_payload" { + for_each = var.gateway_target_lambda_config.tool_schema_type == "INLINE" && var.gateway_target_lambda_config.inline_schema != null ? [1] : [] + + content { + name = var.gateway_target_lambda_config.inline_schema.name + description = var.gateway_target_lambda_config.inline_schema.description + + # Input schema + input_schema { + type = var.gateway_target_lambda_config.inline_schema.input_schema.type + description = var.gateway_target_lambda_config.inline_schema.input_schema.description + + # Properties for object type + dynamic "property" { + for_each = var.gateway_target_lambda_config.inline_schema.input_schema.type == "object" && var.gateway_target_lambda_config.inline_schema.input_schema.properties != null ? var.gateway_target_lambda_config.inline_schema.input_schema.properties : [] + + content { + name = property.value.name + type = property.value.type + description = lookup(property.value, "description", null) + required = lookup(property.value, "required", false) + + # Nested properties for object properties + dynamic "property" { + for_each = property.value.type == "object" && lookup(property.value, "nested_properties", null) != null ? property.value.nested_properties : [] + + content { + name = property.value.name + type = property.value.type + description = lookup(property.value, "description", null) + required = lookup(property.value, "required", false) + } + } + + # Items for array properties + dynamic "items" { + for_each = property.value.type == "array" && lookup(property.value, "items", null) != null ? [property.value.items] : [] + + content { + type = items.value.type + description = lookup(items.value, "description", null) + } + } + } + } + + # Items for array type + dynamic "items" { + for_each = var.gateway_target_lambda_config.inline_schema.input_schema.type == "array" && lookup(var.gateway_target_lambda_config.inline_schema.input_schema, "items", null) != null ? [var.gateway_target_lambda_config.inline_schema.input_schema.items] : [] + + content { + type = items.value.type + description = lookup(items.value, "description", null) + } + } + } + + # Output schema (optional) + dynamic "output_schema" { + for_each = var.gateway_target_lambda_config.inline_schema.output_schema != null ? [var.gateway_target_lambda_config.inline_schema.output_schema] : [] + + content { + type = output_schema.value.type + description = lookup(output_schema.value, "description", null) + + # Properties for object type output + dynamic "property" { + for_each = output_schema.value.type == "object" && lookup(output_schema.value, "properties", null) != null ? output_schema.value.properties : [] + + content { + name = property.value.name + type = property.value.type + description = lookup(property.value, "description", null) + required = lookup(property.value, "required", false) + } + } + + # Items for array type output + dynamic "items" { + for_each = output_schema.value.type == "array" && lookup(output_schema.value, "items", null) != null ? [output_schema.value.items] : [] + + content { + type = items.value.type + description = lookup(items.value, "description", null) + } + } + } + } + } + } + + dynamic "s3" { + for_each = var.gateway_target_lambda_config.tool_schema_type == "S3" && var.gateway_target_lambda_config.s3_schema != null ? [1] : [] + + content { + uri = var.gateway_target_lambda_config.s3_schema.uri + bucket_owner_account_id = lookup(var.gateway_target_lambda_config.s3_schema, "bucket_owner_account_id", null) + } + } + } + } + } + + dynamic "mcp_server" { + for_each = var.gateway_target_type == "MCP_SERVER" && var.gateway_target_mcp_server_config != null ? [1] : [] + + content { + endpoint = var.gateway_target_mcp_server_config.endpoint + } + } + } + } +} diff --git a/outputs.tf b/outputs.tf index 104cc2a..239e3a6 100644 --- a/outputs.tf +++ b/outputs.tf @@ -431,6 +431,45 @@ output "browser_use_policy" { value = local.browser_use_policy_doc } +# – Bedrock Agent Core Workload Identity Outputs – + +output "workload_identity_id" { + description = "ID of the created Bedrock AgentCore Workload Identity" + value = try(awscc_bedrockagentcore_workload_identity.workload_identity[0].id, null) +} + +output "workload_identity_arn" { + description = "ARN of the created Bedrock AgentCore Workload Identity" + value = try(awscc_bedrockagentcore_workload_identity.workload_identity[0].workload_identity_arn, null) +} + +output "workload_identity_created_time" { + description = "Creation timestamp of the created Bedrock AgentCore Workload Identity" + value = try(awscc_bedrockagentcore_workload_identity.workload_identity[0].created_time, null) +} + +output "workload_identity_last_updated_time" { + description = "Last update timestamp of the created Bedrock AgentCore Workload Identity" + value = try(awscc_bedrockagentcore_workload_identity.workload_identity[0].last_updated_time, null) +} + +# – Bedrock Agent Core Gateway Target Outputs – + +output "gateway_target_id" { + description = "ID of the created Bedrock AgentCore Gateway Target" + value = try(aws_bedrockagentcore_gateway_target.gateway_target[0].target_id, null) +} + +output "gateway_target_name" { + description = "Name of the created Bedrock AgentCore Gateway Target" + value = try(aws_bedrockagentcore_gateway_target.gateway_target[0].name, null) +} + +output "gateway_target_gateway_id" { + description = "ID of the gateway that this target belongs to" + value = try(aws_bedrockagentcore_gateway_target.gateway_target[0].gateway_identifier, null) +} + # Code Interpreter permissions outputs - Permission sets output "code_interpreter_session_permissions" { description = "IAM permissions for managing code interpreter sessions" diff --git a/variables.tf b/variables.tf index 6538e22..a455c1a 100644 --- a/variables.tf +++ b/variables.tf @@ -593,6 +593,164 @@ variable "code_interpreter_tags" { } } +# – Agent Core Gateway Target – + +variable "create_gateway_target" { + description = "Whether or not to create a Bedrock agent core gateway target." + type = bool + default = false +} + +variable "gateway_target_name" { + description = "The name of the gateway target." + type = string + default = "TerraformBedrockAgentCoreGatewayTarget" +} + +variable "gateway_target_gateway_id" { + description = "Identifier of the gateway that this target belongs to. If not provided, it will use the ID of the gateway created by this module." + type = string + default = null +} + +variable "gateway_target_description" { + description = "Description of the gateway target." + type = string + default = null +} + +variable "gateway_target_credential_provider_type" { + description = "Type of credential provider to use for the gateway target. Valid values: GATEWAY_IAM_ROLE, API_KEY, OAUTH." + type = string + default = "GATEWAY_IAM_ROLE" + + validation { + condition = var.gateway_target_credential_provider_type == null || contains(["GATEWAY_IAM_ROLE", "API_KEY", "OAUTH"], var.gateway_target_credential_provider_type) + error_message = "The gateway_target_credential_provider_type must be one of GATEWAY_IAM_ROLE, API_KEY, OAUTH, or null." + } +} + +variable "gateway_target_api_key_config" { + description = "Configuration for API key authentication for the gateway target." + type = object({ + provider_arn = string + credential_location = optional(string) + credential_parameter_name = optional(string) + credential_prefix = optional(string) + }) + default = null +} + +variable "gateway_target_oauth_config" { + description = "Configuration for OAuth authentication for the gateway target." + type = object({ + provider_arn = string + scopes = optional(list(string)) + custom_parameters = optional(map(string)) + }) + default = null +} + +variable "gateway_target_type" { + description = "Type of target to create. Valid values: LAMBDA, MCP_SERVER." + type = string + default = "LAMBDA" + + validation { + condition = var.gateway_target_type == null || contains(["LAMBDA", "MCP_SERVER"], var.gateway_target_type) + error_message = "The gateway_target_type must be one of LAMBDA, MCP_SERVER, or null." + } +} + +variable "gateway_target_lambda_config" { + description = "Configuration for Lambda function target." + type = object({ + lambda_arn = string + tool_schema_type = string # INLINE or S3 + inline_schema = optional(object({ + name = string + description = string + input_schema = object({ + type = string + description = optional(string) + properties = optional(list(object({ + name = string + type = string + description = optional(string) + required = optional(bool, false) + nested_properties = optional(list(object({ + name = string + type = string + description = optional(string) + required = optional(bool) + }))) + items = optional(object({ + type = string + description = optional(string) + })) + }))) + items = optional(object({ + type = string + description = optional(string) + })) + }) + output_schema = optional(object({ + type = string + description = optional(string) + properties = optional(list(object({ + name = string + type = string + description = optional(string) + required = optional(bool) + }))) + items = optional(object({ + type = string + description = optional(string) + })) + })) + })) + s3_schema = optional(object({ + uri = string + bucket_owner_account_id = optional(string) + })) + }) + default = null +} + +variable "gateway_target_mcp_server_config" { + description = "Configuration for MCP server target." + type = object({ + endpoint = string + }) + default = null +} + +# – Agent Core Workload Identity – + +variable "create_workload_identity" { + description = "Whether or not to create a Bedrock agent core workload identity." + type = bool + default = false +} + +variable "workload_identity_name" { + description = "The name of the workload identity." + type = string + default = "TerraformBedrockAgentCoreWorkloadIdentity" +} + +variable "workload_identity_allowed_resource_oauth_2_return_urls" { + description = "The list of allowed OAuth2 return URLs for resources associated with this workload identity." + type = list(string) + default = null +} + +variable "workload_identity_tags" { + description = "A map of tag keys and values for the workload identity." + type = map(string) + default = null +} + # – Cognito User Pool (for JWT Authentication Fallback) – variable "user_pool_name" { diff --git a/workload_identity.tf b/workload_identity.tf new file mode 100644 index 0000000..418e272 --- /dev/null +++ b/workload_identity.tf @@ -0,0 +1,21 @@ +# – Bedrock Agent Core Workload Identity – + +locals { + create_workload_identity = var.create_workload_identity + # Sanitize workload identity name to ensure it follows any required patterns + sanitized_workload_identity_name = replace(var.workload_identity_name, "-", "_") +} + +resource "awscc_bedrockagentcore_workload_identity" "workload_identity" { + count = local.create_workload_identity ? 1 : 0 + + name = "${random_string.solution_prefix.result}_${local.sanitized_workload_identity_name}" + allowed_resource_oauth_2_return_urls = var.workload_identity_allowed_resource_oauth_2_return_urls + + tags = var.workload_identity_tags != null ? [ + for k, v in var.workload_identity_tags : { + key = k + value = v + } + ] : null +} From 15a11a5292d4600882981ae27a3ad511accf98ba Mon Sep 17 00:00:00 2001 From: Alexa Perlov Date: Fri, 14 Nov 2025 12:37:01 -0800 Subject: [PATCH 2/2] fix: lint --- .header.md | 20 ++++++++++---------- README.md | 13 ++++++++++--- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/.header.md b/.header.md index 1b0d300..7b3c0b4 100644 --- a/.header.md +++ b/.header.md @@ -489,15 +489,15 @@ module "agentcore" { # First, create a gateway create_gateway = true gateway_name = "MyGateway" - + # Then create a gateway target for Lambda create_gateway_target = true gateway_target_name = "MyLambdaTarget" gateway_target_description = "Lambda function target for processing requests" - + # Use the gateway's IAM role for authentication gateway_target_credential_provider_type = "GATEWAY_IAM_ROLE" - + # Configure the Lambda target gateway_target_type = "LAMBDA" gateway_target_lambda_config = { @@ -506,7 +506,7 @@ module "agentcore" { inline_schema = { name = "process_request" description = "Process incoming requests" - + input_schema = { type = "object" description = "Request processing schema" @@ -529,7 +529,7 @@ module "agentcore" { } ] } - + output_schema = { type = "object" properties = [ @@ -560,7 +560,7 @@ module "agentcore" { create_gateway_target = true gateway_target_name = "ApiKeyTarget" gateway_target_gateway_id = "your-gateway-id" # If using existing gateway - + gateway_target_credential_provider_type = "API_KEY" gateway_target_api_key_config = { provider_arn = "arn:aws:iam::123456789012:oidc-provider/example.com" @@ -568,7 +568,7 @@ module "agentcore" { credential_parameter_name = "X-API-Key" credential_prefix = "Bearer" } - + # Configure Lambda target gateway_target_type = "LAMBDA" gateway_target_lambda_config = { @@ -577,7 +577,7 @@ module "agentcore" { inline_schema = { name = "api_tool" description = "External API integration tool" - + input_schema = { type = "string" description = "Simple string input for API calls" @@ -597,7 +597,7 @@ module "agentcore" { # Create a gateway target for an MCP server create_gateway_target = true gateway_target_name = "MCPServerTarget" - + # Configure MCP Server target gateway_target_type = "MCP_SERVER" gateway_target_mcp_server_config = { @@ -622,7 +622,7 @@ module "agentcore" { "https://example.com/oauth2/callback", "https://api.example.com/auth/callback" ] - + # Optional: Add tags workload_identity_tags = { Environment = "production" diff --git a/README.md b/README.md index 965f664..d7640df 100644 --- a/README.md +++ b/README.md @@ -490,12 +490,15 @@ module "agentcore" { # First, create a gateway create_gateway = true gateway_name = "MyGateway" + # Then create a gateway target for Lambda create_gateway_target = true gateway_target_name = "MyLambdaTarget" gateway_target_description = "Lambda function target for processing requests" + # Use the gateway's IAM role for authentication gateway_target_credential_provider_type = "GATEWAY_IAM_ROLE" + # Configure the Lambda target gateway_target_type = "LAMBDA" gateway_target_lambda_config = { @@ -504,7 +507,7 @@ module "agentcore" { inline_schema = { name = "process_request" description = "Process incoming requests" - + input_schema = { type = "object" description = "Request processing schema" @@ -527,7 +530,7 @@ module "agentcore" { } ] } - + output_schema = { type = "object" properties = [ @@ -558,6 +561,7 @@ module "agentcore" { create_gateway_target = true gateway_target_name = "ApiKeyTarget" gateway_target_gateway_id = "your-gateway-id" # If using existing gateway + gateway_target_credential_provider_type = "API_KEY" gateway_target_api_key_config = { provider_arn = "arn:aws:iam::123456789012:oidc-provider/example.com" @@ -565,6 +569,7 @@ module "agentcore" { credential_parameter_name = "X-API-Key" credential_prefix = "Bearer" } + # Configure Lambda target gateway_target_type = "LAMBDA" gateway_target_lambda_config = { @@ -573,7 +578,7 @@ module "agentcore" { inline_schema = { name = "api_tool" description = "External API integration tool" - + input_schema = { type = "string" description = "Simple string input for API calls" @@ -593,6 +598,7 @@ module "agentcore" { # Create a gateway target for an MCP server create_gateway_target = true gateway_target_name = "MCPServerTarget" + # Configure MCP Server target gateway_target_type = "MCP_SERVER" gateway_target_mcp_server_config = { @@ -617,6 +623,7 @@ module "agentcore" { "https://example.com/oauth2/callback", "https://api.example.com/auth/callback" ] + # Optional: Add tags workload_identity_tags = { Environment = "production"