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 .
2
2
3
3
Version: 1.0
4
4
28
28
import sra_repo
29
29
import sra_s3
30
30
import sra_sns
31
+ import sra_sqs
31
32
import sra_ssm_params
32
33
import sra_sts
33
34
@@ -53,7 +54,6 @@ def load_kms_key_policies() -> dict:
53
54
SOLUTION_NAME : str = "sra-bedrock-guardrails"
54
55
GOVERNED_REGIONS = []
55
56
ORGANIZATION_ID = ""
56
- # SRA_ALARM_EMAIL: str = ""
57
57
SRA_ALARM_TOPIC_ARN : str = ""
58
58
STATE_TABLE : str = "sra_state" # for saving resource info
59
59
CFN_CUSTOM_RESOURCE : str = "Custom::LambdaCustomResource"
@@ -173,6 +173,7 @@ def load_kms_key_policies() -> dict:
173
173
cloudwatch = sra_cloudwatch .SRACloudWatch ()
174
174
kms = sra_kms .SRAKMS ()
175
175
bedrock = sra_bedrock .SRABedrock ()
176
+ sqs = sra_sqs .SRASQS ()
176
177
177
178
# propagate solution name to class objects
178
179
cloudwatch .SOLUTION_NAME = SOLUTION_NAME
@@ -191,7 +192,6 @@ def get_resource_parameters(event: dict) -> None:
191
192
global DRY_RUN
192
193
global GOVERNED_REGIONS
193
194
global CFN_RESPONSE_DATA
194
- # global SRA_ALARM_EMAIL
195
195
global ORGANIZATION_ID
196
196
197
197
param_validation : dict = validate_parameters (event ["ResourceProperties" ], PARAMETER_VALIDATION_RULES )
@@ -238,9 +238,6 @@ def get_resource_parameters(event: dict) -> None:
238
238
LOGGER .info ("Error retrieving SRA staging bucket ssm parameter. Is the SRA common prerequisites solution deployed?" )
239
239
raise ValueError ("Error retrieving SRA staging bucket ssm parameter. Is the SRA common prerequisites solution deployed?" ) from None
240
240
241
- # if event["ResourceProperties"]["SRA_ALARM_EMAIL"] != "":
242
- # SRA_ALARM_EMAIL = event["ResourceProperties"]["SRA_ALARM_EMAIL"]
243
-
244
241
if event ["ResourceProperties" ]["DRY_RUN" ] == "true" :
245
242
# dry run
246
243
LOGGER .info ("Dry run enabled..." )
@@ -586,6 +583,33 @@ def create_kms_key(acct: str, region: str) -> None:
586
583
)
587
584
588
585
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
+
589
613
def create_guardrail (acct : str , region : str , params : dict ) -> None :
590
614
"""Deploy the Bedrock guardrail.
591
615
@@ -631,7 +655,6 @@ def set_guardrail_config(params: dict, guardrail_key_id: str) -> Dict:
631
655
"description" : "sra bedrock guardrail" ,
632
656
"blockedInputMessaging" : params ["BLOCKED_INPUT_MESSAGING" ],
633
657
"blockedOutputsMessaging" : params ["BLOCKED_OUTPUTS_MESSAGING" ],
634
- # "clientRequestToken": 'sra-client-request-token-12',
635
658
"kmsKeyId" : guardrail_key_id ,
636
659
"tags" : [
637
660
{"key" : "sra-solution" , "value" : params ["SOLUTION_NAME" ]},
@@ -668,6 +691,75 @@ def set_guardrail_config(params: dict, guardrail_key_id: str) -> Dict:
668
691
return guardrail_params
669
692
670
693
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
+
671
763
def create_event (event : dict , context : Any ) -> str :
672
764
"""Create event.
673
765
@@ -731,7 +823,7 @@ def create_event(event: dict, context: Any) -> str:
731
823
LOGGER .info (f"Guardrail { event ['ResourceProperties' ]['BEDROCK_GUARDRAIL_NAME' ]} does not exist in { acct } in { region } " )
732
824
create_kms_key (acct , region )
733
825
create_guardrail (acct , region , event ["ResourceProperties" ])
734
-
826
+ check_sqs_queue ()
735
827
# End
736
828
if DRY_RUN is False :
737
829
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:
771
863
return CFN_RESOURCE_ID
772
864
773
865
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
-
843
866
def delete_event (event : dict , context : Any ) -> None : # noqa: CFQ001, CCR001, C901
844
867
"""Delete event function.
845
868
@@ -854,15 +877,18 @@ def delete_event(event: dict, context: Any) -> None: # noqa: CFQ001, CCR001, C9
854
877
LIVE_RUN_DATA = {}
855
878
LOGGER .info ("Delete event function" )
856
879
857
- # 4) Delete Bedrock guardrails
880
+ # Delete Bedrock guardrails
858
881
accounts , regions = get_accounts_and_regions (
859
882
event ["ResourceProperties" ]["SRA_BEDROCK_ACCOUNTS" ], event ["ResourceProperties" ]["SRA_BEDROCK_REGIONS" ]
860
883
)
861
884
for acct in accounts :
862
885
for region in regions :
863
886
delete_guardrails (acct , region , event ["ResourceProperties" ]["BEDROCK_GUARDRAIL_NAME" ])
864
887
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 )
866
892
# Must infer the execution role arn because the function is being reported as non-existent at this point
867
893
execution_role_arn = f"arn:aws:iam::{ sts .MANAGEMENT_ACCOUNT } :role/{ SOLUTION_NAME } -lambda"
868
894
LOGGER .info (f"Removing state table record for lambda IAM execution role: { execution_role_arn } " )
0 commit comments