Пример #1
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        api_log_group = cwlogs.LogGroup(self, "HelloWorldAPILogs")

        # Create the api gateway for this lambda set
        self.target_api = apigw.RestApi(
            self,
            'HelloWorldAPI',
            rest_api_name='HelloWorld',
            endpoint_types=[apigw.EndpointType.REGIONAL],
            deploy_options={
                "access_log_destination":
                apigw.LogGroupLogDestination(api_log_group),
                "access_log_format":
                apigw.AccessLogFormat.clf(),
                "method_options": {
                    "/*/*":
                    {  # This special path applies to all resource paths and all HTTP methods
                        "throttling_rate_limit": 100,
                        "throttling_burst_limit": 200
                    }
                }
            })

        hello_world = py_lambda.PythonFunction(
            self,
            "HelloWorld",
            entry='thewafapigateway/lambda_fns',
            index='helloworld.py',
            handler='lambda_handler',
            description='Helloworld',
            timeout=core.Duration.seconds(60))

        entity = self.target_api.root.add_resource('helloworld')
        this_lambda_integration = apigw.LambdaIntegration(
            hello_world,
            proxy=False,
            integration_responses=[{
                'statusCode': '200',
                'responseParameters': {
                    'method.response.header.Access-Control-Allow-Origin':
                    "'*'",
                }
            }])
        method = entity.add_method(
            'GET',
            this_lambda_integration,
            method_responses=[{
                'statusCode': '200',
                'responseParameters': {
                    'method.response.header.Access-Control-Allow-Origin': True,
                }
            }])

        self.resource_arn = f"arn:aws:apigateway:ap-southeast-2::/restapis/{self.target_api.rest_api_id}/stages/{self.target_api.deployment_stage.stage_name}"
