예제 #1
0
from troposphere import Ref, Template, Output
from troposphere.apigateway import RestApi, Method
from troposphere.apigateway import Resource, MethodResponse
from troposphere.apigateway import Integration, IntegrationResponse
from troposphere.apigateway import Deployment, Stage, ApiStage
from troposphere.apigateway import UsagePlan, QuotaSettings, ThrottleSettings
from troposphere.apigateway import ApiKey, StageKey, UsagePlanKey
from troposphere.iam import Role, Policy
from troposphere.awslambda import Function, Code
from troposphere import GetAtt, Join

t = Template()

# Create the Api Gateway
rest_api = t.add_resource(RestApi("ExampleApi", Name="ExampleApi"))

# Create a Lambda function that will be mapped
code = [
    "var response = require('cfn-response');",
    "exports.handler = function(event, context) {",
    "   context.succeed('foobar!');",
    "   return 'foobar!';",
    "};",
]

# Create a role for the lambda function
t.add_resource(
    Role(
        "LambdaExecutionRole",
        Path="/",
        Policies=[
예제 #2
0
    file.close()

EmailSendFunction = t.add_resource(
    Function(
        "EmailSendFunction",
        Code=Code(ZipFile=Join("", code)),
        Handler="index.daily_quote_handler",
        Role=GetAtt(LambdaSesExecutionRole, "Arn"),
        Runtime="python2.7",
        Environment=Environment(
            Variables={"email_from": Ref(from_email_param)}),
        Description="Sends the Daily Quote. No endpoint, runs on a schedule.",
        FunctionName="EmailSendFunction"))

### API GATEWAY
rest_api = t.add_resource(RestApi("EmailListApi", Name="EmailListApi"))

# /subscribe (POST)
subscribe_resource = t.add_resource(
    Resource("subscribeResource",
             RestApiId=Ref(rest_api),
             PathPart="subscribe",
             ParentId=GetAtt("EmailListApi", "RootResourceId")))

subscribe_method = t.add_resource(
    Method("subscribeMethod",
           DependsOn="EmailSubscribeFunction",
           RestApiId=Ref(rest_api),
           AuthorizationType="NONE",
           ResourceId=Ref(subscribe_resource),
           HttpMethod="POST",
예제 #3
0
    def __init__(self,
                 utils,
                 templatePath='./cloudformation/api.json',
                 description='Top Level API Gateway Template for {App}',
                 version='2010-09-09'):
        super(self.__class__, self).__init__()

        self.utils = utils
        self.templatePath = templatePath
        appName = self.utils.config['App']
        domainName = self.utils.config['Domain']
        tags = self.utils.config['Tags']

        self.add_version(version)
        self.add_description(description.format(App=appName))

        ###################
        # ACM Certificate #
        ###################

        self.certificate = self.add_resource(
            Certificate(
                '{App}Certificate'.format(App=appName),
                DomainName=domainName,
                SubjectAlternativeNames=[
                    '*.{Domain}'.format(Domain=domainName)
                ],
                Tags=Tags(tags),
            ))

        #####################
        # Deployment Bucket #
        #####################

        self.bucket = self.add_resource(
            Bucket(
                '{App}DeploymentBucket'.format(App=appName),
                DeletionPolicy='Retain',
                Tags=Tags(tags),
                VersioningConfiguration=VersioningConfiguration(
                    Status='Enabled', ),
            ))

        ###########
        # RestApi #
        ###########

        self.api = self.add_resource(
            RestApi(
                '{App}Api'.format(App=appName),
                Name=appName + 'Api',
                Description='API for {App} AWS SAML Login Redirection'.format(
                    App=appName),
            ))

        ##################
        # RestApi Domain #
        ##################

        self.apiDomain = self.add_resource(
            DomainName(
                '{App}ApiDomainName'.format(App=appName),
                CertificateArn=Ref(self.certificate),
                DomainName=domainName,
            ))

        self.apiDomainMapping = self.add_resource(
            BasePathMapping(
                '{App}ApiDomainNameMapping'.format(App=appName),
                DomainName=Ref(self.apiDomain),
                RestApiId=Ref(self.api),
            ))

        ###########
        # Outputs #
        ###########

        self.add_output(
            Output(
                '{App}Api'.format(App=appName),
                Value=Ref(self.api),
                Export=Export('{App}Api'.format(App=appName), ),
            ))

        self.add_output(
            Output(
                '{App}ApiDomainName'.format(App=appName),
                Value=Ref(self.apiDomain),
                Export=Export('{App}ApiDomainName'.format(App=appName), ),
            ))

        self.add_output(
            Output(
                '{App}ApiDomainDistribution'.format(App=appName),
                Value=GetAtt(self.apiDomain, 'DistributionDomainName'),
                Export=Export(
                    '{App}ApiDomainDistribution'.format(App=appName), ),
            ))

        self.add_output(
            Output(
                '{App}ApiRoot'.format(App=appName),
                Value=GetAtt(self.api, 'RootResourceId'),
                Export=Export('{App}ApiRoot'.format(App=appName), ),
            ))

        self.add_output(
            Output(
                '{App}Certificate'.format(App=appName),
                Value=Ref(self.certificate),
                Export=Export('{App}Certificate'.format(App=appName), ),
            ))

        self.add_output(
            Output(
                '{App}DeploymentBucket'.format(App=appName),
                Value=Ref(self.bucket),
                Export=Export('{App}DeploymentBucket'.format(App=appName), ),
            ))

        ##################
        # Write Template #
        ##################

        with open(templatePath, 'w') as templateFile:
            templateFile.write(self.to_json())
예제 #4
0
    def add_api_gateway(self, apigateway_name):
        self.log.info('Adding API Gateway %s' % apigateway_name)
        assert (self.lambda_function is not None)
        # define all value used by api gateway
        lambda_method_name = '%sLambdaMethod' % apigateway_name
        lambda_permission_name = '%sLambdaPermission' % apigateway_name
        resource_name = '%sResource' % apigateway_name
        deployment_name = '%sDeployment' % self.stage_name
        apikey_name = '%sApiKey' % apigateway_name

        # start creating api gateway template
        self.apigateway = RestApi(apigateway_name, Name=apigateway_name)
        self.template.add_resource(self.apigateway)

        resource = Resource(resource_name,
                            RestApiId=Ref(self.apigateway),
                            PathPart='{proxy+}',
                            ParentId=GetAtt(apigateway_name, 'RootResourceId'))
        self.template.add_resource(resource)

        permission = Permission(lambda_permission_name,
                                Action='lambda:invokeFunction',
                                FunctionName=GetAtt(self.lambda_function,
                                                    'Arn'),
                                Principal='apigateway.amazonaws.com',
                                SourceArn=Join("", [
                                    'arn:aws:execute-api:',
                                    Ref('AWS::Region'), ':',
                                    Ref('AWS::AccountId'), ':',
                                    Ref(self.apigateway), '/*'
                                ]))
        self.template.add_resource(permission)

        method = Method(
            lambda_method_name,
            DependsOn=lambda_permission_name,
            RestApiId=Ref(self.apigateway),
            ResourceId=Ref(resource),
            HttpMethod='ANY',
            AuthorizationType='NONE',
            Integration=Integration(
                Type='AWS_PROXY',
                IntegrationHttpMethod='POST',
                Uri=Join("", [
                    'arn:aws:apigateway:',
                    Ref('AWS::Region'), ':lambda:path/2015-03-31/functions/',
                    GetAtt(self.lambda_function, 'Arn'), '/invocations'
                ])),
            MethodResponses=[MethodResponse(StatusCode='200')])
        self.template.add_resource(method)

        # create a deployment
        deployment = Deployment(deployment_name,
                                DependsOn=lambda_method_name,
                                RestApiId=Ref(self.apigateway))
        self.template.add_resource(deployment)

        stage = Stage('%sStage' % self.stage_name,
                      StageName=self.stage_name,
                      RestApiId=Ref(self.apigateway),
                      DeploymentId=Ref(deployment))
        self.template.add_resource(stage)

        key = ApiKey(apikey_name,
                     StageKeys=[
                         StageKey(RestApiId=Ref(self.apigateway),
                                  StageName=Ref(stage))
                     ])
        self.template.add_resource(key)
    def initiate_api_gateway_creation(self):
        self.template.set_version('2010-09-09')
        self.template.set_description('Creates a API Gateway which is '
                                      'used to get data from dynamoDB.')

        role = self.template.add_resource(
            Role('RootRole',
                 RoleName="monty-cloud-api-role",
                 Path='/',
                 AssumeRolePolicyDocument={
                     "Version":
                     "2012-10-17",
                     "Statement": [{
                         "Action": ["sts:AssumeRole"],
                         "Effect": "Allow",
                         "Principal": {
                             "Service": [
                                 "apigateway.amazonaws.com",
                                 "lambda.amazonaws.com",
                                 "dynamodb.amazonaws.com"
                             ]
                         }
                     }]
                 }))

        self.template.add_resource(
            ManagedPolicy(
                'RolePolicies',
                ManagedPolicyName='api-gw-policy',
                Description='This policy is used for the DynamoDB table ',
                PolicyDocument={
                    "Version":
                    "2012-10-17",
                    "Statement": [{
                        "Action": ["dynamodb:*", "lambda:*", "s3:*"],
                        "Resource": [
                            "arn:aws:dynamodb:*:*:table/*",
                            "arn:aws:lambda:*:*:function:*"
                        ],
                        "Effect":
                        "Allow"
                    }]
                },
                Roles=[Ref(role)]))

        name = self.template.add_resource(
            RestApi('restApiName',
                    Name='monty-cloud-get-api',
                    Description='Monty Cloud API Gateway',
                    EndpointConfiguration=EndpointConfiguration(
                        Types=['REGIONAL'])))

        self.template.add_resource(
            Permission("lambdaApiGatewayInvoke",
                       Action="lambda:InvokeFunction",
                       FunctionName="arn:aws:lambda:{}:{}:function:"
                       "get_data".format(self.region, self.account_number),
                       Principal="apigateway.amazonaws.com",
                       SourceArn="arn:aws:execute-api:{}:{}:*/*"
                       "/GET/get-details".format(self.region,
                                                 self.account_number)))

        get_api_resource = self.template.add_resource(
            Resource('restApiGetDetailsResource',
                     RestApiId=Ref(name),
                     ParentId=GetAtt(name, 'RootResourceId'),
                     PathPart='get-details',
                     DependsOn=name))

        get_api_method = self.template.add_resource(
            Method('restApiGetDetailsMethod',
                   AuthorizationType='None',
                   ApiKeyRequired=False,
                   HttpMethod='GET',
                   ResourceId=Ref(get_api_resource),
                   RestApiId=Ref(name),
                   Integration=Integration(Type='AWS_PROXY',
                                           IntegrationHttpMethod='POST',
                                           Uri=self.uri.format(
                                               self.region, self.region,
                                               self.account_number),
                                           Credentials=GetAtt(role, "Arn")),
                   MethodResponses=[
                       MethodResponse(
                           StatusCode='200',
                           ResponseModels={'application/json': 'Empty'})
                   ],
                   DependsOn=get_api_resource))

        deployment = self.template.add_resource(
            Deployment('restApiDeployment',
                       RestApiId=Ref(name),
                       DependsOn=[get_api_method]))

        self.template.add_resource(
            Stage('restApiStage',
                  DeploymentId=Ref(deployment),
                  Description='Prod Stage',
                  MethodSettings=[
                      MethodSetting(ResourcePath='/get-details',
                                    HttpMethod='GET')
                  ],
                  RestApiId=Ref(name),
                  StageName='prod'))

        return self.template.to_yaml()
예제 #6
0
    def register_resources_template(self, template):

        deployment_resources = []
        api = RestApi(
            self.in_project_cf_name,
            Name=troposphere.Join("-", [self.name, troposphere.Ref('Stage')]),
            Description=self.settings.get('description', '')
        )
        template.add_resource(api)
        deployment_resources.append(api)

        invoke_lambda_role = troposphere.iam.Role(
            utils.valid_cloudformation_name(self.name, 'Role'),
            AssumeRolePolicyDocument={
                "Version": "2012-10-17",
                "Statement": [{
                    "Effect": "Allow",
                    "Principal": {
                        "Service": ["apigateway.amazonaws.com"]
                    },
                    "Action": ["sts:AssumeRole"]
                }]
            },
            Policies=[
                troposphere.iam.Policy(
                    PolicyName=utils.valid_cloudformation_name(self.name, 'Role', 'Policy'),
                    PolicyDocument={
                        "Version": "2012-10-17",
                        "Statement": [
                            {
                                "Effect": "Allow",
                                "Action": [
                                    "lambda:InvokeFunction"
                                ],
                                "Resource": [
                                    "*"
                                ]
                            }
                        ]
                    }
                )
            ]
        )

        template.add_resource(invoke_lambda_role)
        deployment_resources.append(invoke_lambda_role)

        deployment_dependencies = []
        for path, resource in six.iteritems(self.settings.get('resources', {})):
            resource_reference = self.get_or_create_resource(path, api, template)
            methods = resource['methods']

            if isinstance(methods, six.string_types):
                methods = [methods]

            if not isinstance(methods, dict):
                method_properties = copy.deepcopy(resource)
                method_properties.pop('methods', None)
                methods = dict([[method, method_properties] for method in methods])

            for method, configuration in six.iteritems(methods):
                method_name = [self.name]
                method_name.extend(path.split('/'))
                method_name.append(method)

                extra = {}
                if 'parameters' in configuration:
                    extra['RequestParameters'] = configuration['parameters']
                m = Method(
                    utils.valid_cloudformation_name(*method_name),
                    HttpMethod=method,
                    AuthorizationType=self.get_authorization_type(configuration),
                    ApiKeyRequired=self.get_api_key_required(configuration),
                    Integration=self.get_integration(configuration, invoke_lambda_role),
                    MethodResponses=self.get_method_responses(configuration),
                    ResourceId=resource_reference,
                    RestApiId=troposphere.Ref(api),
                    **extra
                )
                template.add_resource(m)
                deployment_dependencies.append(m.name)
                deployment_resources.append(m)

        deploy_hash = hashlib.sha1(six.text_type(uuid.uuid4()).encode('utf-8')).hexdigest()
        deploy = Deployment(
            utils.valid_cloudformation_name(self.name, "Deployment", deploy_hash[:8]),
            DependsOn=sorted(deployment_dependencies),
            StageName=troposphere.Ref('Stage'),
            RestApiId=troposphere.Ref(api)
        )

        template.add_resource(deploy)

        if self._get_true_false('cli-output', 't'):
            template.add_output([
                troposphere.Output(
                    utils.valid_cloudformation_name("Clioutput", self.in_project_name),
                    Value=troposphere.Join(
                        "",
                        [
                            "https://",
                            troposphere.Ref(api),
                            ".execute-api.",
                            troposphere.Ref(troposphere.AWS_REGION),
                            ".amazonaws.com/",
                            troposphere.Ref('Stage')
                        ]
                    ),
                )
            ])
예제 #7
0
    "SendToDiscord",
    Type="String",
    AllowedValues=["True", "False"],
    Default="False",
    Description=
    "Enabling this will tell the lambda function to send messages to a Discord Webhook URL.",
)

DiscordWebhookURL = Parameter(
    "DiscordWebhookURL",
    Type="String",
    Description=
    "Please paste here the URL that Discord provided to you when you created your server's Webhook.",
    NoEcho=True)

Civ6Notif_GW = RestApi("Civ6NotifGW", Name="Civ6Notifications")

Civ6Notif_Role = Role(
    "Civ6NotifLambdaExecutionRole",
    Path="/",
    AssumeRolePolicyDocument={
        "Version":
        "2012-10-17",
        "Statement": [{
            "Action": ["sts:AssumeRole"],
            "Effect": "Allow",
            "Principal": {
                "Service":
                ["lambda.amazonaws.com", "apigateway.amazonaws.com"]
            }
        }]
    Role=GetAtt("LambdaExecutionRole", "Arn"),
    Runtime="nodejs12.x",
    MemorySize=128,
    Timeout=50,
    Layers=[Ref(layer)]
))

#
# API Gateway
#

# create the Api Gateway
rest_api = t.add_resource(RestApi(
    "ApiGateway",
    Name="black-white-troposhpere-lambda-sharp",
    BinaryMediaTypes=["*/*"],  # very important
    EndpointConfiguration=EndpointConfiguration(
        Types=["REGIONAL"]
    )
))

# Create a resource to map the lambda function to
resource = t.add_resource(Resource(
    "ResourceConvert",
    RestApiId=Ref(rest_api),
    PathPart="convert",
    ParentId=GetAtt("ApiGateway", "RootResourceId"),
))

# create a Lambda API method for the Lambda resource
method = t.add_resource(Method(
    "MethodConvert",
예제 #9
0
    def __init__(self, title, template, method_config):
        """
        This class creates an API Gateway object with one or multiple methods attached.
        AWS Cloud Formation Links:
        RestApi: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html
        Resource: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-resource.html
        Method: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-method.html
        Integration:
        https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-apitgateway-method-integration.html
        Troposhere link:
        https://github.com/cloudtools/troposphere/blob/master/troposphere/apigateway.py
        :param title: title of the api gateway and associated resources to be used in cloud formation
        :param template: the troposphere template object to update
        :param method_config: a list of one or many ApiGatewayMethodConfig objects with data prefilled from yaml values
        values
        """
        self.title = title
        self.template = template
        self.methods = []
        self.method_responses = []
        self.integration_responses = []
        self.method_config = method_config
        self.permissions = []

        self.api = self.template.add_resource(
            RestApi(self.title, Name=Join('-',
                                          [Ref('AWS::StackName'), title])))

        for method in self.method_config:
            resource = self.create_resource(method)
            self.get_responses(method)
            integration = self.create_integration(
                method, self.get_lambda_reference(method.lambda_unit))
            self.add_method(resource, integration, method)

        dependencies = []
        for method in self.methods:
            dependencies.append(method.title)

        self.deployment = Deployment(
            '{0}Deployment'.format(self.title),
            Description=Join('', [
                Ref('AWS::StackName'), ' Deployment created for APIGW ',
                self.title
            ]),
            RestApiId=Ref(self.api),
            StageName='amz_deploy',
            DependsOn=dependencies)

        self.template.add_resource(self.deployment)

        self.template.add_output(
            Output(self.deployment.title + 'URL',
                   Description='URL of API deployment: {0}'.format(
                       self.deployment.title),
                   Value=Join('', [
                       'https://',
                       Ref(self.api), '.execute-api.',
                       Ref("AWS::Region"), '.amazonaws.com/',
                       self.deployment.StageName
                   ])))
예제 #10
0
from troposphere.apigateway import RestApi, Method
from troposphere.apigateway import Resource, MethodResponse
from troposphere.apigateway import Integration, IntegrationResponse
from troposphere.apigateway import Deployment, Stage, ApiStage
from troposphere.apigateway import UsagePlan, QuotaSettings, ThrottleSettings
from troposphere.apigateway import ApiKey, StageKey, UsagePlanKey, IntegrationResponse
from troposphere.iam import Role, Policy
from troposphere.awslambda import Function, Code, Permission
from troposphere import GetAtt, Join

bucket = "imjacobclark-artifacts"

t = Template()

# Create the Api Gateway
rest_api = t.add_resource(RestApi("CrimeDataAPI", Name="CrimeDataAPI"))

# Create a role for the lambda function
t.add_resource(
    Role(
        "CrimeDataExecutionRole",
        Path="/",
        Policies=[
            Policy(PolicyName="root",
                   PolicyDocument={
                       "Version":
                       "2012-10-17",
                       "Statement": [{
                           "Action": ["logs:*"],
                           "Resource": "arn:aws:logs:*:*:*",
                           "Effect": "Allow"
예제 #11
0
    def _build_resources(self):
        self.template = Template()
        self.template.set_version("2010-09-09")

        self.template_initial = Template()
        self.template.set_version("2010-09-09")

        # S3 Bucket
        s3_bucket_obj = Bucket("S3Bucket", AccessControl=Private)
        s3_bucket = self.template.add_resource(s3_bucket_obj)
        s3_bucket_output_res = Output("S3BucketName",
                                      Value=Ref(s3_bucket),
                                      Description="S3 bucket")
        self.template.add_output(s3_bucket_output_res)

        self.template_initial.add_resource(s3_bucket_obj)
        self.template_initial.add_output(s3_bucket_output_res)

        # Kinesis Firehose event_in compressor
        event_compressor_name = self.build_resource_name("event-compressor")
        event_compressor = DeliveryStream(
            "EventCompressor",
            DeliveryStreamName=event_compressor_name,
            S3DestinationConfiguration=S3DestinationConfiguration(
                BucketARN=GetAtt("S3Bucket", "Arn"),
                BufferingHints=BufferingHints(IntervalInSeconds=60,
                                              SizeInMBs=25),
                # TODO
                # CloudWatchLoggingOptions=CloudWatchLoggingOptions(
                #     Enabled=True, LogGroupName="FirehosEventCompressor", LogStreamName="FirehosEventCompressor",
                # ),
                CompressionFormat="GZIP",
                Prefix=S3_ENRICHED_PREFIX,
                RoleARN=GetAtt("LambdaExecutionRole", "Arn"),
            ),
        )
        self.template.add_resource(event_compressor)

        # Lambda Execution Role
        self.template.add_resource(
            Role(
                "LambdaExecutionRole",
                Path="/",
                Policies=[
                    Policy(
                        PolicyName="root",
                        PolicyDocument={
                            "Version":
                            "2012-10-17",
                            "Statement": [
                                {
                                    "Action": ["logs:*"],
                                    "Resource": "arn:aws:logs:*:*:*",
                                    "Effect": "Allow"
                                },
                                {
                                    "Action": ["lambda:*"],
                                    "Resource": "*",
                                    "Effect": "Allow"
                                },
                                {
                                    "Action": ["s3:*"],
                                    "Resource":
                                    Join("",
                                         [GetAtt("S3Bucket", "Arn"), "/*"]),
                                    "Effect":
                                    "Allow",
                                },
                                {
                                    "Action": ["firehose:PutRecord"],
                                    "Resource": "*",
                                    "Effect": "Allow"
                                },
                            ],
                        },
                    )
                ],
                AssumeRolePolicyDocument={
                    "Version":
                    "2012-10-17",
                    "Statement": [{
                        "Action": ["sts:AssumeRole"],
                        "Effect": "Allow",
                        "Principal": {
                            "Service": [
                                "lambda.amazonaws.com",
                                "apigateway.amazonaws.com",
                                "firehose.amazonaws.com",
                            ]
                        },
                    }],
                },
            ))

        # Event Receiver Lambda
        matomo_event_receiver_lambda_name = self.build_resource_name(
            "matomo-event-receiver")

        self.template.add_resource(
            Function(
                "LambdaMatomoEventReceiver",
                FunctionName=matomo_event_receiver_lambda_name,
                Code=Code(
                    S3Bucket=Ref(s3_bucket),
                    S3Key=
                    f"{S3_DEPLOYMENT_PREFIX}{self.artifact_filename_hashed(event_receiver_zip_path)}",
                ),
                Handler="lambda.lambda_handler",
                Environment=Environment(
                    Variables={
                        "S3_BUCKET":
                        Ref(s3_bucket),
                        "DELIVERY_STREAM_NAME":
                        event_compressor_name,
                        "IP_GEOCODING_ENABLED":
                        self.cfg.get("ip_geocoding_enabled"),
                        "IP_INFO_API_TOKEN":
                        self.cfg.get("ip_info_api_token"),
                        "USERSTACK_API_TOKEN":
                        self.cfg.get("userstack_api_token"),
                        "DEVICE_DETECTION_ENABLED":
                        self.cfg.get("device_detection_enabled"),
                        "IP_ADDRESS_MASKING_ENABLED":
                        self.cfg.get("ip_address_masking_enabled"),
                    }),
                Role=GetAtt("LambdaExecutionRole", "Arn"),
                Runtime="python3.7",
            ))

        # API Gateway
        api_gateway = self.template.add_resource(
            RestApi("APIGateway",
                    Name=self.build_resource_name("api-gateway")))

        # API Gateway Stage
        api_gateway_deployment = self.template.add_resource(
            Deployment(
                f"APIGatewayDeployment{API_DEPLOYMENT_STAGE}",
                DependsOn="APIGatewayLambdaMatomoEventReceiverMain",
                RestApiId=Ref(api_gateway),
            ))
        api_gateway_stage = self.template.add_resource(
            Stage(
                f"APIGatewayStage{API_DEPLOYMENT_STAGE}",
                StageName=API_DEPLOYMENT_STAGE,
                RestApiId=Ref(api_gateway),
                DeploymentId=Ref(api_gateway_deployment),
            ))

        # API Gateway usage plan
        self.template.add_resource(
            UsagePlan(
                "APIGatewayUsagePlan",
                UsagePlanName="APIGatewayUsagePlan",
                Quota=QuotaSettings(Limit=50000, Period="MONTH"),
                Throttle=ThrottleSettings(BurstLimit=500, RateLimit=5000),
                ApiStages=[
                    ApiStage(ApiId=Ref(api_gateway),
                             Stage=Ref(api_gateway_stage))
                ],
            ))

        # API Gateway resource to map the lambda function to
        def _lambda_method_obj(resource, suffix):
            resource = self.template.add_resource(resource)

            return self.template.add_resource(
                Method(
                    f"APIGatewayLambdaMatomoEventReceiver{suffix}",
                    DependsOn="LambdaMatomoEventReceiver",
                    RestApiId=Ref(api_gateway),
                    AuthorizationType="NONE",
                    ResourceId=Ref(resource),
                    HttpMethod="ANY",
                    Integration=Integration(
                        Credentials=GetAtt("LambdaExecutionRole", "Arn"),
                        Type="AWS_PROXY",
                        IntegrationHttpMethod="POST",
                        Uri=Join(
                            "",
                            [
                                f"arn:aws:apigateway:{self.region_name}:lambda:path/2015-03-31/functions/",
                                GetAtt("LambdaMatomoEventReceiver", "Arn"),
                                "/invocations",
                            ],
                        ),
                    ),
                ), )

        # API Gateway Lambda method
        _lambda_method_obj(
            Resource(
                "APIGatewayResourceMatomoEventReceiverMain",
                RestApiId=Ref(api_gateway),
                PathPart="matomo-event-receiver",
                ParentId=GetAtt("APIGateway", "RootResourceId"),
            ),
            "Main",
        )

        # matomo.php path alias for the event receiver lambda
        _lambda_method_obj(
            Resource(
                "APIGatewayResourceMatomoEventReceiverMatomo",
                RestApiId=Ref(api_gateway),
                PathPart="matomo.php",
                ParentId=GetAtt("APIGateway", "RootResourceId"),
            ),
            "Matomo",
        )

        self.template.add_output([
            Output(
                OUTPUT_API_GATEWAY_ENDPOINT,
                Value=Join(
                    "",
                    [
                        "https://",
                        Ref(api_gateway),
                        f".execute-api.{self.region_name}.amazonaws.com/",
                        API_DEPLOYMENT_STAGE,
                    ],
                ),
                Description="API Endpoint",
            ),
            Output("APIId", Value=Ref(api_gateway), Description="API ID"),
        ])

        # Glue Execution Role
        self.template.add_resource(
            Role(
                "GlueExecutionRole",
                Path="/",
                Policies=[
                    Policy(
                        PolicyName="root",
                        PolicyDocument={
                            "Version":
                            "2012-10-17",
                            "Statement": [
                                {
                                    "Action": ["logs:*"],
                                    "Resource": "arn:aws:logs:*:*:*",
                                    "Effect": "Allow"
                                },
                                {
                                    "Effect":
                                    "Allow",
                                    "Action": [
                                        "glue:*",
                                        "s3:GetBucketLocation",
                                        "s3:ListBucket",
                                        "s3:ListAllMyBuckets",
                                        "s3:GetBucketAcl",
                                        "iam:ListRolePolicies",
                                        "iam:GetRole",
                                        "iam:GetRolePolicy",
                                        "cloudwatch:PutMetricData",
                                    ],
                                    "Resource": ["*"],
                                },
                                {
                                    "Effect": "Allow",
                                    "Action": ["s3:CreateBucket"],
                                    "Resource": ["arn:aws:s3:::aws-glue-*"],
                                },
                                {
                                    "Effect":
                                    "Allow",
                                    "Action": [
                                        "s3:GetObject", "s3:PutObject",
                                        "s3:DeleteObject"
                                    ],
                                    "Resource": [
                                        "arn:aws:s3:::aws-glue-*/*",
                                        "arn:aws:s3:::*/*aws-glue-*/*"
                                    ],
                                },
                                {
                                    "Effect":
                                    "Allow",
                                    "Action": ["s3:GetObject"],
                                    "Resource": [
                                        "arn:aws:s3:::crawler-public*",
                                        "arn:aws:s3:::aws-glue-*"
                                    ],
                                },
                                {
                                    "Effect":
                                    "Allow",
                                    "Action": [
                                        "logs:CreateLogGroup",
                                        "logs:CreateLogStream",
                                        "logs:PutLogEvents"
                                    ],
                                    "Resource":
                                    ["arn:aws:logs:*:*:/aws-glue/*"],
                                },
                                {
                                    "Action": ["s3:*"],
                                    "Resource":
                                    Join("",
                                         [GetAtt("S3Bucket", "Arn"), "/*"]),
                                    "Effect":
                                    "Allow",
                                },
                                {
                                    "Action": ["iam:PassRole"],
                                    "Effect":
                                    "Allow",
                                    "Resource": [
                                        "arn:aws:iam::*:role/service-role/AWSGlueServiceRole*"
                                    ],
                                    "Condition": {
                                        "StringLike": {
                                            "iam:PassedToService":
                                            ["glue.amazonaws.com"]
                                        }
                                    },
                                },
                                {
                                    "Action": ["iam:PassRole"],
                                    "Effect": "Allow",
                                    "Resource":
                                    "arn:aws:iam::*:role/AWSGlueServiceRole*",
                                    "Condition": {
                                        "StringLike": {
                                            "iam:PassedToService":
                                            ["glue.amazonaws.com"]
                                        }
                                    },
                                },
                            ],
                        },
                    )
                ],
                AssumeRolePolicyDocument={
                    "Version":
                    "2012-10-17",
                    "Statement": [{
                        "Action": ["sts:AssumeRole"],
                        "Effect": "Allow",
                        "Principal": {
                            "Service": ["glue.amazonaws.com"]
                        },
                    }],
                },
            ))

        # Glue Database
        glue_catalog_id = Ref("AWS::AccountId")
        glue_database_name = self.build_resource_name("").replace("-", "_")
        glue_database = self.template.add_resource(
            Database(
                "GlueDatabase",
                CatalogId=glue_catalog_id,
                DatabaseInput=DatabaseInput(
                    Name=glue_database_name,
                    LocationUri=Join(
                        "",
                        ["s3://",
                         Ref(s3_bucket), f"/{S3_TEPM_PREFIX}glue/"]),
                ),
            ))

        # build enriched table schema
        table_schema = []
        table_fields = []
        for field, data_type in event_schema.schema_to_glue_schema(
                event_schema.ENRICHED):
            table_schema.append(Column(Name=field, Type=data_type))
            table_fields.append(field)

        # Glue events enriched table
        self.template.add_resource(
            Table(
                "GlueTableEventsEnriched",
                DatabaseName=Ref(glue_database),
                CatalogId=glue_catalog_id,
                TableInput=TableInput(
                    Name="events_enriched",
                    TableType="EXTERNAL_TABLE",
                    StorageDescriptor=StorageDescriptor(
                        Columns=table_schema,
                        InputFormat="org.apache.hadoop.mapred.TextInputFormat",
                        OutputFormat=
                        "org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat",
                        Location=Join(
                            "",
                            ["s3://",
                             Ref(s3_bucket), "/", S3_ENRICHED_PREFIX]),
                        Compressed=True,
                        Parameters={
                            "classification": "json",
                            "compressionType": "gzip",
                            "typeOfData": "file"
                        },
                        SerdeInfo=SerdeInfo(
                            Parameters={"paths": ",".join(table_fields)},
                            SerializationLibrary=
                            "org.openx.data.jsonserde.JsonSerDe",
                        ),
                    ),
                ),
            ))

        # add Name tag to all resources that supports tagging
        for resource_name, resource in chain(
                self.template_initial.resources.items(),
                self.template.resources.items()):
            if "Tags" not in resource.props:
                continue
            tags_to_add = Tags(
                Name=f"{self.name}-{camel_case_to_dashed(resource_name)}")
            tags_existing = getattr(resource, "Tags", Tags())
            setattr(resource, "Tags", tags_existing + tags_to_add)

        # add stack templates for enabled modules
        if self.exists:
            for module in self.modules:
                echo.enum_elm(f"preparing stack for module {module.id}")

                # add module prefix to outputs
                module_stack = module.stack
                outputs_prefixed = {}
                for title, output in module_stack.outputs.items():
                    # e.g. emr-spark-cluster => EmrSparkCluster
                    module_name = dashed_to_camel_case(module.id)
                    output.title = f"{module_name}{output.title}"
                    outputs_prefixed[output.title] = output
                module_stack.outputs = outputs_prefixed

                # add Name attr to all resources that supports the Name attr
                for resource_name, resource in module_stack.resources.items():
                    if "Name" not in resource.props:
                        continue
                    name = f"{self.name}-{module.id}-{camel_case_to_dashed(resource_name)}"
                    setattr(resource, "Name", name)

                # add Name tag to all resources that supports tagging
                for resource_name, resource in module_stack.resources.items():
                    if "Tags" not in resource.props:
                        continue
                    name_tag = f"{self.name}-{module.id}-{camel_case_to_dashed(resource_name)}"
                    tags_to_add = Tags(Name=name_tag)
                    tags_existing = getattr(resource, "Tags", Tags())
                    setattr(resource, "Tags", tags_existing + tags_to_add)

                # deploy stack as nested stack
                with TemporaryDirectory() as tmp_dir:
                    # write module stack tpl to tmp file
                    s3_resource = self.boto_session.resource("s3")
                    s3_bucket_name = self.get_output("S3BucketName")
                    tmp_file_path = Path(tmp_dir, f"{module.id}_stack_tpl.yml")
                    with io.open(tmp_file_path, "w+") as tmp_file_fh:
                        # upload nested stack tpl filt to s3
                        tmp_file_fh.write(module_stack.to_yaml())
                        tmp_file_fh.seek(0)
                        s3_filename = f"{S3_DEPLOYMENT_PREFIX}{self.artifact_filename_hashed(tmp_file_fh.name)}"
                        s3_resource.Object(
                            s3_bucket_name,
                            s3_filename).put(Body=tmp_file_fh.read())

                        # add stack resource
                        module_id = module.id
                        module_id = module_id.replace("-", "")
                        self.template.add_resource(
                            Stack(
                                module_id,
                                TemplateURL=
                                f"https://s3.amazonaws.com/{s3_bucket_name}/{s3_filename}",
                            ))
예제 #12
0
def add_apigateway_to_lambda(t: Template):
    # Create the Api Gateway
    rest_api = t.add_resource(RestApi("RecordsApi", Name="ExampleApi"))

    return rest_api
예제 #13
0
                                                       "DomainName"))))

        # Redirect outputs
        t.add_output([
            Output(
                'CDNDomainOutput{}'.format(src_domain.replace('.', '0')),
                Description="Domain for CDN",
                Value=GetAtt(cdnDistribution, 'DomainName'),
            )
        ])

#####################################################################################################################
# API Gateway
#####################################################################################################################
rest_api = t.add_resource(
    RestApi("api", Name="{}-{}".format(env_l, app_group_l)))

#####################################################################################################################
# DynamoDB table
#####################################################################################################################
myDynamoDB = t.add_resource(
    Table("myDynamoDBTable",
          TableName='counters',
          AttributeDefinitions=[
              AttributeDefinition(AttributeName='website', AttributeType='S')
          ],
          KeySchema=[KeySchema(AttributeName='website', KeyType='HASH')],
          ProvisionedThroughput=ProvisionedThroughput(
              ReadCapacityUnits=readunits, WriteCapacityUnits=writeunits)))

#####################################################################################################################
예제 #14
0
))

cloudfront_certificate = template.add_resource(Certificate(
    "CloudFrontCertificate",
    DomainName=Ref(domain_name),
    DomainValidationOptions=[DomainValidationOption(
        DomainName=Ref(domain_name),
        ValidationDomain=ImportValue(Join('-', [Ref(dns_stack), 'HostedZoneName'])),
    )],
    ValidationMethod='DNS',
))

api_gateway = template.add_resource(RestApi(
    'ApiGateway',
    Name=Ref(AWS_STACK_NAME),
    Description='REST API to handle requests that fall through lambda @ edge.',
    EndpointConfiguration=EndpointConfiguration(
        Types=['REGIONAL'],
    )
))

health_resource = template.add_resource(Resource(
    'HealthResource',
    RestApiId=Ref(api_gateway),
    PathPart="health",
    ParentId=GetAtt(api_gateway, "RootResourceId"),
))

upvote_resource = template.add_resource(Resource(
    'UpvoteResource',
    RestApiId=Ref(api_gateway),
    PathPart="upvote",
    def get_framework_template(self):

        from troposphere import (
            GetAtt,
            Ref,
            Sub,
            Tags,
            Template,
        )

        from troposphere.apigateway import (
            BasePathMapping,
            Deployment,
            DomainName,
            Integration,
            IntegrationResponse,
            Method,
            MethodResponse,
            Resource,
            RestApi,
            Stage,
        )

        from troposphere.ec2 import (
            VPCEndpoint, )

        from troposphere.s3 import (
            Bucket,
            BucketPolicy,
            VersioningConfiguration,
        )

        t = Template()

        ###############
        # API Gateway #
        ###############

        api = t.add_resource(
            RestApi(
                'ApiGateway',
                Name=self.args.stack + 'Api',
                Description=
                'API for portal and redirects for the Cornell AppStream Service',
            ))

        ####################
        # Redirect Methods #
        ####################

        stack_url = "'https://shibidp.cit.cornell.edu/idp/profile/SAML2/Unsolicited/SSO?providerId=urn:amazon:webservices&target=https://appstream2.{region}.aws.amazon.com/saml?accountId={account}%26stack={stack}'"
        stack_link = '<li><a href="./{redirect_nal}">{redirect}</a></li>'

        methods = []
        stack_links = ''
        for redirect in sorted(self.config['Redirects'].keys()):
            redirect_info = self.config['Redirects'][redirect]
            redirect_nal = re.sub('\W+', '', redirect)
            redirect_url = stack_url.format(account=redirect_info['account'],
                                            region=redirect_info['region'],
                                            stack=redirect_info['stack'])
            methods.append('ApiGatewayRedirect' + redirect_nal)
            stack_links += stack_link.format(redirect=redirect,
                                             redirect_nal=redirect_nal)

            resource = t.add_resource(
                Resource(
                    'ApiGatewayResource' + redirect_nal,
                    ParentId=GetAtt(api, 'RootResourceId'),
                    PathPart=redirect_nal,
                    RestApiId=Ref(api),
                ))

            method = t.add_resource(
                Method(
                    'ApiGatewayRedirect' + redirect_nal,
                    AuthorizationType='None',
                    HttpMethod='ANY',
                    Integration=Integration(
                        Type='MOCK',
                        IntegrationResponses=[
                            IntegrationResponse(
                                ResponseParameters={
                                    'method.response.header.Location':
                                    redirect_url,
                                },
                                ResponseTemplates={
                                    'application/json': '{"redirect": 302}'
                                },
                                StatusCode='302',
                            ),
                        ],
                        RequestTemplates={
                            'application/json': '{"statusCode":200}'
                        },
                    ),
                    MethodResponses=[
                        MethodResponse(
                            ResponseParameters={
                                'method.response.header.Location': True,
                            },
                            StatusCode='302',
                        ),
                    ],
                    ResourceId=Ref(resource),
                    RestApiId=Ref(api),
                ))

        ###########################
        # API Gateway Root Method #
        ###########################

        with open('./include/root_integration_template.html',
                  'r') as rootTemplateHTML:
            rootTemplate = rootTemplateHTML.read()

        root_method = t.add_resource(
            Method(
                'ApiGatewayRootMethod',
                AuthorizationType='None',
                HttpMethod='ANY',
                Integration=Integration(
                    Type='MOCK',
                    IntegrationResponses=[
                        IntegrationResponse(
                            ResponseParameters={
                                'method.response.header.Content-Type':
                                "'text/html'",
                            },
                            ResponseTemplates={
                                'text/html':
                                rootTemplate.format(stack_links=stack_links),
                            },
                            StatusCode='200',
                        ),
                    ],
                    RequestTemplates={
                        'application/json': '{"statusCode":200}'
                    },
                ),
                MethodResponses=[
                    MethodResponse(
                        ResponseParameters={
                            'method.response.header.Content-Type': True,
                        },
                        StatusCode='200',
                    ),
                ],
                ResourceId=GetAtt(api, 'RootResourceId'),
                RestApiId=Ref(api),
            ))

        #####################
        # API Gateway Stage #
        #####################

        api_deployment = t.add_resource(
            Deployment(
                'ApiGatewayDeployment' + self.run_time,
                Description=
                'Deployment for API portal and redirects for the Cornell AppStream Service',
                RestApiId=Ref(api),
                DependsOn=methods + ['ApiGatewayRootMethod'],
            ))

        api_stage = t.add_resource(
            Stage(
                'ApiGatewayStage',
                DeploymentId=Ref(api_deployment),
                Description=
                'Stage for API portal and redirects for the Cornell AppStream Service',
                RestApiId=Ref(api),
                StageName='apps',
            ))

        ######################
        # API Gateway Domain #
        ######################

        api_domain = t.add_resource(
            DomainName(
                'ApiGatewayDomain',
                CertificateArn=self.config['ACM_ARN'],
                DomainName=self.config['DomainName'],
            ))

        api_domain_mapping = t.add_resource(
            BasePathMapping(
                'ApiGatewayDomainMapping',
                DomainName=Ref(api_domain),
                RestApiId=Ref(api),
                Stage=Ref(api_stage),
            ))

        ###################
        # VPC S3 Endpoint #
        ###################

        s3_endpoint = t.add_resource(
            VPCEndpoint(
                'S3VPCEndpoint',
                ServiceName=Sub('com.amazonaws.${AWS::Region}.s3'),
                VpcId=self.config['VPC'],
                RouteTableIds=self.config['RouteTables'],
            ))

        ####################
        # S3 Bucket Policy #
        ####################

        sub_args = {
            'bucket_name': self.config['Bucket'],
            'vpc_id': self.config['VPC']
        }
        with open('./include/bucket_policy.json', 'r') as bucketPolicyJSON:
            bucket_policy_document = bucketPolicyJSON.read()

        bucket_policy = t.add_resource(
            BucketPolicy(
                'FrameworkBucketPolicy',
                Bucket=self.config['Bucket'],
                PolicyDocument=Sub(bucket_policy_document, **sub_args),
            ))

        with open('./cloudformation/framework.json', 'w') as frameworkTemplate:
            frameworkTemplate.write(t.to_json())

        return t
예제 #16
0
    def __init__(self, lambda_names):
        self.t = Template()
        self.lambda_uris = []

        lambda_iam_policy_arn = self.t.add_parameter(Parameter(
            "LambdaIAMPolicyARN",
            Description="ARN of the base IAM policy for Lambda functions",
            Type="String"
        ))

        apigw_stage_name = self.t.add_parameter(Parameter(
            "APIGWStageName",
            Description="Stage name for API Gateway deployment",
            Type="String"
        ))

        json_mapping_template = self.t.add_parameter(Parameter(
            "MappingTemplate",
            Description="Mapping template for request body, uri and body params, and stage variables",
            Default=MAPPING_TEMPLATE,
            Type="String"
        ))

        for l in sorted(lambda_names):
            self.add_lambda_uri_parameters(l)

        apigw_role = self.t.add_resource(Role(
            "APIGWRole",
            AssumeRolePolicyDocument={
                "Version": "2012-10-17",
                "Statement": [{
                    "Action": ["sts:AssumeRole"],
                    "Effect": "Allow",
                    "Principal": {
                        "Service": ["apigateway.amazonaws.com"]
                    }
                }]
            },
            Policies=[Policy(
                PolicyName="APIGateway",
                PolicyDocument={
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Action": ["lambda:InvokeFunction", "iam:PassRole"],
                            "Resource": "*",
                        },
                    ]
                })
            ],
        ))

        apigw = self.t.add_resource(RestApi(
            "APIGW",
            Body=self.get_swagger()
        ))

        custom_apigw_deployment_role = self.t.add_resource(Role(
            "CustomAPIGWDeploymentRole",
            AssumeRolePolicyDocument={
                "Version": "2012-10-17",
                "Statement": [{
                    "Action": ["sts:AssumeRole"],
                    "Effect": "Allow",
                    "Principal": {
                        "Service": ["lambda.amazonaws.com"]
                    }
                }]
            },
            ManagedPolicyArns=[
                Ref(lambda_iam_policy_arn),
            ],
            Policies=[Policy(
                PolicyName="CreateDeployment",
                PolicyDocument={
                    "Version": "2012-10-17",
                    "Statement": [
                        {
                            "Effect": "Allow",
                            "Action": ["apigateway:POST"],
                            "Resource": [
                                Join('', [
                                    "arn:aws:apigateway:",
                                    Ref('AWS::Region'),
                                    "::/restapis/",
                                    Ref(apigw),
                                    "/deployments",
                                ]),
                            ],
                        },
                    ]
                })
            ],
        ))

        self.custom_apigw_deployment_lambda = self.t.add_resource(Function(
            f"CustomAPIGWDeploymentLambda",
            FunctionName="CustomAPIGWDeploymentLambda",
            Handler="index.handler",
            Runtime="python3.6",
            Role=GetAtt(custom_apigw_deployment_role, "Arn"),
            Code=Code(
                ZipFile=self.get_custom_apigw_deployment_code()
            )
        ))

        apigw_deployment = self.t.add_resource(CustomAPIGWDeployment(
            "APIGWDeployment",
            ServiceToken=GetAtt(self.custom_apigw_deployment_lambda, "Arn"),
            RestApiId=Ref(apigw),
            StageName=Ref(apigw_stage_name),
            LambdaUris=self.lambda_uris
        ))

        self.t.add_output(Output(
            "URL",
            Value=Join('', [
                'https://',
                Ref(apigw),
                '.execute-api.',
                Ref('AWS::Region'),
                '.amazonaws.com/',
                Ref(apigw_stage_name),
            ]),
            Description="API Gateway stage's URL"
        ))