1- """This script performs operations to enable , configure, and disable Bedrock security controls .
1+ """This script performs operations to create , configure, and delete Bedrock guardrails .
22
33Version: 1.0
44
2828import sra_repo
2929import sra_s3
3030import sra_sns
31+ import sra_sqs
3132import sra_ssm_params
3233import sra_sts
3334
@@ -53,7 +54,6 @@ def load_kms_key_policies() -> dict:
5354SOLUTION_NAME : str = "sra-bedrock-guardrails"
5455GOVERNED_REGIONS = []
5556ORGANIZATION_ID = ""
56- # SRA_ALARM_EMAIL: str = ""
5757SRA_ALARM_TOPIC_ARN : str = ""
5858STATE_TABLE : str = "sra_state" # for saving resource info
5959CFN_CUSTOM_RESOURCE : str = "Custom::LambdaCustomResource"
@@ -173,6 +173,7 @@ def load_kms_key_policies() -> dict:
173173cloudwatch = sra_cloudwatch .SRACloudWatch ()
174174kms = sra_kms .SRAKMS ()
175175bedrock = sra_bedrock .SRABedrock ()
176+ sqs = sra_sqs .SRASQS ()
176177
177178# propagate solution name to class objects
178179cloudwatch .SOLUTION_NAME = SOLUTION_NAME
@@ -191,7 +192,6 @@ def get_resource_parameters(event: dict) -> None:
191192 global DRY_RUN
192193 global GOVERNED_REGIONS
193194 global CFN_RESPONSE_DATA
194- # global SRA_ALARM_EMAIL
195195 global ORGANIZATION_ID
196196
197197 param_validation : dict = validate_parameters (event ["ResourceProperties" ], PARAMETER_VALIDATION_RULES )
@@ -238,9 +238,6 @@ def get_resource_parameters(event: dict) -> None:
238238 LOGGER .info ("Error retrieving SRA staging bucket ssm parameter. Is the SRA common prerequisites solution deployed?" )
239239 raise ValueError ("Error retrieving SRA staging bucket ssm parameter. Is the SRA common prerequisites solution deployed?" ) from None
240240
241- # if event["ResourceProperties"]["SRA_ALARM_EMAIL"] != "":
242- # SRA_ALARM_EMAIL = event["ResourceProperties"]["SRA_ALARM_EMAIL"]
243-
244241 if event ["ResourceProperties" ]["DRY_RUN" ] == "true" :
245242 # dry run
246243 LOGGER .info ("Dry run enabled..." )
@@ -586,6 +583,33 @@ def create_kms_key(acct: str, region: str) -> None:
586583 )
587584
588585
586+ def check_sqs_queue () -> str :
587+ """Add sqs queue record if DLQ exists.
588+
589+ Returns:
590+ str: sns topic arn
591+ """
592+ global DRY_RUN_DATA
593+ global LIVE_RUN_DATA
594+ global CFN_RESPONSE_DATA
595+
596+ sns .SNS_CLIENT = sts .assume_role (sts .MANAGEMENT_ACCOUNT , sts .CONFIGURATION_ROLE , "sns" , sts .HOME_REGION )
597+ queue_search = sqs .find_sqs_queue (f"{ SOLUTION_NAME } -DLQ" )
598+ if queue_search is None :
599+ LOGGER .info (f"{ SOLUTION_NAME } -DLQ doesn't exist" )
600+
601+ else :
602+ LOGGER .info (f"{ SOLUTION_NAME } -DLQ sqs queue exists." )
603+ queue_arn = queue_search
604+ if DRY_RUN is False :
605+ # SQS State table record:
606+ add_state_table_record ("sqs" , "implemented" , "sqs queue" , "queue" , queue_arn , ACCOUNT , sts .HOME_REGION , f"{ SOLUTION_NAME } -DLQ" )
607+ else :
608+ DRY_RUN_DATA ["SQSCreate" ] = f"DRY_RUN: { SOLUTION_NAME } -DLQ sqs queue exists"
609+
610+ return queue_arn
611+
612+
589613def create_guardrail (acct : str , region : str , params : dict ) -> None :
590614 """Deploy the Bedrock guardrail.
591615
@@ -631,7 +655,6 @@ def set_guardrail_config(params: dict, guardrail_key_id: str) -> Dict:
631655 "description" : "sra bedrock guardrail" ,
632656 "blockedInputMessaging" : params ["BLOCKED_INPUT_MESSAGING" ],
633657 "blockedOutputsMessaging" : params ["BLOCKED_OUTPUTS_MESSAGING" ],
634- # "clientRequestToken": 'sra-client-request-token-12',
635658 "kmsKeyId" : guardrail_key_id ,
636659 "tags" : [
637660 {"key" : "sra-solution" , "value" : params ["SOLUTION_NAME" ]},
@@ -668,6 +691,75 @@ def set_guardrail_config(params: dict, guardrail_key_id: str) -> Dict:
668691 return guardrail_params
669692
670693
694+ def delete_bedrock_guardrails_key (acct : str , region : str ) -> None :
695+ """Delete KMS key.
696+
697+ Args:
698+ acct (str): AWS account ID
699+ region (str): AWS region name
700+ """
701+ # Delete KMS key (schedule deletion) and delete kms alias
702+ kms .KMS_CLIENT = sts .assume_role (acct , sts .CONFIGURATION_ROLE , "kms" , region )
703+ search_bedrock_guardrails_kms_key , bedrock_guardrails_key_alias , bedrock_guardrails_key_id , bedrock_guardrails_key_arn = kms .check_alias_exists (
704+ kms .KMS_CLIENT , f"alias/{ GUARDRAILS_KEY_ALIAS } "
705+ )
706+ if search_bedrock_guardrails_kms_key is True :
707+ if DRY_RUN is False :
708+ LOGGER .info (f"Deleting { GUARDRAILS_KEY_ALIAS } KMS key" )
709+ kms .delete_alias (kms .KMS_CLIENT , f"alias/{ GUARDRAILS_KEY_ALIAS } " )
710+ LIVE_RUN_DATA [f"KMSDeleteAlias-{ acct } -{ region } " ] = f"Deleted { GUARDRAILS_KEY_ALIAS } KMS key alias"
711+ CFN_RESPONSE_DATA ["deployment_info" ]["action_count" ] += 1
712+ CFN_RESPONSE_DATA ["deployment_info" ]["resources_deployed" ] -= 1
713+ LOGGER .info (f"Deleting { GUARDRAILS_KEY_ALIAS } KMS key ({ bedrock_guardrails_key_id } )" )
714+ remove_state_table_record (bedrock_guardrails_key_arn )
715+
716+ kms .schedule_key_deletion (kms .KMS_CLIENT , bedrock_guardrails_key_id )
717+ LIVE_RUN_DATA [f"KMSDelete-{ acct } -{ region } " ] = f"Deleted { GUARDRAILS_KEY_ALIAS } KMS key ({ bedrock_guardrails_key_id } )"
718+ CFN_RESPONSE_DATA ["deployment_info" ]["action_count" ] += 1
719+ CFN_RESPONSE_DATA ["deployment_info" ]["resources_deployed" ] -= 1
720+ LOGGER .info (f"Scheduled deletion of { GUARDRAILS_KEY_ALIAS } KMS key ({ bedrock_guardrails_key_id } )" )
721+ kms_key_arn = f"arn:{ sts .PARTITION } :kms:{ region } :{ acct } :key/{ bedrock_guardrails_key_id } "
722+ remove_state_table_record (kms_key_arn )
723+
724+ else :
725+ LOGGER .info (f"DRY_RUN: Deleting { GUARDRAILS_KEY_ALIAS } KMS key" )
726+ DRY_RUN_DATA [f"KMSAliasDelete-{ acct } -{ region } " ] = f"DRY_RUN: Delete { GUARDRAILS_KEY_ALIAS } KMS key"
727+ LOGGER .info (f"DRY_RUN: Deleting { GUARDRAILS_KEY_ALIAS } KMS key ({ bedrock_guardrails_key_id } )" )
728+ DRY_RUN_DATA [f"KMSDelete-{ acct } -{ region } " ] = f"DRY_RUN: Delete { GUARDRAILS_KEY_ALIAS } KMS key ({ bedrock_guardrails_key_id } )"
729+ else :
730+ LOGGER .info (f"{ GUARDRAILS_KEY_ALIAS } KMS key does not exist." )
731+
732+
733+ def delete_guardrails (account : str , region : str , guardrail_name : str ) -> None :
734+ """Delete the Bedrock guardrails.
735+
736+ Args:
737+ account: AWS account id
738+ region: AWS region
739+ guardrail_name: Name of the Bedrock guardrail to delete.
740+ """
741+ global DRY_RUN_DATA
742+ global LIVE_RUN_DATA
743+ global CFN_RESPONSE_DATA
744+
745+ if DRY_RUN is False :
746+ bedrock .BEDROCK_CLIENT = sts .assume_role (account , sts .CONFIGURATION_ROLE , "bedrock" , region )
747+ LOGGER .info (f"Deleting Bedrock guardrail in { account } in { region } ..." )
748+ guardrail_id = bedrock .get_guardrail_id (guardrail_name )
749+ if guardrail_id != "" :
750+ bedrock .delete_guardrail (guardrail_id )
751+ LIVE_RUN_DATA [f"Bedrock-guardrail-{ account } _{ region } " ] = f"Deleted Bedrock Guardrail ({ guardrail_name } ) in { account } in { region } "
752+ CFN_RESPONSE_DATA ["deployment_info" ]["action_count" ] += 1
753+ CFN_RESPONSE_DATA ["deployment_info" ]["resources_deployed" ] -= 1
754+ guardrail_arn = f"arn:aws:bedrock:{ region } :{ account } :guardrail/{ guardrail_id } "
755+ remove_state_table_record (guardrail_arn )
756+ else :
757+ LOGGER .info (f"Guardrail { guardrail_name } does not exist in { account } in { region } " )
758+ else :
759+ LOGGER .info (f"DRY_RUN: Delete Bedrock guardrail { guardrail_name } in { account } in { region } " )
760+ DRY_RUN_DATA [f"Bedrock-guardrail-{ account } _{ region } " ] = f"DRY_RUN: Delete Bedrock guardrail { guardrail_name } "
761+
762+
671763def create_event (event : dict , context : Any ) -> str :
672764 """Create event.
673765
@@ -731,7 +823,7 @@ def create_event(event: dict, context: Any) -> str:
731823 LOGGER .info (f"Guardrail { event ['ResourceProperties' ]['BEDROCK_GUARDRAIL_NAME' ]} does not exist in { acct } in { region } " )
732824 create_kms_key (acct , region )
733825 create_guardrail (acct , region , event ["ResourceProperties" ])
734-
826+ check_sqs_queue ()
735827 # End
736828 if DRY_RUN is False :
737829 LOGGER .info (json .dumps ({"RUN STATS" : CFN_RESPONSE_DATA , "RUN DATA" : LIVE_RUN_DATA }))
@@ -771,75 +863,6 @@ def update_event(event: dict, context: Any) -> str:
771863 return CFN_RESOURCE_ID
772864
773865
774- def delete_bedrock_guardrails_key (acct : str , region : str ) -> None :
775- """Delete KMS key.
776-
777- Args:
778- acct (str): AWS account ID
779- region (str): AWS region name
780- """
781- # Delete KMS key (schedule deletion) and delete kms alias
782- kms .KMS_CLIENT = sts .assume_role (acct , sts .CONFIGURATION_ROLE , "kms" , region )
783- search_bedrock_guardrails_kms_key , bedrock_guardrails_key_alias , bedrock_guardrails_key_id , bedrock_guardrails_key_arn = kms .check_alias_exists (
784- kms .KMS_CLIENT , f"alias/{ GUARDRAILS_KEY_ALIAS } "
785- )
786- if search_bedrock_guardrails_kms_key is True :
787- if DRY_RUN is False :
788- LOGGER .info (f"Deleting { GUARDRAILS_KEY_ALIAS } KMS key" )
789- kms .delete_alias (kms .KMS_CLIENT , f"alias/{ GUARDRAILS_KEY_ALIAS } " )
790- LIVE_RUN_DATA [f"KMSDeleteAlias-{ acct } -{ region } " ] = f"Deleted { GUARDRAILS_KEY_ALIAS } KMS key alias"
791- CFN_RESPONSE_DATA ["deployment_info" ]["action_count" ] += 1
792- CFN_RESPONSE_DATA ["deployment_info" ]["resources_deployed" ] -= 1
793- LOGGER .info (f"Deleting { GUARDRAILS_KEY_ALIAS } KMS key ({ bedrock_guardrails_key_id } )" )
794- remove_state_table_record (bedrock_guardrails_key_arn )
795-
796- kms .schedule_key_deletion (kms .KMS_CLIENT , bedrock_guardrails_key_id )
797- LIVE_RUN_DATA [f"KMSDelete-{ acct } -{ region } " ] = f"Deleted { GUARDRAILS_KEY_ALIAS } KMS key ({ bedrock_guardrails_key_id } )"
798- CFN_RESPONSE_DATA ["deployment_info" ]["action_count" ] += 1
799- CFN_RESPONSE_DATA ["deployment_info" ]["resources_deployed" ] -= 1
800- LOGGER .info (f"Scheduled deletion of { GUARDRAILS_KEY_ALIAS } KMS key ({ bedrock_guardrails_key_id } )" )
801- kms_key_arn = f"arn:{ sts .PARTITION } :kms:{ region } :{ acct } :key/{ bedrock_guardrails_key_id } "
802- remove_state_table_record (kms_key_arn )
803-
804- else :
805- LOGGER .info (f"DRY_RUN: Deleting { GUARDRAILS_KEY_ALIAS } KMS key" )
806- DRY_RUN_DATA [f"KMSAliasDelete-{ acct } -{ region } " ] = f"DRY_RUN: Delete { GUARDRAILS_KEY_ALIAS } KMS key"
807- LOGGER .info (f"DRY_RUN: Deleting { GUARDRAILS_KEY_ALIAS } KMS key ({ bedrock_guardrails_key_id } )" )
808- DRY_RUN_DATA [f"KMSDelete-{ acct } -{ region } " ] = f"DRY_RUN: Delete { GUARDRAILS_KEY_ALIAS } KMS key ({ bedrock_guardrails_key_id } )"
809- else :
810- LOGGER .info (f"{ GUARDRAILS_KEY_ALIAS } KMS key does not exist." )
811-
812-
813- def delete_guardrails (account : str , region : str , guardrail_name : str ) -> None :
814- """Delete the Bedrock guardrails.
815-
816- Args:
817- account: AWS account id
818- region: AWS region
819- guardrail_name: Name of the Bedrock guardrail to delete.
820- """
821- global DRY_RUN_DATA
822- global LIVE_RUN_DATA
823- global CFN_RESPONSE_DATA
824-
825- if DRY_RUN is False :
826- bedrock .BEDROCK_CLIENT = sts .assume_role (account , sts .CONFIGURATION_ROLE , "bedrock" , region )
827- LOGGER .info (f"Deleting Bedrock guardrail in { account } in { region } ..." )
828- guardrail_id = bedrock .get_guardrail_id (guardrail_name )
829- if guardrail_id != "" :
830- bedrock .delete_guardrail (guardrail_id )
831- LIVE_RUN_DATA [f"Bedrock-guardrail-{ account } _{ region } " ] = f"Deleted Bedrock Guardrail ({ guardrail_name } ) in { account } in { region } "
832- CFN_RESPONSE_DATA ["deployment_info" ]["action_count" ] += 1
833- CFN_RESPONSE_DATA ["deployment_info" ]["resources_deployed" ] -= 1
834- guardrail_arn = f"arn:aws:bedrock:{ region } :{ account } :guardrail/{ guardrail_id } "
835- remove_state_table_record (guardrail_arn )
836- else :
837- LOGGER .info (f"Guardrail { guardrail_name } does not exist in { account } in { region } " )
838- else :
839- LOGGER .info (f"DRY_RUN: Delete Bedrock guardrail { guardrail_name } in { account } in { region } " )
840- DRY_RUN_DATA [f"Bedrock-guardrail-{ account } _{ region } " ] = f"DRY_RUN: Delete Bedrock guardrail { guardrail_name } "
841-
842-
843866def delete_event (event : dict , context : Any ) -> None : # noqa: CFQ001, CCR001, C901
844867 """Delete event function.
845868
@@ -854,15 +877,18 @@ def delete_event(event: dict, context: Any) -> None: # noqa: CFQ001, CCR001, C9
854877 LIVE_RUN_DATA = {}
855878 LOGGER .info ("Delete event function" )
856879
857- # 4) Delete Bedrock guardrails
880+ # Delete Bedrock guardrails
858881 accounts , regions = get_accounts_and_regions (
859882 event ["ResourceProperties" ]["SRA_BEDROCK_ACCOUNTS" ], event ["ResourceProperties" ]["SRA_BEDROCK_REGIONS" ]
860883 )
861884 for acct in accounts :
862885 for region in regions :
863886 delete_guardrails (acct , region , event ["ResourceProperties" ]["BEDROCK_GUARDRAIL_NAME" ])
864887 delete_bedrock_guardrails_key (acct , region )
865-
888+ # Remove sqs queue record
889+ queue_arn = check_sqs_queue ()
890+ if queue_arn is not None :
891+ remove_state_table_record (queue_arn )
866892 # Must infer the execution role arn because the function is being reported as non-existent at this point
867893 execution_role_arn = f"arn:aws:iam::{ sts .MANAGEMENT_ACCOUNT } :role/{ SOLUTION_NAME } -lambda"
868894 LOGGER .info (f"Removing state table record for lambda IAM execution role: { execution_role_arn } " )
0 commit comments