Пример #2
0
    def __init__(self, scope: core.Construct, id: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        api_log_group = cw_logs.LogGroup(self, "HelloWorldAPILogs")

        # Create the api gateway for this lambda set
        self.target_api = api_gw.RestApi(
            self,
            'HelloWorldAPI',
            rest_api_name='HelloWorld',
            endpoint_types=[api_gw.EndpointType.REGIONAL],
            deploy_options=api_gw.StageOptions(
                access_log_destination=api_gw.LogGroupLogDestination(
                    api_log_group),
                access_log_format=api_gw.AccessLogFormat.clf(),
                method_options={
                    # This special path applies to all resource paths and all HTTP methods
                    "/*/*":
                    api_gw.MethodDeploymentOptions(throttling_rate_limit=100,
                                                   throttling_burst_limit=200)
                }))

        hello_world = _lambda.Function(
            self,
            "HelloWorld",
            runtime=_lambda.Runtime.PYTHON_3_8,
            handler='helloworld.lambda_handler',
            code=_lambda.Code.from_asset("lambda_fns"),
            timeout=core.Duration.seconds(60))

        entity = self.target_api.root.add_resource('helloworld')
        this_lambda_integration = api_gw.LambdaIntegration(
            hello_world,
            proxy=False,
            integration_responses=[
                api_gw.IntegrationResponse(
                    status_code='200',
                    response_parameters={
                        'method.response.header.Access-Control-Allow-Origin':
                        "'*'"
                    })
            ])
        entity.add_method(
            'GET',
            this_lambda_integration,
            method_responses=[
                api_gw.MethodResponse(
                    status_code='200',
                    response_parameters={
                        'method.response.header.Access-Control-Allow-Origin':
                        True
                    })
            ])

        self.resource_arn = f"arn:aws:apigateway:{core.Stack.of(self).region}::/restapis/{self.target_api.rest_api_id}/stages/{self.target_api.deployment_stage.stage_name}"
Пример #3
0
    def __init__(self, scope: cdk.Construct, construct_id: str,
                 **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # Lambda function

        hello_function = lambda_.Function(
            self,
            "hello-function",
            code=lambda_.Code.from_asset("src/hello/"),
            handler="main.handler",
            runtime=lambda_.Runtime.PYTHON_3_8,
            tracing=lambda_.Tracing.ACTIVE)

        logs.LogGroup(
            self,
            "hello-logs",
            log_group_name=f"/aws/lambda/{hello_function.function_name}",
            retention=logs.RetentionDays.ONE_WEEK)

        # API Gateway

        api_logs = logs.LogGroup(self,
                                 "hello-api-logs",
                                 retention=logs.RetentionDays.ONE_WEEK)

        api = apigw.RestApi(
            self,
            "hello-api",
            deploy_options=apigw.StageOptions(
                access_log_destination=apigw.LogGroupLogDestination(api_logs),
                access_log_format=apigw.AccessLogFormat.
                json_with_standard_fields(caller=True,
                                          http_method=True,
                                          ip=True,
                                          protocol=True,
                                          request_time=True,
                                          resource_path=True,
                                          response_length=True,
                                          status=True,
                                          user=True),
                throttling_burst_limit=1000,
                throttling_rate_limit=10,
                tracing_enabled=True))

        hello_integration = apigw.LambdaIntegration(hello_function, proxy=True)
        api.root.add_method("GET", hello_integration)
Пример #4
0
    def __init__(
        self,
        scope: core.Construct,
        id: str,
        webhook_function,
        on_demand_function,
        schedule_update_function,
        status_query_function,
        slack_function,
        ingest_allowed_ips,
    ):
        super().__init__(scope, id)

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

        policy = iam.PolicyDocument(
            statements=[
                iam.PolicyStatement(
                    effect=iam.Effect.ALLOW,
                    actions=["execute-api:Invoke"],
                    principals=[iam.AnyPrincipal()],
                    # note that the policy is a prop of the api which cannot
                    # reference itself, see the Cloudformation documentation
                    # for api gateway policy attribute
                    resources=[core.Fn.join("", ["execute-api:/", "*"])],
                ),
                iam.PolicyStatement(
                    effect=iam.Effect.DENY,
                    actions=["execute-api:Invoke"],
                    principals=[iam.AnyPrincipal()],
                    resources=[
                        core.Fn.join("", ["execute-api:/", "*/POST/ingest"]),
                        core.Fn.join("", ["execute-api:/", "*/GET/status"]),
                    ],
                    conditions={
                        "NotIpAddress": {"aws:SourceIp": ingest_allowed_ips}
                    },
                ),
            ]
        )

        self.rest_api_name = f"{stack_name}-{names.REST_API}"

        log_group = logs.LogGroup(
            self,
            "apilogs",
            log_group_name=f"/aws/apigateway/{self.rest_api_name}/access_logs",
            removal_policy=core.RemovalPolicy.DESTROY,
            retention=logs.RetentionDays.SIX_MONTHS,
        )

        self.api = apigw.LambdaRestApi(
            self,
            "api",
            handler=webhook_function,  # default handler
            rest_api_name=self.rest_api_name,
            proxy=False,
            deploy=True,
            policy=policy,
            deploy_options=apigw.StageOptions(
                access_log_destination=apigw.LogGroupLogDestination(log_group),
                access_log_format=apigw.AccessLogFormat.clf(),
                data_trace_enabled=True,
                metrics_enabled=True,
                logging_level=apigw.MethodLoggingLevel.INFO,
                stage_name=names.API_STAGE,
            ),
        )

        self.api.add_api_key("ZoomIngesterApiKey")

        self.new_recording_resource = self.create_resource(
            "new_recording",
            webhook_function,
            "POST",
        )

        self.ingest_resource = self.create_resource(
            "ingest",
            on_demand_function,
            "POST",
            cors_options=apigw.CorsOptions(
                allow_origins=apigw.Cors.ALL_ORIGINS,
                allow_methods=["POST", "OPTIONS"],
                allow_headers=apigw.Cors.DEFAULT_HEADERS
                + ["Accept-Language", "X-Requested-With"],
            ),
        )

        self.schedule_update_resource = self.create_resource(
            "schedule_update",
            schedule_update_function,
            "POST",
        )

        self.status_query_resource = self.create_resource(
            "status",
            status_query_function,
            "GET",
        )

        self.slack_resource = self.create_resource(
            "slack",
            slack_function,
            "POST",
        )

        def endpoint_url(resource_name):
            return (
                f"https://{self.api.rest_api_id}.execute-api."
                f"{core.Stack.of(self).region}.amazonaws.com/"
                f"{names.API_STAGE}/{resource_name}"
            )

        on_demand_function.add_environment(
            "WEBHOOK_ENDPOINT_URL",
            endpoint_url("new_recording"),
        )

        core.CfnOutput(
            self,
            "WebhookEndpoint",
            export_name=f"{stack_name}-{names.WEBHOOK_ENDPOINT}-url",
            value=endpoint_url("new_recording"),
        )

        core.CfnOutput(
            self,
            "OnDemandEndpoint",
            export_name=f"{stack_name}-{names.ON_DEMAND_ENDPOINT}-url",
            value=endpoint_url("ingest"),
        )

        core.CfnOutput(
            self,
            "ScheduleUpdateEndpoint",
            export_name=f"{stack_name}-{names.SCHEDULE_UPDATE_ENDPOINT}-url",
            value=endpoint_url("schedule_update"),
        )

        core.CfnOutput(
            self,
            "StatusQueryEndpoint",
            export_name=f"{stack_name}-{names.STATUS_ENDPOINT}-url",
            value=endpoint_url("status"),
        )

        core.CfnOutput(
            self,
            "SlackEndpoint",
            export_name=f"{stack_name}-{names.SLACK_ENDPOINT}-url",
            value=endpoint_url("slack"),
        )

        core.CfnOutput(
            self,
            "WebhookResourceId",
            export_name=f"{stack_name}-{names.WEBHOOK_ENDPOINT}-resource-id",
            value=self.new_recording_resource.resource_id,
        )

        core.CfnOutput(
            self,
            "OnDemandResourceId",
            export_name=f"{stack_name}-{names.ON_DEMAND_ENDPOINT}-resource-id",
            value=self.ingest_resource.resource_id,
        )

        core.CfnOutput(
            self,
            "ScheduleUpdateResourceId",
            export_name=f"{stack_name}-{names.SCHEDULE_UPDATE_ENDPOINT}-resource-id",
            value=self.schedule_update_resource.resource_id,
        )

        core.CfnOutput(
            self,
            "StatusQueryResourceId",
            export_name=f"{stack_name}-{names.STATUS_ENDPOINT}-resource-id",
            value=self.status_query_resource.resource_id,
        )

        core.CfnOutput(
            self,
            "SlackResourceId",
            export_name=f"{stack_name}-{names.SLACK_ENDPOINT}-resource-id",
            value=self.slack_resource.resource_id,
        )

        core.CfnOutput(
            self,
            "RestApiId",
            export_name=f"{stack_name}-{names.REST_API}-id",
            value=self.api.rest_api_id,
        )
Пример #5
0
    def __init__(self, scope: core.Construct, id: str, webhook_function,
                 on_demand_function, ingest_allowed_ips):
        super().__init__(scope, id)

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

        policy = iam.PolicyDocument(statements=[
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                actions=["execute-api:Invoke"],
                principals=[iam.AnyPrincipal()],
                # note that the policy is a prop of the api which cannot reference itself
                # see the Cloudformation documentation for api gateway policy attribute
                resources=[core.Fn.join('', ['execute-api:/', '*'])]),
            iam.PolicyStatement(effect=iam.Effect.DENY,
                                actions=["execute-api:Invoke"],
                                principals=[iam.AnyPrincipal()],
                                resources=[
                                    core.Fn.join(
                                        '', ['execute-api:/', '*/POST/ingest'])
                                ],
                                conditions={
                                    "NotIpAddress": {
                                        "aws:SourceIp": ingest_allowed_ips
                                    }
                                })
        ])

        self.rest_api_name = f"{stack_name}-{names.REST_API}"

        log_group = logs.LogGroup(
            self,
            "apilogs",
            log_group_name=f"/aws/apigateway/{self.rest_api_name}/access_logs",
            removal_policy=core.RemovalPolicy.DESTROY,
            retention=logs.RetentionDays.SIX_MONTHS)

        self.api = apigw.LambdaRestApi(
            self,
            "api",
            handler=webhook_function,  # default handler
            rest_api_name=self.rest_api_name,
            proxy=False,
            deploy=True,
            policy=policy,
            deploy_options=apigw.StageOptions(
                access_log_destination=apigw.LogGroupLogDestination(log_group),
                access_log_format=apigw.AccessLogFormat.clf(),
                data_trace_enabled=True,
                metrics_enabled=True,
                logging_level=apigw.MethodLoggingLevel.INFO,
                stage_name=names.API_STAGE))

        self.api.add_api_key("ZoomIngesterApiKey")

        self.new_recording_resource = self.api.root.add_resource(
            "new_recording")
        self.new_recording_method = self.new_recording_resource.add_method(
            "POST",
            method_responses=[
                apigw.MethodResponse(status_code="200",
                                     response_models={
                                         "application/json":
                                         apigw.Model.EMPTY_MODEL
                                     })
            ])

        self.ingest_resource = self.api.root.add_resource("ingest",
            default_cors_preflight_options=apigw.CorsOptions(
                allow_origins=apigw.Cors.ALL_ORIGINS,
                allow_methods=["POST", "OPTIONS"],
                allow_headers=apigw.Cors.DEFAULT_HEADERS \
                              + ["Accept-Language","X-Requested-With"]
            )
        )
        on_demand_integration = apigw.LambdaIntegration(on_demand_function)
        self.ingest_method = self.ingest_resource.add_method(
            "POST",
            on_demand_integration,
            method_responses=[
                apigw.MethodResponse(status_code="200",
                                     response_models={
                                         "application/json":
                                         apigw.Model.EMPTY_MODEL
                                     })
            ])

        def endpoint_url(resource_name):
            return (f"https://{self.api.rest_api_id}.execute-api."
                    f"{core.Stack.of(self).region}.amazonaws.com/"
                    f"{names.API_STAGE}/{resource_name}")

        on_demand_function.add_environment("WEBHOOK_ENDPOINT_URL",
                                           endpoint_url("new_recording"))

        core.CfnOutput(
            self,
            "WebhookEndpoint",
            export_name=f"{stack_name}-{names.WEBHOOK_ENDPOINT}-url",
            value=endpoint_url("new_recording"))

        core.CfnOutput(
            self,
            "OnDemandEndpoint",
            export_name=f"{stack_name}-{names.ON_DEMAND_ENDPOINT}-url",
            value=endpoint_url("ingest"))

        core.CfnOutput(
            self,
            "WebhookResourceId",
            export_name=f"{stack_name}-{names.WEBHOOK_ENDPOINT}-resource-id",
            value=self.new_recording_resource.resource_id)

        core.CfnOutput(
            self,
            "OnDemandResourceId",
            export_name=f"{stack_name}-{names.ON_DEMAND_ENDPOINT}-resource-id",
            value=self.ingest_resource.resource_id)

        core.CfnOutput(self,
                       "RestApiId",
                       export_name=f"{stack_name}-{names.REST_API}-id",
                       value=self.api.rest_api_id)
Пример #6
0
    def __init__(self, scope: core.Construct, id: str, stack_log_level: str,
                 back_end_api_name: str, **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # Create Serverless Event Processor using Lambda):
        # Read Lambda Code):
        try:
            with open(
                    "api_with_stage_variables/stacks/back_end/lambda_src/serverless_greeter.py",
                    mode="r") as f:
                greeter_fn_code = f.read()
        except OSError as e:
            print("Unable to read Lambda Function Code")
            raise e

        greeter_fn = _lambda.Function(
            self,
            "secureGreeterFn",
            function_name=f"greeter_fn_{id}",
            runtime=_lambda.Runtime.PYTHON_3_7,
            handler="index.lambda_handler",
            code=_lambda.InlineCode(greeter_fn_code),
            timeout=core.Duration.seconds(15),
            reserved_concurrent_executions=20,
            environment={
                "LOG_LEVEL": f"{stack_log_level}",
                "Environment": "Production",
                "ANDON_CORD_PULLED": "False",
                "RANDOM_SLEEP_ENABLED": "False"
            },
            description=
            "A simple greeter function, which responds with a timestamp")
        greeter_fn_version = greeter_fn.latest_version
        greeter_fn_version_alias = _lambda.Alias(
            self,
            "greeterFnMystiqueAutomationAlias",
            alias_name="MystiqueAutomation",
            version=greeter_fn_version)

        greeter_fn_dev_alias = _lambda.Alias(self,
                                             "greeterFnDevAlias",
                                             alias_name="dev",
                                             version=greeter_fn_version)

        greeter_fn_test_alias = _lambda.Alias(self,
                                              "greeterFnTestAlias",
                                              alias_name="test",
                                              version=greeter_fn_version)

        greeter_fn_prod_alias = _lambda.Alias(self,
                                              "greeterFnProdAlias",
                                              alias_name="prod",
                                              version=greeter_fn_version)

        # Create Custom Loggroup
        # /aws/lambda/function-name
        greeter_fn_lg = _logs.LogGroup(
            self,
            "greeterFnLoggroup",
            log_group_name=f"/aws/lambda/{greeter_fn.function_name}",
            retention=_logs.RetentionDays.ONE_WEEK,
            removal_policy=core.RemovalPolicy.DESTROY)
        # %%

        # Create API Gateway
        wa_api = _apigw.RestApi(
            self,
            "backEnd01Api",
            rest_api_name=f"{back_end_api_name}",
            # deploy_options=wa_api_dev_stage_options,
            retain_deployments=False,
            deploy=False,
            endpoint_types=[_apigw.EndpointType.EDGE],
            description=
            f"{GlobalArgs.OWNER}: API Best Practices. Stage Variables for APIs. This stack deploys an API and integrates with Lambda using Stage Variables."
        )

        wa_api_logs = _logs.LogGroup(
            self,
            "waApiLogs",
            log_group_name=f"/aws/apigateway/{back_end_api_name}/access_logs",
            removal_policy=core.RemovalPolicy.DESTROY,
            retention=_logs.RetentionDays.ONE_DAY)

        ######################################
        ##    CONFIG FOR API STAGE : DEV    ##
        ######################################
        dev_wa_api_deploy = _apigw.Deployment(
            self,
            "devDeploy",
            api=wa_api,
            description=f"{GlobalArgs.OWNER}: Deployment of 'dev' Api Stage",
            retain_deployments=False)

        dev_api_stage = _apigw.Stage(
            self,
            "devStage",
            deployment=dev_wa_api_deploy,
            stage_name="miztiik-dev",
            throttling_rate_limit=10,
            throttling_burst_limit=100,
            # Log full requests/responses data
            data_trace_enabled=True,
            # Enable Detailed CloudWatch Metrics
            metrics_enabled=True,
            logging_level=_apigw.MethodLoggingLevel.INFO,
            access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs),
            variables={"lambdaAlias": "dev"})

        # wa_api.deployment_stage = dev_api_stage

        test_wa_api_deploy = _apigw.Deployment(
            self,
            "testDeploy",
            api=wa_api,
            description=f"{GlobalArgs.OWNER}: Deployment of 'test' Api Stage",
            retain_deployments=False)
        test_api_stage = _apigw.Stage(
            self,
            "testStage",
            deployment=test_wa_api_deploy,
            stage_name="miztiik-test",
            throttling_rate_limit=10,
            throttling_burst_limit=100,
            # Log full requests/responses data
            data_trace_enabled=True,
            # Enable Detailed CloudWatch Metrics
            metrics_enabled=True,
            logging_level=_apigw.MethodLoggingLevel.INFO,
            access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs),
            variables={"lambdaAlias": "test"})

        wa_api.deployment_stage = test_api_stage

        prod_wa_api_deploy = _apigw.Deployment(
            self,
            "prodDeploy",
            api=wa_api,
            description=f"{GlobalArgs.OWNER}: Deployment of 'prod' Api Stage",
            retain_deployments=False)
        prod_api_stage = _apigw.Stage(
            self,
            "prodStage",
            deployment=prod_wa_api_deploy,
            stage_name="miztiik-prod",
            throttling_rate_limit=10,
            throttling_burst_limit=100,
            # Log full requests/responses data
            data_trace_enabled=True,
            # Enable Detailed CloudWatch Metrics
            metrics_enabled=True,
            logging_level=_apigw.MethodLoggingLevel.INFO,
            access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs),
            variables={"lambdaAlias": "prod"})

        prod_api_stage.node.add_dependency(test_api_stage)

        wa_api.deployment_stage = prod_api_stage

        wa_api_res = wa_api.root.add_resource("wa-api")
        greeter = wa_api_res.add_resource("greeter")

        backend_stage_uri = (f"arn:aws:apigateway:"
                             f"{core.Aws.REGION}"
                             f":lambda:path/2015-03-31/functions/"
                             f"{greeter_fn.function_arn}"
                             f":"
                             f"${{stageVariables.lambdaAlias}}"
                             f"/invocations")

        greeter_method_get = greeter.add_method(
            http_method="GET",
            request_parameters={
                "method.request.header.InvocationType": True,
                "method.request.path.mystique": True
            },
            # integration=_apigw.LambdaIntegration(
            #     # handler=greeter_fn,
            #     handler=backend_stage_uri,
            #     proxy=True
            # )
            integration=_apigw.Integration(
                type=_apigw.IntegrationType.AWS_PROXY,
                integration_http_method="GET",
                uri=backend_stage_uri))

        # "arn:aws:apigateway:eu-west-2:lambda:path/2015-03-31/functions/arn:aws:lambda:eu-west-2:614517326458:function:${stageVariables.preflightFunction}/invocations",
        # https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1:230023004178:function:greeter_fn_well-architected-api:${stageVariable.lambdaAlias}/invocations

        # We need to manually add permissions for the stages to invoke
        # CDK By default adds permission only for the last .deployment_stage
        #####################################################################
        ##  CDK BUG: CONDITIONS DOES NOT TAKE EFFECT IN SERVICE PRINCIPAL  ##
        #####################################################################
        """
        greeter_fn.grant_invoke(
            _iam.ServicePrincipal(
                service="apigateway.amazonaws.com",
                conditions={
                    "ArnLike": {"aws:SourceArn": "this-does-not-work"}
                }
            )
        )
        """

        greeter_fn.add_permission(
            "allowStageInvocation",
            principal=_iam.ServicePrincipal("apigateway.amazonaws.com"),
            # source_arn=f"arn:aws:execute-api:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:{wa_api.rest_api_id}/{dev_api_stage.stage_name}/{greeter_method_get.resource.path}"
            source_arn=greeter_method_get.method_arn.replace(
                wa_api.deployment_stage.stage_name, "*"),
            action="lambda:InvokeFunction",
        )

        greeter_fn_dev_alias.add_permission(
            "greeter_fn_devAliasApiPerms",
            principal=_iam.ServicePrincipal("apigateway.amazonaws.com"),
            action="lambda:InvokeFunction",
            source_arn=greeter_method_get.method_arn.replace(
                wa_api.deployment_stage.stage_name, "*"),
        )
        greeter_fn_test_alias.add_permission(
            "greeter_fn_testAliasApiPerms",
            principal=_iam.ServicePrincipal("apigateway.amazonaws.com"),
            action="lambda:InvokeFunction",
            source_arn=greeter_method_get.method_arn.replace(
                wa_api.deployment_stage.stage_name, "*"),
        )
        greeter_fn_prod_alias.add_permission(
            "greeter_fn_prodAliasApiPerms",
            principal=_iam.ServicePrincipal("apigateway.amazonaws.com"),
            action="lambda:InvokeFunction",
            source_arn=greeter_method_get.method_arn.replace(
                wa_api.deployment_stage.stage_name, "*"),
        )

        # Outputs
        output_0 = core.CfnOutput(
            self,
            "AutomationFrom",
            value=f"{GlobalArgs.SOURCE_INFO}",
            description=
            "To know more about this automation stack, check out our github page."
        )

        output_1 = core.CfnOutput(
            self,
            "WaApiUrl",
            value=f"{greeter.url}",
            description=
            "Use an utility like curl from the same VPC as the API to invoke it."
        )
