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
3 changes: 3 additions & 0 deletions permissions/prowler-additions-policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
"backup:Get*",
"bedrock:List*",
"bedrock:Get*",
"bedrock-agentcore:ListAgentRuntimes",
"bedrock-agentcore:GetAgentRuntime",
"bedrock-agentcore:ListTagsForResource",
"cloudtrail:GetInsightSelectors",
"codeartifact:List*",
"codebuild:BatchGet*",
Expand Down
6 changes: 6 additions & 0 deletions permissions/templates/cloudformation/prowler-scan-role.yml
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,9 @@ Resources:
- "backup:Get*"
- "bedrock:List*"
- "bedrock:Get*"
- "bedrock-agentcore:ListAgentRuntimes"
- "bedrock-agentcore:GetAgentRuntime"
- "bedrock-agentcore:ListTagsForResource"
- "cloudtrail:GetInsightSelectors"
- "codeartifact:List*"
- "codebuild:BatchGet*"
Expand Down Expand Up @@ -456,6 +459,9 @@ Resources:
- "backup:Get*"
- "bedrock:List*"
- "bedrock:Get*"
- "bedrock-agentcore:ListAgentRuntimes"
- "bedrock-agentcore:GetAgentRuntime"
- "bedrock-agentcore:ListTagsForResource"
- "cloudtrail:GetInsightSelectors"
- "codeartifact:List*"
- "codebuild:BatchGet*"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
`bedrockagentcore_runtime_vpc_configured` check for AWS provider, verifying that Amazon Bedrock AgentCore runtimes use VPC network mode with configured subnets and security groups
32 changes: 32 additions & 0 deletions prowler/providers/aws/aws_regions_by_service.json
Original file line number Diff line number Diff line change
Expand Up @@ -1915,6 +1915,38 @@
"aws-us-gov": []
}
},
"bedrock-agentcore-control": {
"regions": {
"aws": [
"ap-northeast-1",
"ap-northeast-2",
"ap-south-1",
"ap-southeast-1",
"ap-southeast-2",
"ap-southeast-5",
"ap-southeast-7",
"ca-central-1",
"eu-central-1",
"eu-north-1",
"eu-south-1",
"eu-south-2",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"sa-east-1",
"us-east-1",
"us-east-2",
"us-west-2"
],
"aws-cn": [],
"aws-eusc": [],
"aws-iso": [],
"aws-iso-b": [],
"aws-iso-e": [],
"aws-iso-f": [],
"aws-us-gov": []
}
},
"bedrock-data-automation": {
"regions": {
"aws": [
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from prowler.providers.aws.services.bedrockagentcore.bedrockagentcore_service import (
BedrockAgentCore,
)
from prowler.providers.common.provider import Provider

bedrockagentcore_client = BedrockAgentCore(Provider.get_global_provider())
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"Provider": "aws",
"CheckID": "bedrockagentcore_runtime_vpc_configured",
"CheckTitle": "Amazon Bedrock AgentCore runtime uses VPC network mode with subnets and security groups",
"CheckType": [
"Software and Configuration Checks/AWS Security Best Practices/Network Reachability",
"Software and Configuration Checks/Industry and Regulatory Standards/AWS Foundational Security Best Practices"
],
"ServiceName": "bedrockagentcore",
"SubServiceName": "",
"ResourceIdTemplate": "",
"Severity": "high",
"ResourceType": "AwsBedrockAgentCoreRuntime",
"ResourceGroup": "ai_ml",
"Description": "**Amazon Bedrock AgentCore runtimes** are evaluated for **VPC network mode**. A runtime with `networkMode` set to `VPC` and non-empty `subnets` and `securityGroups` in `networkModeConfig` keeps agent traffic inside a customer VPC rather than AWS-managed public connectivity.",
"Risk": "A **public or default** AgentCore runtime can reach the internet without VPC controls, weakening **confidentiality** and **integrity**. Agents can exfiltrate data or contact untrusted endpoints. Missing subnets or security groups leave VPC mode incomplete, so traffic is not confined to the intended network boundary.",
"RelatedUrl": "",
"AdditionalURLs": [
"https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agentcore-vpc.html",
"https://docs.aws.amazon.com/bedrock-agentcore-control/latest/APIReference/API_NetworkConfiguration.html",
"https://docs.aws.amazon.com/bedrock-agentcore-control/latest/APIReference/API_GetAgentRuntime.html"
],
"Remediation": {
"Code": {
"CLI": "aws bedrock-agentcore-control create-agent-runtime --agent-runtime-name <example_resource_name> --role-arn <example_resource_id> --agent-runtime-artifact '{\"containerConfiguration\":{\"containerUri\":\"<example_resource_id>\"}}' --network-configuration '{\"networkMode\":\"VPC\",\"networkModeConfig\":{\"subnets\":[\"<example_resource_id>\"],\"securityGroups\":[\"<example_resource_id>\"]}}'",
"NativeIaC": "```yaml\nResources:\n AgentRuntime:\n Type: AWS::BedrockAgentCore::Runtime\n Properties:\n AgentRuntimeName: <example_resource_name>\n RoleArn: <example_resource_id>\n AgentRuntimeArtifact:\n ContainerConfiguration:\n ContainerUri: <example_resource_id>\n NetworkConfiguration:\n NetworkMode: VPC # Critical: places the runtime in a customer VPC so the check passes\n NetworkModeConfig:\n Subnets:\n - <example_resource_id> # Critical: at least one VPC subnet\n SecurityGroups:\n - <example_resource_id> # Critical: at least one security group\n```",
"Other": "1. Open the Amazon Bedrock AgentCore console\n2. Open Agent Runtimes and select the runtime\n3. Under Network configuration, choose VPC\n4. Select at least one subnet and one security group\n5. Save the runtime configuration",
"Terraform": "```hcl\nresource \"aws_bedrockagentcore_agent_runtime\" \"example\" {\n agent_runtime_name = \"<example_resource_name>\"\n role_arn = \"<example_resource_id>\"\n\n agent_runtime_artifact {\n container_configuration {\n container_uri = \"<example_resource_id>\"\n }\n }\n\n # Critical: VPC mode with subnets and security groups makes the check PASS\n network_configuration {\n network_mode = \"VPC\"\n network_mode_config {\n subnets = [\"<example_resource_id>\"]\n security_groups = [\"<example_resource_id>\"]\n }\n }\n}\n```"
},
"Recommendation": {
"Text": "Deploy AgentCore runtimes in **VPC** mode with private subnets and least-privilege security groups. Use **VPC endpoints** for AgentCore, ECR, S3, and CloudWatch Logs so agents do not require public egress.",
"Url": "https://hub.prowler.com/check/bedrockagentcore_runtime_vpc_configured"
}
},
"Categories": [
"internet-exposed",
"trust-boundaries",
"gen-ai"
],
"DependsOn": [],
"RelatedTo": [],
"Notes": "Reports one finding per AgentCore runtime. A runtime whose detail could not be retrieved returns MANUAL rather than PASS/FAIL, preventing false PASS results when permissions are insufficient."
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
from prowler.lib.check.models import Check, Check_Report_AWS
from prowler.providers.aws.services.bedrockagentcore.bedrockagentcore_client import (
bedrockagentcore_client,
)
from prowler.providers.aws.services.bedrockagentcore.bedrockagentcore_service import (
AgentRuntime,
)


class bedrockagentcore_runtime_vpc_configured(Check):
"""Ensure Bedrock AgentCore runtimes use VPC network mode.

This check evaluates each Amazon Bedrock AgentCore runtime for VPC
networking with required subnets and security groups.
- PASS: networkMode is VPC and networkModeConfig has subnets and security groups.
- FAIL: networkMode is PUBLIC/default, or VPC mode is missing required fields.
- MANUAL: runtime listing failed in a region or runtime detail could not be retrieved.
"""

def execute(self) -> list[Check_Report_AWS]:
"""Execute the check logic.

Returns:
A list of reports containing the PASS, FAIL, or MANUAL results.
"""
findings = []

for region, error in sorted(
bedrockagentcore_client.agent_runtimes_scan_errors.items()
):
report = Check_Report_AWS(
metadata=self.metadata(), resource={"region": region}
)
report.region = region
report.resource_id = "runtime/unknown"
report.resource_arn = (
f"arn:{bedrockagentcore_client.audited_partition}:bedrock-agentcore:"
f"{region}:{bedrockagentcore_client.audited_account}:runtime/unknown"
)
report.status = "MANUAL"
report.status_extended = (
f"Bedrock AgentCore runtimes could not be listed in region {region} "
f"({error}); verify manually that every runtime uses VPC network mode "
f"with subnets and security groups."
)
findings.append(report)

for runtime in bedrockagentcore_client.agent_runtimes.values():
report = Check_Report_AWS(metadata=self.metadata(), resource=runtime)

if not runtime.detail_retrieved:
report.status = "MANUAL"
report.status_extended = (
f"Bedrock AgentCore runtime {runtime.name} network configuration "
f"could not be retrieved in region {runtime.region}; verify "
f"manually that it uses VPC network mode with subnets and "
f"security groups."
)
elif _is_vpc_configured(runtime):
report.status = "PASS"
report.status_extended = (
f"Bedrock AgentCore runtime {runtime.name} is configured with VPC "
f"network mode and has subnets and security groups in region "
f"{runtime.region}."
)
elif runtime.network_mode == "VPC":
report.status = "FAIL"
report.status_extended = (
f"Bedrock AgentCore runtime {runtime.name} uses VPC network mode "
f"but is missing required subnets or security groups in region "
f"{runtime.region}."
)
else:
network_mode = runtime.network_mode or "PUBLIC"
report.status = "FAIL"
report.status_extended = (
f"Bedrock AgentCore runtime {runtime.name} is configured with "
f"{network_mode} network mode instead of VPC in region "
f"{runtime.region}."
)

findings.append(report)

return findings


def _is_vpc_configured(runtime: AgentRuntime) -> bool:
"""Return whether a runtime has VPC mode with subnets and security groups.

Args:
runtime: AgentRuntime collected by the AgentCore service.

Returns:
True when networkMode is VPC and both subnets and security groups are set.
"""
if runtime.network_mode != "VPC" or not runtime.network_mode_config:
return False
return bool(runtime.network_mode_config.subnets) and bool(
runtime.network_mode_config.security_groups
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
from typing import Optional

from botocore.exceptions import ClientError
from pydantic.v1 import BaseModel

from prowler.lib.logger import logger
from prowler.lib.scan_filters.scan_filters import is_resource_filtered
from prowler.providers.aws.lib.service.service import AWSService

# Errors that mean AgentCore is not available in the region, not an
# unreadable inventory. These must not become MANUAL findings.
_UNSUPPORTED_REGION_ERROR_CODES = (
"ValidationException",
"ResourceNotFoundException",
"UnrecognizedClientException",
"UnknownOperationException",
)


class BedrockAgentCore(AWSService):
"""Amazon Bedrock AgentCore control-plane collector."""

def __init__(self, provider):
"""Initialize the Bedrock AgentCore service.

Args:
provider: Prowler AWS provider object.
"""
super().__init__("bedrock-agentcore-control", provider)
self.agent_runtimes = {}
self.agent_runtimes_scan_errors = {}
self.__threading_call__(self._list_agent_runtimes)
self.__threading_call__(self._get_agent_runtime, self.agent_runtimes.values())
self.__threading_call__(
self._list_tags_for_resource, self.agent_runtimes.values()
)

def _list_agent_runtimes(self, regional_client):
"""List Bedrock AgentCore runtimes in a region.

Args:
regional_client: Regional Bedrock AgentCore boto3 client.
"""
logger.info("Bedrock AgentCore - Listing Agent Runtimes...")
try:
paginator = regional_client.get_paginator("list_agent_runtimes")
for page in paginator.paginate():
try:
for runtime in page.get("agentRuntimes", []):
runtime_id = runtime.get("agentRuntimeId", "")
runtime_arn = runtime.get("agentRuntimeArn") or (
f"arn:{self.audited_partition}:bedrock-agentcore:"
f"{regional_client.region}:{self.audited_account}:"
f"runtime/{runtime_id}"
)
if not self.audit_resources or is_resource_filtered(
runtime_arn, self.audit_resources
):
self.agent_runtimes[runtime_arn] = AgentRuntime(
id=runtime_id,
name=runtime.get("agentRuntimeName") or runtime_id,
arn=runtime_arn,
version=runtime.get("agentRuntimeVersion"),
status=runtime.get("status"),
description=runtime.get("description"),
region=regional_client.region,
)
except Exception as error:
logger.error(
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
except ClientError as error:
code = error.response["Error"].get("Code", error.__class__.__name__)
if code not in _UNSUPPORTED_REGION_ERROR_CODES:
self.agent_runtimes_scan_errors[regional_client.region] = code
logger.error(
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
except Exception as error:
self.agent_runtimes_scan_errors[regional_client.region] = (
error.__class__.__name__
)
logger.error(
f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)

def _get_agent_runtime(self, runtime):
"""Get detailed configuration for a Bedrock AgentCore runtime.

Args:
runtime: AgentRuntime instance to enrich with network configuration.
"""
logger.info("Bedrock AgentCore - Getting Agent Runtime...")
try:
runtime_info = self.regional_clients[runtime.region].get_agent_runtime(
agentRuntimeId=runtime.id
)
network_config = runtime_info.get("networkConfiguration") or {}
runtime.network_mode = network_config.get("networkMode")
mode_config = network_config.get("networkModeConfig") or {}
runtime.network_mode_config = VpcNetworkModeConfig(
subnets=mode_config.get("subnets") or [],
security_groups=mode_config.get("securityGroups") or [],
)
runtime.detail_retrieved = True
except Exception as error:
logger.error(
f"{runtime.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)

def _list_tags_for_resource(self, runtime):
"""List tags for a Bedrock AgentCore runtime.

Args:
runtime: AgentRuntime instance to attach tags to.
"""
logger.info("Bedrock AgentCore - Listing Tags for Resource...")
try:
runtime.tags = (
self.regional_clients[runtime.region]
.list_tags_for_resource(resourceArn=runtime.arn)
.get("tags", {})
)
except Exception as error:
logger.error(
f"{runtime.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)


class VpcNetworkModeConfig(BaseModel):
"""VPC network mode configuration for an AgentCore runtime."""

subnets: list[str] = []
security_groups: list[str] = []


class AgentRuntime(BaseModel):
"""Bedrock AgentCore runtime resource model."""

id: str
name: str
arn: str
region: str
version: Optional[str] = None
status: Optional[str] = None
description: Optional[str] = None
network_mode: Optional[str] = None
network_mode_config: Optional[VpcNetworkModeConfig] = None
tags: Optional[dict] = {}
detail_retrieved: bool = False
Loading
Loading