Ejemplo n.º 1
0
    def provision_buckets(self, name: str, s3: List[S3]):
        self.buckets = {}
        for bucket, attrs in s3.buckets.items():
            use_sse_kms_key = False
            if attrs.sse_kms_key_id:
                use_sse_kms_key = True
                sse_kms_key = Key.from_key_arn(self, f"{bucket}-kms-key",
                                               attrs.sse_kms_key_id)

            self.buckets[bucket] = Bucket(
                self.scope,
                bucket,
                bucket_name=f"{name}-{bucket}",
                auto_delete_objects=attrs.auto_delete_objects
                and attrs.removal_policy_destroy,
                removal_policy=cdk.RemovalPolicy.DESTROY
                if attrs.removal_policy_destroy else cdk.RemovalPolicy.RETAIN,
                enforce_ssl=True,
                bucket_key_enabled=use_sse_kms_key,
                encryption_key=(sse_kms_key if use_sse_kms_key else None),
                encryption=(BucketEncryption.KMS if use_sse_kms_key else
                            BucketEncryption.S3_MANAGED),
            )
            self.buckets[bucket].add_to_resource_policy(
                iam.PolicyStatement(
                    sid="DenyIncorrectEncryptionHeader",
                    effect=iam.Effect.DENY,
                    principals=[iam.ArnPrincipal("*")],
                    actions=[
                        "s3:PutObject",
                    ],
                    resources=[f"{self.buckets[bucket].bucket_arn}/*"],
                    conditions={
                        "StringNotEquals": {
                            "s3:x-amz-server-side-encryption":
                            "aws:kms" if use_sse_kms_key else "AES256"
                        }
                    },
                ))
            self.buckets[bucket].add_to_resource_policy(
                iam.PolicyStatement(
                    sid="DenyUnEncryptedObjectUploads",
                    effect=iam.Effect.DENY,
                    principals=[iam.ArnPrincipal("*")],
                    actions=[
                        "s3:PutObject",
                    ],
                    resources=[f"{self.buckets[bucket].bucket_arn}/*"],
                    conditions={
                        "Null": {
                            "s3:x-amz-server-side-encryption": "true"
                        }
                    },
                ))
            self.s3_api_statement.add_resources(
                f"{self.buckets[bucket].bucket_arn}*")
            cdk.CfnOutput(self.scope,
                          f"{bucket}-output",
                          value=self.buckets[bucket].bucket_name)
Ejemplo n.º 2
0
    def vpc_network(self, bucket_arn):
        vpc = ec2.Vpc(self,
                      "demoVPC",
                      max_azs=2,
                      cidr="10.0.0.0/16",
                      nat_gateways=1,
                      subnet_configuration=[{
                          "cidrMask":
                          24,
                          "name":
                          'private',
                          "subnetType":
                          ec2.SubnetType.PRIVATE
                      }, {
                          "cidrMask": 24,
                          "name": 'public',
                          "subnetType": ec2.SubnetType.PUBLIC
                      }])
        subnets = vpc.select_subnets(
            subnet_type=ec2.SubnetType.PRIVATE).subnets
        endpoint = vpc.add_gateway_endpoint(
            's3Endpoint',
            service=ec2.GatewayVpcEndpointAwsService.S3,
            subnets=[{
                "subnet_id": subnets[0].subnet_id
            }, {
                "subnet_id": subnets[1].subnet_id
            }])

        endpoint.add_to_policy(
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                resources=[bucket_arn, f"{bucket_arn}/*"],
                principals=[iam.ArnPrincipal("*")],
                actions=[
                    "s3:GetObject", "s3:GetObjects", "s3:ListObjects",
                    "S3:ListBucket"
                ],
            ))

        # Provides access to the Amazon S3 bucket containing the layers for each Docker image.
        endpoint.add_to_policy(
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                resources=[
                    f"arn:aws:s3:::prod-{self.region}-starport-layer-bucket/*"
                ],
                principals=[iam.ArnPrincipal("*")],
                actions=["s3:GetObject"],
            ))

        return vpc, subnets
Ejemplo n.º 3
0
    def _configure_mutual_assume_role(self, role: iam.Role):
        self._roles.instance_role.add_to_policy(
            iam.PolicyStatement(effect=iam.Effect.ALLOW,
                                principals=[iam.ArnPrincipal(role.role_arn)],
                                actions=['sts:AssumeRole']))

        role.add_to_policy(
            iam.PolicyStatement(effect=iam.Effect.ALLOW,
                                principals=[
                                    iam.ArnPrincipal(
                                        self._roles.instance_role.role_arn)
                                ],
                                actions=['sts:AssumeRole']))
    def __init__(self, scope: core.Construct, name: str, vpc: ec2.IVpc, **kwargs) -> None:
        super().__init__(scope, name, **kwargs)

        cluster = eks.Cluster(
            self, 'jenkins-workshop-eks-control-plane',
            vpc=vpc,
            default_capacity=0
        )

        asg_worker_nodes = cluster.add_capacity(
            'worker-node',
            instance_type=ec2.InstanceType('t3.medium'),
            desired_capacity=2,
        )

        asg_jenkins_slave = cluster.add_capacity(
            'worker-node-jenkins-slave',
            instance_type=ec2.InstanceType('t3.medium'),
            desired_capacity=1,
            bootstrap_options=eks.BootstrapOptions(
                kubelet_extra_args='--node-labels jenkins=slave --register-with-taints jenkins=slave:NoSchedule',
                docker_config_json=read_docker_daemon_resource('kubernetes_resources/docker-daemon.json')
            )
        )
        asg_jenkins_slave.add_to_role_policy(iam.PolicyStatement(
            actions=[
                'ecr:CompleteLayerUpload',
                'ecr:InitiateLayerUpload',
                'ecr:PutImage',
                'ecr:UploadLayerPart'
                ],
            resources=["*"]
            )
        )

        asg_worker_nodes.connections.allow_from(
            asg_jenkins_slave,
            ec2.Port.all_traffic()
        )
        asg_jenkins_slave.connections.allow_from(
            asg_worker_nodes,
            ec2.Port.all_traffic()
        )

        eks_master_role = iam.Role(
            self, 'AdminRole',
            assumed_by=iam.ArnPrincipal(get_eks_admin_iam_username())
        )

        cluster.aws_auth.add_masters_role(eks_master_role)

        helm_tiller_rbac = eks.KubernetesResource(
            self, 'helm-tiller-rbac',
            cluster=cluster,
            manifest=read_k8s_resource('kubernetes_resources/helm-tiller-rbac.yaml')
        )
Ejemplo n.º 5
0
 def _build_kms_key_for_env(self) -> None:
     administrator_arns: List[str] = [
     ]  # A place to add other admins if needed for KMS
     admin_principals = iam.CompositePrincipal(
         *[iam.ArnPrincipal(arn) for arn in administrator_arns],
         iam.ArnPrincipal(f"arn:aws:iam::{self.context.account_id}:root"),
     )
     self.env_kms_key: kms.Key = kms.Key(
         self,
         id="kms-key",
         removal_policy=core.RemovalPolicy.RETAIN,
         enabled=True,
         enable_key_rotation=True,
         policy=iam.PolicyDocument(statements=[
             iam.PolicyStatement(effect=iam.Effect.ALLOW,
                                 actions=["kms:*"],
                                 resources=["*"],
                                 principals=[admin_principals])
         ]),
     )
    def __init__(self, scope: core.Construct, id: str,
                 landing_zone: ILandingZone, **kwargs):
        """
    Configure Dns Resolver
    """
        super().__init__(scope, id, **kwargs)

        region = core.Stack.of(self).region

        self.encryption_key = kms.Key(
            self,
            'EncryptionKey',
            description='Encryption Key for BackupStrategy')

        self.topic = sns.Topic(self, 'Topic')
        self.role = iam.Role(self,
                             'Role',
                             description='Account Backup Role',
                             assumed_by=iam.ServicePrincipal(service='backup'))

        self.vault = backup.BackupVault(
            self,
            'Vault',
            encryption_key=self.encryption_key,
            notification_topic=self.topic,
            backup_vault_name='{}-Backup-Vault'.format(landing_zone.zone_name),
            access_policy=iam.PolicyDocument(statements=[
                iam.PolicyStatement(
                    effect=iam.Effect.ALLOW,
                    resources=["*"],
                    actions=['backup:CopyIntoBackupVault'],
                    principals=[iam.ArnPrincipal(arn=self.role.role_arn)])
            ]))

        self.default_plan = backup.BackupPlan(
            self,
            'DefaultPlan',
            backup_vault=self.vault,
            backup_plan_name='Default Plan {} in {}'.format(
                landing_zone.zone_name, region),
            backup_plan_rules=[
                backup.BackupPlanRule.daily(),
                backup.BackupPlanRule.weekly(),
            ])

        self.default_plan.add_selection('SelectionPolicy',
                                        allow_restores=True,
                                        role=self.role,
                                        resources=[
                                            backup.BackupResource.from_tag(
                                                "landing_zone",
                                                landing_zone.zone_name),
                                        ])
