Beispiel #1
0
 def subscribe_emails_to_topic(self, sns_topic: Topic,
                               email_address: str) -> None:
     aws_sns.Subscription(self,
                          "eternal-guess-error-subscription",
                          topic=sns_topic,
                          protocol=aws_sns.SubscriptionProtocol.EMAIL,
                          endpoint=email_address)
Beispiel #2
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        db_table_name = "findAflatDB"

        # create dynamoDB table
        table = aws_dynamodb.Table(self,
                                   "findAflat_db",
                                   table_name=db_table_name,
                                   partition_key=aws_dynamodb.Attribute(
                                       name="dataID",
                                       type=aws_dynamodb.AttributeType.STRING))

        # create lambda function
        function = aws_lambda.Function(
            self,
            "findAflat_fnc",
            runtime=aws_lambda.Runtime.PYTHON_3_7,
            code=aws_lambda.Code.asset("findAFlat"),
            handler="lambda_function.lambda_handler",
            timeout=core.Duration.minutes(1))

        function.add_environment("LAMBDA", "True")
        function.add_environment("DB_TABLE", db_table_name)
        table.grant_read_write_data(function)

        # create and configure sns topic
        sns_topic = aws_sns.Topic(self,
                                  "findAflat_sns_tpc",
                                  display_name="flatsWeeklyUpdate",
                                  topic_name="flatsWeeklyUpdate")

        sns_topic.grant_publish(function)

        sns_subscr = aws_sns.Subscription(
            self,
            "findAflat_sns_sbscr",
            topic=sns_topic,
            protocol=aws_sns.SubscriptionProtocol.EMAIL,
            endpoint="*****@*****.**")

        function.add_environment("SNS_TOPIC", sns_topic.topic_arn)

        # add EventBridge
        event = aws_events.Rule(self,
                                "findAflat_event",
                                enabled=True,
                                rule_name="daily_at_17",
                                schedule=aws_events.Schedule.cron(hour="17",
                                                                  minute="00"))

        event.add_target(aws_events_targets.LambdaFunction(handler=function))
 def __init__(
     self, scope: core.Construct, id: str, map_params: dict, **kwargs
 ):  # pylint: disable=W0622
     super().__init__(scope, id, **kwargs)
     LOGGER.debug('Notification configuration required for %s', map_params['name'])
     stack = core.Stack.of(self)
     # pylint: disable=no-value-for-parameter
     _slack_func = _lambda.Function.from_function_arn(
         self,
         'slack_lambda_function',
         f'arn:{stack.partition}:lambda:{ADF_DEPLOYMENT_REGION}:'
         f'{ADF_DEPLOYMENT_ACCOUNT_ID}:function:SendSlackNotification'
     )
     kms_alias = _kms.Alias.from_alias_name(self, "KMSAlias", f"alias/codepipeline-{ADF_DEPLOYMENT_ACCOUNT_ID}")
     _topic = _sns.Topic(self, "PipelineTopic", master_key=kms_alias)
     _statement = _iam.PolicyStatement(
         actions=["sns:Publish"],
         effect=_iam.Effect.ALLOW,
         principals=[
             _iam.ServicePrincipal("sns.amazonaws.com"),
             _iam.ServicePrincipal("codecommit.amazonaws.com"),
             _iam.ServicePrincipal("events.amazonaws.com"),
         ],
         resources=["*"],
     )
     _topic.add_to_resource_policy(_statement)
     _endpoint = map_params.get("params", {}).get("notification_endpoint", "")
     _sub = _sns.Subscription(
         self,
         "sns_subscription",
         topic=_topic,
         endpoint=_endpoint if "@" in _endpoint else _slack_func.function_arn,
         protocol=_sns.SubscriptionProtocol.EMAIL
         if "@" in _endpoint
         else _sns.SubscriptionProtocol.LAMBDA,
     )
     if "@" not in _endpoint:
         _lambda.CfnPermission(
             self,
             "slack_notification_sns_permissions",
             principal="sns.amazonaws.com",
             action="lambda:InvokeFunction",
             source_arn=_topic.topic_arn,
             function_name="SendSlackNotification",
         )
         _slack_func.add_event_source(source=_event_sources.SnsEventSource(_topic))
     self.topic_arn = _topic.topic_arn
 def __init__(self, scope: core.Construct, id: str, map_params: dict,
              **kwargs):  #pylint: disable=W0622
     super().__init__(scope, id, **kwargs)
     LOGGER.debug('Notification configuration required for %s',
                  map_params['name'])
     # pylint: disable=no-value-for-parameter
     _slack_func = _lambda.Function.from_function_arn(
         self, 'slack_lambda_function',
         'arn:aws:lambda:{0}:{1}:function:SendSlackNotification'.format(
             ADF_DEPLOYMENT_REGION, ADF_DEPLOYMENT_ACCOUNT_ID))
     _topic = _sns.Topic(self, 'PipelineTopic')
     _statement = _iam.PolicyStatement(
         actions=["sns:Publish"],
         effect=_iam.Effect.ALLOW,
         principals=[
             _iam.ServicePrincipal('sns.amazonaws.com'),
             _iam.ServicePrincipal('codecommit.amazonaws.com'),
             _iam.ServicePrincipal('events.amazonaws.com')
         ],
         resources=["*"])
     _topic.add_to_resource_policy(_statement)
     _lambda.CfnPermission(self,
                           'slack_notification_sns_permissions',
                           principal='sns.amazonaws.com',
                           action='lambda:InvokeFunction',
                           source_arn=_topic.topic_arn,
                           function_name='SendSlackNotification')
     _endpoint = map_params.get('params', {}).get('notification_endpoint',
                                                  '')
     _sub = _sns.Subscription(
         self,
         'sns_subscription',
         topic=_topic,
         endpoint=_endpoint
         if '@' in _endpoint else _slack_func.function_arn,
         protocol=_sns.SubscriptionProtocol.EMAIL
         if '@' in _endpoint else _sns.SubscriptionProtocol.LAMBDA)
     if '@' not in _endpoint:
         _slack_func.add_event_source(
             source=_event_sources.SnsEventSource(_topic))
     self.topic_arn = _topic.topic_arn