Пример #7
0
    def __init__(
        self,
        scope: core.Construct,
        id: str,
        stack_log_level: str,
        back_end_api_name: str,
        **kwargs
    ) -> None:
        super().__init__(scope, id, **kwargs)

        # Read Lambda Code):
        try:
            with open("api_request_validation/stacks/back_end/lambda_src/serverless_greeter.py", mode="r") as f:
                greeter_fn_code = f.read()
        except OSError as e:
            print("Unable to read Lambda Function Code")
            raise e

        greeter_fn = _lambda.Function(
            self,
            "secureGreeterFn",
            function_name=f"greeter_fn_{id}",
            runtime=_lambda.Runtime.PYTHON_3_7,
            handler="index.lambda_handler",
            code=_lambda.InlineCode(greeter_fn_code),
            current_version_options={
                "removal_policy": core.RemovalPolicy.DESTROY,  # Remove old versions
                "retry_attempts": 1,
                "description": "Mystique Factory Build Version"
            },
            timeout=core.Duration.seconds(5),
            reserved_concurrent_executions=10,
            environment={
                "LOG_LEVEL": f"{stack_log_level}",
                "Environment": "Production",
                "ANDON_CORD_PULLED": "False",
                "RANDOM_SLEEP_ENABLED": "False",
                "RANDOM_SLEEP_SECS": "2",
            },
            description="A simple greeter function, which responds with a timestamp"
        )

        greeter_fn_version_alias = greeter_fn.current_version.add_alias(
            "MystiqueAutomation")
        greeter_fn_prod_alias = greeter_fn.current_version.add_alias("prod")

        # Create Custom Loggroup
        greeter_fn_lg = _logs.LogGroup(
            self,
            "squareFnLoggroup",
            log_group_name=f"/aws/lambda/{greeter_fn.function_name}",
            retention=_logs.RetentionDays.ONE_WEEK,
            removal_policy=core.RemovalPolicy.DESTROY
        )