Ejemplo n.º 7
0
 def _assumed_by(self, principals: typing.Union[aws_iam.IPrincipal, typing.List[str]]) -> aws_iam.IPrincipal:
     pps = list()
     for principal in principals:
         if isinstance(principal, str):
             if principal.startswith("arn:aws"):
                 pps.append(aws_iam.ArnPrincipal(arn=principal))
             else:
                 pps.append(aws_iam.AccountPrincipal(account_id=principal))
         else:
             pps.append(principal)
     if len(pps) > 1:
         return aws_iam.CompositePrincipal(*pps)
     return pps[0]
    def __init__(self, scope: cdk.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        trusted_role_arn = "arn:aws:iam::" + MAIN_ACCOUNT_ID + ":role/ConsoleMeTaskRole"

        spoke_role = iam.Role(
            self,
            f"{SPOKE_BASE_NAME}TrustRole",
            role_name="ConsoleMeTrustRole",
            assumed_by=iam.ArnPrincipal(arn=trusted_role_arn),
        )

        spoke_role.add_to_policy(
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                actions=[
                    "autoscaling:Describe*",
                    "cloudwatch:Get*",
                    "cloudwatch:List*",
                    "config:BatchGet*",
                    "config:List*",
                    "config:Select*",
                    "ec2:describeregions",
                    "ec2:DescribeSubnets",
                    "ec2:describevpcendpoints",
                    "ec2:DescribeVpcs",
                    "iam:*",
                    "s3:GetBucketPolicy",
                    "s3:GetBucketTagging",
                    "s3:ListAllMyBuckets",
                    "s3:ListBucket",
                    "s3:PutBucketPolicy",
                    "s3:PutBucketTagging",
                    "sns:GetTopicAttributes",
                    "sns:ListTagsForResource",
                    "sns:ListTopics",
                    "sns:SetTopicAttributes",
                    "sns:TagResource",
                    "sns:UnTagResource",
                    "sqs:GetQueueAttributes",
                    "sqs:GetQueueUrl",
                    "sqs:ListQueues",
                    "sqs:ListQueueTags",
                    "sqs:SetQueueAttributes",
                    "sqs:TagQueue",
                    "sqs:UntagQueue",
                ],
                resources=["*"],
            ))
Ejemplo n.º 9
0
    def __init__(self, scope: core.Construct, display_name: str,
                 topic_name: str):
        super().__init__(scope=scope,
                         id=topic_name,
                         display_name=display_name,
                         topic_name=topic_name)

        policy_statement = aws_iam.PolicyStatement(
            actions=['SNS:Subscribe', 'SNS:publish'],
            conditions=[],
            effect=aws_iam.Effect.ALLOW,
            resources=[self.topic_arn],
            principals=[aws_iam.ArnPrincipal('*')])

        self.add_to_resource_policy(policy_statement)
    def __init__(self, scope: core.Construct, id: str, vpc: ec2.Vpc,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        kms_policy = iam.PolicyDocument()
        kms_policy.add_statements(
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                actions=["kms:*"],
                resources=['*'],
                principals=[iam.AccountPrincipal(account_id=self.account)]))

        redshift_key = kms.Key(self,
                               "volumeKey",
                               enable_key_rotation=True,
                               policy=kms_policy,
                               removal_policy=core.RemovalPolicy.RETAIN)

        redshift_bucket = s3.Bucket(self, "redshiftBucket")
        redshift_bucket.add_to_resource_policy(permission=iam.PolicyStatement(
            effect=iam.Effect.ALLOW,
            actions=["s3:*"],
            resources=[
                f"{redshift_bucket.bucket_arn}/*", redshift_bucket.bucket_arn
            ],
            principals=[
                iam.ArnPrincipal(f"arn:aws:iam::193672423079:user/logs")
            ]))

        self._cluster = redshift.Cluster(
            self,
            id,
            master_user=redshift.Login(master_username="******",
                                       encryption_key=redshift_key),
            port=5439,
            vpc=vpc,
            cluster_name="dwh",
            cluster_type=redshift.ClusterType.MULTI_NODE,
            number_of_nodes=2,
            default_database_name="aml",
            encrypted=True,
            encryption_key=redshift_key,
            logging_bucket=redshift_bucket,
            logging_key_prefix="dwh",
            node_type=redshift.NodeType.DC2_LARGE,
            removal_policy=core.RemovalPolicy.DESTROY,
            security_groups=[self.redshift_sg(vpc)],
            vpc_subnets=ec2.SubnetSelection(subnet_group_name="DBS"))
Ejemplo n.º 11
0
def provide_access_to_artifacts(scope: core.Construct, *,
                                pipeline_def: Pipeline,
                                artifact_bucket: aws_s3.Bucket) -> None:
    role_arns = set()
    for role_arn in pipeline_def.get("artifact_access",
                                     {}).get("role_arns", []):
        role_arns.add(role_arn)
    for stage_def in pipeline_def["stages"]:
        for action_def in stage_def["actions"]:
            if "role_arn" in action_def:
                account = core.Arn.parse(action_def["role_arn"]).account
                if account != core.Stack.of(scope).account:
                    role_arns.add(action_def["role_arn"])
    for role_arn in role_arns:
        artifact_bucket.add_to_resource_policy(
            aws_iam.PolicyStatement(
                actions=["s3:Get*"],
                resources=[artifact_bucket.arn_for_objects("*")],
                effect=aws_iam.Effect.ALLOW,
                principals=[aws_iam.ArnPrincipal(role_arn)],
            ))
 def __create_s3_source_bucket_policy(
     self, s3_source_bucket: aws_s3.Bucket,
     cloud_front_origin_access_identity: aws_cloudfront.OriginAccessIdentity
 ):
     return aws_s3.CfnBucketPolicy(
         self,
         'S3SourceBucketPolicy',
         bucket=s3_source_bucket.bucket_name,
         policy_document=PolicyDocument(statements=[
             PolicyStatement(
                 effect=Effect.ALLOW,
                 actions=['s3:GetObject'],
                 sid='1',
                 resources=[
                     f'arn:aws:s3:::{s3_source_bucket.bucket_name}/*'
                 ],
                 principals=[
                     aws_iam.ArnPrincipal(
                         f'arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity '
                         f'{cloud_front_origin_access_identity.origin_access_identity_name}'
                     )
                 ])
         ]))
Ejemplo n.º 13
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # CloudFormation Parameters

        glue_db_name = core.CfnParameter(
            self,
            "GlueDatabaseName",
            type="String",
            description="Glue Database where the Table belongs.",
            allowed_pattern="[\w-]+",
        )

        glue_table_name = core.CfnParameter(
            self,
            "GlueTableName",
            type="String",
            description="Glue Table where access will be granted.",
            allowed_pattern="[\w-]+",
        )

        grantee_role_arn = core.CfnParameter(
            self,
            "GranteeIAMRoleARN",
            type="String",
            description="IAM Role's ARN.",
            allowed_pattern=
            "arn:(aws[a-zA-Z-]*)?:iam::\d{12}:role\/?[a-zA-Z0-9_+=,.@\-]+")

        grantee_vpc = core.CfnParameter(
            self,
            "GranteeVPC",
            type="String",
            description=
            "VPC ID from where the S3 access point will be accessed.",
            allowed_pattern="vpc-[a-zA-Z0-9]+")

        is_lakeformation = core.CfnParameter(
            self,
            "LakeFormationParam",
            type="String",
            description=
            "If Lake Formation is used, the stack must be deployed using an IAM role with Lake Formation Admin permissions.",
            allowed_values=["Yes", "No"])

        # CloudFormation Parameter Groups

        self.template_options.description = "\
This template deploys an S3 Access Point which provides a given IAM Role \
access to the underlying data location for a given Glue Table.\n\
Main use case for this template is to grant an ETL process in another AWS Account, \
access to the S3 objects (e.g., Parquet files) associated to a Glue Table."

        self.template_options.metadata = {
            "AWS::CloudFormation::Interface": {
                "License":
                "MIT-0",
                "ParameterGroups": [{
                    "Label": {
                        "default": "Lake Formation (Producer Account)"
                    },
                    "Parameters": [is_lakeformation.logical_id]
                }, {
                    "Label": {
                        "default":
                        "Source Data Catalog Resource (Producer Account)"
                    },
                    "Parameters":
                    [glue_db_name.logical_id, glue_table_name.logical_id]
                }, {
                    "Label": {
                        "default": "Grantee IAM Role (Consumer Account)"
                    },
                    "Parameters":
                    [grantee_role_arn.logical_id, grantee_vpc.logical_id]
                }],
                "ParameterLabels": {
                    is_lakeformation.logical_id: {
                        "default":
                        "Are data permissions managed by Lake Formation?"
                    },
                    glue_db_name.logical_id: {
                        "default": "What is the Glue DB Name for the Table?"
                    },
                    glue_table_name.logical_id: {
                        "default": "What is the Glue Table Name?"
                    },
                    grantee_role_arn.logical_id: {
                        "default": "What is the ARN of the IAM Role?"
                    },
                    grantee_vpc.logical_id: {
                        "default":
                        "What VPC will be used to access the S3 Access Point?"
                    }
                }
            }
        }

        is_lakeformation_condition = core.CfnCondition(
            self,
            "IsLakeFormation",
            expression=core.Fn.condition_equals("Yes", is_lakeformation))

        # Create S3 Access Point to share dataset objects

        grantee_role = iam.Role.from_role_arn(self, "GranteeIAMRole",
                                              grantee_role_arn.value_as_string)

        glue_table_arn = f"arn:aws:glue:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:table/{glue_db_name.value_as_string}/{glue_table_name.value_as_string}"

        glue_table = glue.Table.from_table_arn(self,
                                               "GlueTable",
                                               table_arn=glue_table_arn)

        # Invoke Lambda to obtain S3 bucket and S3 prefix from Glue Table

        get_s3_from_table_execution_role = iam.Role(
            self,
            "GetS3FromTableServiceRole",
            assumed_by=iam.ServicePrincipal('lambda.amazonaws.com'),
            managed_policies=[
                iam.ManagedPolicy.from_aws_managed_policy_name(
                    "service-role/AWSLambdaBasicExecutionRole"),
                iam.ManagedPolicy.from_aws_managed_policy_name(
                    "service-role/AWSGlueServiceRole")
            ])

        lf_permission = lf.CfnPermissions(
            self,
            "LFPermissionForLambda",
            data_lake_principal=lf.CfnPermissions.DataLakePrincipalProperty(
                data_lake_principal_identifier=get_s3_from_table_execution_role
                .role_arn),
            resource=lf.CfnPermissions.ResourceProperty(
                table_resource=lf.CfnPermissions.TableResourceProperty(
                    name=glue_table_name.value_as_string,
                    database_name=glue_db_name.value_as_string)),
            permissions=["DESCRIBE"])

        lf_permission.apply_removal_policy(core.RemovalPolicy.DESTROY,
                                           apply_to_update_replace_policy=True)
        lf_permission.node.add_dependency(get_s3_from_table_execution_role)
        lf_permission.cfn_options.condition = is_lakeformation_condition

        lf_wait_condition_handle = cfn.CfnWaitConditionHandle(
            self, "LFWaitConditionHandle")
        lf_wait_condition_handle.add_metadata(
            "WaitForLFPermissionIfExists",
            core.Fn.condition_if(is_lakeformation_condition.logical_id,
                                 lf_permission.logical_id, ""))

        with open("lambda/get_s3_from_table.py", encoding="utf8") as fp:
            get_s3_from_table_code = fp.read()

        get_s3_from_table_fn = _lambda.Function(
            self,
            "GetS3FromTableHandler",
            runtime=_lambda.Runtime.PYTHON_3_7,
            code=_lambda.InlineCode.from_inline(get_s3_from_table_code),
            handler="index.handler",
            role=get_s3_from_table_execution_role,
            timeout=core.Duration.seconds(600))

        get_s3_from_table = core.CustomResource(
            self,
            "GetS3FromTable",
            service_token=get_s3_from_table_fn.function_arn,
            resource_type="Custom::GetS3FromTable",
            properties={
                "GlueDatabase": glue_db_name.value_as_string,
                "GlueTable": glue_table_name.value_as_string
            })

        get_s3_from_table.node.add_dependency(lf_wait_condition_handle)

        table_bucket = get_s3_from_table.get_att_string("TableBucket")
        table_prefix = get_s3_from_table.get_att_string("TablePrefix")

        # Create S3 Access Point

        table_name_normalized = core.Fn.join(
            "-", core.Fn.split("_", glue_table_name.value_as_string))
        random_suffix = core.Fn.select(
            0,
            core.Fn.split(
                "-", core.Fn.select(2, core.Fn.split("/", core.Aws.STACK_ID))))

        s3_accesspoint_name = f"{table_name_normalized}-{random_suffix}"

        s3_accesspoint_arn = f"arn:aws:s3:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:accesspoint/{s3_accesspoint_name}"

        glue_table_accesspoint_path = f"{s3_accesspoint_arn}/object/{table_prefix}"

        # s3_accesspoint_block_config = s3.CfnAccessPoint.PublicAccessBlockConfigurationProperty(block_public_acls=True, block_public_policy=True, ignore_public_acls=True, restrict_public_buckets=True)

        s3_accesspoint_policy = iam.PolicyDocument(statements=[
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                principals=[iam.ArnPrincipal(arn=grantee_role.role_arn)],
                actions=["s3:GetObject*"],
                resources=[f"{glue_table_accesspoint_path}*"]),
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                principals=[iam.ArnPrincipal(arn=grantee_role.role_arn)],
                actions=["s3:ListBucket*"],
                resources=[s3_accesspoint_arn],
                conditions={"StringLike": {
                    "s3:prefix": f"{table_prefix}*"
                }})
        ])

        s3_accesspoint = s3.CfnAccessPoint(
            self,
            "S3AccessPoint",
            bucket=f"{table_bucket}",
            name=s3_accesspoint_name,
            # network_origin = "Internet",
            policy=s3_accesspoint_policy,
            vpc_configuration=s3.CfnAccessPoint.VpcConfigurationProperty(
                vpc_id=grantee_vpc.value_as_string))

        glue_table_accesspoint_path_output = f"arn:aws:s3:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:accesspoint/{s3_accesspoint.name}/object/{table_prefix}"

        # Output

        core.CfnOutput(self,
                       "IAMRoleArnOutput",
                       value=grantee_role.role_arn,
                       description="IAM Role Arn")

        core.CfnOutput(self,
                       "GlueTableOutput",
                       value=glue_table.table_arn,
                       description="Glue Table ARN")

        core.CfnOutput(self,
                       "S3AccessPointPathOutput",
                       value=glue_table_accesspoint_path_output,
                       description="S3 Access Point Path for Glue Table")