Beispiel #5
0
    def __init__(self, scope: core.Construct, construct_id: str,
                 **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        test_queue = sqs.Queue(self, 'test-queue', queue_name='test1')

        test_topic = sns.Topic(self, 'test-topic')

        sns.Subscription(self,
                         'test-subscription',
                         topic=test_topic,
                         endpoint=test_queue.queue_arn,
                         protocol=sns.SubscriptionProtocol.SQS)

        kinesis.Stream(self,
                       'test-stream',
                       stream_name='donut-sales',
                       shard_count=2)

        create_order = step.Pass(self,
                                 'create-order',
                                 result=step.Result.from_object({
                                     "Order": {
                                         "Customer": "Alice",
                                         "Product": "Coffee",
                                         "Billing": {
                                             "Price": 10.0,
                                             "Quantity": 4.0
                                         }
                                     }
                                 }))
        calculate_amount = step.Pass(self,
                                     'calculate-amount',
                                     result=step.Result.from_number(40.0),
                                     result_path='$.Order.Billing.Amount',
                                     output_path='$.Order.Billing')
        order_definition = create_order.next(calculate_amount)
        step.StateMachine(self,
                          'test-state-machine',
                          state_machine_name='order-machine',
                          definition=order_definition)

        make_tea = step.Choice(
            self, 'make-tea', comment='Input should look like {"tea":"green"}')
        green = step.Pass(self,
                          'green',
                          result=step.Result.from_string('Green tea'))
        make_tea.when(step.Condition.string_equals('$.tea', 'green'), green)
        black = step.Pass(self,
                          'black',
                          result=step.Result.from_string('Black tea'))
        make_tea.when(step.Condition.string_equals('$.tea', 'black'), black)
        orange = step.Pass(self,
                           'orange',
                           result=step.Result.from_string('Black tea'))
        make_tea.when(step.Condition.string_equals('$.tea', 'orange'), orange)
        error = step.Pass(self,
                          'error',
                          result=step.Result.from_string('Bad input'))
        make_tea.otherwise(error)
        step.StateMachine(self,
                          'test-state-machine-2',
                          state_machine_name='tea-machine',
                          definition=make_tea)
    def __init__(self, scope: core.Construct, construct_id: str,
                 **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        bucket_name = 'devassoc-monitored'
        bucket = s3.Bucket(self,
                           'bucket-monitored',
                           bucket_name=bucket_name,
                           removal_policy=core.RemovalPolicy.DESTROY,
                           auto_delete_objects=True)

        core.CfnOutput(self, 'monitored-bucket', value=bucket.bucket_name)

        size_metric = cw.Metric(namespace='AWS/S3',
                                metric_name='BucketSizeBytes',
                                dimensions={
                                    'BucketName': bucket.bucket_name,
                                    'StorageType': 'StandardStorage'
                                },
                                period=core.Duration.days(1))
        size_alarm = size_metric.create_alarm(
            self,
            'bucket-alarm',
            alarm_name='S3 Storage Alarm',
            comparison_operator=cw.ComparisonOperator.
            GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
            evaluation_periods=1,
            period=core.Duration.days(1),
            threshold=1000,
            actions_enabled=True)
        size_topic = sns.Topic(self,
                               'size-topic',
                               display_name='My S3 Alarm List')
        email_param = ssm.StringParameter.from_string_parameter_name(
            self, 'email-param', 'notification-email')
        size_topic_sub = sns.Subscription(
            self,
            'size-topic-sub',
            topic=size_topic,
            protocol=sns.SubscriptionProtocol.EMAIL,
            endpoint=email_param.string_value)
        size_action = cwa.SnsAction(size_topic)
        size_alarm.add_alarm_action(size_action)

        bucket_name = 'devassoc-s3-logs'
        log_bucket = s3.Bucket(self,
                               'bucket-s3-logs',
                               bucket_name=bucket_name,
                               removal_policy=core.RemovalPolicy.DESTROY,
                               auto_delete_objects=True)
        s3_trail = ct.Trail(self,
                            'bucket-trail',
                            bucket=log_bucket,
                            trail_name='s3_logs')
        s3_trail.add_s3_event_selector([ct.S3EventSelector(bucket=bucket)])
        s3_trail.log_all_s3_data_events()

        single_value_widget = cw.SingleValueWidget(metrics=[size_metric])
        graph_widget = cw.GraphWidget(left=[size_metric])
        cw.Dashboard(self,
                     'cloudwatch-dashboard',
                     dashboard_name='S3Dashboard',
                     widgets=[[single_value_widget, graph_widget]])
    def __init__(self, scope: Cdk.Construct, id: str, **kwargs) -> None:
        super().__init__(
            scope,
            id,
            description=
            "2.2.1 CloudFormation Custom Resource Lambda for invoking cross-region Custom Resources",
            **kwargs)

        allowedRoleArnsParameter = Cdk.CfnParameter(
            self,
            "AllowedRoleArns",
            description=
            "Role ARNs to allow to publish to the SNS topic of the Custom Resource Proxy to enable cross-account use",
            type="CommaDelimitedList")
        organizationIdParameter = Cdk.CfnParameter(
            self,
            "OrganizationId",
            description=
            "Organization ID to use to allow access to the SNS topic of the Custom Resource Proxy",
            type="String")

        path = os.path.join(os.path.dirname(__file__), "src/app.py")
        with open(path) as f:
            code = Lambda.Code.from_inline(f.read())

        function = Lambda.Function(
            self,
            "Function",
            code=code,
            function_name="LittleOrangeCustomResourceProxy",
            handler="index.handler",
            runtime=Lambda.Runtime.PYTHON_3_7,
            timeout=Cdk.Duration.seconds(30))

        topic = Sns.Topic(self,
                          "Topic",
                          topic_name="LittleOrangeCustomResourceProxy")

        topic.add_to_resource_policy(statement=Iam.PolicyStatement(
            sid="OrganizationsCloudFormationAccess",
            actions=["sns:Publish"],
            conditions={
                "StringLike": {
                    "aws:PrincipalArn": allowedRoleArnsParameter.value_as_list
                },
                "StringEquals": {
                    "aws:CalledViaLast": "cloudformation.amazonaws.com",
                    "aws:PrincipalOrgID":
                    organizationIdParameter.value_as_string
                }
            },
            effect=Iam.Effect.ALLOW,
            principals=[Iam.AnyPrincipal()],
            resources=[topic.topic_arn]))

        subscription = Sns.Subscription(
            self,
            "TopicSubscription",
            topic=topic,
            endpoint=function.function_arn,
            protocol=Sns.SubscriptionProtocol.LAMBDA)

        function.add_permission(
            "CloudFormationPermission",
            principal=Iam.ServicePrincipal("cloudformation.amazonaws.com"),
            action="lambda:InvokeFunction")

        function.add_permission(
            "SNSPermission",
            principal=Iam.ServicePrincipal("sns.amazonaws.com"),
            action="lambda:InvokeFunction",
            source_arn=topic.topic_arn)

        function.add_to_role_policy(
            Iam.PolicyStatement(actions=["lambda:InvokeFunction"],
                                effect=Iam.Effect.ALLOW,
                                resources=["*"]))

        parameter = Ssm.StringParameter(
            self,
            "ServiceTokenParameter",
            parameter_name=
            "/LittleOrange/CloudFormation/CustomResourceProxyServiceToken",
            description=
            "Lambda ARN for the Custom Resource Proxy CloudFormation Custom Resource in this region",
            type=Ssm.ParameterType.STRING,
            string_value=function.function_arn)

        parameterSns = Ssm.StringParameter(
            self,
            "SNSServiceTokenParameter",
            parameter_name=
            "/LittleOrange/CloudFormation/CustomResourceProxySNSServiceToken",
            description=
            "SNS Topic ARN for the Custom Resource Proxy CloudFormation Custom Resource in this region",
            type=Ssm.ParameterType.STRING,
            string_value=topic.topic_arn)

        output = Cdk.CfnOutput(self,
                               "ServiceToken",
                               value=function.function_arn)

        snsOutput = Cdk.CfnOutput(self,
                                  "SNSServiceToken",
                                  value=topic.topic_arn)
Beispiel #8
0
    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)
Beispiel #9
0
    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)])
    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # Parameters
        notification_email_address = CfnParameter(
            self,
            "notification_email_address",
            type="String",
            min_length=7,
            description=
            "The E-mail address subscribed to notifications when an S3 bucket is detected as open to the public."
        )
        profiling = CfnParameter(
            self,
            "profiling",
            type="String",
            allowed_values=["TRUE", "FALSE"],
            default="FALSE",
            description=
            "Enable Profiling on Lambda functions: TRUE or FALSE. Default: FALSE"
        )
        tracing = CfnParameter(
            self,
            "tracing",
            type="String",
            allowed_values=["TRUE", "FALSE"],
            default="FALSE",
            description=
            "Enable tracing on Lambda functions: TRUE or FALSE. Default: FALSE"
        )
        trusted_advisor_refresh_minutes = CfnParameter(
            self,
            "trusted_advisor_refresh_minutes",
            type="Number",
            default=6,
            min_value=5,
            max_value=1440,
            description=
            "Number of minutes to schedule a trusted advisor refresh. Default: 6"
        )
        enable_profiling = profiling.value_as_string == 'TRUE'
        enable_tracing = aws_lambda.Tracing.ACTIVE
        if tracing.value_as_string != 'TRUE':
            enable_tracing = aws_lambda.Tracing.DISABLED

        # Layers
        dependencies_layer = aws_lambda.LayerVersion(
            self,
            "dependenciesLayer",
            code=aws_lambda.Code.from_asset(
                "lambda_functions/dependencies_layer/"),
            compatible_runtimes=[aws_lambda.Runtime.PYTHON_3_8],
        )
        # create SNS target
        email_notification_topic = sns.Topic(
            self,
            'taEmailNotificationTopic',
            display_name='taEmailNotificationTopic',
            topic_name='taEmailNotificationTopic')
        # add subscription
        sns.Subscription(self,
                         'emailSubscription',
                         protocol=sns.SubscriptionProtocol.EMAIL,
                         endpoint=notification_email_address.value_as_string,
                         topic=email_notification_topic)

        default_event_bus = events.EventBus.from_event_bus_name(
            self, 'default', 'default')
        ta_event_pattern = events.EventPattern(
            source=['aws.trustedadvisor'],
            detail_type=['Trusted Advisor Check Item Refresh Notification'],
            detail={
                'check-name': ['Amazon S3 Bucket Permissions'],
                'status': ['WARN', 'ERROR']
            })
        # Lambda function to trigger when TA check flagged
        ta_check_s3_open_lambda_function_code = aws_lambda.AssetCode(
            'lambda_functions/s3openbucket')
        ta_check_s3_open_lambda_function = aws_lambda.Function(
            self,
            'ta_s3_open_bucket',
            code=ta_check_s3_open_lambda_function_code,
            runtime=aws_lambda.Runtime.PYTHON_3_8,
            handler='s3openbucket.lambda_handler',
            description='Function Triggered from Trusted Advisor '
            'to Block public access to an S3 Bucket',
            function_name='ta-check-s3-open-lambda-function',
            memory_size=128,
            profiling=enable_profiling,
            tracing=enable_tracing,
            log_retention=aws_logs.RetentionDays.ONE_WEEK,
            timeout=Duration.seconds(10),
            environment={'topic_arn': email_notification_topic.topic_arn},
            initial_policy=[
                aws_iam.PolicyStatement(actions=[
                    's3:GetBucketPolicy', 's3:DeleteBucketPolicy',
                    's3:PutBucketPolicy', 's3:GetAccountPublicAccessBlock',
                    's3:GetBucketPublicAccessBlock',
                    's3:PutAccountPublicAccessBlock',
                    's3:PutBucketPublicAccessBlock', 's3:GetBucketAcl',
                    's3:GetObjectAcl', 's3:PutBucketAcl', 's3:PutObjectAcl'
                ],
                                        effect=aws_iam.Effect.ALLOW,
                                        resources=['*']),
                aws_iam.PolicyStatement(
                    actions=['SNS:Publish'],
                    effect=aws_iam.Effect.ALLOW,
                    resources=[email_notification_topic.topic_arn])
            ])
        events.Rule(
            self,
            's3PublicBucketRule',
            description=
            'Blocks Public access on an S3 bucket once detected by Trusted Advisor',
            event_pattern=ta_event_pattern,
            event_bus=default_event_bus,
            targets=[targets.LambdaFunction(ta_check_s3_open_lambda_function)])
        # Refresh TA check every X minutes
        # Lambda function to trigger when TA check flagged
        ta_refresh_lambda_function_code = aws_lambda.AssetCode(
            'lambda_functions/refreshTrustedAdvisorCheck')
        ta_refresh_lambda_function = aws_lambda.Function(
            self,
            'refresh_ta_check',
            code=ta_refresh_lambda_function_code,
            runtime=aws_lambda.Runtime.PYTHON_3_8,
            handler='refreshTrustedAdvisorCheck.lambda_handler',
            description='Refreshes Trusted Advisor checks',
            function_name='ta-refresh-ta-check-lambda-function',
            memory_size=128,
            profiling=enable_profiling,
            tracing=enable_tracing,
            log_retention=aws_logs.RetentionDays.ONE_WEEK,
            timeout=Duration.seconds(5),
            initial_policy=[
                aws_iam.PolicyStatement(actions=[
                    'support:DescribeTrustedAdvisorChecks',
                    'support:RefreshTrustedAdvisorCheck',
                    'support:DescribeTrustedAdvisorCheckResult'
                ],
                                        effect=aws_iam.Effect.ALLOW,
                                        resources=['*'])
            ])
        ta_refresh_lambda_function.add_layers(dependencies_layer)
        events.Rule(
            self,
            'refreshTAS3BucketPermissionsRule',
            schedule=events.Schedule.rate(
                Duration.minutes(
                    trusted_advisor_refresh_minutes.value_as_number)),
            rule_name='refreshTAS3BucketPermissionsRule',
            targets=[targets.LambdaFunction(ta_refresh_lambda_function)])
