Skip to content

Commit 1b7bca5

Browse files
committed
fixing errors and permissions
1 parent 4292ec4 commit 1b7bca5

File tree

2 files changed

+42
-15
lines changed

2 files changed

+42
-15
lines changed

aws_sra_examples/solutions/genai/bedrock_org/lambda/rules/sra_bedrock_check_kb_opensearch_encryption/app.py

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,15 +72,16 @@ def check_opensearch_domain(domain_name: str, kb_name: str) -> str | None: # ty
7272
encryption_config = domain.get("DomainStatus", {}).get("EncryptionAtRestOptions", {})
7373
if not encryption_config.get("Enabled", False):
7474
return f"{kb_name} (OpenSearch domain encryption not enabled)"
75-
if not encryption_config.get("KmsKeyId"):
75+
kms_key_id = encryption_config.get("KmsKeyId", "")
76+
if not kms_key_id or "aws/opensearch" in kms_key_id:
7677
return f"{kb_name} (OpenSearch domain not using CMK)"
7778
except ClientError as e:
7879
LOGGER.error(f"Error checking OpenSearch domain: {str(e)}")
7980
return f"{kb_name} (error checking OpenSearch domain)"
8081
return None
8182

8283

83-
def check_knowledge_base(kb_id: str, kb_name: str) -> str | None: # type: ignore # noqa: CFQ004
84+
def check_knowledge_base(kb_id: str, kb_name: str) -> tuple[bool, str | None]: # type: ignore # noqa: CFQ004
8485
"""Check a knowledge base's OpenSearch configuration.
8586
8687
Args:
@@ -91,40 +92,56 @@ def check_knowledge_base(kb_id: str, kb_name: str) -> str | None: # type: ignor
9192
ClientError: If there is an error checking the knowledge base
9293
9394
Returns:
94-
str | None: Error message if non-compliant, None if compliant
95+
tuple[bool, str | None]: (has_opensearch, error_message)
9596
"""
9697
try:
9798
kb_details = bedrock_agent_client.get_knowledge_base(knowledgeBaseId=kb_id)
98-
vector_store = kb_details.get("vectorStoreConfiguration")
99+
# Convert datetime objects to strings before JSON serialization
100+
kb_details_serializable = json.loads(json.dumps(kb_details, default=str))
101+
LOGGER.info(f"Knowledge base details for {kb_name}: {json.dumps(kb_details_serializable)}")
102+
103+
# Access the knowledgeBase key from the response
104+
kb_data = kb_details.get("knowledgeBase", {})
105+
106+
# Check both possible locations for vector store config
107+
vector_store = kb_data.get("vectorStoreConfiguration") or kb_data.get("storageConfiguration", {})
108+
LOGGER.info(f"Vector store config for {kb_name}: {json.dumps(vector_store)}")
99109

100110
if not vector_store or not isinstance(vector_store, dict):
101-
return None
111+
LOGGER.info(f"No vector store configuration found for {kb_name}")
112+
return False, None
102113

103-
if vector_store.get("vectorStoreType") != "OPENSEARCH":
104-
return None
114+
vector_store_type = vector_store.get("vectorStoreType") or vector_store.get("type")
115+
LOGGER.info(f"Vector store type for {kb_name}: {vector_store_type}")
116+
if not vector_store_type or (vector_store_type.upper() != "OPENSEARCH" and vector_store_type.upper() != "OPENSEARCH_SERVERLESS"):
117+
LOGGER.info(f"Vector store type is not OpenSearch for {kb_name}")
118+
return False, None
105119

106120
opensearch_config = vector_store.get("opensearchServerlessConfiguration") or vector_store.get("opensearchConfiguration")
121+
LOGGER.info(f"OpenSearch config for {kb_name}: {json.dumps(opensearch_config)}")
107122
if not opensearch_config:
108-
return f"{kb_name} (missing OpenSearch configuration)"
123+
return True, f"{kb_name} (missing OpenSearch configuration)"
109124

110125
if "collectionArn" in opensearch_config:
111126
collection_id = opensearch_config["collectionArn"].split("/")[-1]
112-
return check_opensearch_serverless(collection_id, kb_name)
127+
LOGGER.info(f"Found OpenSearch Serverless collection {collection_id} for {kb_name}")
128+
return True, check_opensearch_serverless(collection_id, kb_name)
113129

114130
domain_endpoint = opensearch_config.get("endpoint", "")
115131
if not domain_endpoint:
116-
return f"{kb_name} (missing OpenSearch domain endpoint)"
132+
return True, f"{kb_name} (missing OpenSearch domain endpoint)"
117133
domain_name = domain_endpoint.split(".")[0]
118-
return check_opensearch_domain(domain_name, kb_name)
134+
LOGGER.info(f"Found OpenSearch domain {domain_name} for {kb_name}")
135+
return True, check_opensearch_domain(domain_name, kb_name)
119136

120137
except ClientError as e:
121138
LOGGER.error(f"Error checking knowledge base {kb_id}: {str(e)}")
122139
if e.response["Error"]["Code"] == "AccessDeniedException":
123-
return f"{kb_name} (access denied)"
140+
return True, f"{kb_name} (access denied)"
124141
raise
125142

126143

127-
def evaluate_compliance(rule_parameters: dict) -> tuple[str, str]: # noqa: U100
144+
def evaluate_compliance(rule_parameters: dict) -> tuple[str, str]: # noqa: U100, CFQ004
128145
"""Evaluate if Bedrock Knowledge Base OpenSearch vector stores are encrypted with KMS CMK.
129146
130147
Args:
@@ -135,16 +152,20 @@ def evaluate_compliance(rule_parameters: dict) -> tuple[str, str]: # noqa: U100
135152
"""
136153
try:
137154
non_compliant_kbs = []
155+
has_opensearch = False
138156
paginator = bedrock_agent_client.get_paginator("list_knowledge_bases")
139157

140158
for page in paginator.paginate():
141159
for kb in page["knowledgeBaseSummaries"]:
142160
kb_id = kb["knowledgeBaseId"]
143161
kb_name = kb.get("name", kb_id)
144-
error = check_knowledge_base(kb_id, kb_name)
162+
is_opensearch, error = check_knowledge_base(kb_id, kb_name)
163+
has_opensearch = has_opensearch or is_opensearch
145164
if error:
146165
non_compliant_kbs.append(error)
147166

167+
if not has_opensearch:
168+
return "COMPLIANT", "No OpenSearch vector stores found in knowledge bases"
148169
if non_compliant_kbs:
149170
return "NON_COMPLIANT", (
150171
"The following knowledge bases have OpenSearch vector stores not encrypted with CMK: " + f"{'; '.join(non_compliant_kbs)}"
@@ -153,7 +174,7 @@ def evaluate_compliance(rule_parameters: dict) -> tuple[str, str]: # noqa: U100
153174

154175
except Exception as e:
155176
LOGGER.error(f"Error evaluating Bedrock Knowledge Base OpenSearch encryption: {str(e)}")
156-
return "ERROR", f"Error evaluating compliance: {str(e)}"
177+
return "INSUFFICIENT_DATA", f"Error evaluating compliance: {str(e)}"
157178

158179

159180
def lambda_handler(event: dict, context: Any) -> None: # noqa: U100

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,12 @@
224224
"opensearch:GetSecurityPolicy"
225225
],
226226
"Resource": "*"
227+
},
228+
{
229+
"Sid": "AllowOpenSearchServerlessAccess",
230+
"Effect": "Allow",
231+
"Action": ["aoss:GetSecurityPolicy"],
232+
"Resource": "*"
227233
}
228234
]
229235
}

0 commit comments

Comments
 (0)