Skip to content

Commit de6e5de

Browse files
committed
adding kb ingestion encryption check rule
1 parent 411f480 commit de6e5de

File tree

4 files changed

+141
-0
lines changed

4 files changed

+141
-0
lines changed
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"""Config rule to check knowledge base data ingestion encryption for Bedrock environments.
2+
3+
Version: 1.0
4+
5+
Config rule for SRA in the repo, https://github.com/aws-samples/aws-security-reference-architecture-examples
6+
7+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
8+
SPDX-License-Identifier: MIT-0
9+
"""
10+
import json
11+
import logging
12+
import os
13+
from typing import Any
14+
15+
import boto3
16+
from botocore.exceptions import ClientError
17+
18+
# Setup Default Logger
19+
LOGGER = logging.getLogger(__name__)
20+
log_level = os.environ.get("LOG_LEVEL", logging.INFO)
21+
LOGGER.setLevel(log_level)
22+
LOGGER.info(f"boto3 version: {boto3.__version__}")
23+
24+
# Get AWS region from environment variable
25+
AWS_REGION = os.environ.get("AWS_REGION")
26+
27+
# Initialize AWS clients
28+
bedrock_agent_client = boto3.client("bedrock-agent", region_name=AWS_REGION)
29+
config_client = boto3.client("config", region_name=AWS_REGION)
30+
31+
def evaluate_compliance(rule_parameters: dict) -> tuple[str, str]:
32+
"""Evaluate if Bedrock Knowledge Base data sources are encrypted with KMS.
33+
34+
Args:
35+
rule_parameters (dict): Rule parameters from AWS Config rule.
36+
37+
Returns:
38+
tuple[str, str]: Compliance type and annotation message.
39+
"""
40+
try:
41+
# List all knowledge bases
42+
non_compliant_kbs = []
43+
paginator = bedrock_agent_client.get_paginator("list_knowledge_bases")
44+
45+
for page in paginator.paginate():
46+
for kb in page["knowledgeBaseSummaries"]:
47+
kb_id = kb["knowledgeBaseId"]
48+
kb_name = kb.get("name", kb_id)
49+
50+
# Get data sources for each knowledge base
51+
try:
52+
data_sources = bedrock_agent_client.list_data_sources(
53+
knowledgeBaseId=kb_id
54+
)
55+
56+
# Check if any data source is not encrypted
57+
unencrypted_sources = []
58+
for source in data_sources.get("dataSourceSummaries", []):
59+
if not source.get("serverSideEncryptionConfiguration", {}).get("kmsKeyArn"):
60+
unencrypted_sources.append(source.get("name", source["dataSourceId"]))
61+
62+
if unencrypted_sources:
63+
non_compliant_kbs.append(f"{kb_name} (unencrypted sources: {', '.join(unencrypted_sources)})")
64+
65+
except ClientError as e:
66+
LOGGER.error(f"Error checking data sources for knowledge base {kb_name}: {str(e)}")
67+
if e.response["Error"]["Code"] == "AccessDeniedException":
68+
non_compliant_kbs.append(f"{kb_name} (access denied)")
69+
else:
70+
raise
71+
72+
if non_compliant_kbs:
73+
return "NON_COMPLIANT", f"The following knowledge bases have unencrypted data sources: {'; '.join(non_compliant_kbs)}"
74+
return "COMPLIANT", "All knowledge base data sources are encrypted with KMS"
75+
76+
except Exception as e:
77+
LOGGER.error(f"Error evaluating Bedrock Knowledge Base encryption: {str(e)}")
78+
return "ERROR", f"Error evaluating compliance: {str(e)}"
79+
80+
def lambda_handler(event: dict, context: Any) -> None: # noqa: U100
81+
"""Lambda handler.
82+
83+
Args:
84+
event (dict): Lambda event object
85+
context (Any): Lambda context object
86+
"""
87+
LOGGER.info("Evaluating compliance for AWS Config rule")
88+
LOGGER.info(f"Event: {json.dumps(event)}")
89+
90+
invoking_event = json.loads(event["invokingEvent"])
91+
rule_parameters = json.loads(event["ruleParameters"]) if "ruleParameters" in event else {}
92+
93+
compliance_type, annotation = evaluate_compliance(rule_parameters)
94+
95+
evaluation = {
96+
"ComplianceResourceType": "AWS::::Account",
97+
"ComplianceResourceId": event["accountId"],
98+
"ComplianceType": compliance_type,
99+
"Annotation": annotation,
100+
"OrderingTimestamp": invoking_event["notificationCreationTime"],
101+
}
102+
103+
LOGGER.info(f"Compliance evaluation result: {compliance_type}")
104+
LOGGER.info(f"Annotation: {annotation}")
105+
106+
config_client.put_evaluations(Evaluations=[evaluation], ResultToken=event["resultToken"]) # type: ignore
107+
108+
LOGGER.info("Compliance evaluation complete.")