# %%
        #######################################
        ##    CONFIG FOR API STAGE : PROD    ##
        #######################################
        wa_api_logs = _logs.LogGroup(
            self,
            "waApiLogs",
            log_group_name=f"/aws/apigateway/{back_end_api_name}/access_logs",
            removal_policy=core.RemovalPolicy.DESTROY,
            retention=_logs.RetentionDays.ONE_DAY
        )

        # Add API GW front end for the Lambda
        prod_api_stage_options = _apigw.StageOptions(
            stage_name="miztiik",
            throttling_rate_limit=10,
            throttling_burst_limit=100,
            # Log full requests/responses data
            data_trace_enabled=True,
            # Enable Detailed CloudWatch Metrics
            metrics_enabled=True,
            logging_level=_apigw.MethodLoggingLevel.INFO,
            access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs),
            variables={
                "lambdaAlias": "prod",
                "appOwner": "Mystique"
            }
        )

        # Create API Gateway
        wa_api = _apigw.RestApi(
            self,
            "backEnd01Api",
            rest_api_name=f"{back_end_api_name}",
            deploy_options=prod_api_stage_options,
            minimum_compression_size=0,
            endpoint_types=[
                _apigw.EndpointType.EDGE
            ],
            description=f"{GlobalArgs.OWNER}: API Best Practice Demonstration. Validate HTTP Requests at API Gateway"
        )

        wa_api_res = wa_api.root.add_resource("well-architected-api")
        stationary_by_category = wa_api_res.add_resource("get-stationary")

        # Because this is NOT a proxy integration, we need to define our response model
        response_model = wa_api.add_model(
            "ResponseModel",
            content_type="application/json",
            model_name="MiztiikResponseModel",
            schema=_apigw.JsonSchema(
                schema=_apigw.JsonSchemaVersion.DRAFT4,
                title="updateResponse",
                type=_apigw.JsonSchemaType.OBJECT,
                properties={
                    "message": _apigw.JsonSchema(type=_apigw.JsonSchemaType.STRING)
                }
            )
        )

        # "pencil": [{"id": 1, "type": "microtip", "status": "unavailable", "price": 19}]
        req_model_stationary = wa_api.add_model(
            "RequestModel",
            content_type="application/json",
            model_name="RequestModelForStationary",
            schema=_apigw.JsonSchema(
                schema=_apigw.JsonSchemaVersion.DRAFT4,
                title="RequestValidation",
                type=_apigw.JsonSchemaType.OBJECT,
                properties={
                    "category": {
                        "type": _apigw.JsonSchemaType.STRING,
                        "enum": ["pens", "pencil", "eraser"]
                    }
                },
                required=["category"]
            )
        )

        stationary_by_category_req_validator = wa_api.add_request_validator(
            "apiReqValidator",
            validate_request_parameters=True,
            validate_request_body=True
        )

        req_template = """$input.json('$')"""

        # resp_template = """$input.path('$.body.message')"""
        resp_template = """$input.path('$.body')"""

        stationary_by_category_method_get = stationary_by_category.add_method(
            http_method="POST",
            request_parameters={
                "method.request.header.InvocationType": False,
                "method.request.path.category": False
            },
            request_models={
                "application/json": req_model_stationary
            },
            request_validator=stationary_by_category_req_validator,
            integration=_apigw.LambdaIntegration(
                handler=greeter_fn,
                proxy=False,
                request_parameters={
                    "integration.request.path.category": "method.request.path.category"
                },
                cache_key_parameters=[
                    "method.request.path.category"
                ],
                request_templates={
                    "application/json": req_template
                },
                passthrough_behavior=_apigw.PassthroughBehavior.NEVER,
                integration_responses=[
                    _apigw.IntegrationResponse(
                        status_code="200",
                        # selection_pattern="2\d{2}",  # Use for mapping Lambda Errors
                        response_parameters={
                            "method.response.header.Access-Control-Allow-Headers": "'cache-control,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'",
                            "method.response.header.Content-Type": "'application/json'",
                        },
                        response_templates={
                            "application/json": f"{resp_template}"
                        }
                    )
                ]
            ),
            method_responses=[
                _apigw.MethodResponse(
                    status_code="200",
                    response_parameters={
                        "method.response.header.Content-Type": True,
                        "method.response.header.Access-Control-Allow-Headers": True,
                    },
                    response_models={
                        "application/json": response_model
                    }
                ),
                _apigw.MethodResponse(
                    status_code="400",
                    response_parameters={
                        "method.response.header.Content-Length": True,
                    },
                    response_models={
                        "application/json": _apigw.EmptyModel()
                    }
                )
            ]
        )

        # Outputs
        output_0 = core.CfnOutput(
            self,
            "AutomationFrom",
            value=f"{GlobalArgs.SOURCE_INFO}",
            description="To know more about this automation stack, check out our github page."
        )

        output_1 = core.CfnOutput(
            self,
            "WellArchitectedApiUrl",
            value=f"{stationary_by_category.url}",
            description="Use an utility like curl from the same VPC as the API to invoke it."
        )
    def __init__(self, scope: core.Construct, id: str, vpc, efs_sg, efs_share,
                 efs_ap_nginx, stack_log_level: str, back_end_api_name: str,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # Create Serverless Event Processor using Lambda):
        # Read Lambda Code):
        try:
            with open(
                    "fargate_with_efs/stacks/back_end/lambda_src/serverless_greeter.py",
                    mode="r") as f:
                greeter_fn_code = f.read()
        except OSError as e:
            print("Unable to read Lambda Function Code")
            raise e

        efs_mnt_path = "/mnt/html"

        greeter_fn = _lambda.Function(
            self,
            "secureGreeterFn",
            function_name=f"greeter_fn_{id}",
            runtime=_lambda.Runtime.PYTHON_3_7,
            handler="index.lambda_handler",
            code=_lambda.InlineCode(greeter_fn_code),
            current_version_options={
                "removal_policy":
                core.RemovalPolicy.DESTROY,  # retain old versions
                "retry_attempts": 1,
                "description": "Mystique Factory Build Version"
            },
            timeout=core.Duration.seconds(15),
            reserved_concurrent_executions=20,
            retry_attempts=1,
            environment={
                "LOG_LEVEL": f"{stack_log_level}",
                "Environment": "Production",
                "ANDON_CORD_PULLED": "False",
                "RANDOM_SLEEP_ENABLED": "False",
                "EFS_MNT_PATH": efs_mnt_path
            },
            description=
            "A simple greeter function, which responds with a timestamp",
            vpc=vpc,
            vpc_subnets=_ec2.SubnetType.PRIVATE,
            security_groups=[efs_sg],
            filesystem=_lambda.FileSystem.from_efs_access_point(
                efs_ap_nginx, efs_mnt_path))
        greeter_fn_version = greeter_fn.latest_version
        greeter_fn_dev_alias = _lambda.Alias(
            self,
            "greeterFnMystiqueAutomationAlias",
            alias_name="MystiqueAutomation",
            version=greeter_fn_version,
            description=
            "Mystique Factory Build Version to ingest content from API GW to EFS",
            retry_attempts=1)

        # Create Custom Loggroup
        greeter_fn_lg = _logs.LogGroup(
            self,
            "greeterFnLoggroup",
            log_group_name=f"/aws/lambda/{greeter_fn.function_name}",
            retention=_logs.RetentionDays.ONE_WEEK,
            removal_policy=core.RemovalPolicy.DESTROY)

        # %%
        wa_api_logs = _logs.LogGroup(
            self,
            "waApiLogs",
            log_group_name=f"/aws/apigateway/{back_end_api_name}/access_logs",
            removal_policy=core.RemovalPolicy.DESTROY,
            retention=_logs.RetentionDays.ONE_DAY)

        #######################################
        ##    CONFIG FOR API STAGE : PROD    ##
        #######################################

        # Add API GW front end for the Lambda
        prod_api_stage_options = _apigw.StageOptions(
            stage_name="prod",
            throttling_rate_limit=10,
            throttling_burst_limit=100,
            # Log full requests/responses data
            data_trace_enabled=True,
            # Enable Detailed CloudWatch Metrics
            metrics_enabled=True,
            logging_level=_apigw.MethodLoggingLevel.INFO,
            access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs),
            variables={
                "lambdaAlias": "prod",
                "appOwner": "Mystique"
            })

        # Create API Gateway
        wa_api = _apigw.RestApi(
            self,
            "backEnd01Api",
            rest_api_name=f"{back_end_api_name}",
            deploy_options=prod_api_stage_options,
            endpoint_types=[_apigw.EndpointType.EDGE],
            description=
            f"{GlobalArgs.OWNER}: API Best Practices. This stack deploys an API and integrates with Lambda $LATEST alias."
        )

        wa_api_res = wa_api.root.add_resource("well-architected-api")
        create_content = wa_api_res.add_resource("create-content")

        # Add POST method to API
        create_content_get = create_content.add_method(
            http_method="POST",
            request_parameters={
                "method.request.header.InvocationType": True,
                "method.request.path.mystique": True
            },
            integration=_apigw.LambdaIntegration(handler=greeter_fn,
                                                 proxy=True))

        # Outputs
        output_0 = core.CfnOutput(
            self,
            "AutomationFrom",
            value=f"{GlobalArgs.SOURCE_INFO}",
            description=
            "To know more about this automation stack, check out our github page."
        )

        output_1 = core.CfnOutput(
            self,
            "ContentCreatorApiUrl",
            value=
            f"curl -X POST -H 'Content-Type: text/plain' -d 'Hello again :)' {create_content.url}",
            description=
            'Use an utility like curl to add content to EFS. For ex: curl -X POST -H "Content-Type: text/plain" -d "Hello again :)" ${API_URL}'
        )
