@@ -53,16 +53,19 @@ def load_kms_key_policies() -> dict:
5353 with open ("sra_kms_keys.json" , "r" ) as file :
5454 return json .load (file )
5555
56+
5657def load_cloudwatch_oam_sink_policy () -> dict :
5758 with open ("sra_cloudwatch_oam_sink_policy.json" , "r" ) as file :
5859 return json .load (file )
5960 # ["sra-oam-sink-policy"]["Statement"][0]["Condition"]["ForAnyValue:StringEquals"]["aws:PrincipalOrgID"]
6061
62+
6163def load_sra_cloudwatch_oam_trust_policy () -> dict :
6264 with open ("sra_cloudwatch_oam_trust_policy.json" , "r" ) as file :
6365 return json .load (file )
6466 # ["Statement"][0]["Principal"]["AWS"]
6567
68+
6669# Global vars
6770RESOURCE_TYPE : str = ""
6871STATE_TABLE : str = "sra_state"
@@ -139,7 +142,9 @@ def get_resource_parameters(event):
139142 repo .SOLUTIONS_DIR = f"/tmp/aws-security-reference-architecture-examples-{ repo .REPO_BRANCH } /aws_sra_examples/solutions"
140143
141144 sts .CONFIGURATION_ROLE = "sra-execution"
142- governed_regions_param = ssm_params .get_ssm_parameter (ssm_params .MANAGEMENT_ACCOUNT_SESSION , REGION , "/sra/regions/customer-control-tower-regions" )
145+ governed_regions_param = ssm_params .get_ssm_parameter (
146+ ssm_params .MANAGEMENT_ACCOUNT_SESSION , REGION , "/sra/regions/customer-control-tower-regions"
147+ )
143148 if governed_regions_param [0 ] is True :
144149 GOVERNED_REGIONS = governed_regions_param [1 ]
145150 LOGGER .info (f"Successfully retrieved the SRA governed regions parameter: { GOVERNED_REGIONS } " )
@@ -304,6 +309,7 @@ def get_filter_params(filter_name, event):
304309 return False , [], [], {}
305310 return filter_deploy , filter_accounts , filter_regions , filter_params
306311
312+
307313def build_s3_metric_filter_pattern (bucket_names : list , filter_pattern_template : str ) -> str :
308314 # Get the S3 filter
309315 s3_filter = filter_pattern_template
@@ -459,13 +465,11 @@ def create_event(event, context):
459465 LOGGER .info ("Customizing key policy..." )
460466 kms_key_policy = json .loads (json .dumps (KMS_KEY_POLICIES [ALARM_SNS_KEY_ALIAS ]))
461467 LOGGER .info (f"kms_key_policy: { kms_key_policy } " )
462- kms_key_policy ["Statement" ][0 ]["Principal" ]["AWS" ] = KMS_KEY_POLICIES [ALARM_SNS_KEY_ALIAS ]["Statement" ][0 ][
463- "Principal "
464- ][ "AWS" ] .replace ("ACCOUNT_ID" , acct )
468+ kms_key_policy ["Statement" ][0 ]["Principal" ]["AWS" ] = KMS_KEY_POLICIES [ALARM_SNS_KEY_ALIAS ]["Statement" ][0 ]["Principal" ][
469+ "AWS "
470+ ].replace ("ACCOUNT_ID" , acct )
465471 LOGGER .info (f"Customizing key policy...done: { kms_key_policy } " )
466- alarm_key_id = kms .create_kms_key (
467- kms .KMS_CLIENT , json .dumps (kms_key_policy ), "Key for CloudWatch Alarm SNS Topic Encryption"
468- )
472+ alarm_key_id = kms .create_kms_key (kms .KMS_CLIENT , json .dumps (kms_key_policy ), "Key for CloudWatch Alarm SNS Topic Encryption" )
469473 LOGGER .info (f"Created SRA alarm KMS key: { alarm_key_id } " )
470474 LIVE_RUN_DATA ["KMSKeyCreate" ] = "Created SRA alarm KMS key"
471475 CFN_RESPONSE_DATA ["deployment_info" ]["action_count" ] += 1
@@ -497,9 +501,7 @@ def create_event(event, context):
497501 CFN_RESPONSE_DATA ["deployment_info" ]["action_count" ] += 1
498502 CFN_RESPONSE_DATA ["deployment_info" ]["resources_deployed" ] += 1
499503
500- LOGGER .info (
501- f"Setting access for CloudWatch alarms in { acct } to publish to { SOLUTION_NAME } -alarms SNS topic"
502- )
504+ LOGGER .info (f"Setting access for CloudWatch alarms in { acct } to publish to { SOLUTION_NAME } -alarms SNS topic" )
503505 # TODO(liamschn): search for policy on SNS topic before adding the policy
504506 sns .set_topic_access_for_alarms (SRA_ALARM_TOPIC_ARN , acct )
505507 LIVE_RUN_DATA ["SNSAlarmPolicy" ] = "Added policy for CloudWatch alarms to publish to SNS topic"
@@ -571,33 +573,33 @@ def create_event(event, context):
571573
572574 # 5) Central CloudWatch Observability
573575 # TODO(liamschn): determine if we need the CloudWatch-CrossAccountListAccountsRole (needed for "Enable account selector"?).
574- # TRUST
575- # {
576- # "Version": "2012-10-17",
577- # "Statement": [
578- # {
579- # "Effect": "Allow",
580- # "Principal": {
581- # "AWS": "arn:aws:iam::533267199951:root"
582- # },
583- # "Action": "sts:AssumeRole"
584- # }
585- # ]
586- # }
587- # PERMISSIONS
588- # {
589- # "Version": "2012-10-17",
590- # "Statement": [
591- # {
592- # "Action": [
593- # "organizations:ListAccounts",
594- # "organizations:ListAccountsForParent"
595- # ],
596- # "Resource": "*",
597- # "Effect": "Allow"
598- # }
599- # ]
600- # }
576+ # TRUST
577+ # {
578+ # "Version": "2012-10-17",
579+ # "Statement": [
580+ # {
581+ # "Effect": "Allow",
582+ # "Principal": {
583+ # "AWS": "arn:aws:iam::533267199951:root"
584+ # },
585+ # "Action": "sts:AssumeRole"
586+ # }
587+ # ]
588+ # }
589+ # PERMISSIONS
590+ # {
591+ # "Version": "2012-10-17",
592+ # "Statement": [
593+ # {
594+ # "Action": [
595+ # "organizations:ListAccounts",
596+ # "organizations:ListAccountsForParent"
597+ # ],
598+ # "Resource": "*",
599+ # "Effect": "Allow"
600+ # }
601+ # ]
602+ # }
601603 central_observability_params = json .loads (event ["ResourceProperties" ]["SRA-BEDROCK-CENTRAL-OBSERVABILITY" ])
602604 # TODO(liamschn): create a parameter to choose to deploy central observability or not: deploy_central_observability = true/false
603605 # 5a) OAM Sink in security account
@@ -660,11 +662,14 @@ def create_event(event, context):
660662 for bedrock_region in central_observability_params ["regions" ]:
661663 iam .IAM_CLIENT = sts .assume_role (bedrock_account , sts .CONFIGURATION_ROLE , "iam" , iam .get_iam_global_region ())
662664 cloudwatch .CROSS_ACCOUNT_TRUST_POLICY = CLOUDWATCH_OAM_TRUST_POLICY [cloudwatch .CROSS_ACCOUNT_ROLE_NAME ]
663- cloudwatch .CROSS_ACCOUNT_TRUST_POLICY ["Statement" ][0 ]["Principal" ]["AWS" ] = \
664- cloudwatch .CROSS_ACCOUNT_TRUST_POLICY ["Statement" ][0 ]["Principal" ]["AWS" ].replace ("<SECURITY_ACCOUNT>" , SECURITY_ACCOUNT )
665+ cloudwatch .CROSS_ACCOUNT_TRUST_POLICY ["Statement" ][0 ]["Principal" ]["AWS" ] = cloudwatch .CROSS_ACCOUNT_TRUST_POLICY ["Statement" ][0 ][
666+ "Principal"
667+ ]["AWS" ].replace ("<SECURITY_ACCOUNT>" , SECURITY_ACCOUNT )
665668 search_iam_role = iam .check_iam_role_exists (cloudwatch .CROSS_ACCOUNT_ROLE_NAME )
666669 if search_iam_role [0 ] is False :
667- LOGGER .info (f"CloudWatch observability access manager cross-account role not found, creating { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role..." )
670+ LOGGER .info (
671+ f"CloudWatch observability access manager cross-account role not found, creating { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role..."
672+ )
668673 if DRY_RUN is False :
669674 iam .create_role (cloudwatch .CROSS_ACCOUNT_ROLE_NAME , cloudwatch .CROSS_ACCOUNT_TRUST_POLICY , SOLUTION_NAME )
670675 LIVE_RUN_DATA ["OAMCrossAccountRoleCreate" ] = f"Created { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role"
@@ -680,20 +685,24 @@ def create_event(event, context):
680685 cross_account_policies = [
681686 "arn:aws:iam::aws:policy/AWSXrayReadOnlyAccess" ,
682687 "arn:aws:iam::aws:policy/CloudWatchAutomaticDashboardsAccess" ,
683- "arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess"
688+ "arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess" ,
684689 ]
685690 for policy_arn in cross_account_policies :
686691 search_attached_policies = iam .check_iam_policy_attached (cloudwatch .CROSS_ACCOUNT_ROLE_NAME , policy_arn )
687692 if search_attached_policies is False :
688693 LOGGER .info (f"Attaching { policy_arn } policy to { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role..." )
689694 if DRY_RUN is False :
690695 iam .attach_policy (cloudwatch .CROSS_ACCOUNT_ROLE_NAME , policy_arn )
691- LIVE_RUN_DATA ["OAMCrossAccountRolePolicyAttach" ] = f"Attached { policy_arn } policy to { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role"
696+ LIVE_RUN_DATA [
697+ "OAMCrossAccountRolePolicyAttach"
698+ ] = f"Attached { policy_arn } policy to { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role"
692699 CFN_RESPONSE_DATA ["deployment_info" ]["action_count" ] += 1
693700 CFN_RESPONSE_DATA ["deployment_info" ]["configuration_changes" ] += 1
694701 LOGGER .info (f"Attached { policy_arn } policy to { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role" )
695702 else :
696- DRY_RUN_DATA ["OAMCrossAccountRolePolicyAttach" ] = f"DRY_RUN: Attach { policy_arn } policy to { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role"
703+ DRY_RUN_DATA [
704+ "OAMCrossAccountRolePolicyAttach"
705+ ] = f"DRY_RUN: Attach { policy_arn } policy to { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role"
697706
698707 # 5d) OAM link in bedrock account
699708 cloudwatch .CWOAM_CLIENT = sts .assume_role (bedrock_account , sts .CONFIGURATION_ROLE , "oam" , bedrock_region )
@@ -769,7 +778,6 @@ def delete_event(event, context):
769778 else :
770779 LOGGER .info (f"{ SOLUTION_NAME } -configuration SNS topic does not exist." )
771780
772-
773781 # 2) Delete Central CloudWatch Observability
774782 central_observability_params = json .loads (event ["ResourceProperties" ]["SRA-BEDROCK-CENTRAL-OBSERVABILITY" ])
775783
@@ -811,14 +819,18 @@ def delete_event(event, context):
811819 for policy in cross_account_policies :
812820 LOGGER .info (f"Detaching { policy ['PolicyArn' ]} policy from { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role..." )
813821 iam .detach_policy (cloudwatch .CROSS_ACCOUNT_ROLE_NAME , policy ["PolicyArn" ])
814- LIVE_RUN_DATA ["OAMCrossAccountRolePolicyDetach" ] = f"Detached { policy ['PolicyArn' ]} policy from { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role"
822+ LIVE_RUN_DATA [
823+ "OAMCrossAccountRolePolicyDetach"
824+ ] = f"Detached { policy ['PolicyArn' ]} policy from { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role"
815825 CFN_RESPONSE_DATA ["deployment_info" ]["action_count" ] += 1
816826 CFN_RESPONSE_DATA ["deployment_info" ]["configuration_changes" ] += 1
817827 LOGGER .info (f"Detached { policy ['PolicyArn' ]} policy from { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role" )
818828 else :
819829 for policy in cross_account_policies :
820830 LOGGER .info (f"DRY_RUN: Detaching { policy ['PolicyArn' ]} policy from { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role..." )
821- DRY_RUN_DATA ["OAMCrossAccountRolePolicyDetach" ] = f"DRY_RUN: Detach { policy ['PolicyArn' ]} policy from { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role"
831+ DRY_RUN_DATA [
832+ "OAMCrossAccountRolePolicyDetach"
833+ ] = f"DRY_RUN: Detach { policy ['PolicyArn' ]} policy from { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role"
822834 else :
823835 LOGGER .info (f"No policies attached to { cloudwatch .CROSS_ACCOUNT_ROLE_NAME } IAM role" )
824836
@@ -859,7 +871,6 @@ def delete_event(event, context):
859871 filter_deploy , filter_accounts , filter_regions , filter_params = get_filter_params (filter , event )
860872 for acct in filter_accounts :
861873 for region in filter_regions :
862-
863874 # 3a) Delete KMS key (schedule deletion)
864875 kms .KMS_CLIENT = sts .assume_role (acct , sts .CONFIGURATION_ROLE , "kms" , region )
865876 search_alarm_kms_key , alarm_key_alias , alarm_key_id = kms .check_alias_exists (kms .KMS_CLIENT , f"alias/{ ALARM_SNS_KEY_ALIAS } " )
0 commit comments