Ejemplo n.º 14
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        Zach_AWSBackupPlanName = self.__class__.__name__
        Zach_AWSBackup_Vault = bk.CfnBackupVault(
            self,
            id=Zach_AWSBackupPlanName,
            backup_vault_name=Zach_AWSBackupPlanName)
        Zach_AWSBackup_IAM_ROLE = "arn:aws:iam::098380756085:role/service-role/AWSBackupDefaultServiceRole"
        if Zach_AWSBackup_IAM_ROLE == "":
            IAM_ACCOUNT = self.node.try_get_context(
                "account") or '098380756085'
            IAM_Princial = iam.CompositePrincipal(
                iam.ServicePrincipal("backup.amazonaws.com"),
                iam.AccountPrincipal(IAM_ACCOUNT),
                iam.ArnPrincipal("arn:aws:ec2:*"))
            Zach_AWSBackup_IAM_ROLE = iam.Role(
                self,
                id="Zach_" + Zach_AWSBackupPlanName,
                role_name="Zach_" + Zach_AWSBackupPlanName,
                assumed_by=IAM_Princial,
                max_session_duration=core.Duration.hours(6))

        # FIXME
        '''
        jsii.errors.JSIIError: Value did not match any type in union: Value did not match any type in union: Expected object reference, got [{"CompletionWindowMinutes":30,"Lifecycle":{"DeleteAfterDays":90,"MoveToColdStorageAfterDays":28},"RuleName":"Zach_AWSBackup_Stack_A"
,"ScheduleExpression":"cron(0 5 ? * * *)","StartWindowMinutes":480,"TargetBackupVault":"Zach_AWSBackup_Stack_A"}],Value did not match any type in union: Expected object reference, got {"CompletionWindowMinutes":30,"Lifecycle":{"DeleteAfterDays":90,"MoveToColdStorag
eAfterDays":28},"RuleName":"Zach_AWSBackup_Stack_A","ScheduleExpression":"cron(0 5 ? * * *)","StartWindowMinutes":480,"TargetBackupVault":"Zach_AWSBackup_Stack_A"},Missing required properties for @aws-cdk/aws-backup.CfnBackupPlan.BackupRuleResourceTypeProperty: rul
eName,targetBackupVault,Expected object reference, got {"backupPlanName":"Zach_AWSBackup_Stack_A","backupPlanRule":[{"CompletionWindowMinutes":30,"Lifecycle":{"DeleteAfterDays":90,"MoveToColdStorageAfterDays":28},"RuleName":"Zach_AWSBackup_Stack_A","ScheduleExpress
ion":"cron(0 5 ? * * *)","StartWindowMinutes":480,"TargetBackupVault":"Zach_AWSBackup_Stack_A"}]}
        '''
        BackupPlanRule = [{
            "CompletionWindowMinutes":
            30,
            "Lifecycle": {
                "DeleteAfterDays": 90,
                "MoveToColdStorageAfterDays": 28
            },
            "RuleName":
            Zach_AWSBackupPlanName,
            "ScheduleExpression":
            "cron(0 5 ? * * *)",
            "StartWindowMinutes":
            480,
            "TargetBackupVault":
            Zach_AWSBackup_Vault.backup_vault_name
        }]
        Zach_AWSBackup = bk.CfnBackupPlan(self,
                                          id=Zach_AWSBackupPlanName,
                                          backup_plan={
                                              "backupPlanName":
                                              Zach_AWSBackupPlanName,
                                              "backupPlanRule": BackupPlanRule
                                          })
        # , backup_plan_tags = ['dev', 'zach', Zach_AWSBackupPlanName]
        JobList = {
            "IamRoleArn":
            "arn:aws:iam::098380756085:role/service-role/AWSBackupDefaultServiceRole",
            "ListOfTags": [],
            "Resources": [
                "arn:ap-southeast-1:ec2:ap-southeast-1a:098380756085:volume/vol-02a2664501c88e696"
            ],
            "SelectionName":
            Zach_AWSBackupPlanName + "EBS-00001"
        }
        Zach_AWSBackup_Job = bk.CfnBackupSelection(
            self,
            id=Zach_AWSBackupPlanName + "EBS-00001",
            backup_plan_id=Zach_AWSBackup.attr_backup_plan_id,
            backup_selection=JobList)

        core.CfnOutput(self,
                       "ZachAWSBackupID",
                       value=Zach_AWSBackup.logical_id)
        core.CfnOutput(self,
                       "ZachAWSBackupPlanID",
                       value=Zach_AWSBackup.attr_backup_plan_id)
        core.CfnOutput(self,
                       "ZachAWSBackupPlanARN",
                       value=Zach_AWSBackup.attr_backup_plan_arn)
        core.CfnOutput(self,
                       "ZachAWSBackupPlan",
                       value=Zach_AWSBackup.backup_plan.to_string)
        core.CfnOutput(self,
                       "ZachAWSBackupRoleARN",
                       value=Zach_AWSBackup_IAM_ROLE.role_arn)
        core.CfnOutput(self,
                       "ZachAWSBackupVaultARN",
                       value=Zach_AWSBackup_Vault.attr_backup_vault_arn)
        core.CfnOutput(self,
                       "ZachAWSBackupVaultName",
                       value=Zach_AWSBackup_Vault.backup_vault_name)
    def __init__(self, app: App, id: str) -> None:
        super().__init__(app, id)
        self.access_point = f"arn:aws:s3:{Aws.REGION}:{Aws.ACCOUNT_ID}:accesspoint/" \
                            f"{S3_ACCESS_POINT_NAME}"

        # Set up a bucket
        bucket = s3.Bucket(
            self,
            "example-bucket",
            access_control=s3.BucketAccessControl.BUCKET_OWNER_FULL_CONTROL,
            encryption=s3.BucketEncryption.S3_MANAGED,
            block_public_access=s3.BlockPublicAccess.BLOCK_ALL)
        # Delegating access control to access points
        # https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-points-policies.html
        bucket.add_to_resource_policy(
            iam.PolicyStatement(
                actions=["*"],
                principals=[iam.AnyPrincipal()],
                resources=[bucket.bucket_arn,
                           bucket.arn_for_objects('*')],
                conditions={
                    "StringEquals": {
                        "s3:DataAccessPointAccount": f"{Aws.ACCOUNT_ID}"
                    }
                }))

        # lambda to process our objects during retrieval
        retrieve_transformed_object_lambda = _lambda.Function(
            self,
            "retrieve_transformed_obj_lambda",
            runtime=_lambda.Runtime.PYTHON_3_8,
            handler="index.handler",
            code=_lambda.Code.from_asset(
                "lambda/retrieve_transformed_object_lambda"))

        # Object lambda s3 access
        retrieve_transformed_object_lambda.add_to_role_policy(
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                resources=["*"],
                actions=["s3-object-lambda:WriteGetObjectResponse"]))
        # Restrict Lambda to be invoked from own account
        retrieve_transformed_object_lambda.add_permission(
            "invocationRestriction",
            action="lambda:InvokeFunction",
            principal=iam.AccountRootPrincipal(),
            source_account=Aws.ACCOUNT_ID)

        # Associate Bucket's access point with lambda get access
        policy_doc = iam.PolicyDocument()
        policy_statement = iam.PolicyStatement(
            effect=iam.Effect.ALLOW,
            actions=["s3:GetObject"],
            principals=[
                iam.ArnPrincipal(
                    retrieve_transformed_object_lambda.role.role_arn)
            ],
            resources=[f"{self.access_point}/object/*"])
        policy_statement.sid = "AllowLambdaToUseAccessPoint"
        policy_doc.add_statements(policy_statement)

        example_bucket_ap = s3.CfnAccessPoint(self,
                                              "example-bucket_ap",
                                              bucket=bucket.bucket_name,
                                              name=S3_ACCESS_POINT_NAME,
                                              policy=policy_doc)

        # Access point to receive GET request and use lambda to process objects
        object_lambda_ap = s3_object_lambda.CfnAccessPoint(
            self,
            "s3_object_lambda_ap",
            name=OBJECT_LAMBDA_ACCESS_POINT_NAME,
            object_lambda_configuration=s3_object_lambda.CfnAccessPoint.
            ObjectLambdaConfigurationProperty(
                supporting_access_point=self.access_point,
                transformation_configurations=[
                    s3_object_lambda.CfnAccessPoint.
                    TransformationConfigurationProperty(
                        actions=["GetObject"],
                        content_transformation={
                            "AwsLambda": {
                                "FunctionArn":
                                f"{retrieve_transformed_object_lambda.function_arn}"
                            }
                        })
                ]))

        CfnOutput(self, "exampleBucketArn", value=bucket.bucket_arn)
        CfnOutput(self,
                  "objectLambdaArn",
                  value=retrieve_transformed_object_lambda.function_arn)
        CfnOutput(self,
                  "objectLambdaAccessPointArn",
                  value=object_lambda_ap.attr_arn)
        CfnOutput(
            self,
            "objectLambdaAccessPointUrl",
            value=f"https://console.aws.amazon.com/s3/olap/{Aws.ACCOUNT_ID}/"
            f"{OBJECT_LAMBDA_ACCESS_POINT_NAME}?region={Aws.REGION}")
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # API Gateway needs to have resource policy granting FHIR Works on AWS lambda
        # execute permissions. Lambda function ARN will be passed during deployment as CDK context variable
        # FHIR Works lambda will need to have policy attached to its execution role
        # allowing it to invoke API
        # From --context resource-router-lambda-role="arn:aws:iam::123456789012:role/rolename"
        imported_resource_router_lambda_role = self.node.try_get_context(
            "resource-router-lambda-role"
        )
        # Amazon ECS on AWS Fargate container implementing connection manager
        # will be launched into a VPC that needs to have private and public subnets
        # and NAT gateway or instance
        # From --context vpc-id="vpc-123456"
        vpc_id = self.node.try_get_context("vpc-id")

        # The following parameters specify name of the HL7 server
        # that will be receiving transformed HL7v2 messages and TCP port
        # that it will be listening on
        # From --context hl7-server-name="hl7.example.com"
        # From --context hl7-port="2575"
        hl7_server_name = self.node.try_get_context("hl7-server-name")
        hl7_port = self.node.try_get_context("hl7-port")

        # In this proof of concept source of data for read interactions
        # is S3 bucket where mock HL7 server stores processed HL7 messages
        # From --context test-server-output-bucket-name="DOC-EXAMPLE-BUCKET"
        test_server_output_bucket_name = self.node.try_get_context(
            "test-server-output-bucket-name"
        )

        # SQS queue
        # Custom transform lambda communicates with Connectivity Manager using this SQS queue
        queue = sqs.Queue(
            self, f"{COMPONENT_PREFIX}Queue", encryption=sqs.QueueEncryption.KMS_MANAGED
        )

        # S3 Bucket to retrieve HL7v2 messages in proof of concept deployment
        test_server_output_bucket = s3.Bucket.from_bucket_name(
            self, f"{COMPONENT_PREFIX}OutputBucket", test_server_output_bucket_name
        )

        # Transform Lambda
        # Reference implementation of Custom Transform component of Transform Execution Environment

        transform_lambda = lambda_.Function(
            self,
            f"{COMPONENT_PREFIX}TransformLambda",
            handler="transform.handler",
            runtime=lambda_.Runtime.PYTHON_3_8,
            code=lambda_.Code.from_asset(
                path.join(dirname, "../../lambda"),
                bundling={
                    "image": lambda_.Runtime.PYTHON_3_8.bundling_docker_image,
                    "command": [
                        "bash",
                        "-c",
                        " && ".join(
                            [
                                "pip install --no-cache-dir -r requirements.txt -t /asset-output",
                                "(tar -c --exclude-from=exclude.lst -f - .)|(cd /asset-output; tar -xf -)",
                            ]
                        ),
                    ],
                },
            ),
            timeout=core.Duration.seconds(60),
            environment=dict(
                SQS_QUEUE=queue.queue_url,
                # The following parameter is optional
                S3_BUCKET_NAME=test_server_output_bucket_name,
            ),
        )
        queue.grant_send_messages(transform_lambda)

        # API Gateway with Lambda construct (using https://aws.amazon.com/solutions/constructs/patterns)
        # Reference implementation of Custom Transform component of Transform Execution Environment

        api_lambda = apigw_lambda.ApiGatewayToLambda(
            self,
            "ApiGw",
            existing_lambda_obj=transform_lambda,
            api_gateway_props=apigw.LambdaRestApiProps(
                handler=transform_lambda,
                proxy=False,
                rest_api_name=f"{COMPONENT_PREFIX_DASHES}-api",
                endpoint_export_name=f"{COMPONENT_PREFIX}ApiEndPoint",
                description=f"{COMPONENT_PREFIX} APIGW with Transform Lambda (FHIR to HL7v2)",
                default_method_options=apigw.MethodOptions(
                    authorization_type=apigw.AuthorizationType.IAM,
                ),
                policy=iam.PolicyDocument(
                    statements=[
                        iam.PolicyStatement(
                            actions=["execute-api:Invoke"],
                            effect=iam.Effect.ALLOW,
                            principals=[
                                iam.ArnPrincipal(imported_resource_router_lambda_role),
                            ],
                            resources=["execute-api:/*/*/*"],
                        )
                    ]
                ),
            ),
        )
        rest_api = api_lambda.api_gateway
        persistence = rest_api.root.add_resource("persistence")
        resource_type = persistence.add_resource("{resource_type}")
        resource_type.add_method("POST")
        resource_id = resource_type.add_resource("{id}")
        resource_id.add_method("GET")
        resource_id.add_method("PUT")
        resource_id.add_method("DELETE")

        # ECS Fargate Container (HL7v2 sender)
        # This container implements Connectivity Manager component
        # of Transform Execution Environment

        vpc = ec2.Vpc.from_lookup(self, "DefaultVpc", vpc_id=vpc_id)

        cluster = ecs.Cluster(self, f"{COMPONENT_PREFIX}Cluster", vpc=vpc)

        ecs_patterns.QueueProcessingFargateService(
            self,
            f"{COMPONENT_PREFIX}Service",
            cluster=cluster,
            image=ecs.ContainerImage.from_asset(path.join(dirname, "../../container")),
            queue=queue,
            desired_task_count=1,
            log_driver=ecs.LogDriver.aws_logs(
                stream_prefix=f"{COMPONENT_PREFIX}HL7Client",
                log_retention=logs.RetentionDays.ONE_DAY,
            ),
            environment=dict(
                SERVER_NAME=hl7_server_name,
                PORT_NUMBER=hl7_port,
            ),
        )

        # The following permission grants are needed to support
        # read interactions with integration transform
        test_server_output_bucket.grant_read(transform_lambda)

        transform_lambda.add_to_role_policy(
            iam.PolicyStatement(
                actions=["s3:ListBucket"],
                effect=iam.Effect.ALLOW,
                resources=[test_server_output_bucket.bucket_arn],
            )
        )
        transform_lambda.add_to_role_policy(
            iam.PolicyStatement(
                actions=["s3:GetObject"],
                effect=iam.Effect.ALLOW,
                resources=[test_server_output_bucket.arn_for_objects("*")],
            )
        )

        # CloudFormation Stack outputs
        # The following outputs needed to configure FHIR Works on AWS API interface
        core.CfnOutput(
            self,
            "TransformApiRootUrl",
            value=rest_api.url,
            export_name="TransformApiRootUrl",
        )
        core.CfnOutput(
            self,
            "TransformApiRegion",
            value=self.region,
            export_name="TransformApiRegion",
        )
        core.CfnOutput(
            self,
            "TransformApiAccountId",
            value=self.account,
            export_name="TransformApiAccountId",
        )
