def create_integration(self, method_config, lambda_arn): """ Creates an integration object using a single provided ApiGatewayMethodConfig object. :param method_config: a single ApiGatewayMethodConfig object :param lambda_arn: the ARN of a lambda function to point this integration at. :return: a troposphere integration object """ integration = Integration( '{0}Integration'.format(method_config.method_name), Type='AWS', IntegrationHttpMethod=method_config.httpmethod, IntegrationResponses=self.integration_responses, RequestTemplates=method_config.request.templates, Uri=Join('', [ 'arn:aws:apigateway:ap-southeast-2:lambda:path/2015-03-31/functions/', lambda_arn, '/invocations' ])) perm = self.template.add_resource( Permission('{0}Permission'.format(integration.title), Action='lambda:InvokeFunction', FunctionName=lambda_arn, Principal='apigateway.amazonaws.com')) self.permissions.append(perm) # At time of creation of this class, the PassthroughBehavior parameter is not implemented for integrations # in troposphere. The below assigns it for now. This can be reworked into the above troposphere object once # troposphere is updated. integration.resource['PassthroughBehavior'] = "WHEN_NO_TEMPLATES" return integration
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", ], ), ), ), )
def create_integration(self, method_config, lambda_arn): """ Creates an integration object using a single provided ApiGatewayMethodConfig object. :param method_config: a single ApiGatewayMethodConfig object :param lambda_arn: the ARN of a lambda function to point this integration at. :return: a troposphere integration object """ integration = Integration( '{0}Integration'.format(method_config.method_name), Type='AWS', IntegrationHttpMethod=method_config.httpmethod, IntegrationResponses=self.integration_responses, RequestTemplates=method_config.request.templates, Uri=Join('', [ 'arn:aws:apigateway:ap-southeast-2:lambda:path/2015-03-31/functions/', lambda_arn, '/invocations' ] ) ) perm = self.template.add_resource(Permission( '{0}Permission'.format(integration.title), Action='lambda:InvokeFunction', FunctionName=lambda_arn, Principal='apigateway.amazonaws.com' )) self.permissions.append(perm) # At time of creation of this class, the PassthroughBehavior parameter is not implemented for integrations # in troposphere. The below assigns it for now. This can be reworked into the above troposphere object once # troposphere is updated. integration.resource['PassthroughBehavior'] = "WHEN_NO_TEMPLATES" return integration
def generate_proxy_method(self, name, auth, uriParams, resource, api): return Method( name, AuthorizationType=auth, HttpMethod='ANY', Integration=Integration( IntegrationHttpMethod='POST', Type='AWS_PROXY', Uri=Sub( 'arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:${FunctionName}/invocations', **uriParams), ), ResourceId=resource, RestApiId=api, )
def get_integration(self, resource, invoke_lambda_role): integration_type = self.get_integration_type(resource) if integration_type: extra = {} if 'parameters' in resource['integration']: extra['RequestParameters'] = resource['integration']['parameters'] return Integration( IntegrationResponses=self.get_integration_responses(resource), IntegrationHttpMethod=self.get_integration_http_method(resource), Type=integration_type, Credentials=self.get_integration_credentials(resource, invoke_lambda_role), RequestTemplates=self.get_request_templates(resource), Uri=self.get_integration_uri(resource), **extra ) return troposphere.Ref(troposphere.AWS_NO_VALUE)
def add_method_to_apigateway(t: Template, lambda_function: Function, apigwlambda_role: Role, rest_api: RestApi, resource: Resource, method_type: str): return t.add_resource( Method( f'Method{lambda_function.name}', DependsOn=lambda_function, RestApiId=Ref(rest_api), AuthorizationType="NONE", ResourceId=Ref(resource), HttpMethod=method_type, Integration=Integration( Credentials=GetAtt(apigwlambda_role, "Arn"), Type="AWS", IntegrationHttpMethod='POST', IntegrationResponses=[IntegrationResponse(StatusCode='200')], Uri=Join("", [ "arn:aws:apigateway:eu-west-1:lambda:path/2015-03-31/functions/", GetAtt(lambda_function, "Arn"), "/invocations" ])), MethodResponses=[MethodResponse("CatResponse", StatusCode='200')]))
)) # Create a Lambda API method for the Lambda resource method = t.add_resource( Method( "LambdaMethod", DependsOn='FoobarFunction', RestApiId=Ref(rest_api), AuthorizationType="NONE", ResourceId=Ref(resource), HttpMethod="GET", Integration=Integration( Credentials=GetAtt("LambdaExecutionRole", "Arn"), Type="AWS", IntegrationHttpMethod='POST', IntegrationResponses=[IntegrationResponse(StatusCode='200')], Uri=Join("", [ "arn:aws:apigateway:eu-west-1:lambda:path/2015-03-31/functions/", GetAtt("FoobarFunction", "Arn"), "/invocations" ])), MethodResponses=[MethodResponse("CatResponse", StatusCode='200')])) # Create a deployment stage_name = 'v1' deployment = t.add_resource( Deployment( "%sDeployment" % stage_name, DependsOn="LambdaMethod", RestApiId=Ref(rest_api), ))
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", Integration=Integration( Type="AWS", IntegrationHttpMethod="POST", IntegrationResponses=[IntegrationResponse(StatusCode="200")], Uri=Join("", [ "arn:aws:apigateway:", Ref('AWS::Region'), ":lambda:path/2015-03-31/functions/", GetAtt(EmailSubscribeFunction, "Arn"), "/invocations" ])), MethodResponses=[MethodResponse("CatResponse", StatusCode="200")])) # /unsubscribe unsubscribe_resource = t.add_resource( Resource("unsubscribeResource", RestApiId=Ref(rest_api), PathPart="unsubscribe", ParentId=GetAtt("EmailListApi", "RootResourceId"))) unsubscribe_method = t.add_resource( Method("unsubscribeMethod",
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()
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)
PathPart="civ6", ParentId=GetAtt("Civ6NotifGW", "RootResourceId"), ) Civ6Notif_PostMethod = Method( "Civ6NotifPostMethod", DependsOn='Civ6NotifFunction', RestApiId=Ref(Civ6Notif_GW), AuthorizationType="NONE", ResourceId=Ref(Civ6Notif_GW_Resource), HttpMethod="POST", Integration=Integration( Credentials=GetAtt("Civ6NotifLambdaExecutionRole", "Arn"), Type="AWS", IntegrationHttpMethod='POST', IntegrationResponses=[IntegrationResponse(StatusCode='200')], Uri=Join("", [ "arn:aws:apigateway:", Ref("AWS::Region"), ":lambda:path/2015-03-31/functions/", GetAtt("Civ6NotifFunction", "Arn"), "/invocations" ])), MethodResponses=[MethodResponse("CatResponse", StatusCode='200')]) stage_name = "prod" Civ6Notif_GW_Deployment = Deployment(f'{stage_name}Deployment', RestApiId=Ref(Civ6Notif_GW), DependsOn="Civ6NotifPostMethod") Civ6Notif_GW_Stage = Stage(f'{stage_name}Stage', StageName=stage_name, RestApiId=Ref(Civ6Notif_GW),
ParentId=GetAtt("ApiGateway", "RootResourceId"), )) # create a Lambda API method for the Lambda resource method = t.add_resource(Method( "MethodConvert", DependsOn="Lambda", # The Lambda Ref RestApiId=Ref(rest_api), AuthorizationType="NONE", ResourceId=Ref(resource), HttpMethod="POST", Integration=Integration( Credentials=GetAtt("LambdaExecutionRole", "Arn"), Type="AWS_PROXY", IntegrationHttpMethod='POST', Uri=Join("", [ "arn:aws:apigateway:" + args.region + ":lambda:path/2015-03-31/functions/", GetAtt("Lambda", "Arn"), "/invocations" ]) ), )) # allow the API Gateway to invoke Lambda permission = t.add_resource(Permission( "Permission", Action="lambda:InvokeFunction", FunctionName=GetAtt("Lambda", "Arn"), Principal="apigateway.amazonaws.com", SourceArn=Join("", [ "arn:aws:execute-api:" + args.region + ":", Ref("AWS::AccountId"),
ParentId=Ref(method + "Date"), )) # Create a Lambda API method for the Lambda resource method = t.add_resource( Method( "CrimeDataAPIMethod" + method, DependsOn='CrimeDataAPIFunction', RestApiId=Ref(rest_api), AuthorizationType="NONE", ResourceId=Ref(query), HttpMethod="GET", Integration=Integration( Credentials=GetAtt("CrimeDataExecutionRole", "Arn"), Type="AWS_PROXY", IntegrationHttpMethod='POST', Uri=Join("", [ "arn:aws:apigateway:eu-west-1:lambda:path/2015-03-31/functions/", GetAtt("CrimeDataAPIFunction", "Arn"), "/invocations" ])), )) # Allow the gateway to invoke Lambda permission = t.add_resource( Permission("CrimeDataAPILambdaPermission", Action="lambda:InvokeFunction", FunctionName=GetAtt("CrimeDataAPIFunction", "Arn"), Principal="apigateway.amazonaws.com", SourceArn=Join("", [ "arn:aws:execute-api:", Ref("AWS::Region"), ":", Ref("AWS::AccountId"), ":",
ResourceId=Ref(resource), HttpMethod="GET", MethodResponses=[ MethodResponse("CatResponse", StatusCode='200', ResponseModels={'application/json': 'Empty'}) ], Integration=Integration( Credentials=GetAtt("LambdaExecutionRole", "Arn"), PassthroughBehavior='WHEN_NO_MATCH', Type="AWS", IntegrationHttpMethod='POST', IntegrationResponses=[ IntegrationResponse( StatusCode='200', ResponseTemplates={'application/json': ''}, ) ], Uri=Join("", [ "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/", GetAtt("function", "Arn"), "/invocations" ]), RequestTemplates={'application/json': '{"statusCode": 200}'}, ), )) deployment = t.add_resource( Deployment( "%sDeployment" % stage_name, DependsOn="optionsmethod", RestApiId=Ref(rest_api),
health_method = template.add_resource(Method( "HealthMethod", ApiKeyRequired=True, RestApiId=Ref(api_gateway), AuthorizationType="NONE", ResourceId=Ref(health_resource), HttpMethod="GET", OperationName='mock', Integration=Integration( Type='MOCK', IntegrationResponses=[IntegrationResponse( ResponseTemplates={ 'application/json': "{\"message\": \"OK\"}" }, StatusCode='200' )], PassthroughBehavior='WHEN_NO_TEMPLATES', RequestTemplates={ 'application/json': "{\"statusCode\": 200, \"message\": \"OK\"}" }, ), MethodResponses=[ MethodResponse( 'HealthResponse', ResponseModels={ 'application/json': Ref(health_model), }, StatusCode='200', ) ],
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