Beispiel #11
0
    def __init__(self,
                 scope: cdk.Stack,
                 id: str,
                 sla_stream_monitor_dynamo_table,
                 git_hash,
                 notifier_zip='change-notifier.zip',
                 **kwargs):
        super().__init__(scope, id, **kwargs)
        self.sla_stream_monitor_dynamo_table = sla_stream_monitor_dynamo_table
        self.notifier_zip = git_hash + "-" + notifier_zip

        self.sns_topic = aws_sns.Topic(self,
                                       "SNSTopic",
                                       display_name="SLA Notification Topic",
                                       topic_name=self.stack_name)

        self.subscribe_to_topic = aws_sns.Subscription(
            self,
            "TopicSubscribe",
            endpoint=os.getenv("EMAIL_NOTIFICATION"),
            protocol=aws_sns.SubscriptionProtocol.Email,
            topic=self.sns_topic)

        self.sla_notifier_lambda_function = aws_lambda.Function(
            self,
            "SLANotifierLambdaFunction",
            function_name=self.stack_name,
            code=aws_lambda.AssetCode(self.notifier_zip),
            handler="sns.lambda_handler",
            runtime=aws_lambda.Runtime.PYTHON37,
            #layers=[self.dynamodb_lambda_layer],
            description="Notifies SNS Topic if SLAs change",
            environment={
                "STACK_NAME":
                self.stack_name,
                "SNS_TOPIC_ARN":
                self.sns_topic.topic_arn,
                "DYNAMO_TABLE_NAME":
                self.sla_stream_monitor_dynamo_table.table_name
            },
            memory_size=128,
            timeout=90,
        )

        # TODO: Make into reusable function
        self.notifier_cw_event_rule = aws_events.Rule(
            self,
            "LambdaCWEventRuleSLANotifier",
            description="Scheduled event to trigger AWS SLA monitor",
            enabled=True,
            #schedule_expression='cron(10 22 */3 * ? *)',
            schedule_expression='cron(*/6 * * * ? *)',
            targets=[
                aws_events_targets.LambdaFunction(
                    handler=self.sla_notifier_lambda_function)
            ],
        )

        # Permissions to access stream_monitor dynamo table
        self.sla_stream_monitor_dynamo_table.grant_read_write_data(
            self.sla_notifier_lambda_function.role)

        # Grant publish access from Lambda function to SNS topic
        self.sns_topic.grant_publish(self.sla_notifier_lambda_function)