aws_sra_examples/solutions/genai/bedrock_org/lambda/src/app.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ def load_sra_cloudwatch_dashboard() -> dict:
202202
+ r'\[((?:"[0-9]+"(?:\s*,\s*)?)*)\],\s*"regions"\s*:\s*\[((?:"[a-z0-9-]+"(?:\s*,\s*)?)*)\]\}$',
203203
"SRA-BEDROCK-CHECK-KB-LOGGING": r'^\{"deploy"\s*:\s*"(true|false)",\s*"accounts"\s*:\s*\[((?:"[0-9]+"(?:\s*,\s*)?)*)\],\s*"regions"\s*:\s*'
204204
+ r'\[((?:"[a-z0-9-]+"(?:\s*,\s*)?)*)\],\s*"input_params"\s*:\s*(\{\})\}$',
205+
"SRA-BEDROCK-CHECK-KB-INGESTION-ENCRYPTION": r'^\{"deploy"\s*:\s*"(true|false)",\s*"accounts"\s*:\s*\[((?:"[0-9]+"(?:\s*,\s*)?)*)\],\s*"regions"\s*:\s*'
206+
+ r'\[((?:"[a-z0-9-]+"(?:\s*,\s*)?)*)\],\s*"input_params"\s*:\s*(\{\})\}$',
205207
}
206208

207209
# Instantiate sra class objects

aws_sra_examples/solutions/genai/bedrock_org/lambda/src/sra_config_lambda_iam_permissions.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,5 +137,21 @@
137137
"Resource": "*"
138138
}
139139
]
140+
},
141+
"sra-bedrock-check-kb-ingestion-encryption": {
142+
"Version": "2012-10-17",
143+
"Statement": [
144+
{
145+
"Sid": "AllowKnowledgeBaseAccess",
146+
"Effect": "Allow",
147+
"Action": [
148+
"bedrock:ListKnowledgeBases",
149+
"bedrock:GetKnowledgeBase",
150+
"bedrock:ListDataSources",
151+
"bedrock:GetDataSource"
152+
],
153+
"Resource": "*"
154+
}
155+
]
140156
}
141157
}

aws_sra_examples/solutions/genai/bedrock_org/templates/sra-bedrock-org-main.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,17 @@ Parameters:
292292
Example: {\"deploy\": \"true\", \"accounts\": [\"123456789012\"], \"regions\": [\"us-east-1\"], \"input_params\": {}} or
293293
{\"deploy\": \"false\", \"accounts\": [], \"regions\": [], \"input_params\": {}}"
294294

295+
pBedrockKBIngestionEncryptionRuleParams:
296+
Type: String
297+
Default: '{"deploy": "true", "accounts": ["444455556666"], "regions": ["us-west-2"], "input_params": {}}'
298+
Description: Bedrock Knowledge Base Data Ingestion Encryption Config Rule Parameters
299+
AllowedPattern: ^\{"deploy"\s*:\s*"(true|false)",\s*"accounts"\s*:\s*\[((?:"[0-9]+"(?:\s*,\s*)?)*)\],\s*"regions"\s*:\s*\[((?:"[a-z0-9-]+"(?:\s*,\s*)?)*)\],\s*"input_params"\s*:\s*(\{\})\}$
300+
ConstraintDescription:
301+
"Must be a valid JSON string containing: 'deploy' (true/false), 'accounts' (array of account numbers),
302+
'regions' (array of region names), and 'input_params' object/dict (input params must be empty). Arrays can be empty.
303+
Example: {\"deploy\": \"true\", \"accounts\": [\"123456789012\"], \"regions\": [\"us-east-1\"], \"input_params\": {}} or
304+
{\"deploy\": \"false\", \"accounts\": [], \"regions\": [], \"input_params\": {}}"
305+
295306
Metadata:
296307
AWS::CloudFormation::Interface:
297308
ParameterGroups:
@@ -333,6 +344,7 @@ Metadata:
333344
- pBedrockS3EndpointsRuleParams
334345
- pBedrockGuardrailEncryptionRuleParams
335346
- pBedrockKBLoggingRuleParams
347+
- pBedrockKBIngestionEncryptionRuleParams
336348
- Label:
337349
default: Bedrock CloudWatch Metric Filters
338350
Parameters:
@@ -402,6 +414,8 @@ Metadata:
402414
default: Bedrock Regions
403415
pBedrockKBLoggingRuleParams:
404416
default: Bedrock Knowledge Base Logging Config Rule Parameters
417+
pBedrockKBIngestionEncryptionRuleParams:
418+
default: Bedrock Knowledge Base Data Ingestion Encryption Config Rule Parameters
405419

406420
Resources:
407421
rBedrockOrgLambdaRole:
@@ -683,6 +697,7 @@ Resources:
683697
SRA-BEDROCK-FILTER-SENSITIVE-INFO: !Ref pBedrockSensitiveInfoFilterParams
684698
SRA-BEDROCK-CENTRAL-OBSERVABILITY: !Ref pBedrockCentralObservabilityParams
685699
SRA-BEDROCK-CHECK-KB-LOGGING: !Ref pBedrockKBLoggingRuleParams
700+
SRA-BEDROCK-CHECK-KB-INGESTION-ENCRYPTION: !Ref pBedrockKBIngestionEncryptionRuleParams
686701

687702
rBedrockOrgLambdaInvokePermission:
688703
Type: AWS::Lambda::Permission

0 commit comments

Comments
 (0)