Skip to content

Add AgentCore Web Search Tool managed connector for customer service agent#1749

Open
sumanayanamandra wants to merge 3 commits into
awslabs:mainfrom
sumanayanamandra:feature/web-search-tool
Open

Add AgentCore Web Search Tool managed connector for customer service agent#1749
sumanayanamandra wants to merge 3 commits into
awslabs:mainfrom
sumanayanamandra:feature/web-search-tool

Conversation

@sumanayanamandra

Copy link
Copy Markdown

Amazon Bedrock AgentCore Samples Pull Request

Concise description of the PR

Changes to 05-blueprints/end-to-end-customer-service-agent/infra/, because the blueprint now uses the AgentCore Web Search Tool managed connector for web search — a fully managed, MCP-compliant capability that requires no external API keys, no Lambda functions, and keeps all queries within AWS.

User experience

Before: Web search required provisioning and managing a separate Lambda function with third-party API keys, handling rate limits, and parsing external response formats.

After: Web search is available as a zero-infrastructure managed connector on the AgentCore Gateway. Agents discover it via tools/list and invoke it like any other MCP tool. Queries never leave AWS, results include semantic snippets optimized for LLM context, and no API keys or external services are needed.

Acknowledgment

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

Acknowledgment

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

@@ -87,12 +87,144 @@ module "secrets" {
langfuse_secret_key = var.langfuse_secret_key
gateway_url = var.gateway_url
gateway_api_key = var.gateway_api_key
tavily_api_key = var.tavily_api_key
tavily_api_key = "" # No longer used — replaced by AgentCore Web Search Tool connector

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If it's unused, pls remove it completely

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Removed this and all the references to it.

@@ -0,0 +1,150 @@
# AgentCore Web Search Tool integration

Provides web search capability for the customer service agent using the AgentCore managed Web Search Tool connector — zero infrastructure, no API keys, queries stay within AWS.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We do not need a readme for Websearch only.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Removed it

@github-actions

Copy link
Copy Markdown

Latest scan for commit: a74ef43 | Updated: 2026-06-30 15:32:15 UTC

Security Scan Results

Scan Metadata

  • Project: ASH
  • Scan executed: 2026-06-30T15:31:56+00:00
  • ASH version: 3.0.0

Summary

Scanner Results

The table below shows findings by scanner, with status based on severity thresholds and dependencies:

Column Explanations:

Severity Levels (S/C/H/M/L/I):

  • Suppressed (S): Security findings that have been explicitly suppressed/ignored and don't affect the scanner's pass/fail status
  • Critical (C): The most severe security vulnerabilities requiring immediate remediation (e.g., SQL injection, remote code execution)
  • High (H): Serious security vulnerabilities that should be addressed promptly (e.g., authentication bypasses, privilege escalation)
  • Medium (M): Moderate security risks that should be addressed in normal development cycles (e.g., weak encryption, input validation issues)
  • Low (L): Minor security concerns with limited impact (e.g., information disclosure, weak recommendations)
  • Info (I): Informational findings for awareness with minimal security risk (e.g., code quality suggestions, best practice recommendations)

Other Columns:

  • Time: Duration taken by each scanner to complete its analysis
  • Action: Total number of actionable findings at or above the configured severity threshold that require attention

Scanner Results:

  • PASSED: Scanner found no security issues at or above the configured severity threshold - code is clean for this scanner
  • FAILED: Scanner found security vulnerabilities at or above the threshold that require attention and remediation
  • MISSING: Scanner could not run because required dependencies/tools are not installed or available
  • SKIPPED: Scanner was intentionally disabled or excluded from this scan
  • ERROR: Scanner encountered an execution error and could not complete successfully

Severity Thresholds (Thresh Column):

  • CRITICAL: Only Critical severity findings cause scanner to fail
  • HIGH: High and Critical severity findings cause scanner to fail
  • MEDIUM (MED): Medium, High, and Critical severity findings cause scanner to fail
  • LOW: Low, Medium, High, and Critical severity findings cause scanner to fail
  • ALL: Any finding of any severity level causes scanner to fail

Threshold Source: Values in parentheses indicate where the threshold is configured:

  • (g) = global: Set in the global_settings section of ASH configuration
  • (c) = config: Set in the individual scanner configuration section
  • (s) = scanner: Default threshold built into the scanner itself

Statistics calculation:

  • All statistics are calculated from the final aggregated SARIF report
  • Suppressed findings are counted separately and do not contribute to actionable findings
  • Scanner status is determined by comparing actionable findings to the threshold
Scanner S C H M L I Time Action Result Thresh
bandit 0 0 0 0 0 0 837ms 0 PASSED MED (g)
cdk-nag 0 0 0 0 0 0 6.3s 0 PASSED MED (g)
cfn-nag 0 0 0 0 0 0 6ms 0 PASSED MED (g)
checkov 0 9 0 0 0 0 5.4s 9 FAILED MED (g)
detect-secrets 0 0 0 0 0 0 801ms 0 PASSED MED (g)
grype 0 0 0 0 0 0 44.1s 0 PASSED MED (g)
npm-audit 0 0 0 0 0 0 182ms 0 PASSED MED (g)
opengrep 0 0 0 0 0 0 <1ms 0 SKIPPED MED (g)
semgrep 0 0 0 0 0 0 <1ms 0 MISSING MED (g)
syft 0 0 0 0 0 0 2.3s 0 PASSED MED (g)

Detailed Findings

Show 9 actionable findings

Finding 1: CKV_AWS_28

  • Severity: HIGH
  • Scanner: checkov
  • Rule ID: CKV_AWS_28
  • Location: 05-blueprints/end-to-end-customer-service-agent/infra/main.tf:124-143

Description:
Ensure DynamoDB point in time recovery (backup) is enabled

Code Snippet:

resource "aws_dynamodb_table" "rate_limit_table" {
  name         = "agentcore-gateway-rate-limits"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "pk"

  attribute {
    name = "pk"
    type = "S"
  }

  # TTL so stale counters are automatically cleaned up
  ttl {
    attribute_name = "ttl"
    enabled        = true
  }

  tags = {
    Purpose = "AgentCore Gateway rate limiting"
  }
}

Finding 2: CKV_AWS_119

  • Severity: HIGH
  • Scanner: checkov
  • Rule ID: CKV_AWS_119
  • Location: 05-blueprints/end-to-end-customer-service-agent/infra/main.tf:124-143

Description:
Ensure DynamoDB Tables are encrypted using a KMS Customer Managed CMK

Code Snippet:

resource "aws_dynamodb_table" "rate_limit_table" {
  name         = "agentcore-gateway-rate-limits"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "pk"

  attribute {
    name = "pk"
    type = "S"
  }

  # TTL so stale counters are automatically cleaned up
  ttl {
    attribute_name = "ttl"
    enabled        = true
  }

  tags = {
    Purpose = "AgentCore Gateway rate limiting"
  }
}

Finding 3: CKV_AWS_116

  • Severity: HIGH
  • Scanner: checkov
  • Rule ID: CKV_AWS_116
  • Location: 05-blueprints/end-to-end-customer-service-agent/infra/main.tf:188-214

Description:
Ensure that AWS Lambda function is configured for a Dead Letter Queue(DLQ)

Code Snippet:

resource "aws_lambda_function" "gateway_interceptor" {
  filename         = data.archive_file.interceptor_lambda_zip.output_path
  source_code_hash = data.archive_file.interceptor_lambda_zip.output_base64sha256
  function_name    = "cx-gateway-interceptor"
  role             = aws_iam_role.interceptor_lambda_role.arn
  handler          = "gateway_interceptor.lambda_handler"
  runtime          = "python3.12"
  timeout          = 10 # keep low — interceptor is on the hot path

  tracing_config {
    mode = "Active"
  }

  environment {
    variables = {
      RATE_LIMIT_TABLE        = aws_dynamodb_table.rate_limit_table.name
      RATE_LIMIT_MAX          = tostring(var.interceptor_rate_limit_max)
      RATE_LIMIT_WINDOW       = tostring(var.interceptor_rate_limit_window)
      ENABLE_RATE_LIMIT       = tostring(var.interceptor_enable_rate_limit)
      ENABLE_GUARDRAIL_CHECKS = tostring(var.interceptor_enable_guardrail_checks)
      GUARDRAIL_BLOCK_THRESHOLD    = tostring(var.interceptor_guardrail_block_threshold)
      GUARDRAIL_ESCALATE_THRESHOLD = tostring(var.interceptor_guardrail_escalate_threshold)
    }
  }

  depends_on = [data.archive_file.interceptor_lambda_zip]
}

Finding 4: CKV_AWS_173

  • Severity: HIGH
  • Scanner: checkov
  • Rule ID: CKV_AWS_173
  • Location: 05-blueprints/end-to-end-customer-service-agent/infra/main.tf:188-214

Description:
Check encryption settings for Lambda environmental variable

Code Snippet:

resource "aws_lambda_function" "gateway_interceptor" {
  filename         = data.archive_file.interceptor_lambda_zip.output_path
  source_code_hash = data.archive_file.interceptor_lambda_zip.output_base64sha256
  function_name    = "cx-gateway-interceptor"
  role             = aws_iam_role.interceptor_lambda_role.arn
  handler          = "gateway_interceptor.lambda_handler"
  runtime          = "python3.12"
  timeout          = 10 # keep low — interceptor is on the hot path

  tracing_config {
    mode = "Active"
  }

  environment {
    variables = {
      RATE_LIMIT_TABLE        = aws_dynamodb_table.rate_limit_table.name
      RATE_LIMIT_MAX          = tostring(var.interceptor_rate_limit_max)
      RATE_LIMIT_WINDOW       = tostring(var.interceptor_rate_limit_window)
      ENABLE_RATE_LIMIT       = tostring(var.interceptor_enable_rate_limit)
      ENABLE_GUARDRAIL_CHECKS = tostring(var.interceptor_enable_guardrail_checks)
      GUARDRAIL_BLOCK_THRESHOLD    = tostring(var.interceptor_guardrail_block_threshold)
      GUARDRAIL_ESCALATE_THRESHOLD = tostring(var.interceptor_guardrail_escalate_threshold)
    }
  }

  depends_on = [data.archive_file.interceptor_lambda_zip]
}

Finding 5: CKV_AWS_272

  • Severity: HIGH
  • Scanner: checkov
  • Rule ID: CKV_AWS_272
  • Location: 05-blueprints/end-to-end-customer-service-agent/infra/main.tf:188-214

Description:
Ensure AWS Lambda function is configured to validate code-signing

Code Snippet:

resource "aws_lambda_function" "gateway_interceptor" {
  filename         = data.archive_file.interceptor_lambda_zip.output_path
  source_code_hash = data.archive_file.interceptor_lambda_zip.output_base64sha256
  function_name    = "cx-gateway-interceptor"
  role             = aws_iam_role.interceptor_lambda_role.arn
  handler          = "gateway_interceptor.lambda_handler"
  runtime          = "python3.12"
  timeout          = 10 # keep low — interceptor is on the hot path

  tracing_config {
    mode = "Active"
  }

  environment {
    variables = {
      RATE_LIMIT_TABLE        = aws_dynamodb_table.rate_limit_table.name
      RATE_LIMIT_MAX          = tostring(var.interceptor_rate_limit_max)
      RATE_LIMIT_WINDOW       = tostring(var.interceptor_rate_limit_window)
      ENABLE_RATE_LIMIT       = tostring(var.interceptor_enable_rate_limit)
      ENABLE_GUARDRAIL_CHECKS = tostring(var.interceptor_enable_guardrail_checks)
      GUARDRAIL_BLOCK_THRESHOLD    = tostring(var.interceptor_guardrail_block_threshold)
      GUARDRAIL_ESCALATE_THRESHOLD = tostring(var.interceptor_guardrail_escalate_threshold)
    }
  }

  depends_on = [data.archive_file.interceptor_lambda_zip]
}

Finding 6: CKV_AWS_117

  • Severity: HIGH
  • Scanner: checkov
  • Rule ID: CKV_AWS_117
  • Location: 05-blueprints/end-to-end-customer-service-agent/infra/main.tf:188-214

Description:
Ensure that AWS Lambda function is configured inside a VPC

Code Snippet:

resource "aws_lambda_function" "gateway_interceptor" {
  filename         = data.archive_file.interceptor_lambda_zip.output_path
  source_code_hash = data.archive_file.interceptor_lambda_zip.output_base64sha256
  function_name    = "cx-gateway-interceptor"
  role             = aws_iam_role.interceptor_lambda_role.arn
  handler          = "gateway_interceptor.lambda_handler"
  runtime          = "python3.12"
  timeout          = 10 # keep low — interceptor is on the hot path

  tracing_config {
    mode = "Active"
  }

  environment {
    variables = {
      RATE_LIMIT_TABLE        = aws_dynamodb_table.rate_limit_table.name
      RATE_LIMIT_MAX          = tostring(var.interceptor_rate_limit_max)
      RATE_LIMIT_WINDOW       = tostring(var.interceptor_rate_limit_window)
      ENABLE_RATE_LIMIT       = tostring(var.interceptor_enable_rate_limit)
      ENABLE_GUARDRAIL_CHECKS = tostring(var.interceptor_enable_guardrail_checks)
      GUARDRAIL_BLOCK_THRESHOLD    = tostring(var.interceptor_guardrail_block_threshold)
      GUARDRAIL_ESCALATE_THRESHOLD = tostring(var.interceptor_guardrail_escalate_threshold)
    }
  }

  depends_on = [data.archive_file.interceptor_lambda_zip]
}

Finding 7: CKV_AWS_115

  • Severity: HIGH
  • Scanner: checkov
  • Rule ID: CKV_AWS_115
  • Location: 05-blueprints/end-to-end-customer-service-agent/infra/main.tf:188-214

Description:
Ensure that AWS Lambda function is configured for function-level concurrent execution limit

Code Snippet:

resource "aws_lambda_function" "gateway_interceptor" {
  filename         = data.archive_file.interceptor_lambda_zip.output_path
  source_code_hash = data.archive_file.interceptor_lambda_zip.output_base64sha256
  function_name    = "cx-gateway-interceptor"
  role             = aws_iam_role.interceptor_lambda_role.arn
  handler          = "gateway_interceptor.lambda_handler"
  runtime          = "python3.12"
  timeout          = 10 # keep low — interceptor is on the hot path

  tracing_config {
    mode = "Active"
  }

  environment {
    variables = {
      RATE_LIMIT_TABLE        = aws_dynamodb_table.rate_limit_table.name
      RATE_LIMIT_MAX          = tostring(var.interceptor_rate_limit_max)
      RATE_LIMIT_WINDOW       = tostring(var.interceptor_rate_limit_window)
      ENABLE_RATE_LIMIT       = tostring(var.interceptor_enable_rate_limit)
      ENABLE_GUARDRAIL_CHECKS = tostring(var.interceptor_enable_guardrail_checks)
      GUARDRAIL_BLOCK_THRESHOLD    = tostring(var.interceptor_guardrail_block_threshold)
      GUARDRAIL_ESCALATE_THRESHOLD = tostring(var.interceptor_guardrail_escalate_threshold)
    }
  }

  depends_on = [data.archive_file.interceptor_lambda_zip]
}

Finding 8: CKV_AWS_290

  • Severity: HIGH
  • Scanner: checkov
  • Rule ID: CKV_AWS_290
  • Location: 05-blueprints/end-to-end-customer-service-agent/infra/main.tf:244-269

Description:
Ensure IAM policies does not allow write access without constraints

Code Snippet:

resource "aws_iam_role_policy" "gateway_policy" {
  name = "gateway-external-api-policy"
  role = aws_iam_role.gateway_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ]
        Resource = "*"
      },
      {
        Effect = "Allow"
        Action = ["lambda:InvokeFunction"]
        Resource = [
          aws_lambda_function.gateway_interceptor.arn,
        ]
      }
    ]
  })
}