Ejemplo n.º 17
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        self.current_dir = os.path.dirname(__file__)

        self.website_bucket = s3.Bucket(
            self,
            "qs-embed-bucket",
            bucket_name=f'quicksight-embed-{core.Aws.ACCOUNT_ID}',
            block_public_access=s3.BlockPublicAccess.BLOCK_ALL)

        self.quicksight_embed_lambda_role = iam.Role(
            self,
            'quicksight-embed-lambda-role',
            description='Role for the Quicksight dashboard embed Lambdas',
            role_name='quicksight-embed-lambda-role',
            max_session_duration=core.Duration.seconds(3600),
            assumed_by=iam.ServicePrincipal('lambda.amazonaws.com'),
            inline_policies={
                'AllowAccess':
                iam.PolicyDocument(statements=[
                    iam.PolicyStatement(
                        effect=iam.Effect.ALLOW,
                        actions=[
                            'logs:CreateLogGroup', 'logs:CreateLogStream',
                            'logs:PutLogEvents'
                        ],
                        resources=[
                            f'arn:aws:logs:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:*'
                        ]),
                    iam.PolicyStatement(
                        effect=iam.Effect.ALLOW,
                        actions=["secrets:GetSecretValue"],
                        resources=[
                            f"arn:aws:secretsmanager:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:secret:*"
                        ]),
                    iam.PolicyStatement(effect=iam.Effect.ALLOW,
                                        actions=[
                                            "quicksight:GetDashboardEmbedUrl",
                                            "quicksight:GetAuthCode"
                                        ],
                                        resources=["*"])
                ])
            })

        self.quicksight_migration_lambda = _lambda.Function(
            self,
            'quicksight-migration-lambda',
            handler='quicksight_embed.lambda_handler',
            runtime=_lambda.Runtime.PYTHON_3_8,
            code=_lambda.Code.from_asset(
                os.path.join(self.current_dir, '../lambda/quicksight_embed/')),
            function_name='quicksight_embed_lambda',
            role=self.quicksight_embed_lambda_role,
            timeout=core.Duration.minutes(3),
            memory_size=512,
            environment={
                'DASHBOARD_ID':
                'CHANGEME_DASHBOARD_ID',
                'QUICKSIGHT_USER_ARN':
                f'arn:aws:quicksight:us-east-1:{core.Aws.ACCOUNT_ID}:user/default/quicksight-migration-user'
            })

        self.apigw_lambda = ApiGatewayToLambda(
            self,
            "ApiGatewayToLambdaQSEmbed",
            existing_lambda_obj=self.quicksight_migration_lambda,
            api_gateway_props=apigw.LambdaRestApiProps(
                rest_api_name="quicksight-embed",
                handler=self.quicksight_migration_lambda,
                deploy=True,
                proxy=False,
                default_method_options=apigw.MethodOptions(
                    authorization_type=apigw.AuthorizationType.NONE),
                policy=iam.PolicyDocument(statements=[
                    iam.PolicyStatement(effect=iam.Effect.ALLOW,
                                        actions=['execute-api:Invoke'],
                                        resources=["execute-api:/prod/*"],
                                        principals=[iam.ArnPrincipal("*")])
                ])))

        self.embedurl = self.apigw_lambda.api_gateway.root.add_resource(
            "embedurl")
        self.embedurl.add_method(
            "GET",
            method_responses=[{
                'statusCode': '200',
                'responseParameters': {
                    'method.response.header.Access-Control-Allow-Headers':
                    True,
                    'method.response.header.Access-Control-Allow-Methods':
                    True,
                    'method.response.header.Access-Control-Allow-Origin': True
                }
            }],
            integration=apigw.LambdaIntegration(
                self.quicksight_migration_lambda,
                proxy=False,
                integration_responses=[{
                    'statusCode': '200',
                    'responseTemplates': {
                        "application/json": ""
                    },
                    'responseParameters': {
                        'method.response.header.Access-Control-Allow-Headers':
                        "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'",
                        'method.response.header.Access-Control-Allow-Origin':
                        "'*'",
                        'method.response.header.Access-Control-Allow-Methods':
                        "'GET'"
                    }
                }]))

        self.embedurl.add_method(
            'OPTIONS',
            apigw.MockIntegration(integration_responses=[{
                'statusCode': '200',
                'responseParameters': {
                    'method.response.header.Access-Control-Allow-Headers':
                    "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'",
                    'method.response.header.Access-Control-Allow-Origin':
                    "'*'",
                    'method.response.header.Access-Control-Allow-Methods':
                    "'GET,OPTIONS'"
                }
            }],
                                  passthrough_behavior=apigw.
                                  PassthroughBehavior.WHEN_NO_MATCH,
                                  request_templates={
                                      "application/json":
                                      "{\"statusCode\":200}"
                                  }),
            method_responses=[{
                'statusCode': '200',
                'responseParameters': {
                    'method.response.header.Access-Control-Allow-Headers':
                    True,
                    'method.response.header.Access-Control-Allow-Methods':
                    True,
                    'method.response.header.Access-Control-Allow-Origin': True
                }
            }])

        # Cloudfront Distribution for authentication
        self.embed_auth_lambda_role = iam.Role(
            self,
            'embed-auth-lambda-role',
            description=
            'Role for the Quicksight dashboard embed authentication Lambda',
            role_name='embed-auth-lambda-role',
            max_session_duration=core.Duration.seconds(3600),
            assumed_by=iam.ServicePrincipal('lambda.amazonaws.com'),
            inline_policies={
                'AllowAccess':
                iam.PolicyDocument(statements=[
                    iam.PolicyStatement(
                        effect=iam.Effect.ALLOW,
                        actions=[
                            'logs:CreateLogGroup', 'logs:CreateLogStream',
                            'logs:PutLogEvents'
                        ],
                        resources=[
                            f'arn:aws:logs:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:*'
                        ])
                ])
            })

        self.embed_auth_lambda = _lambda.Function(
            self,
            'embed-auth-lambda',
            handler='index.handler',
            description=
            "A Lambda@Edge function for QuickSight embed authentication via CloudFront Distribution",
            runtime=_lambda.Runtime.NODEJS_14_X,
            code=_lambda.Code.from_asset(
                os.path.join(self.current_dir, '../lambda/embed_auth/')),
            function_name='embed_auth_lambda',
            role=self.embed_auth_lambda_role,
            timeout=core.Duration.seconds(5),
            memory_size=128)

        self.embed_auth_dist = cloudfront.Distribution(
            self,
            "embed-auth-dist",
            enabled=True,
            default_root_object="index.html",
            default_behavior=cloudfront.BehaviorOptions(
                origin=origins.S3Origin(self.website_bucket),
                allowed_methods=cloudfront.AllowedMethods.ALLOW_GET_HEAD,
                edge_lambdas=[{
                    "functionVersion": self.embed_auth_lambda.current_version,
                    "eventType": cloudfront.LambdaEdgeEventType.VIEWER_REQUEST,
                    "includeBody": True
                }]))

        core.CfnOutput(self,
                       "EmbedAPIGatewayURL",
                       value=self.apigw_lambda.api_gateway.url + "embedurl?",
                       description="Embed API GW URL")

        core.CfnOutput(self,
                       "EmbedCloudFrontURL",
                       value="https://" +
                       self.embed_auth_dist.distribution_domain_name,
                       description="CloudFront Distribution URL")
Ejemplo n.º 18
0
    def __init__(self, scope: Construct, cid: str,
                 application_names: List[str], instance_ids: Dict[str,
                                                                  List[str]],
                 instance_roles_map: Dict[str, _iam.IRole],
                 endpoint_sg: _ec2.ISecurityGroup, vpc: _ec2.Vpc) -> None:

        super().__init__(scope, cid)
        principals = []

        for application_name in application_names:
            for instance_id in instance_ids[application_name]:
                principals.append(
                    _iam.ArnPrincipal(
                        arn="arn:aws:sts::" + self.account + ":assumed-role/" +
                        instance_roles_map[application_name].role_name + "/" +
                        instance_id))

        self.create_interface_endpoint(
            "ssm",
            security_group=endpoint_sg,
            interface_endpoint_policy=_iam.PolicyStatement(
                effect=_iam.Effect.ALLOW,
                actions=[
                    "ssm:DescribeAssociation",
                    "ssm:GetDeployablePatchSnapshotForInstance",
                    "ssm:GetDocument", "ssm:DescribeDocument",
                    "ssm:GetManifest", "ssm:GetParameter", "ssm:GetParameters",
                    "ssm:ListAssociations", "ssm:ListInstanceAssociations",
                    "ssm:PutInventory", "ssm:PutComplianceItems",
                    "ssm:PutConfigurePackageResult",
                    "ssm:UpdateAssociationStatus",
                    "ssm:UpdateInstanceAssociationStatus",
                    "ssm:UpdateInstanceInformation"
                ],
                resources=["*"],
                principals=principals),
            vpc=vpc)
        self.create_interface_endpoint(
            "ec2",
            security_group=endpoint_sg,
            interface_endpoint_policy=_iam.PolicyStatement(
                effect=_iam.Effect.ALLOW,
                actions=["ec2:Describe*"],
                resources=["*"],
                principals=principals),
            vpc=vpc)
        self.create_interface_endpoint(
            "ssmmessages",
            security_group=endpoint_sg,
            interface_endpoint_policy=_iam.PolicyStatement(
                effect=_iam.Effect.ALLOW,
                actions=[
                    "ssmmessages:CreateControlChannel",
                    "ssmmessages:CreateDataChannel",
                    "ssmmessages:OpenControlChannel",
                    "ssmmessages:OpenDataChannel"
                ],
                resources=["*"],
                principals=principals),
            vpc=vpc)
        self.create_interface_endpoint(
            "ec2messages",
            security_group=endpoint_sg,
            interface_endpoint_policy=_iam.PolicyStatement(
                effect=_iam.Effect.ALLOW,
                actions=[
                    "ec2messages:AcknowledgeMessage",
                    "ec2messages:DeleteMessage", "ec2messages:FailMessage",
                    "ec2messages:GetEndpoint", "ec2messages:GetMessages",
                    "ec2messages:SendReply"
                ],
                resources=["*"],
                principals=principals),
            vpc=vpc)
        self.create_interface_endpoint(
            "logs",
            security_group=endpoint_sg,
            interface_endpoint_policy=_iam.PolicyStatement(
                effect=_iam.Effect.ALLOW,
                actions=[
                    "logs:PutLogEvents", "logs:DescribeLogStreams",
                    "logs:DescribeLogGroups", "logs:CreateLogStream",
                    "logs:CreateLogGroup"
                ],
                resources=["*"],
                principals=principals),
            vpc=vpc)
        self.create_interface_endpoint(
            "monitoring",
            security_group=endpoint_sg,
            interface_endpoint_policy=_iam.PolicyStatement(
                effect=_iam.Effect.ALLOW,
                actions=["cloudwatch:PutMetricData"],
                resources=["*"],
                principals=principals),
            vpc=vpc)

        self.create_gateway_endpoint(
            "s3",
            vpc=vpc,
            gateway_endpoint_policy=_iam.PolicyStatement(
                effect=_iam.Effect.ALLOW,
                actions=["s3:GetObject", "s3:PutObject"],
                resources=[
                    "arn:aws:s3:::aws-ssm-" + self.region + "/*",
                    "arn:aws:s3:::aws-windows-downloads-" + self.region + "/*",
                    "arn:aws:s3:::amazon-ssm-" + self.region + "/*",
                    "arn:aws:s3:::amazon-ssm-packages-" + self.region + "/*",
                    "arn:aws:s3:::" + self.region + "-birdwatcher-prod/*",
                    "arn:aws:s3:::aws-ssm-distributor-file-" + self.region +
                    "/*", "arn:aws:s3:::patch-baseline-snapshot-" +
                    self.region + "/*",
                    "arn:aws:s3:::amazoncloudwatch-agent-" + self.region +
                    "/*", "arn:aws:s3:::" +
                    self.node.try_get_context("qs_s3_bucket") + "-" +
                    self.region + "/*"
                ],
                principals=[_iam.AnyPrincipal()]))
Ejemplo n.º 19
0
    def __init__(
        self,
        scope: Construct,
        id: str,
        context: "Context",
        team_name: str,
        team_policies: List[str],
        image: Optional[str],
    ) -> None:
        self.scope = scope
        self.id = id
        self.context: "Context" = context
        self.team_name: str = team_name
        self.team_policies: List[str] = team_policies
        self.image: Optional[str] = image
        super().__init__(
            scope=scope,
            id=id,
            stack_name=id,
            env=Environment(account=self.context.account_id,
                            region=self.context.region),
        )
        Tags.of(scope=cast(IConstruct, self)).add(
            key="Env", value=f"orbit-{self.context.name}")
        Tags.of(scope=cast(IConstruct, self)).add(key="TeamSpace",
                                                  value=self.team_name)

        if self.context.networking.vpc_id is None:
            raise ValueError("self.context.networking.vpc_id is None!")
        self.i_vpc = ec2.Vpc.from_vpc_attributes(
            scope=self,
            id="vpc",
            vpc_id=self.context.networking.vpc_id,
            availability_zones=cast(
                List[str], self.context.networking.availability_zones),
        )
        self.i_isolated_subnets = Ec2Builder.build_subnets(
            scope=self, subnet_manifests=context.networking.isolated_subnets)
        self.i_private_subnets = Ec2Builder.build_subnets(
            scope=self, subnet_manifests=context.networking.private_subnets)
        administrator_arns: List[str] = [
        ]  # A place to add other admins if needed for KMS
        admin_principals = iam.CompositePrincipal(
            *[iam.ArnPrincipal(arn) for arn in administrator_arns],
            iam.ArnPrincipal(f"arn:aws:iam::{self.context.account_id}:root"),
        )
        self.team_kms_key: kms.Key = kms.Key(
            self,
            id="kms-key",
            removal_policy=core.RemovalPolicy.RETAIN,
            enabled=True,
            enable_key_rotation=True,
            policy=iam.PolicyDocument(statements=[
                iam.PolicyStatement(
                    effect=iam.Effect.ALLOW,
                    actions=["kms:*"],
                    resources=["*"],
                    principals=[cast(iam.IPrincipal, admin_principals)],
                )
            ]),
        )
        self.team_security_group: ec2.SecurityGroup = Ec2Builder.build_team_security_group(
            scope=self,
            context=context,
            team_name=self.team_name,
            vpc=self.i_vpc)
        self.policies: List[str] = self.team_policies
        if self.context.scratch_bucket_arn:
            self.scratch_bucket: s3.Bucket = cast(
                s3.Bucket,
                s3.Bucket.from_bucket_attributes(
                    scope=self,
                    id="scratch_bucket",
                    bucket_arn=self.context.scratch_bucket_arn,
                    bucket_name=self.context.scratch_bucket_arn.split(":::")
                    [1],
                ),
            )
        else:
            raise Exception(
                "Scratch bucket was not provided in Manifest ('ScratchBucketArn')"
            )

        self.role_eks_pod = IamBuilder.build_team_role(
            scope=self,
            context=self.context,
            team_name=self.team_name,
            policy_names=self.policies,
            scratch_bucket=cast(s3.IBucket, self.scratch_bucket),
            team_kms_key=self.team_kms_key,
        )
        shared_fs_name: str = f"orbit-{context.name}-{self.team_name}-shared-fs"
        if context.shared_efs_fs_id is None:
            raise Exception(
                "Shared EFS File system ID was not provided in Manifest ('SharedEfsFsId')"
            )

        if context.shared_efs_sg_id is None:
            raise Exception(
                "Shared EFS File system security group ID was not provided in Manifest ('SharedEfsSgId')"
            )

        self.shared_fs: efs.FileSystem = cast(
            efs.FileSystem,
            efs.FileSystem.from_file_system_attributes(
                scope=self,
                id=shared_fs_name,
                file_system_id=context.shared_efs_fs_id,
                security_group=ec2.SecurityGroup.from_security_group_id(
                    scope=self,
                    id="team_sec_group",
                    security_group_id=context.shared_efs_sg_id),
            ),
        )

        self.efs_ap: efs.AccessPoint = EfsBuilder.build_file_system_access_point(
            scope=self, team_name=team_name, shared_fs=self.shared_fs)

        team_ssm_parameter_name: str = f"/orbit/{context.name}/teams/{self.team_name}/team"
        self.context_parameter: ssm.StringParameter = ssm.StringParameter(
            scope=self,
            id=team_ssm_parameter_name,
            string_value=json.dumps({
                "EfsId":
                self.shared_fs.file_system_id,
                "EfsApId":
                self.efs_ap.access_point_id,
                "EksPodRoleArn":
                self.role_eks_pod.role_arn,
                "ScratchBucket":
                self.scratch_bucket.bucket_name,
                "TeamKmsKeyArn":
                self.team_kms_key.key_arn,
                "TeamSecurityGroupId":
                self.team_security_group.security_group_id,
            }),
            type=ssm.ParameterType.STRING,
            description="Orbit Workbench Team Context.",
            parameter_name=team_ssm_parameter_name,
            simple_name=False,
            tier=ssm.ParameterTier.INTELLIGENT_TIERING,
        )
        ssm_profile_name = f"/orbit/{self.context.name}/teams/{self.team_name}/user/profiles"
        self.user_profiles: ssm.StringParameter = ssm.StringParameter(
            scope=self,
            id=ssm_profile_name,
            string_value="[]",
            type=ssm.ParameterType.STRING,
            description="Team additional profiles created by the team users",
            parameter_name=ssm_profile_name,
            simple_name=False,
            tier=ssm.ParameterTier.INTELLIGENT_TIERING,
        )
Ejemplo n.º 20
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        sns_principals_mapping = core.CfnMapping(
            scope=self,
            id="Inspector SNS Principals",
            mapping={
                "eu-central-1": {
                    "ARN": "arn:aws:iam::537503971621:root"
                },
                "us-east-1": {
                    "ARN": "arn:aws:iam::316112463485:root"
                },
                "eu-west-1": {
                    "ARN": "arn:aws:iam::357557129151:root"
                },
                "us-east-2": {
                    "ARN": "arn:aws:iam::646659390643:root"
                },
            }
        )

        inspector_rules_mapping = core.CfnMapping(
            scope=self,
            id="Inspector Rule packages",
            mapping={
                "eu-central-1": {
                    "CVE": "arn:aws:inspector:eu-central-1:537503971621:rulespackage/0-wNqHa8M9",
                    "CIS": "arn:aws:inspector:eu-central-1:537503971621:rulespackage/0-nZrAVuv8",
                    "securityBestPractices": "arn:aws:inspector:eu-central-1:537503971621:rulespackage/0-ZujVHEPB",
                    "runtimeBehaviorAnalysis": "arn:aws:inspector:eu-central-1:537503971621:rulespackage/0-0GMUM6fg"
                },
                "eu-west-1": {
                    "CVE": "arn:aws:inspector:eu-west-1:357557129151:rulespackage/0-ubA5XvBh",
                    "CIS": "arn:aws:inspector:eu-west-1:357557129151:rulespackage/0-sJBhCr0F",
                    "securityBestPractices": "arn:aws:inspector:eu-west-1:357557129151:rulespackage/0-SnojL3Z6",
                    "runtimeBehaviorAnalysis": "arn:aws:inspector:eu-west-1:357557129151:rulespackage/0-lLmwe1zd"
                },
                "us-east-1": {
                    "CVE": "arn:aws:inspector:us-east-1:316112463485:rulespackage/0-gEjTy7T7",
                    "CIS": "arn:aws:inspector:us-east-1:316112463485:rulespackage/0-rExsr2X8",
                    "securityBestPractices": "arn:aws:inspector:us-east-1:316112463485:rulespackage/0-R01qwB5Q",
                    "runtimeBehaviorAnalysis": "arn:aws:inspector:us-east-1:316112463485:rulespackage/0-gBONHN9h"
                },
                "us-east-2": {
                    "CVE": "arn:aws:inspector:us-east-2:646659390643:rulespackage/0-JnA8Zp85",
                    "CIS": "arn:aws:inspector:us-east-2:646659390643:rulespackage/0-m8r61nnh",
                    "securityBestPractices": "arn:aws:inspector:us-east-2:646659390643:rulespackage/0-AxKmMHPX",
                    "runtimeBehaviorAnalysis": "arn:aws:inspector:us-east-2:646659390643:rulespackage/0-UCYZFKPV"
                },
            }
        )

        resource_group = inspector.CfnResourceGroup(
            scope=self,
            id="CDK test resource group",
            resource_group_tags=[core.CfnTag(key="Inspector", value="true")]
        )
        assessment_target = inspector.CfnAssessmentTarget(
            scope=self,
            id="CDK test assessment target",
            resource_group_arn=resource_group.attr_arn
        )
        assessment_template = inspector.CfnAssessmentTemplate(
            scope=self,
            id="CDK test assessment template",
            assessment_target_arn=assessment_target.attr_arn,
            duration_in_seconds=300,
            rules_package_arns=[
                inspector_rules_mapping.find_in_map(self.region, package) for package in (
                    "CVE", "CIS", "securityBestPractices", "runtimeBehaviorAnalysis"
                )
            ]
        )
        report_function = aws_lambda.Function(
            scope=self,
            id="CDK Inspector test report processor",
            code=aws_lambda.Code.from_asset("report_function"),
            handler="report.lambda_handler",
            runtime=aws_lambda.Runtime.PYTHON_3_7
        )
        topic = sns.Topic(
            scope=self,
            id="CDK Inspector topic"
        )

        topic.add_to_resource_policy(
            statement=iam.PolicyStatement(
                actions=["SNS:Publish"],
                principals=[iam.ArnPrincipal(arn=sns_principals_mapping.find_in_map(self.region, "ARN"))],
                resources=[topic.topic_arn]
            )
        )
        topic.add_subscription(
            subscription=sns_subs.LambdaSubscription(fn=report_function)
        )

        subscriber = InspectorSubscriberCustomResource(
            scope=self,
            id="Inspector SNS Subscriber",
            Template=assessment_template.attr_arn,
            Topic=topic.topic_arn
        )