Пример #9
0
    def __init__(self, scope: core.Construct, id: str, vpc, efs_sg, efs_share,
                 efs_ap, stack_log_level: str, back_end_api_name: str,
                 **kwargs) -> None:
        super().__init__(scope, id, **kwargs)

        # Create Serverless Event Processor using Lambda):
        # Read Lambda Code):
        try:
            with open(
                    "lambda_with_efs/stacks/back_end/lambda_src/serverless_greeter.py",
                    mode="r") as f:
                greeter_fn_code = f.read()
        except OSError as e:
            print("Unable to read Lambda Function Code")
            raise e

        greeter_fn = _lambda.Function(
            self,
            "secureGreeterFn",
            function_name=f"greeter_fn_{id}",
            runtime=_lambda.Runtime.PYTHON_3_7,
            handler="index.lambda_handler",
            code=_lambda.InlineCode(greeter_fn_code),
            current_version_options={
                "removal_policy":
                core.RemovalPolicy.DESTROY,  # retain old versions
                "retry_attempts": 1,
                "description": "Mystique Factory Build Version"
            },
            timeout=core.Duration.seconds(15),
            reserved_concurrent_executions=20,
            retry_attempts=1,
            environment={
                "LOG_LEVEL": f"{stack_log_level}",
                "Environment": "Production",
                "ANDON_CORD_PULLED": "False",
                "RANDOM_SLEEP_ENABLED": "False"
            },
            description=
            "A simple greeter function, which responds with a timestamp",
            vpc=vpc,
            vpc_subnets=_ec2.SubnetType.PRIVATE,
            security_groups=[efs_sg],
            filesystem=_lambda.FileSystem.from_efs_access_point(
                efs_ap, '/mnt/efs'))
        greeter_fn_version = greeter_fn.latest_version
        greeter_fn_dev_alias = _lambda.Alias(
            self,
            "greeterFnMystiqueAutomationAlias",
            alias_name="MystiqueAutomation",
            version=greeter_fn_version)

        # greeter_fn_version_alias = greeter_fn.current_version.add_alias("dev")
        # greeter_fn_prod_alias = greeter_fn.current_version.add_alias("prod")

        # Create Custom Loggroup
        # /aws/lambda/function-name
        greeter_fn_lg = _logs.LogGroup(
            self,
            "greeterFnLoggroup",
            log_group_name=f"/aws/lambda/{greeter_fn.function_name}",
            retention=_logs.RetentionDays.ONE_WEEK,
            removal_policy=core.RemovalPolicy.DESTROY)

        # Permissions to mount EFS (CDK May add them automatically)
        # roleStmt1 = _iam.PolicyStatement(
        #     effect=_iam.Effect.ALLOW,
        #     resources=[
        # f"arn:aws:elasticfilesystem:{core.Aws.REGION}:{core.Aws.ACCOUNT_ID}:file-system/{efs_share.file_system_id}"
        #     ],
        #     actions=["elasticfilesystem:*"]
        # )
        # roleStmt1.sid = "AllowLambdaToReadWriteToEfs"
        # greeter_fn.add_to_role_policy(roleStmt1)
        # %%

        wa_api_logs = _logs.LogGroup(
            self,
            "waApiLogs",
            log_group_name=f"/aws/apigateway/{back_end_api_name}/access_logs",
            removal_policy=core.RemovalPolicy.DESTROY,
            retention=_logs.RetentionDays.ONE_DAY)

        #######################################
        ##    CONFIG FOR API STAGE : PROD    ##
        #######################################

        # Add API GW front end for the Lambda
        prod_api_stage_options = _apigw.StageOptions(
            stage_name="prod",
            throttling_rate_limit=10,
            throttling_burst_limit=100,
            # Log full requests/responses data
            data_trace_enabled=True,
            # Enable Detailed CloudWatch Metrics
            metrics_enabled=True,
            logging_level=_apigw.MethodLoggingLevel.INFO,
            access_log_destination=_apigw.LogGroupLogDestination(wa_api_logs),
            variables={
                "lambdaAlias": "prod",
                "appOwner": "Mystique"
            })

        # Create API Gateway
        wa_api = _apigw.RestApi(
            self,
            "backEnd01Api",
            rest_api_name=f"{back_end_api_name}",
            deploy_options=prod_api_stage_options,
            endpoint_types=[_apigw.EndpointType.EDGE],
            description=
            f"{GlobalArgs.OWNER}: API Best Practices. This stack deploys an API and integrates with Lambda $LATEST alias."
        )

        wa_api_res = wa_api.root.add_resource("well-architected-api")
        greetings_wall = wa_api_res.add_resource("message-wall")

        # Add GET method to API
        greetings_wall_get = greetings_wall.add_method(
            http_method="GET",
            request_parameters={
                "method.request.header.InvocationType": True,
                "method.request.path.mystique": True
            },
            integration=_apigw.LambdaIntegration(handler=greeter_fn,
                                                 proxy=True))

        # Add POST method to API
        greeter_method_get = greetings_wall.add_method(
            http_method="POST",
            request_parameters={
                "method.request.header.InvocationType": True,
                "method.request.path.mystique": True
            },
            integration=_apigw.LambdaIntegration(handler=greeter_fn,
                                                 proxy=True))

        # Add DELETE method to API
        greeter_method_get = greetings_wall.add_method(
            http_method="DELETE",
            request_parameters={
                "method.request.header.InvocationType": True,
                "method.request.path.mystique": True
            },
            integration=_apigw.LambdaIntegration(handler=greeter_fn,
                                                 proxy=True))

        # Outputs
        output_0 = core.CfnOutput(
            self,
            "AutomationFrom",
            value=f"{GlobalArgs.SOURCE_INFO}",
            description=
            "To know more about this automation stack, check out our github page."
        )

        output_1 = core.CfnOutput(
            self,
            "GreetingsWallApiUrl",
            value=f"{greetings_wall.url}",
            description=
            "Use an utility like curl from the same VPC as the API to invoke it."
        )