Finding 9: CKV_AWS_355

  • Severity: HIGH
  • Scanner: checkov
  • Rule ID: CKV_AWS_355
  • Location: 05-blueprints/end-to-end-customer-service-agent/infra/main.tf:244-269

Description:
Ensure no IAM policies documents allow "*" as a statement's resource for restrictable actions

Code Snippet:

resource "aws_iam_role_policy" "gateway_policy" {
  name = "gateway-external-api-policy"
  role = aws_iam_role.gateway_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ]
        Resource = "*"
      },
      {
        Effect = "Allow"
        Action = ["lambda:InvokeFunction"]
        Resource = [
          aws_lambda_function.gateway_interceptor.arn,
        ]
      }
    ]
  })
}

Report generated by Automated Security Helper (ASH) at 2026-06-30T15:31:52+00:00

…ix checkov findings (PITR, DLQ, concurrency, scoped IAM)
@sumanayanamandra sumanayanamandra force-pushed the feature/web-search-tool branch from 9bcfe91 to 80cd9a9 Compare July 2, 2026 10:30
@sumanayanamandra

Copy link
Copy Markdown
Author

@akshseh Thanks for the review. Here is the review feedback addressed:

Code fixes:

Removed tavily_api_key completely (main.tf, secrets module variables, outputs, rotation policy)
Deleted WEB_SEARCH_README.md
CKV_AWS_28: DynamoDB point-in-time recovery enabled
CKV_AWS_115: Lambda reserved concurrency set to 100
CKV_AWS_116: Lambda DLQ (encrypted SQS queue) added
CKV_AWS_290/355: IAM logs resource scoped to log-group:/aws/bedrock-agentcore/*

Findings accepted with justification (not fixable in a sample blueprint):

CKV_AWS_119 (DynamoDB CMK): Table stores only ephemeral rate-limit counters (caller ID + request count) with short TTLs. AWS-owned encryption is enabled.
CKV_AWS_117 (Lambda in VPC): This interceptor only calls DynamoDB and Bedrock APIs (public endpoints).
CKV_AWS_272 (Lambda code signing): Code signing requires a Signer profile and signed deployment workflow — excessive for a sample. Code integrity is ensured via source control and source_code_hash.
CKV_AWS_173 (Lambda env var CMK): Environment variables contain only non-sensitive config (table names, numeric thresholds, boolean flags). No secrets stored. AWS-managed encryption at rest is already applied by default.

@sumanayanamandra sumanayanamandra requested a review from akshseh July 2, 2026 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants