Exemple #1
0
    def map_base_subdomain(self, subdomain: str, api: aws_apigateway.RestApi) -> str:
        """
        Maps a sub-domain of aws.job4u.io to an API gateway

        :param subdomain: The sub-domain (e.g. "www")
        :param api: The API gateway endpoint
        :return: The base url (e.g. "https://www.aws.job4u.io")
        """
        domain_name = subdomain + '.' + ZONE_NAME
        url = 'https://' + domain_name

        cert = aws_certificatemanager.Certificate.from_certificate_arn(self, 'DomainCertificate', ZONE_CERT)
        hosted_zone = aws_route53.HostedZone.from_hosted_zone_attributes(self, 'HostedZone',
                                                                         hosted_zone_id=ZONE_ID,
                                                                         zone_name=ZONE_NAME)

        # add the domain name to the api and the A record to our hosted zone
        domain = api.add_domain_name('Domain', certificate=cert, domain_name=domain_name)

        aws_route53.ARecord(
            self, 'UrlShortenerDomain',
            record_name=subdomain,
            zone=hosted_zone,
            target=aws_route53.RecordTarget.from_alias(aws_route53_targets.ApiGatewayDomain(domain)))

        return url
Exemple #2
0
    def __init__(self, scope: core.App, id: str, props: DomainStackProps,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        domain = apigw.DomainName(
            self,
            "domain",
            domain_name=props.domain_name,
            certificate=acm.Certificate.from_certificate_arn(
                self, 'cert', props.certificate_arn),
            endpoint_type=apigw.EndpointType.REGIONAL,
        )
        self.domain = domain

        route53.ARecord(self,
                        "AliasRecord",
                        zone=route53.HostedZone.from_lookup(
                            self, 'zone', domain_name=props.domain_name),
                        target=route53.RecordTarget.from_alias(
                            route53_targets.ApiGatewayDomain(domain)))
Exemple #3
0
    def __init__(self, scope: core.Construct, id: str, **kwargs):
        super().__init__(scope, id, **kwargs)

        # note assumption zone is named after domain
        hosted_zone = route53.HostedZone.from_hosted_zone_attributes(
            self,
            "HostedZone",
            hosted_zone_id=startuptoolbag_config.hosted_zone_id,
            zone_name=startuptoolbag_config.website_domain_name)

        # SSL/TLS Certificate
        # https://github.com/aws/aws-cdk/pull/8552
        # Experimental vs 'Certificate' (which requires validation in the console)
        tls_cert = certificatemanager.DnsValidatedCertificate(
            self,
            "SiteCertificate",
            hosted_zone=hosted_zone,
            domain_name=f'*.{startuptoolbag_config.website_domain_name}',
            subject_alternative_names=[
                startuptoolbag_config.website_domain_name
            ],
            region='us-east-1',
        )

        # Import the bucket that was created outside the stack
        self.www_site_bucket = s3.Bucket.from_bucket_name(
            self, 'SiteBucket', core.Fn.import_value("WWWSITEBUCKETNAME"))

        # CloudFront distribution that provides HTTPS - for www
        www_alias_configuration = cloudfront.AliasConfiguration(
            acm_cert_ref=tls_cert.certificate_arn,
            names=[f'www.{startuptoolbag_config.website_domain_name}'],
            ssl_method=cloudfront.SSLMethod.SNI,
            security_policy=cloudfront.SecurityPolicyProtocol.TLS_V1_1_2016)

        www_source_configuration = cloudfront.SourceConfiguration(
            s3_origin_source=cloudfront.S3OriginConfig(
                s3_bucket_source=self.www_site_bucket),
            behaviors=[cloudfront.Behavior(is_default_behavior=True)])

        www_distribution = cloudfront.CloudFrontWebDistribution(
            self,
            'SiteDistribution',
            alias_configuration=www_alias_configuration,
            origin_configs=[www_source_configuration])

        route53.ARecord(
            self,
            'CloudFrontARecord',
            zone=hosted_zone,
            record_name=
            f'www.{startuptoolbag_config.website_domain_name}',  #site domain
            target=aws_route53.RecordTarget.from_alias(
                aws_route53_targets.CloudFrontTarget(www_distribution)))

        # NAKED site bucket which redirects to naked to www
        redirect = aws_route53_patterns.HttpsRedirect(
            self,
            'NakedRedirect',
            record_names=[startuptoolbag_config.website_domain_name],
            target_domain=f'www.{startuptoolbag_config.website_domain_name}',
            zone=hosted_zone,
            certificate=tls_cert)

        # Create the API Gateway
        self.rest_api = aws_apigateway.RestApi(self,
                                               'RestApiGateway',
                                               deploy=False)
        api_domain_name = f'api.{startuptoolbag_config.website_domain_name}'
        domain = self.rest_api.add_domain_name('APIDomain',
                                               certificate=tls_cert,
                                               domain_name=api_domain_name)

        route53.ARecord(
            self,
            'APIGWAliasRecord',
            zone=hosted_zone,
            record_name=api_domain_name,  #site domain
            target=aws_route53.RecordTarget.from_alias(
                aws_route53_targets.ApiGatewayDomain(domain)))
    def __init__(self, scope: core.Construct, id: str, cert_arn,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # The code that defines your stack goes here

        # -- Lambda function
        my_function = _lambda.Function(
            self,
            "MyFunction",
            code=_lambda.Code.from_asset("dist"),
            handler="myfunction",
            runtime=_lambda.Runtime.GO_1_X,
            log_retention=aws_logs.RetentionDays.ONE_WEEK,
            memory_size=128,
            events=[],
        )

        # -- API Gateway
        my_api = apigateway.RestApi(self, "MyApi")

        myfunction_integration = apigateway.LambdaIntegration(my_function)

        test_resource = my_api.root.add_resource("test")
        test_resource.add_method("GET", myfunction_integration)

        # -- DNS Configuration
        # Get the Route53 Zone
        dns_zone = route53.HostedZone.from_lookup(self,
                                                  "ApiZone",
                                                  private_zone=False,
                                                  domain_name="zoolite.eu")

        # Get the certificate
        api_domain_cert = certificatemanager.Certificate.from_certificate_arn(
            self, "DomainCertificate", cert_arn)

        # Create the Custom Domain
        api_dns_name = apigateway.DomainName(
            self,
            "ApiDomainName",
            domain_name="my-api.zoolite.eu",
            endpoint_type=apigateway.EndpointType.REGIONAL,
            certificate=api_domain_cert,
            security_policy=apigateway.SecurityPolicy.TLS_1_2)

        #api_dns_name.add_base_path_mapping(my_api, base_path="test")
        api_dns_name.add_base_path_mapping(my_api)

        # Create the Route53 record
        api_dns_record = route53.ARecord(
            self,
            "MyAPiDNSRecord",
            target=route53.RecordTarget.from_alias(
                route53_targets.ApiGatewayDomain(api_dns_name)),
            record_name="my-api",
            zone=dns_zone)

        # Configure latency based routing on record
        recordset = api_dns_record.node.default_child
        recordset.region = self.region
        recordset.set_identifier = api_dns_record.node.unique_id
Exemple #5
0
    def __init__(self, scope: core.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        core.Tags.of(self).add("Project", "Blog")

        core_layer = lambda_.LayerVersion(
            self,
            "blog-core-layer",
            code=lambda_.Code.from_asset("lambda/core_layer"),
            compatible_runtimes=[lambda_.Runtime.PYTHON_3_8]
        )

        proxy_fn = lambda_.Function(
            self,
            "blog-proxy-fn",
            runtime=lambda_.Runtime.PYTHON_3_8,
            handler="lambda_function.handler",
            code=lambda_.Code.from_asset("lambda/proxy"),
            layers=[core_layer]
        )

        proxy_fn_integration = apigw.LambdaIntegration(proxy_fn)

        domain_name = apigw.DomainName(
            self,
            "blog-api-domain-name",
            domain_name="api.juliuskrahn.com",
            certificate=cm.Certificate.from_certificate_arn(
                self,
                "blog-domain-name-certificate",
                "arn:aws:acm:us-east-1:473883619336:certificate/1ad12871-4b46-44ef-a24d-7af5ac43972b"
            ),
            endpoint_type=apigw.EndpointType.EDGE
        )

        api = apigw.RestApi(
            self,
            "blog-api",
            default_cors_preflight_options=apigw.CorsOptions(
                allow_origins=apigw.Cors.ALL_ORIGINS,
                allow_methods=apigw.Cors.ALL_METHODS
            ),
            default_integration=proxy_fn_integration
        )

        domain_name.add_base_path_mapping(api)

        route53.ARecord(
            self,
            "blog-api-a-record",
            record_name="api",
            target=route53.RecordTarget.from_alias(route53_targets.ApiGatewayDomain(domain_name)),
            zone=route53.HostedZone.from_lookup(self, "blog-hosted-zone", domain_name="juliuskrahn.com")
        )

        api.root.add_proxy()

        article_table = dynamodb.Table(
            self,
            "blog-article-table",
            table_name="blog-article",
            partition_key=dynamodb.Attribute(name="urlTitle", type=dynamodb.AttributeType.STRING),
            billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST,
            point_in_time_recovery=True
        )

        article_table.add_global_secondary_index(
            index_name="tagIndex",
            partition_key=dynamodb.Attribute(name="tag", type=dynamodb.AttributeType.STRING),
            sort_key=dynamodb.Attribute(name="published", type=dynamodb.AttributeType.STRING),
            projection_type=dynamodb.ProjectionType.INCLUDE,
            non_key_attributes=["urlTitle", "title", "description"]
        )

        article_table.grant_read_write_data(proxy_fn)

        comment_table = dynamodb.Table(
            self,
            "blog-comment-table",
            table_name="blog-comment",
            partition_key=dynamodb.Attribute(name="articleUrlTitle", type=dynamodb.AttributeType.STRING),
            sort_key=dynamodb.Attribute(name="id", type=dynamodb.AttributeType.STRING),
            billing_mode=dynamodb.BillingMode.PAY_PER_REQUEST
        )

        comment_table.grant_read_write_data(proxy_fn)

        admin_key_secret = sm.Secret(
            self,
            "blog-admin-key",
            secret_name="blog-admin-key"
        )

        admin_key_secret.grant_read(proxy_fn)
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # set variables for site s3 bucket
        bucket_name = DOMAIN_WEBSITE['bucket_name']
        website_index = DOMAIN_WEBSITE['website_index']
        website_error = DOMAIN_WEBSITE['website_error']
        website_code_folder = DOMAIN_WEBSITE['website_code_folder']
        site_domain = DOMAIN_WEBSITE['site_domain']
        certificate_domain = DOMAIN_WEBSITE['certificate_domain']
        api_domain = DOMAIN_WEBSITE['api_domain']
        hosted_zone_name = DOMAIN_WEBSITE['hosted_zone_name']
        hosted_zone_id = DOMAIN_WEBSITE['hosted_zone_id']

        #self.lambda_code = aws_lambda.Code.from_cfn_parameters()

        # retrieve hosted zone
        hosted_zone = aws_route53.HostedZone.from_hosted_zone_attributes(
            self,
            'hostedZone',
            hosted_zone_id=hosted_zone_id,
            zone_name=hosted_zone_name)

        # set variables for backend
        lambda_code_location = "jukebike/backend/"

        # Construct code goes here
        CfnOutput(self, "Site", value=f"https://{site_domain}")

        # Content bucket
        site_bucket = aws_s3.Bucket(self,
                                    "websitebucket",
                                    bucket_name=bucket_name,
                                    website_index_document=website_index,
                                    website_error_document=website_error,
                                    public_read_access=True,
                                    removal_policy=RemovalPolicy.DESTROY)
        CfnOutput(self, "BucketArn", value=site_bucket.bucket_arn)
        CfnOutput(self, "WebsiteUrl", value=site_bucket.bucket_website_url)

        # Certificate
        cert = aws_certificatemanager.DnsValidatedCertificate(
            self,
            "certificate_website",
            domain_name=site_domain,
            hosted_zone=hosted_zone,
            region="us-east-1")
        CfnOutput(self, 'CertificateArn', value=cert.certificate_arn)

        distr = CloudFrontWebDistribution(
            self,
            "SiteDistribution",
            alias_configuration=AliasConfiguration(
                acm_cert_ref=cert.certificate_arn,
                names=[site_domain],
                ssl_method=aws_cloudfront.SSLMethod.SNI,
                security_policy=aws_cloudfront.SecurityPolicyProtocol.
                TLS_V1_1_2016,
            ),
            origin_configs=[
                SourceConfiguration(
                    s3_origin_source=aws_cloudfront.S3OriginConfig(
                        s3_bucket_source=site_bucket),
                    behaviors=[
                        aws_cloudfront.Behavior(is_default_behavior=True)
                    ])
            ])
        CfnOutput(self, "DistributionId", value=distr.distribution_id)
        #
        # Route 53 alias record for the cloudfront distribution
        aws_route53.ARecord(self,
                            "SiteAliasRecord",
                            zone=hosted_zone,
                            target=aws_route53.AddressRecordTarget.from_alias(
                                aws_route53_targets.CloudFrontTarget(distr)),
                            record_name=site_domain)

        aws_s3_deployment.BucketDeployment(
            self,
            "DeployWithInvalidation",
            sources=[aws_s3_deployment.Source.asset(website_code_folder)],
            destination_bucket=site_bucket,
            distribution=distr,
            distribution_paths=["/*"])

        ########################### Backend #################

        certificate = aws_certificatemanager.DnsValidatedCertificate(
            self,
            "domaincertificate",
            hosted_zone=hosted_zone,
            region='us-east-1',
            domain_name=certificate_domain,
            validation_method=aws_certificatemanager.ValidationMethod.DNS)

        ############# Search API ###################

        search_lambda = aws_lambda.Function(
            self,
            "SearchLambda",
            code=aws_lambda.Code.from_asset(lambda_code_location),
            handler="search.handler",
            runtime=aws_lambda.Runtime.PYTHON_3_7)

        CfnOutput(self, "SearchLambda_", value=search_lambda.function_arn)

        search_api = aws_apigateway.LambdaRestApi(
            self,
            'SearchSpotifyEndpoint',
            handler=search_lambda,
        )

        ############# Whats-Next API ###################
        whats_next_lambda = aws_lambda.Function(
            self,
            "WhatsNextLambda",
            code=aws_lambda.Code.from_asset(lambda_code_location),
            handler="whats_next.handler",
            runtime=aws_lambda.Runtime.PYTHON_3_7)
        CfnOutput(self,
                  "WhatsNextLambda_",
                  value=whats_next_lambda.function_arn)

        whats_next_api = aws_apigateway.LambdaRestApi(
            self,
            'WhatsNextEndpoint',
            handler=whats_next_lambda,
        )

        ############# Whats-Next API ###################
        wish_track_lambda = aws_lambda.Function(
            self,
            "WishTrackLambda",
            code=aws_lambda.Code.from_asset(lambda_code_location),
            handler="wish_track.handler",
            runtime=aws_lambda.Runtime.PYTHON_3_7)
        CfnOutput(self,
                  "WishTrackLambda_",
                  value=wish_track_lambda.function_arn)

        wish_track_api = aws_apigateway.LambdaRestApi(
            self,
            'WishTrackEndpoint',
            handler=wish_track_lambda,
        )

        ################## Publish APIS with custom domain name ##############
        # Pre-Requirements:
        # [Manual] 1) Registered Domain with Route 53 (e.g. jacubasch.com)
        # 2) Certificate in North Virgina for domain (e.g. api.jacubasch.com) -> AWS Certification Manager
        # 3) API Gateway Custom Domain with Edge
        # 4) Alias-Record in Route53 forwarding to Cloudfront Target Domain Name (can be found in API Gateway)
        # TODO: in separaten Base-Stack auslagern?
        # https://medium.com/@maciejtreder/custom-domain-in-aws-api-gateway-a2b7feaf9c74

        domain = aws_apigateway.DomainName(
            self,
            'searchDomain',
            certificate=certificate,
            endpoint_type=aws_apigateway.EndpointType.EDGE,
            domain_name=api_domain)
        domain.add_base_path_mapping(target_api=search_api, base_path="search")
        domain.add_base_path_mapping(target_api=whats_next_api,
                                     base_path="whats-next")
        domain.add_base_path_mapping(target_api=wish_track_api,
                                     base_path="wish-track")

        target = aws_route53_targets.ApiGatewayDomain(domain)
        record_target = aws_route53.RecordTarget.from_alias(target)
        alias_record = aws_route53.ARecord(self,
                                           'aliasRecord',
                                           target=record_target,
                                           record_name=api_domain,
                                           zone=hosted_zone)

        CfnOutput(self, "AliasRecord_", value=alias_record.to_string())

        ################## Dynamo DB ##############

        # create dynamo table
        track_table = aws_dynamodb.Table(
            self,
            "track_table",
            partition_key=aws_dynamodb.Attribute(
                name="track_uri", type=aws_dynamodb.AttributeType.STRING))

        # grant permission to lambda  & provide environment variable
        track_table.grant_write_data(wish_track_lambda)
        wish_track_lambda.add_environment("TRACK_TABLE_NAME",
                                          track_table.table_name)

        track_table.grant_read_write_data(whats_next_lambda)
        whats_next_lambda.add_environment("TRACK_TABLE_NAME",
                                          track_table.table_name)
Exemple #7
0
    def __init__(self, scope: core.Construct, id: str, redirect_handler, create_handler, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        base_api = api_gw.RestApi(
            scope=self,
            id='ShortenURLAPI',
            rest_api_name='dev-url-shortener-api',
            deploy=True,
            deploy_options=api_gw.StageOptions(stage_name='devShortenURL')
        )

        # shortenUrl
        shorten_url = base_api.root.add_resource('shortenUrl')

        shorten_url_responses = [
            api_gw.MethodResponse(
                status_code='200',
                response_models={"application/json": api_gw.Model.EMPTY_MODEL},
                response_parameters={'method.response.header.Access-Control-Allow-Origin': True}
            ),
            api_gw.MethodResponse(
                status_code='500',
                response_models={"application/json": api_gw.Model.ERROR_MODEL},
            )
        ]
        shorten_url_lambda_integration = api_gw.LambdaIntegration(
            handler=create_handler,
            request_templates={"application/json": '{ "statusCode": "200" }'},
            integration_responses=[
                api_gw.IntegrationResponse(
                    status_code='200',
                    response_templates={'application/json': ''}
                )
            ]
        )
        shorten_url.add_method(
            http_method='POST',
            api_key_required=False,
            integration=shorten_url_lambda_integration,
            method_responses=shorten_url_responses
        )

        shorten_url_integration_mock = api_gw.MockIntegration(
            request_templates={"application/json": json.dumps({"statusCode": 200})},
            integration_responses=[
                api_gw.IntegrationResponse(
                    status_code='200',
                    response_templates={'application/json': ''},
                    response_parameters={
                        "method.response.header.Access-Control-Allow-Methods": "'OPTIONS,POST'",
                        "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": "'*'",
                    },
                )
            ],
            passthrough_behavior=api_gw.PassthroughBehavior.WHEN_NO_MATCH
        )
        shorten_url_mock_reponses = api_gw.MethodResponse(
            status_code='200',
            response_models={
                "application/json": api_gw.Model.EMPTY_MODEL
            },
            response_parameters={
                "method.response.header.Access-Control-Allow-Methods": True,
                "method.response.header.Access-Control-Allow-Headers": True,
                "method.response.header.Access-Control-Allow-Origin": True
            }
        )
        shorten_url.add_method(
            http_method='OPTIONS',
            integration=shorten_url_integration_mock,
            method_responses=[shorten_url_mock_reponses]
        )

        # {id}
        id_url = base_api.root.add_resource("{id}")

        id_url_responses = [
            api_gw.MethodResponse(
                status_code='200',
                response_models={"application/json": api_gw.Model.EMPTY_MODEL},
                response_parameters={'method.response.header.Access-Control-Allow-Origin': True}
            )
        ]
        id_url_lambda_integration = api_gw.LambdaIntegration(
            handler=redirect_handler,
            request_templates={"application/json": '{ "statusCode": "200" }'},
            integration_responses=[
                api_gw.IntegrationResponse(
                    status_code='200',
                    response_templates={'application/json': ''}
                )
            ]
        )
        id_url.add_method(
            http_method='GET',
            integration=id_url_lambda_integration,
            method_responses=id_url_responses,
            request_parameters={'method.request.path.proxy': True}
        )

        id_url_integration_mock = api_gw.MockIntegration(
            request_templates={"application/json": json.dumps({"statusCode": 200})},
            integration_responses=[
                api_gw.IntegrationResponse(
                    status_code='200',
                    response_templates={'application/json': ''},
                    response_parameters={
                        "method.response.header.Access-Control-Allow-Methods": "'DELETE,GET,HEAD,OPTIONS,PATCH,POST,PUT'",
                        "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": "'*'",
                    },
                )
            ],
            passthrough_behavior=api_gw.PassthroughBehavior.WHEN_NO_MATCH
        )
        id_url_mock_responses = api_gw.MethodResponse(
            status_code='200',
            response_models={
                "application/json": api_gw.Model.EMPTY_MODEL
            },
            response_parameters={
                "method.response.header.Access-Control-Allow-Methods": True,
                "method.response.header.Access-Control-Allow-Headers": True,
                "method.response.header.Access-Control-Allow-Origin": True
            }
        )
        id_url.add_method(
            http_method='OPTIONS',
            integration=id_url_integration_mock,
            method_responses=[id_url_mock_responses]
        )

        # Create custom domain mapping API
        sel_cert_arn = "arn:aws:acm:ap-northeast-2:111111111111:certificate/b1111bf5-ae1b-1f61-a111-f1d839428f5f"
        apigw_domain = base_api.add_domain_name(
            id='ShortenURLIDCustomDomain',
            certificate=_acm.Certificate.from_certificate_arn(
                scope=self,
                id="ShortenURLIDCert",
                certificate_arn=sel_cert_arn
            ),
            security_policy=api_gw.SecurityPolicy.TLS_1_2,
            domain_name='s.cloudopz.co'
        )

        dev_hosted_zone = 'A11AA1A1A1AAAA'
        hz_dev = _route53.HostedZone.from_hosted_zone_attributes(
            self, id="ShortenURLHostedZoneDev", hosted_zone_id=dev_hosted_zone, zone_name='cloudopz.co')

        _route53.ARecord(
            self, 'ShortenURLRoute53',
            record_name='s',
            zone=hz_dev,
            target=_route53.RecordTarget.from_alias(_route53_target.ApiGatewayDomain(apigw_domain))
        )
Exemple #8
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # Setting up a salck bot Lambda function
        bot_handler = aws_lambda.Function(
            self,
            "HitterBot",
            runtime=aws_lambda.Runtime.GO_1_X,
            handler="main",
            timeout=core.Duration.seconds(900),
            memory_size=2048,
            code=aws_lambda.AssetCode(path="./lambda"))

        # Creating Mutex Table in DynamoDB
        mutex_table = aws_dynamodb.Table(
            self,
            "HitterMutexTable",
            partition_key=aws_dynamodb.Attribute(
                name="ID", type=aws_dynamodb.AttributeType.STRING),
            billing_mode=aws_dynamodb.BillingMode.PAY_PER_REQUEST,
            time_to_live_attribute="TTL",
            removal_policy=core.RemovalPolicy.DESTROY,
        )

        # Creating URL Table in DynamoDB
        url_table = aws_dynamodb.Table(
            self,
            "HitterURLTable",
            partition_key=aws_dynamodb.Attribute(
                name="ID", type=aws_dynamodb.AttributeType.STRING),
            billing_mode=aws_dynamodb.BillingMode.PAY_PER_REQUEST,
            time_to_live_attribute="TTL",
            removal_policy=core.RemovalPolicy.DESTROY,
        )

        # Creating a bucket to be used in a Pre-Signed URL
        bucket = aws_s3.Bucket(
            self,
            "HitterS3",
            removal_policy=core.RemovalPolicy.RETAIN,
            block_public_access=aws_s3.BlockPublicAccess.BLOCK_ALL,
        )

        # Configuring the S3 Lifecycle
        bucket.add_lifecycle_rule(expiration=core.Duration.days(2))

        # Setting permission to the salck bot Lambda function
        mutex_table.grant_read_write_data(bot_handler)
        url_table.grant_read_write_data(bot_handler)
        bucket.grant_put(bot_handler)
        bucket.grant_read(bot_handler)
        bot_handler.add_to_role_policy(
            aws_iam.PolicyStatement(
                resources=["*"],
                actions=[
                    "comprehend:BatchDetectDominantLanguage",
                    "translate:TranslateText"
                ]))

        # Setting environment variables to the salck bot Lambda function
        bot_handler.add_environment('SLACK_OAUTH_ACCESS_TOKEN',
                                    SLACK_OAUTH_ACCESS_TOKEN)
        bot_handler.add_environment('SLACK_VERIFICATION_TOKEN',
                                    SLACK_VERIFICATION_TOKEN)
        bot_handler.add_environment('MUTEX_TABLE_NAME', mutex_table.table_name)
        bot_handler.add_environment('URL_TABLE_NAME', url_table.table_name)
        bot_handler.add_environment('S3_BUCKET_NAME', bucket.bucket_name)
        bot_handler.add_environment('DEBUG_LOG', "false")

        # Creating an API Gateway for a slack bot
        bot_api = aws_apigateway.LambdaRestApi(self,
                                               "HitterBotAPI",
                                               handler=bot_handler)

        # Only once for the hosted zone.
        hosted_zone = aws_route53.HostedZone.from_hosted_zone_attributes(
            self,
            'HitterHostedZone',
            hosted_zone_id=ZONE_ID,
            zone_name=ZONE_NAME)

        # Set the domain for a bot
        bot_subdomain = "hitter"
        bot_domain_name = bot_subdomain + '.' + ZONE_NAME

        # Using AWS ACM to create a certificate for a bot
        bot_cert = aws_certificatemanager.DnsValidatedCertificate(
            self,
            'HitterBotCertificate',
            domain_name=bot_domain_name,
            hosted_zone=hosted_zone)

        # Add the domain name to the api and the A record to our hosted zone for a bot
        bot_domain = bot_api.add_domain_name('HitterBotDomain',
                                             certificate=bot_cert,
                                             domain_name=bot_domain_name)

        # Set the A record for a bot
        aws_route53.ARecord(
            self,
            'HitterBotARecord',
            record_name=bot_subdomain,
            zone=hosted_zone,
            target=aws_route53.RecordTarget.from_alias(
                aws_route53_targets.ApiGatewayDomain(bot_domain)))

        # Setting up Short URL Lambda function
        short_url_handler = aws_lambda.Function(
            self,
            "HitterShortURL",
            runtime=aws_lambda.Runtime.GO_1_X,
            handler="main",
            timeout=core.Duration.seconds(900),
            memory_size=128,
            code=aws_lambda.AssetCode(path="./lambda_api"))

        # Setting environment variables to the Short URL Lambda function
        url_table.grant_read_data(short_url_handler)

        # Setting environment variables to the salck bot Lambda function
        short_url_handler.add_environment('URL_TABLE_NAME',
                                          url_table.table_name)
        short_url_handler.add_environment('DEBUG_LOG', "false")

        # Creating an API Gateway for a Short URL
        short_url_api = aws_apigateway.LambdaRestApi(self,
                                                     "HitterShortURLAPI",
                                                     handler=short_url_handler)

        # Set the domain for a Short URL
        short_url_subdomain = "sl"
        short_url_domain_name = short_url_subdomain + '.' + ZONE_NAME
        short_url = 'https://' + short_url_domain_name

        # Using AWS ACM to create a certificate for a Short URL
        short_url_cert = aws_certificatemanager.DnsValidatedCertificate(
            self,
            'HitterShortURLCertificate',
            domain_name=short_url_domain_name,
            hosted_zone=hosted_zone)

        # Add the domain name to the api and the A record to our hosted zone for a Short URL
        short_url_domain = short_url_api.add_domain_name(
            'HitterShortURLDomain',
            certificate=short_url_cert,
            domain_name=short_url_domain_name)

        # Set the A record for a Short URL
        aws_route53.ARecord(
            self,
            'HitterShortURLARecord',
            record_name=short_url_subdomain,
            zone=hosted_zone,
            target=aws_route53.RecordTarget.from_alias(
                aws_route53_targets.ApiGatewayDomain(short_url_domain)))

        # Set the URL of the API Gateway to receive the shortened URL to an environment variable.
        bot_handler.add_environment('API_BASE_URL', short_url)
    def __init__(self, scope: cdk.Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # Create a Lambda function
        # Code in ./src directory
        lambda_fn = lambda_.Function(
            self, "MyFunction",
            runtime=lambda_.Runtime.PYTHON_3_9,
            handler="index.handler",
            code=lambda_.Code.from_asset(os.path.join(DIRNAME, "src"))
        )
        #Input parameter for custom domain name created for API Gateway, ex: apis.example.com
        custom_domain_name = cdk.CfnParameter(self, "customdomainname", type="String",
        description="The custom domain name for AWS REST API Gateway")

        #Input parameter for ACM certificate arn
        certificate_arn = cdk.CfnParameter(self, "certificatearn", type="String",
        description="The ACM certificate ARN for custom domain name")

        #Input parameter for s3 bucket name that has truststore pem file
        truststore_bucket = cdk.CfnParameter(self, "truststorebucket", type="String",
        description="The S3 trustsore uri for custom domain name")

        #Input parameter for public hosted zone id
        public_zone_id = cdk.CfnParameter(self, "publiczoneid", type="String",
        description="The public hosted zone id to create a record for custom domain name")

        #Input parameter for public hosted zone id
        public_zone_name = cdk.CfnParameter(self, "publiczonename", type="String",
        description="The public hosted zone name to create a record for custom domain name")

        # Create the Rest API
        rest_api = apigateway.RestApi(
            self, "TLSRestAPI",
            endpoint_types=[apigateway.EndpointType.REGIONAL],
            description="RestAPI Gateway to verify mutual TLS",
            deploy=False,
            retain_deployments=False,
            disable_execute_api_endpoint=True
        )

        # Create the custom domain
        api_domain = apigateway.DomainName(
            self, "MyDomainName",
            domain_name=custom_domain_name.value_as_string,
            certificate=acm.Certificate.from_certificate_arn(self, "cert", certificate_arn.value_as_string),
            mtls=apigateway.MTLSConfig(
                bucket=s3.Bucket.from_bucket_name(self, "Bucket", truststore_bucket.value_as_string),
                key="/truststore.pem"
            ),
            security_policy=apigateway.SecurityPolicy.TLS_1_2
        )

        # Create API deployment
        deployment = apigateway.Deployment(
            self, "Deployment",
            api=rest_api,
            retain_deployments=False
        )

        # Create prod Stage for deployment
        stage = apigateway.Stage(
            self, "prod",
            deployment=deployment,
        )

        # Create API mapping to custom domain
        base_path_mapping = apigateway.BasePathMapping(self, "MyBasePathMapping",
            domain_name=api_domain,
            rest_api=rest_api,
            stage=stage
        )

        #Get public hosted zone object
        public_zone = route53.HostedZone.from_hosted_zone_attributes(self, "publiczone", hosted_zone_id=public_zone_id.value_as_string,zone_name=public_zone_name.value_as_string)

        #Create A record for custom domain name in public hosted zone
        #Record name will be taken from custom domain name, ex: for apis.example.com, record name will be apis
        record = route53.ARecord(self, 'MyAliasRecord',
            zone=public_zone,
            record_name=cdk.Fn.select(0,cdk.Fn.split('.',custom_domain_name.value_as_string)),
            target=route53.RecordTarget.from_alias(targets.ApiGatewayDomain(api_domain))
        )

        rest_api.deployment_stage = stage

        # Create URI for lambda function
        stage_uri = f"arn:aws:apigateway:{cdk.Aws.REGION}:lambda:path/2015-03-31/functions/{lambda_fn.function_arn}/invocations"

        # Create Lambda Integration
        integration = apigateway.Integration(
            type=apigateway.IntegrationType.AWS_PROXY,
            integration_http_method="POST",
            uri=stage_uri
        )

        # Create APIGW Method
        method = rest_api.root.add_method("GET", integration)

        # Add Lambda permissions
        lambda_fn.add_permission(
            "lambdaPermission",
            action="lambda:InvokeFunction",
            principal=iam.ServicePrincipal("apigateway.amazonaws.com"),
            source_arn=method.method_arn.replace(
                rest_api.deployment_stage.stage_name, "*"
            )
        )

        # OUTPUTS
        cdk.CfnOutput(self, "LambdaFunction", export_name="MyLambdaFunction", value=lambda_fn.function_arn)
        cdk.CfnOutput(self, "ApigwId", export_name="MyAPIGWID", value=rest_api.rest_api_id)
        cdk.CfnOutput(self, "CustomDomainName", export_name="MyCustomDomain", value=api_domain.domain_name)
        cdk.CfnOutput(self, "CustomDomainHostedZone", export_name="MyCustomeZone", value=api_domain.domain_name_alias_hosted_zone_id)
        cdk.CfnOutput(self, "CustomDomainAlias", export_name="MyCustomAlias", value=api_domain.domain_name_alias_domain_name)