Ejemplo n.º 21
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        self.current_dir = os.path.dirname(__file__)

        self.bucket = s3.Bucket(
            self,
            "qs-migration-bucket",
            bucket_name=f'quicksight-migration-{core.Aws.ACCOUNT_ID}',
            block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
        )

        self.quicksight_migration_lambda_role = iam.Role(
            self,
            'quicksight-migration-lambda-role',
            description='Role for the Quicksight dashboard migration Lambdas',
            role_name='quicksight-migration-lambda-role',
            max_session_duration=core.Duration.seconds(3600),
            assumed_by=iam.ServicePrincipal('lambda.amazonaws.com'),
            inline_policies={
                'AllowAccess':
                iam.PolicyDocument(statements=[
                    iam.PolicyStatement(
                        effect=iam.Effect.ALLOW,
                        actions=[
                            'logs:CreateLogGroup', 'logs:CreateLogStream',
                            'logs:PutLogEvents'
                        ],
                        resources=[
                            f'arn:aws:logs:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:*'
                        ]),
                    iam.PolicyStatement(
                        effect=iam.Effect.ALLOW,
                        actions=["sts:AssumeRole", "iam:ListRoles"],
                        resources=[
                            "arn:aws:iam::*:role/quicksight-migration-*-assume-role"
                        ]),
                    iam.PolicyStatement(
                        effect=iam.Effect.ALLOW,
                        actions=["s3:PutObject", "s3:ListBucket"],
                        resources=[
                            self.bucket.bucket_arn,
                            f"{self.bucket.bucket_arn}/*"
                        ]),
                    iam.PolicyStatement(
                        effect=iam.Effect.ALLOW,
                        actions=["secrets:GetSecretValue"],
                        resources=[
                            f"arn:aws:secretsmanager:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:secret:*"
                        ]),
                    iam.PolicyStatement(effect=iam.Effect.ALLOW,
                                        actions=[
                                            "quicksight:*",
                                        ],
                                        resources=["*"])
                ])
            })

        # API Gateway to SQS
        self.apigw_sqs = ApiGatewayToSqs(
            self,
            "ApiGatewayToSQSqsMigration",
            allow_create_operation=True,
            allow_read_operation=False,
            allow_delete_operation=False,
            api_gateway_props=apigw.RestApiProps(
                rest_api_name="quicksight-migration-sqs",
                deploy=True,
                default_method_options=apigw.MethodOptions(
                    authorization_type=apigw.AuthorizationType.NONE),
                default_cors_preflight_options=apigw.CorsOptions(
                    allow_origins=apigw.Cors.ALL_ORIGINS,
                    allow_methods=apigw.Cors.ALL_METHODS,
                    allow_headers=[
                        'Access-Control-Allow-Origin',
                        'Access-Control-Allow-Headers', 'Content-Type'
                    ]),
                policy=iam.PolicyDocument(statements=[
                    iam.PolicyStatement(effect=iam.Effect.ALLOW,
                                        actions=['execute-api:Invoke'],
                                        resources=["execute-api:/prod/*"],
                                        principals=[iam.ArnPrincipal("*")])
                ])),
            queue_props=sqs.QueueProps(
                queue_name="quicksight-migration-sqs",
                visibility_timeout=core.Duration.minutes(15)))

        self.quicksight_migration_lambda = _lambda.Function(
            self,
            'quicksight-migration-lambda',
            handler='quicksight_migration.lambda_function.lambda_handler',
            runtime=_lambda.Runtime.PYTHON_3_8,
            code=_lambda.Code.from_asset(
                os.path.join(self.current_dir,
                             '../lambda/quicksight_migration/')),
            function_name='quicksight_migration_lambda',
            role=self.quicksight_migration_lambda_role,
            timeout=core.Duration.minutes(15),
            memory_size=1024,
            environment={
                'BUCKET_NAME': self.bucket.bucket_name,
                'S3_KEY': 'None',
                'INFRA_CONFIG_PARAM': '/infra/config',
                'SQS_URL': self.apigw_sqs.sqs_queue.queue_url
            })

        self.quicksight_migration_lambda.add_event_source(
            event_sources.SqsEventSource(
                enabled=True,
                queue=self.apigw_sqs.sqs_queue,
            ))
Ejemplo n.º 22
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)
        self.current_dir = os.path.dirname(__file__)

        self.website_bucket = s3.Bucket(
            self,
            "qs-embed-bucket",
            bucket_name=f'quicksight-embed-{core.Aws.ACCOUNT_ID}',
            website_index_document="index.html",
            public_read_access=True)

        self.quicksight_embed_lambda_role = iam.Role(
            self,
            'quicksight-embed-lambda-role',
            description='Role for the Quicksight dashboard embed Lambdas',
            role_name='quicksight-embed-lambda-role',
            max_session_duration=core.Duration.seconds(3600),
            assumed_by=iam.ServicePrincipal('lambda.amazonaws.com'),
            inline_policies={
                'AllowAccess':
                iam.PolicyDocument(statements=[
                    iam.PolicyStatement(
                        effect=iam.Effect.ALLOW,
                        actions=[
                            'logs:CreateLogGroup', 'logs:CreateLogStream',
                            'logs:PutLogEvents'
                        ],
                        resources=[
                            f'arn:aws:logs:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:*'
                        ]),
                    iam.PolicyStatement(
                        effect=iam.Effect.ALLOW,
                        actions=["sts:AssumeRole", "iam:ListRoles"],
                        resources=[
                            "arn:aws:iam::*:role/quicksight-migration-*-assume-role"
                        ]),
                    iam.PolicyStatement(
                        effect=iam.Effect.ALLOW,
                        actions=["secrets:GetSecretValue"],
                        resources=[
                            f"arn:aws:secretsmanager:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:secret:*"
                        ]),
                    iam.PolicyStatement(effect=iam.Effect.ALLOW,
                                        actions=[
                                            "quicksight:*",
                                        ],
                                        resources=["*"])
                ])
            })

        self.quicksight_migration_lambda = _lambda.Function(
            self,
            'quicksight-migration-lambda',
            handler='quicksight_embed.lambda_handler',
            runtime=_lambda.Runtime.PYTHON_3_8,
            code=_lambda.Code.from_asset(
                os.path.join(self.current_dir, '../lambda/quicksight_embed/')),
            function_name='quicksight_embed_lambda',
            role=self.quicksight_embed_lambda_role,
            timeout=core.Duration.minutes(3),
            memory_size=512,
            environment={
                'DASHBOARD_ID':
                '938b365e-c001-4723-9a27-029654da7531',
                'QUICKSIGHT_USER_ARN':
                f'arn:aws:quicksight:us-east-1:{core.Aws.ACCOUNT_ID}:user/default/quicksight-migration-user'
            })

        self.apigw_lambda = ApiGatewayToLambda(
            self,
            "ApiGatewayToLambdaQSEmbed",
            existing_lambda_obj=self.quicksight_migration_lambda,
            api_gateway_props=apigw.LambdaRestApiProps(
                rest_api_name="quicksight-embed",
                handler=self.quicksight_migration_lambda,
                deploy=True,
                proxy=False,
                default_method_options=apigw.MethodOptions(
                    authorization_type=apigw.AuthorizationType.NONE),
                default_cors_preflight_options=apigw.CorsOptions(
                    allow_origins=apigw.Cors.ALL_ORIGINS,
                    allow_methods=apigw.Cors.ALL_METHODS,
                    allow_headers=[
                        'Access-Control-Allow-Origin',
                        'Access-Control-Allow-Headers', 'Content-Type'
                    ]),
                policy=iam.PolicyDocument(statements=[
                    iam.PolicyStatement(effect=iam.Effect.ALLOW,
                                        actions=['execute-api:Invoke'],
                                        resources=["execute-api:/prod/*"],
                                        principals=[iam.ArnPrincipal("*")])
                ])))

        self.embedurl = self.apigw_lambda.api_gateway.root.add_resource(
            "embedurl")
        self.embedurl.add_method("GET")
