def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) #template = cfn_inc.CfnInclude(self, id='Template', template_file='template.yaml') # The code that defines your stack goes here bucket_names = 'config-1' + str(core.Aws.ACCOUNT_ID) sns_topic = _sns.Topic(self, id='topic-config', topic_name='config-topic') sns_topic.add_subscription(subscriptions.EmailSubscription("*****@*****.**")) bucket = s3.Bucket(self, id='s3cdkbuckets',bucket_name=bucket_names,versioned=True) bucket_arn2 = str(bucket.bucket_arn) + "/AWSLogs/" + str(core.Aws.ACCOUNT_ID) + "/Config/*" bucket_policy = bucket.add_to_resource_policy(iam.PolicyStatement(effect=iam.Effect.ALLOW, resources=[bucket.bucket_arn], actions=["s3:GetBucketAcl"], sid = "AWSConfigBucketPermissionsCheck", principals=[iam.ServicePrincipal("config.amazonaws.com")] )) bucket_policy2 = bucket.add_to_resource_policy(iam.PolicyStatement(effect=iam.Effect.ALLOW, resources=[bucket_arn2], actions=["s3:PutObject"], sid = "AWSConfigBucketDelivery", principals=[iam.ServicePrincipal("config.amazonaws.com")], conditions={"StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control"} })) recorder = config.CfnConfigurationRecorder(self, id='recorder', role_arn='arn:aws:iam::306646308112:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig', recording_group=None) channel = config.CfnDeliveryChannel(self, id='channel', s3_bucket_name=bucket.bucket_name, sns_topic_arn=sns_topic.topic_arn) time.sleep(20) srule = config.CfnConfigRule(self, id='rule1', source=config.CfnConfigRule.SourceProperty(owner="AWS", source_identifier="REQUIRED_TAGS"), input_parameters={"tag1Key":"tagVal"}) srule2 = config.CfnConfigRule(self, id='rule2', source=config.CfnConfigRule.SourceProperty(owner="AWS", source_identifier="S3_BUCKET_LEVEL_PUBLIC_ACCESS_PROHIBITED")) srule3 = config.CfnConfigRule(self, id='rule3', source=config.CfnConfigRule.SourceProperty(owner="AWS", source_identifier="VPC_SG_OPEN_ONLY_TO_AUTHORIZED_PORTS")) srule.add_depends_on(recorder) srule2.add_depends_on(recorder) srule3.add_depends_on(recorder) event_rule = _events.Rule(self, id='event_rule', event_pattern = { "source": ["aws.config"], "detail": { "messageType": ["ConfigurationItemChangeNotification"], "newEvaluationResult": { "compliance_type": ["NON_COMPLIANT"] } } }) event_rule.add_target(targets.SnsTopic(sns_topic))
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) ## Config #- Create bucket #- Create IAM role #- Setup Recorder #- Setup Delivery Channel: https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_config/CfnDeliveryChannel.html cliSts = boto3.client('sts') caller = cliSts.get_caller_identity() roleConfig = _iam.CfnRole(self, "CustomAWSConfigService", role_name="CustomAWSConfigService", assume_role_policy_document={ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "config.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }, managed_policy_arns=[ "arn:aws:iam::aws:policy/service-role/AWSConfigRole", "arn:aws:iam::aws:policy/AmazonS3FullAccess" ]) bname = "aws-config-custom-{}".format(caller['Account']) bucketConfig = _s3.CfnBucket(self, bname, bucket_name=bname) bucketConfig.apply_removal_policy(apply_to_update_replace_policy=False) rec = _config.CfnConfigurationRecorder(self, "ConfigRec", name="ConfigRec", role_arn=roleConfig.attr_arn, recording_group=CfnConfigurationRecorder.RecordingGroupProperty( all_supported=True, include_global_resource_types=True )) rec.add_depends_on(roleConfig) cfgDC = _config.CfnDeliveryChannel(self, 'aws-config', s3_bucket_name=bname, config_snapshot_delivery_properties=CfnDeliveryChannel.ConfigSnapshotDeliveryPropertiesProperty( delivery_frequency="Twelve_Hours"), name='aws-config') cfgDC.add_depends_on(bucketConfig)
def __init__(self, app: core.App, id: str) -> None: super().__init__(app, id) # Setting up a role to represent config service principal aws_role = iam.Role( self, 'ConfigRole', assumed_by=iam.ServicePrincipal('config.amazonaws.com') ) # Adding a managed policy to the above role aws_role.add_managed_policy(iam.ManagedPolicy.from_aws_managed_policy_name("service-role/AWSConfigRole")) # Setting up ConfigurationRecorder for AWS Config aws_config_recorder = config.CfnConfigurationRecorder( self, 'ConfigRecorder', role_arn=aws_role.role_arn, recording_group={"allSupported": True} ) # Setting up the S3 bucket for Config to deliver the changes aws_config_bucket = s3.Bucket(self, 'ConfigBucket') # Adding policies to the S3 bucket aws_config_bucket.add_to_resource_policy(iam.PolicyStatement( effect=iam.Effect.ALLOW, principals=[aws_role], resources=[aws_config_bucket.bucket_arn], actions=["s3:GetBucketAcl", "s3:ListBucket"] )) cst_resource = 'AWSLogs/' + core.Stack.of(self).account + '/Config/*' aws_config_bucket.add_to_resource_policy(iam.PolicyStatement( effect=iam.Effect.ALLOW, principals=[aws_role], resources=[aws_config_bucket.arn_for_objects(cst_resource)], actions=["s3:PutObject"], conditions={"StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control"}} )) # Creating the deliverchannel for Config config.CfnDeliveryChannel( self, 'ConfigDeliveryChannel', s3_bucket_name=aws_config_bucket.bucket_name ) # Create CloulTrail trail trail.Trail(self, 'Trail') # Create Config managed rule aws_config_managed_rule = config.ManagedRule( self, "restricted-ssh", identifier=config.ManagedRuleIdentifiers.EC2_SECURITY_GROUPS_INCOMING_SSH_DISABLED ) # You cant create a rule if recorder is not enabled aws_config_managed_rule.node.add_dependency(aws_config_recorder) # Event pattern triggered by change in the AWS Config compliance rule dtl = """{ "requestParameters": { "evaluations": { "complianceType": [ "NON_COMPLIANT" ] } }, "additionalEventData": { "managedRuleIdentifier": [ "INCOMING_SSH_DISABLED" ] } }""" # detail needs to be a JSON object detail = json.loads(dtl) # Create an eventbridge rule to be triggered by AWS Config aws_event_rule = events.Rule( self, "Rule", description='rule that triggers a lambda function to revoke SSH public access directly after AWS Config NON COMFORM event', event_pattern=events.EventPattern( detail=detail, source=["aws.config"] ) ) # Create role for the lambda function aws_lambda_se_group_role = iam.Role( self, 'aws_lambda_security_group_role', assumed_by=iam.ServicePrincipal('lambda.amazonaws.com'), managed_policies=[ iam.ManagedPolicy.from_aws_managed_policy_name("service-role/AWSLambdaBasicExecutionRole") ]) # Add policy to Lambda role aws_lambda_se_group_role.add_to_policy(iam.PolicyStatement( effect=iam.Effect.ALLOW, resources=["*"], actions=["ec2:RevokeSecurityGroupIngress", "config:GetComplianceDetailsByConfigRule", "sts:GetCallerIdentity", "ec2:DescribeSecurityGroups"])) # Create lambda function and pass it the above role with open("lambda.py", encoding="utf8") as fp: handler_code = fp.read() aws_lambda_fn = lambda_.Function( self, "revoke-ssh-access", role=aws_lambda_se_group_role, code=lambda_.InlineCode(handler_code), handler="index.lambda_handler", timeout=core.Duration.seconds(300), runtime=lambda_.Runtime.PYTHON_3_7, ) # Add environment variable for lambda function aws_lambda_fn.add_environment("SSH_RULE_NAME", aws_config_managed_rule.config_rule_name) # Adding the lambda function as a target of the rule aws_event_rule.add_target(targets.LambdaFunction(aws_lambda_fn))
def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) high_cpu_topic = sns.Topic(self, 'high-cpu-topic', display_name='myHighCpuAlarm') # phone number format must be 12225558888 for US phone_param = ssm.StringParameter.from_string_parameter_name(self, 'phone-param', 'notification-phone') high_cpu_topic_sub = sns.Subscription(self, 'high-cpu-topic-sub', topic=high_cpu_topic, protocol=sns.SubscriptionProtocol.SMS, endpoint=phone_param.string_value) default_vpc = ec2.Vpc.from_lookup(self, 'default-vpc', is_default=True) monitored_instance = ec2.Instance(self, 'monitored-instance', instance_name='devassoc-monitored', instance_type=type.R3_XLARGE, machine_image=ec2.MachineImage.generic_linux( ami_map=ami_map ), vpc=default_vpc) high_cpu_metric = cw.Metric(namespace='AWS/EC2', metric_name='CPUUtilization', dimensions={ 'InstanceId': monitored_instance.instance_id }, statistic='Average', unit=cw.Unit.PERCENT, period=core.Duration.seconds(300)) high_cpu_alarm = high_cpu_metric.create_alarm(self, 'high-cpu-alarm', alarm_name='cpu-mon', alarm_description='Alarm when CPU exceeds 70%', comparison_operator=cw.ComparisonOperator.GREATER_THAN_THRESHOLD, evaluation_periods=2, period=core.Duration.seconds(300), threshold=70, actions_enabled=True) high_cpu_action = cwa.SnsAction(high_cpu_topic) high_cpu_alarm.add_alarm_action(high_cpu_action) ec2.CfnEIP(self, 'devassoc-elastic-ip') # not really a service role, but there are problems with that, per # https://github.com/aws/aws-cdk/issues/3492 config_service_role = iam.Role(self, 'devassoc-config-service-role', assumed_by=iam.ServicePrincipal('config.amazonaws.com'), managed_policies=[ iam.ManagedPolicy.from_aws_managed_policy_name('service-role/AWSConfigRole') ]) config_recorder = config.CfnConfigurationRecorder(self, 'devassoc-recorder', name='ConfigRecorder', role_arn=config_service_role.role_arn, recording_group=config.CfnConfigurationRecorder.RecordingGroupProperty( all_supported=True) ) config_bucket = s3.Bucket(self, 'config-bucket', bucket_name='devassoc-config', removal_policy=core.RemovalPolicy.DESTROY, auto_delete_objects=True) config_bucket.add_to_resource_policy(iam.PolicyStatement(effect=iam.Effect.ALLOW, principals=[iam.ServicePrincipal('config.amazonaws.com')], resources=[config_bucket.bucket_arn], actions=['s3:GetBucketAcl'])) config_bucket.add_to_resource_policy(iam.PolicyStatement(effect=iam.Effect.ALLOW, principals=[iam.ServicePrincipal('config.amazonaws.com')], resources=[config_bucket.arn_for_objects( f"AWSLogs/{core.Stack.of(self).account}/Config/*")], actions=['s3:PutObject'], conditions={'StringEquals': { 's3:x-amz-acl': 'bucket-owner-full-control'}})) eip_rule = config.ManagedRule(self, 'devassoc-managed-rule', identifier=config.ManagedRuleIdentifiers.EIP_ATTACHED, config_rule_name='devassoc-eip-rule') eip_rule.node.add_dependency(config_recorder) eip_compliance_topic = sns.Topic(self, 'eip-compliance-topic', display_name='EIP Compliance Topic') eip_compliance_topic_sub = sns.Subscription(self, 'eip-compliance-topic-sub', topic=eip_compliance_topic, protocol=sns.SubscriptionProtocol.SMS, endpoint=phone_param.string_value) eip_rule.on_compliance_change('eip-compliance-change', target=targets.SnsTopic(eip_compliance_topic)) config.CfnDeliveryChannel(self, 'devassoc-config-delivery', s3_bucket_name=config_bucket.bucket_name, sns_topic_arn=eip_compliance_topic.topic_arn)
def __init__(self, scope: core.Construct, id: str, **kwargs) -> None: super().__init__(scope, id, **kwargs) security_distribution_list_email = '*****@*****.**' # securityhub_instance = securityhub.CfnHub(self, 'SecurityHub') # Ensure AWS Config is enabled / Ensure CloudTrail is enabled in all Regions 2.1 - 2.8 cloudtrail_bucket_accesslogs = s3.Bucket( self, "CloudTrailS3Accesslogs", block_public_access=s3.BlockPublicAccess.BLOCK_ALL, encryption=s3.BucketEncryption.S3_MANAGED, removal_policy=core.RemovalPolicy.RETAIN) cloudtrail_bucket = s3.Bucket( self, "CloudTrailS3", block_public_access=s3.BlockPublicAccess.BLOCK_ALL, encryption=s3.BucketEncryption.S3_MANAGED, removal_policy=core.RemovalPolicy.RETAIN, server_access_logs_bucket=cloudtrail_bucket_accesslogs, ) cloudtrail_kms = kms.Key(self, "CloudTrailKey", enable_key_rotation=True) # CloudTrail - single account, not Organization trail = cloudtrail.Trail( self, "CloudTrail", enable_file_validation=True, is_multi_region_trail=True, include_global_service_events=True, send_to_cloud_watch_logs=True, cloud_watch_logs_retention=logs.RetentionDays.FOUR_MONTHS, bucket=cloudtrail_bucket, kms_key=cloudtrail_kms) cloudtrail_kms.grant(iam.ServicePrincipal('cloudtrail.amazonaws.com'), 'kms:DescribeKey') cloudtrail_kms.grant( iam.ServicePrincipal( 'cloudtrail.amazonaws.com', conditions={ 'StringLike': { 'kms:EncryptionContext:aws:cloudtrail:arn': 'arn:aws:cloudtrail:*:' + core.Stack.of(self).account + ':trail/*' } }), 'kms:GenerateDataKey*') cloudtrail_kms.add_to_resource_policy( iam.PolicyStatement( actions=["kms:Decrypt", "kms:ReEncryptFrom"], conditions={ 'StringEquals': { 'kms:CallerAccount': core.Stack.of(self).account }, 'StringLike': { 'kms:EncryptionContext:aws:cloudtrail:arn': 'arn:aws:cloudtrail:*:' + core.Stack.of(self).account + ':trail/*' } }, effect=iam.Effect.ALLOW, principals=[iam.AnyPrincipal()], resources=['*'])) cloudtrail_kms.add_to_resource_policy( iam.PolicyStatement(actions=["kms:CreateAlias"], conditions={ 'StringEquals': { 'kms:CallerAccount': core.Stack.of(self).account, 'kms:ViaService': 'ec2.' + core.Stack.of(self).region + '.amazonaws.com' } }, effect=iam.Effect.ALLOW, principals=[iam.AnyPrincipal()], resources=['*'])) cloudtrail_kms.add_to_resource_policy( iam.PolicyStatement( actions=["kms:Decrypt", "kms:ReEncryptFrom"], conditions={ 'StringEquals': { 'kms:CallerAccount': core.Stack.of(self).account }, 'StringLike': { 'kms:EncryptionContext:aws:cloudtrail:arn': 'arn:aws:cloudtrail:*:' + core.Stack.of(self).account + ':trail/*' } }, effect=iam.Effect.ALLOW, principals=[iam.AnyPrincipal()], resources=['*'])) config_role = iam.CfnServiceLinkedRole( self, id='ServiceLinkedRoleConfig', aws_service_name='config.amazonaws.com') global_config = config.CfnConfigurationRecorder(self, 'ConfigRecorder', name='default', # role_arn=config_role.role_arn, role_arn="arn:aws:iam::" + \ core.Stack.of( self).account+":role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig", # role_arn=config_role.get_att( # attribute_name='resource.arn').to_string(), recording_group=config.CfnConfigurationRecorder.RecordingGroupProperty( all_supported=True, include_global_resource_types=True ) ) config_bucket = s3.Bucket( self, "ConfigS3", block_public_access=s3.BlockPublicAccess.BLOCK_ALL, encryption=s3.BucketEncryption.S3_MANAGED, removal_policy=core.RemovalPolicy.RETAIN, ) config_bucket.add_to_resource_policy( iam.PolicyStatement( actions=['s3:GetBucketAcl'], effect=iam.Effect.ALLOW, principals=[iam.ServicePrincipal('config.amazonaws.com')], resources=[config_bucket.bucket_arn])) config_bucket.add_to_resource_policy( iam.PolicyStatement( actions=['s3:PutObject'], effect=iam.Effect.ALLOW, principals=[iam.ServicePrincipal('config.amazonaws.com')], resources=[ config_bucket.arn_for_objects('AWSLogs/' + core.Stack.of(self).account + '/Config/*') ], conditions={ "StringEquals": { 's3:x-amz-acl': 'bucket-owner-full-control', } })) config_delivery_stream = config.CfnDeliveryChannel( self, "ConfigDeliveryChannel", s3_bucket_name=config_bucket.bucket_name) # Config Aggregator in Organizations account # config_aggregator = config.CfnConfigurationAggregator(self, 'ConfigAggregator', # configuration_aggregator_name='ConfigAggregator', # organization_aggregation_source=config.CfnConfigurationAggregator.OrganizationAggregationSourceProperty( # role_arn=iam.Role(self, "AWSConfigRoleForOrganizations", # assumed_by=iam.ServicePrincipal( # 'config.amazonaws.com'), # managed_policies=[iam.ManagedPolicy.from_aws_managed_policy_name( # 'service-role/AWSConfigRoleForOrganizations')] # ).role_arn, # all_aws_regions=True # ) # ) # 2.9 – Ensure VPC flow logging is enabled in all VPCs # vpc = ec2.Vpc.from_lookup(self, "VPC", # is_default=True, # ) # S3 for VPC flow logs # vpc_flow_logs_bucket = s3.Bucket(self, "VPCFlowLogsBucket", # block_public_access=s3.BlockPublicAccess.BLOCK_ALL, # encryption=s3.BucketEncryption.S3_MANAGED, # removal_policy=core.RemovalPolicy.RETAIN # ) # Ensure a log metric filter and alarm exist for 3.1 – 3.14 security_notifications_topic = sns.Topic(self, 'CIS_Topic', display_name='CIS_Topic', topic_name='CIS_Topic') sns.Subscription(self, 'CIS_Subscription', topic=security_notifications_topic, protocol=sns.SubscriptionProtocol.EMAIL, endpoint=security_distribution_list_email) cloudwatch_actions_cis = cloudwatch_actions.SnsAction( security_notifications_topic) cis_metricfilter_alarms = { 'CIS-3.1-UnauthorizedAPICalls': '($.errorCode="*UnauthorizedOperation") || ($.errorCode="AccessDenied*")', 'CIS-3.2-ConsoleSigninWithoutMFA': '($.eventName="ConsoleLogin") && ($.additionalEventData.MFAUsed !="Yes")', 'RootAccountUsageAlarm': '$.userIdentity.type="Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType !="AwsServiceEvent"', 'CIS-3.4-IAMPolicyChanges': '($.eventName=DeleteGroupPolicy) || ($.eventName=DeleteRolePolicy) || ($.eventName=DeleteUserPolicy) || ($.eventName=PutGroupPolicy) || ($.eventName=PutRolePolicy) || ($.eventName=PutUserPolicy) || ($.eventName=CreatePolicy) || ($.eventName=DeletePolicy) || ($.eventName=CreatePolicyVersion) || ($.eventName=DeletePolicyVersion) || ($.eventName=AttachRolePolicy) || ($.eventName=DetachRolePolicy) || ($.eventName=AttachUserPolicy) || ($.eventName=DetachUserPolicy) || ($.eventName=AttachGroupPolicy) || ($.eventName=DetachGroupPolicy)', 'CIS-3.5-CloudTrailChanges': '($.eventName=CreateTrail) || ($.eventName=UpdateTrail) || ($.eventName=DeleteTrail) || ($.eventName=StartLogging) || ($.eventName=StopLogging)', 'CIS-3.6-ConsoleAuthenticationFailure': '($.eventName=ConsoleLogin) && ($.errorMessage="Failed authentication")', 'CIS-3.7-DisableOrDeleteCMK': '($.eventSource=kms.amazonaws.com) && (($.eventName=DisableKey) || ($.eventName=ScheduleKeyDeletion))', 'CIS-3.8-S3BucketPolicyChanges': '($.eventSource=s3.amazonaws.com) && (($.eventName=PutBucketAcl) || ($.eventName=PutBucketPolicy) || ($.eventName=PutBucketCors) || ($.eventName=PutBucketLifecycle) || ($.eventName=PutBucketReplication) || ($.eventName=DeleteBucketPolicy) || ($.eventName=DeleteBucketCors) || ($.eventName=DeleteBucketLifecycle) || ($.eventName=DeleteBucketReplication))', 'CIS-3.9-AWSConfigChanges': '($.eventSource=config.amazonaws.com) && (($.eventName=StopConfigurationRecorder) || ($.eventName=DeleteDeliveryChannel) || ($.eventName=PutDeliveryChannel) || ($.eventName=PutConfigurationRecorder))', 'CIS-3.10-SecurityGroupChanges': '($.eventName=AuthorizeSecurityGroupIngress) || ($.eventName=AuthorizeSecurityGroupEgress) || ($.eventName=RevokeSecurityGroupIngress) || ($.eventName=RevokeSecurityGroupEgress) || ($.eventName=CreateSecurityGroup) || ($.eventName=DeleteSecurityGroup)', 'CIS-3.11-NetworkACLChanges': '($.eventName=CreateNetworkAcl) || ($.eventName=CreateNetworkAclEntry) || ($.eventName=DeleteNetworkAcl) || ($.eventName=DeleteNetworkAclEntry) || ($.eventName=ReplaceNetworkAclEntry) || ($.eventName=ReplaceNetworkAclAssociation)', 'CIS-3.12-NetworkGatewayChanges': '($.eventName=CreateCustomerGateway) || ($.eventName=DeleteCustomerGateway) || ($.eventName=AttachInternetGateway) || ($.eventName=CreateInternetGateway) || ($.eventName=DeleteInternetGateway) || ($.eventName=DetachInternetGateway)', 'CIS-3.13-RouteTableChanges': '($.eventName=CreateRoute) || ($.eventName=CreateRouteTable) || ($.eventName=ReplaceRoute) || ($.eventName=ReplaceRouteTableAssociation) || ($.eventName=DeleteRouteTable) || ($.eventName=DeleteRoute) || ($.eventName=DisassociateRouteTable)', 'CIS-3.14-VPCChanges': '($.eventName=CreateVpc) || ($.eventName=DeleteVpc) || ($.eventName=ModifyVpcAttribute) || ($.eventName=AcceptVpcPeeringConnection) || ($.eventName=CreateVpcPeeringConnection) || ($.eventName=DeleteVpcPeeringConnection) || ($.eventName=RejectVpcPeeringConnection) || ($.eventName=AttachClassicLinkVpc) || ($.eventName=DetachClassicLinkVpc) || ($.eventName=DisableVpcClassicLink) || ($.eventName=EnableVpcClassicLink)', } for x, y in cis_metricfilter_alarms.items(): str_x = str(x) str_y = str(y) logs.MetricFilter( self, "MetricFilter_" + str_x, log_group=trail.log_group, filter_pattern=logs.JsonPattern(json_pattern_string=str_y), metric_name=str_x, metric_namespace="LogMetrics", metric_value='1') cloudwatch.Alarm( self, "Alarm_" + str_x, alarm_name=str_x, alarm_description=str_x, statistic='Sum', period=core.Duration.minutes(5), comparison_operator=cloudwatch.ComparisonOperator. GREATER_THAN_OR_EQUAL_TO_THRESHOLD, evaluation_periods=1, threshold=1, metric=cloudwatch.Metric(metric_name=str_x, namespace="LogMetrics"), ).add_alarm_action(cloudwatch_actions_cis) # IAM Password Policy custom resource CIS 1.5 - 1.11 cfn_template = cfn_inc.CfnInclude( self, "includeTemplate", template_file="account-password-policy.yaml", parameters={ "MaxPasswordAge": 90, "MinimumPasswordLength": 14, "PasswordReusePrevention": 24, "RequireLowercaseCharacters": True, "RequireNumbers": True, "RequireSymbols": True, "RequireUppercaseCharacters": True, }) # CIS 1.20 support_role = iam.Role( self, "SupportRole", assumed_by=iam.AccountPrincipal( account_id=core.Stack.of(self).account), managed_policies=[ iam.ManagedPolicy.from_aws_managed_policy_name( 'AWSSupportAccess') ], role_name='AWSSupportAccess') guardduty_detector = guardduty.CfnDetector(self, 'GuardDutyDetector', enable=True) guardduty_event = events.Rule( self, 'GuardDutyEvent', rule_name='guardduty-notification', description='GuardDuty Notification', event_pattern=events.EventPattern( source=['aws.guardduty'], detail_type=['GuardDuty Finding']), targets=[events_targets.SnsTopic(security_notifications_topic)])