Ejemplo n.º 23
0
    def __init__(self, scope: core.Construct, name: str, vpc: ec2.Vpc,
                 **kwargs) -> None:
        super().__init__(scope, name, **kwargs)

        cluster = eks.Cluster(self,
                              'coscup-jenkins-demo-cluster',
                              vpc=vpc,
                              version=eks.KubernetesVersion.V1_16,
                              default_capacity=0)

        asg_worker_nodes = cluster.add_capacity(
            'worker-node',
            instance_type=ec2.InstanceType('t3a.large'),
            spot_price='0.0936',
            desired_capacity=2)

        asg_jenkins_slave = cluster.add_capacity(
            'worker-node-jenkins-slave',
            instance_type=ec2.InstanceType('t3a.small'),
            spot_price='0.0234',
            desired_capacity=1,
            bootstrap_options=eks.BootstrapOptions(
                kubelet_extra_args=
                '--node-labels jenkins=slave --register-with-taints jenkins=slave:NoSchedule'
            ))

        asg_worker_nodes.connections.allow_from(asg_jenkins_slave,
                                                ec2.Port.all_traffic())
        asg_jenkins_slave.connections.allow_from(asg_worker_nodes,
                                                 ec2.Port.all_traffic())

        eks_master_role = iam.Role(self,
                                   'AdminRole',
                                   assumed_by=iam.ArnPrincipal(
                                       get_eks_admin_iam_username()))

        cluster.aws_auth.add_masters_role(eks_master_role)

        stable_chart = 'https://kubernetes-charts.storage.googleapis.com'

        eks.HelmChart(
            self,
            'jenkins',
            release='jenkins',
            cluster=cluster,
            repository=stable_chart,
            chart='jenkins',
            namespace='jenkins',
            version='2.3.3',
            values={
                'master': {
                    'tag':
                    '2.235.1',
                    'adminPassword':
                    '******',
                    'serviceType':
                    'LoadBalancer',
                    'installPlugins': [
                        'kubernetes:1.26.3', 'git:4.3.0',
                        'workflow-aggregator:2.6', 'credentials-binding:1.23',
                        'workflow-job:2.39', 'configuration-as-code:1.42',
                        'job-dsl:1.77'
                    ],
                    'serviceAnnotations': {
                        'service.beta.kubernetes.io/aws-load-balancer-type':
                        'nlb'
                    },
                    'JCasC': {
                        'enabled': True,
                        'configScripts': {
                            'settings':
                            read_helm_config(
                                'eks_cluster/helm_config/jenkins-jcasc-settings.yaml'
                            )
                        }
                    }
                }
            })

        eks.HelmChart(self,
                      'kube-ops-view',
                      release='kube-ops-view',
                      cluster=cluster,
                      repository=stable_chart,
                      chart='kube-ops-view',
                      namespace='monitor',
                      version='1.2.0',
                      values={
                          'service': {
                              'type': 'LoadBalancer'
                          },
                          'rbac': {
                              'create': True
                          }
                      })

        eks.HelmChart(self,
                      'dummy-service',
                      release='dummy-service',
                      cluster=cluster,
                      repository=stable_chart,
                      chart='kibana',
                      namespace='default',
                      version='3.2.6',
                      values={'replicaCount': '60'})
Ejemplo n.º 24
0
    def __init__(self, scope: cdk.Construct, id: str, s3_bucket: s3.Bucket,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # Define IAM roles and policies

        ecs_task_role = iam.Role(
            self,
            "TaskRole",
            role_name="ConsoleMeTaskRole",
            assumed_by=iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
        )

        ecs_task_role.add_to_policy(
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                actions=[
                    "access-analyzer:*",
                    "cloudtrail:*",
                    "cloudwatch:*",
                    "config:SelectResourceConfig",
                    "config:SelectAggregateResourceConfig",
                    "dynamodb:batchgetitem",
                    "dynamodb:batchwriteitem",
                    "dynamodb:deleteitem",
                    "dynamodb:describe*",
                    "dynamodb:getitem",
                    "dynamodb:getrecords",
                    "dynamodb:getsharditerator",
                    "dynamodb:putitem",
                    "dynamodb:query",
                    "dynamodb:scan",
                    "dynamodb:updateitem",
                    "secretsmanager:GetResourcePolicy",
                    "secretsmanager:GetSecretValue",
                    "secretsmanager:DescribeSecret",
                    "secretsmanager:ListSecretVersionIds",
                    "secretsmanager:ListSecrets",
                    "sns:createplatformapplication",
                    "sns:createplatformendpoint",
                    "sns:deleteendpoint",
                    "sns:deleteplatformapplication",
                    "sns:getendpointattributes",
                    "sns:getplatformapplicationattributes",
                    "sns:listendpointsbyplatformapplication",
                    "sns:publish",
                    "sns:setendpointattributes",
                    "sns:setplatformapplicationattributes",
                    "sts:assumerole",
                ],
                resources=["*"],
            ))

        ecs_task_role.add_to_policy(
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                actions=["ses:sendemail", "ses:sendrawemail"],
                resources=["*"],
            ))

        ecs_task_role.add_to_policy(
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                actions=[
                    "autoscaling:Describe*",
                    "cloudwatch:Get*",
                    "cloudwatch:List*",
                    "config:BatchGet*",
                    "config:List*",
                    "config:Select*",
                    "ec2:DescribeSubnets",
                    "ec2:describevpcendpoints",
                    "ec2:DescribeVpcs",
                    "iam:GetAccountAuthorizationDetails",
                    "iam:ListAccountAliases",
                    "iam:ListAttachedRolePolicies",
                    "ec2:describeregions",
                    "s3:GetBucketPolicy",
                    "s3:GetBucketTagging",
                    "s3:ListAllMyBuckets",
                    "s3:ListBucket",
                    "s3:PutBucketPolicy",
                    "s3:PutBucketTagging",
                    "sns:GetTopicAttributes",
                    "sns:ListTagsForResource",
                    "sns:ListTopics",
                    "sns:SetTopicAttributes",
                    "sns:TagResource",
                    "sns:UnTagResource",
                    "sqs:GetQueueAttributes",
                    "sqs:GetQueueUrl",
                    "sqs:ListQueues",
                    "sqs:ListQueueTags",
                    "sqs:SetQueueAttributes",
                    "sqs:TagQueue",
                    "sqs:UntagQueue",
                ],
                resources=["*"],
            ))

        ecs_task_role.add_to_policy(
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                actions=["s3:GetObject", "s3:ListBucket"],
                resources=[s3_bucket.bucket_arn, s3_bucket.bucket_arn + "/*"],
            ))

        trust_role = iam.Role(
            self,
            "TrustRole",
            role_name="ConsoleMeTrustRole",
            assumed_by=iam.ArnPrincipal(arn=ecs_task_role.role_arn),
        )

        trust_role.add_to_policy(
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                actions=[
                    "access-analyzer:*",
                    "cloudtrail:*",
                    "cloudwatch:*",
                    "config:SelectResourceConfig",
                    "config:SelectAggregateResourceConfig",
                    "dynamodb:batchgetitem",
                    "dynamodb:batchwriteitem",
                    "dynamodb:deleteitem",
                    "dynamodb:describe*",
                    "dynamodb:getitem",
                    "dynamodb:getrecords",
                    "dynamodb:getsharditerator",
                    "dynamodb:putitem",
                    "dynamodb:query",
                    "dynamodb:scan",
                    "dynamodb:updateitem",
                    "sns:createplatformapplication",
                    "sns:createplatformendpoint",
                    "sns:deleteendpoint",
                    "sns:deleteplatformapplication",
                    "sns:getendpointattributes",
                    "sns:getplatformapplicationattributes",
                    "sns:listendpointsbyplatformapplication",
                    "sns:publish",
                    "sns:setendpointattributes",
                    "sns:setplatformapplicationattributes",
                    "sts:assumerole",
                    "autoscaling:Describe*",
                    "cloudwatch:Get*",
                    "cloudwatch:List*",
                    "config:BatchGet*",
                    "config:List*",
                    "config:Select*",
                    "ec2:DescribeSubnets",
                    "ec2:describevpcendpoints",
                    "ec2:DescribeVpcs",
                    "iam:GetAccountAuthorizationDetails",
                    "iam:ListAccountAliases",
                    "iam:ListAttachedRolePolicies",
                    "ec2:describeregions",
                    "s3:GetBucketPolicy",
                    "s3:GetBucketTagging",
                    "s3:ListAllMyBuckets",
                    "s3:ListBucket",
                    "s3:PutBucketPolicy",
                    "s3:PutBucketTagging",
                    "sns:GetTopicAttributes",
                    "sns:ListTagsForResource",
                    "sns:ListTopics",
                    "sns:SetTopicAttributes",
                    "sns:TagResource",
                    "sns:UnTagResource",
                    "sqs:GetQueueAttributes",
                    "sqs:GetQueueUrl",
                    "sqs:ListQueues",
                    "sqs:ListQueueTags",
                    "sqs:SetQueueAttributes",
                    "sqs:TagQueue",
                    "sqs:UntagQueue",
                ],
                resources=["*"],
            ))

        ecs_task_execution_role = iam.Role(
            self,
            "TaskExecutionRole",
            assumed_by=iam.ServicePrincipal("ecs-tasks.amazonaws.com"),
        )

        ecs_task_execution_role.add_managed_policy(
            iam.ManagedPolicy.from_managed_policy_arn(
                self,
                "ServiceRole",
                managed_policy_arn=
                "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy",
            ))

        create_configuration_lambda_role = iam.Role(
            self,
            "CreateConfigurationFileLambdaRole",
            assumed_by=iam.ServicePrincipal(service="lambda.amazonaws.com"),
        )

        create_configuration_lambda_role.add_managed_policy(
            iam.ManagedPolicy.from_managed_policy_arn(
                self,
                "ConfigurationBasicExecution",
                managed_policy_arn=
                "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole",
            ))

        create_configuration_lambda_role.add_to_policy(
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                actions=["s3:PutObject", "s3:DeleteObject"],
                resources=[s3_bucket.bucket_arn + "/*"],
            ))

        self.ecs_task_role = ecs_task_role
        self.ecs_task_execution_role = ecs_task_execution_role
        self.create_configuration_lambda_role = create_configuration_lambda_role