Lambda permission not being created when using cloudformation - amazon-web-services

I am trying to create a simple infra using cloudformation. I have to create an Rest API Gateway and Lambda function. That function will be called using API Gateway.
Api Gateway > Lambda
The cloudformation code is below ( I am not showing the code related to role creation or managed policy).
medtestFunction:
Type: "AWS::Lambda::Function"
Properties:
Description: ""
Environment:
Variables:
APIID: !Ref medTestRestapi
SLACK_VERIFICATION_TOKEN:
Ref: SlackVerificationToken
SLACK_INCOMING_WEBHOOK_URL:
Ref: SlackIncomingWebhookURL
FunctionName: "med-test2"
Handler: "index.handler"
Architectures:
- "x86_64"
Code:
S3Bucket:
Ref: S3CodeBucket
S3Key:
Ref: MedTestFunctionS3Key
MemorySize: 128
Role: !GetAtt medtestrole.Arn
Runtime: "nodejs14.x"
Timeout: 6
TracingConfig:
Mode: "PassThrough"
medTestRestapi:
Type: "AWS::ApiGateway::RestApi"
Properties:
Name: "medtest2"
Description: "medtest2"
ApiKeySourceType: "HEADER"
EndpointConfiguration:
Types:
medTestApiStage:
Type: "AWS::ApiGateway::Stage"
Properties:
StageName: "a"
DeploymentId: !Ref medTestApiDeployment
RestApiId: !Ref medTestRestapi
Description: "a"
CacheClusterEnabled: false
TracingEnabled: false
medTestApiMethod:
DependsOn: medtestFunction
Type: "AWS::ApiGateway::Method"
Properties:
RestApiId: !Ref medTestRestapi
ResourceId: !GetAtt medTestRestapi.RootResourceId
HttpMethod: "POST"
AuthorizationType: "NONE"
ApiKeyRequired: false
RequestParameters: {}
MethodResponses:
-
ResponseModels:
"application/json": "Empty"
StatusCode: "200"
Integration:
ContentHandling: "CONVERT_TO_TEXT"
IntegrationHttpMethod: "POST"
IntegrationResponses:
-
ResponseTemplates: {}
StatusCode: "200"
PassthroughBehavior: "WHEN_NO_MATCH"
TimeoutInMillis: 29000
Type: "AWS_PROXY"
Uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:med-test2/invocations"
medTestApiDeployment:
DependsOn: medTestApiMethod
Type: "AWS::ApiGateway::Deployment"
Properties:
RestApiId: !Ref medTestRestapi
Description: "a"
medTestFunctionPermission:
DependsOn: [medTestApiDeployment, medTestApiMethod]
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt medtestFunction.Arn
Principal: "apigateway.amazonaws.com"
SourceArn: !Join [ ":", ["arn:aws:execute-api", !Ref AWS::Region, !Ref AWS::AccountId, !Ref medTestRestapi, "/*/POST/" ] ]
After stack creation when I am checking the function it says
The API with ID : could not be found.
But when I add the trigger manually using console on top of the created stack then it works. Any idea what I am doing wrong? Thanks

you've got one colon too many in SourceArn of medTestFunctionPermission
The one just after the API Gateway ID
You have:
arn:aws:execute-api:eu-west-1:<accountId>:<apiGWId>:/*/POST/
Should be:
arn:aws:execute-api:eu-west-1:<accountId>:<apiGWId>/*/POST/
You can use !Sub instead of !Join. It's easier to read:
SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${medTestRestapi}/*/POST/

Related

cloudFormation: api-gateway with nested resources - 500 error during testing workflow

I built an cloudFormation template. It perform a simple workflow: client make a request -> api gateway handle it and send to lambda fucntion via proxy integration. There is a role between api gateway an a lambda.
My template consist of:
root resource (AudienceApi)
nested resource (Segment)
method post (PostMethod) with lambda`s integration
lambda fucntion (lambdaFunction)
lambda invoker (it is a permission for api gateway to invoke the lambda)
lambda role
And during testing the whole workflow I have faced with a problem - api responce with an error 500 Internal Server Error. From log I found message:
Invalid permissions on Lambda function.
I continue testing and find out when I remove nested resource (Segment) and connect method post resource (PostMethod) directly to root resource (AudienceApi) my workflow started to working.
Question: What wrong with my template? why it is not working with nested resource path?
Maybe someone look at my template and find an error?
template:
AWSTemplateFormatVersion: "2010-09-09"
Description: "My API Gateway and Lambda function"
Parameters:
apiGatewayStageName:
Type: "String"
AllowedPattern: "^[a-z0-9]+$"
Default: "call"
lambdaFunctionName:
Type: "String"
AllowedPattern: "^[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+$"
Default: "my-function"
Resources:
AudienceApi:
Type: "AWS::ApiGateway::RestApi"
Properties:
Name: "my-api"
Description: "My API"
Segment:
Type: 'AWS::ApiGateway::Resource'
Properties:
RestApiId: !Ref AudienceApi
ParentId: !GetAtt
- AudienceApi
- RootResourceId
PathPart: segment
PostMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
HttpMethod: POST
# RequestModels:
# application/json: !Ref SegmentationRequestModel
AuthorizationType: NONE
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
Uri: !Sub
- "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations"
- lambdaArn: !GetAtt "lambdaFunction.Arn"
ResourceId: !Ref Segment
RestApiId: !Ref AudienceApi
lambdaFunction:
Type: "AWS::Lambda::Function"
Properties:
Code:
ZipFile: |
def handler(event,context):
return {
'body': 'Hello there {0}'.format(event['requestContext']['identity']['sourceIp']),
'headers': {
'Content-Type': 'text/plain'
},
'statusCode': 200
}
Description: "My function"
FunctionName: !Ref "lambdaFunctionName"
Handler: "index.handler"
MemorySize: 128
Role: !GetAtt "lambdaIAMRole.Arn"
Runtime: "python2.7"
Timeout: 10
lambdaApiGatewayInvoke:
Type: "AWS::Lambda::Permission"
Properties:
Action: "lambda:InvokeFunction"
FunctionName: !GetAtt "lambdaFunction.Arn"
Principal: "apigateway.amazonaws.com"
SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${AudienceApi}/*/POST/"
lambdaIAMRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- "sts:AssumeRole"
Effect: "Allow"
Principal:
Service:
- "lambda.amazonaws.com"
Policies:
- PolicyDocument:
Version: "2012-10-17"
Statement:
- Action:
- "logs:CreateLogGroup"
- "logs:CreateLogStream"
- "logs:PutLogEvents"
Effect: "Allow"
Resource:
- !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${lambdaFunctionName}:*"
PolicyName: "lambda"
lambdaLogGroup:
Type: "AWS::Logs::LogGroup"
Properties:
LogGroupName: !Sub "/aws/lambda/${lambdaFunctionName}"
RetentionInDays: 90
Based on the comments, the solution was to add * to the ARN after the POST/ in SourceArn:
SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${AudienceApi}/*/POST/*"

AWS CloudFormation stack: API Gateway resource with nested paths?

I have an API Gateway resource manually built that looks like:
GET
/assets/{items} - (points to S3 bucket)
/{proxy+} - points to Lambda function
I would like to mimic this setup in a Cloudformation YAML template but unsure how to do so. Here is the current template I'm working with (partially reduced for brevity):
AWSTemplateFormatVersion: 2010-09-09
Parameters:
apiGatewayStageName:
Type: String
AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+$'
Default: call
lambdaFunctionName:
Type: String
AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+$'
Default: my-function
s3BucketName:
Type: String
AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+$'
Resources:
apiGateway:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: my-api
Description: My API
Metadata:
...
apiGatewayRootMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
AuthorizationType: NONE
HttpMethod: POST
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
Uri: !Sub
- >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
- lambdaArn: !GetAtt lambdaFunction.Arn
ResourceId: !GetAtt apiGateway.RootResourceId
RestApiId: !Ref apiGateway
Metadata:
...
apiGatewayDeployment:
Type: 'AWS::ApiGateway::Deployment'
DependsOn:
- apiGatewayRootMethod
- apiGatewayGETMethod
Properties:
RestApiId: !Ref apiGateway
StageName: !Ref apiGatewayStageName
Metadata:
...
lambdaFunction:
Type: 'AWS::Lambda::Function'
Properties:
...
lambdaApiGatewayInvoke:
...
lambdaIAMRole:
...
lambdaLogGroup:
...
apiGatewayGETMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
AuthorizationType: NONE
HttpMethod: GET
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
Uri: !Sub
- >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
- lambdaArn: !GetAtt lambdaFunction.Arn
ResourceId: !GetAtt apiGateway.RootResourceId
RestApiId: !Ref apiGateway
Metadata:
'AWS::CloudFormation::Designer':
id: 1a329c4d-9d18-499e-b852-0e361af324f4
s3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Ref s3BucketName
Metadata:
...
Outputs:
apiGatewayInvokeURL:
Value: !Sub >-
https://${apiGateway}.execute-api.${AWS::Region}.amazonaws.com/${apiGatewayStageName}
lambdaArn:
Value: !GetAtt lambdaFunction.Arn
That is the result of lots of tweaking and me not having any prior CloudFormation knowledge besides going over the official docs. When the stack behind that template gets created, its API Gateway resource looks like:
The POST action is unnecessary, and only there from trial and error. The GET resource is the only important one as application returned by the Lambda function isn't doing any post requests yet.
The GET one must be created from this portion of the Stack:
apiGatewayGETMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
AuthorizationType: NONE
HttpMethod: GET
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
Uri: !Sub
- >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
- lambdaArn: !GetAtt lambdaFunction.Arn
ResourceId: !GetAtt apiGateway.RootResourceId
RestApiId: !Ref apiGateway
What must be done to make it so that GET resource has the nested /assets/{items} path pointing to an S3 bucket and the {proxy+} path pointing to a Lambda? Do I need to specify separate sibling resources for those paths like apiGatewayAssets and apiGatewayLambdaProxy then connect them to apiGatewayGETMethod somehow?
2020-05-17 Update
The current part tripping me up is this resource:
apiGatewayAssetsItemsResourceMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
ResourceId: !Ref apiGatewayAssetsItemsResource
RestApiId: !Ref apiGateway
AuthorizationType: NONE
HttpMethod: GET
Integration:
Type: AWS
Credentials: arn:aws:iam::XXXXXX:role/AnExistingRole
IntegrationHttpMethod: GET
PassthroughBehavior: WHEN_NO_MATCH
RequestParameters:
integration.request.path.item: 'method.request.path.item'
method.request.path.item: true
Uri: !Sub >-
arn:aws:apigateway:${AWS::Region}:s3:path/${s3BucketName}/{item}
That leads to a CloudFormation stack creation error with the status reason being Invalid mapping expression specified: Validation Result: warnings : [], errors : [Invalid mapping expression parameter specified: method.request.path.item] (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: XXXXXX)
However, if I attempt to create it with the exact same resource minus the RequestParameters entry, it gets created successfully. Although when viewing that API Gateway GET method in the console, it's missing the Paths: item line inside the Integration Request box. Full template I'm currently using:
AWSTemplateFormatVersion: 2010-09-09
Parameters:
apiGatewayStageName:
Type: String
AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+$'
Default: call
lambdaFunctionName:
Type: String
AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+$'
Default: my-function
s3BucketName:
Type: String
AllowedPattern: '^[a-zA-Z0-9]+[a-zA-Z0-9-]+[a-zA-Z0-9]+$'
Resources:
apiGateway:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: my-api
Description: My API
apiGatewayDeployment:
Type: 'AWS::ApiGateway::Deployment'
DependsOn:
- apiGatewayGETMethod
Properties:
RestApiId: !Ref apiGateway
StageName: !Ref apiGatewayStageName
lambdaFunction:
...
lambdaApiGatewayInvoke:
...
lambdaIAMRole:
...
lambdaLogGroup:
...
apiGatewayGETMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
AuthorizationType: NONE
HttpMethod: GET
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
Uri: !Sub
- >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
- lambdaArn: !GetAtt lambdaFunction.Arn
ResourceId: !GetAtt apiGateway.RootResourceId
RestApiId: !Ref apiGateway
s3Bucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Ref s3BucketName
BucketPolicy:
...
apiGatewayAssetsResource:
Type: 'AWS::ApiGateway::Resource'
Properties:
RestApiId: !Ref apiGateway
ParentId: !GetAtt
- apiGateway
- RootResourceId
PathPart: assets
apiGatewayAssetsItemsResource:
Type: 'AWS::ApiGateway::Resource'
Properties:
RestApiId: !Ref apiGateway
PathPart: '{item}'
ParentId: !Ref apiGatewayAssetsResource
apiGatewayAssetsItemsResourceMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
ResourceId: !Ref apiGatewayAssetsItemsResource
RestApiId: !Ref apiGateway
AuthorizationType: NONE
HttpMethod: GET
Integration:
Type: AWS
Credentials: arn:aws:iam::XXXXXX:role/AnExistingRole
IntegrationHttpMethod: GET
PassthroughBehavior: WHEN_NO_MATCH
Uri: !Sub >-
arn:aws:apigateway:${AWS::Region}:s3:path/${s3BucketName}/{item}
apiGatewayLambdaResource:
Type: 'AWS::ApiGateway::Resource'
Properties:
RestApiId: !Ref apiGateway
PathPart: '{proxy+}'
ParentId: !GetAtt
- apiGateway
- RootResourceId
apiGatewayLambdaResourceMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
AuthorizationType: NONE
RestApiId: !Ref apiGateway
ResourceId: !Ref apiGatewayLambdaResource
HttpMethod: ANY
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: GET
Uri: !Sub
- >-
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${lambdaArn}/invocations
- lambdaArn: !GetAtt lambdaFunction.Arn
Outputs:
apiGatewayInvokeURL:
Value: !Sub >-
https://${apiGateway}.execute-api.${AWS::Region}.amazonaws.com/${apiGatewayStageName}
lambdaArn:
Value: !GetAtt lambdaFunction.Arn
So what you need to do for this is the following:
Create a AWS::ApiGateway::Resource with a PathPart of assets, this will use a ParentId of the RootResourceId attr from your Rest API
Create a AWS::ApiGateway::Resource with a PathPart of {item}, this will use a ParentId of the assets Resource above.
Create a AWS::ApiGateway::Method for the ResourceId of the resource above. This will use the HTTP_PROXY and set the Uri to be the S3 bucket path, making sure to include the {{ item }} variable in the path.
Create a AWS::ApiGateway::Resource with a PathPart of {proxy+}, this will use a ParentId of the RootResourceId attr from your Rest API
Create a AWS::ApiGateway::Method for the ResourceId of the resource above. This will use the AWS_PROXY and set the uri to reference the Lambda function.
Hope this helps

Why does CloudFormation API Gateway fail stating 'The REST API doesn't contain any methods' even with DependsOn?

I have a CloudFormation template which I'm trying to deploy. This template is very similar to another template I have which works without issue however when deploying this template it keeps failing stating:
APIGatewayDeployment5332c373d4 CREATE_FAILED The REST API doesn't contain any methods (Service: AmazonApiGateway; Status Code: 400; Error Code: BadRequestException; Request ID: 02c0352f-b23b-44d5-a0af-2f3f3ecd7273)
I had this issue previously on my other template and added the DependsOn property on the deployment which fixed the issue however even with this property this template is failing.
See cut down version of my template below:
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Environment:
Variables:
FOO: bah
Api:
EndpointConfiguration: REGIONAL
Resources:
APIGateway:
Type: AWS::Serverless::Api
Properties:
Name: Some API
StageName: !Sub ${EnvironmentTagName}
ApiFooResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt APIGateway.RootResourceId
PathPart: foo
RestApiId: !Ref APIGateway
ApiFooNotificationResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !Ref ApiFooResource
PathPart: notification
RestApiId: !Ref APIGateway
ApiFooNotificationMethod:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: POST
AuthorizationType: NONE
ResourceId: !Ref ApiFooNotificationResource
RestApiId: !Ref APIGateway
MethodResponses:
- StatusCode: '200'
Integration:
Credentials: !GetAtt SQSRole.Arn
IntegrationHttpMethod: POST
IntegrationResponses:
- StatusCode: 200
Type: AWS
Uri: !Sub arn:aws:apigateway:${AWS::Region}:sqs:action/SendMessage
RequestParameters:
integration.request.querystring.QueueUrl: !Sub '''${FooNotificationQueue}'''
integration.request.querystring.MessageBody: method.request.body
ApiTestResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt APIGateway.RootResourceId
PathPart: test
RestApiId: !Ref APIGateway
ApiTestMethod:
Type: AWS::ApiGateway::Method
Properties:
HttpMethod: POST
AuthorizationType: NONE
ResourceId: !Ref ApiTestResource
RestApiId: !Ref APIGateway
MethodResponses:
- StatusCode: '200'
Integration:
Credentials: !GetAtt SQSRole.Arn
IntegrationHttpMethod: POST
IntegrationResponses:
- StatusCode: 200
Type: AWS
Uri: !Sub arn:aws:apigateway:${AWS::Region}:sqs:action/SendMessage
RequestParameters:
integration.request.querystring.QueueUrl: !Sub '''${TestQueue}'''
integration.request.querystring.MessageBody: method.request.body
ApiDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn: ApiTestMethod
Properties:
RestApiId: !Ref APIGateway
Description: !Sub Api Deployment for ${EnvironmentTagName}
StageName: !Sub ${EnvironmentTagName}
...**Removed the rest for brevity**...
Parameters:
StackTagName:
Type: String
Description: Stack Name (injected by Stackery at deployment time)
EnvironmentTagName:
Type: String
Description: Environment Name (injected by Stackery at deployment time)

How to make sure the API Gateway token authorizer is invoked only for specific paths

We have an API Gateway utilising a custom Token authoriser. We have 2 lambdas - Greetings and GenerateToken.
We only want the Greetings lambda to be behind a authoriser - requires to be called in the following way utilising SAM:
curl -X GET \
https://<apigatewayid>.execute-api.eu-west-1.amazonaws.com/Prod/generateToken \
-H 'X-API-KEY: allow'
How can we achieve that the GenerateToken path does not require a HTTP token for authenticating?
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: API Gateway with Lambda Token Authorizer
Resources:
GreetingsApiGateway:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
DefinitionBody:
swagger: 2.0
x-amazon-apigateway-policy:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal: "*"
Action: execute-api:Invoke
Resource:
- execute-api:/*/*/*
paths:
"/hello":
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GreetingsLambda.Arn}/invocations
responses: {}
"/generateToken":
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${GenerateTokenLambda.Arn}/invocations
responses: {}
Auth:
DefaultAuthorizer: CustomAuthorizer
Authorizers:
MyAuthorizer:
FunctionArn: !GetAtt AuthLambda.Arn
Identity:
Header: X-API-KEY
GenerateTokenLambda:
Type: AWS::Serverless::Function
Properties:
Role: !GetAtt LambdaRole.Arn
CodeUri: "s3://<bucket-name>/code.zip"
Handler: src/generateToken.handler
Events:
GetRoot:
Type: Api
Properties:
RestApiId: !Ref GreetingsApiGateway
Path: /generateToken
Method: get
GreetingsLambda:
Type: AWS::Serverless::Function
Properties:
Role: !GetAtt LambdaRole.Arn
CodeUri: "s3://<bucket-name>/code.zip"
Handler: src/greetings.handler
Events:
GetRoot:
Type: Api
Properties:
RestApiId: !Ref GreetingsApiGateway
Path: /hello
Method: get
AuthLambda:
Type: AWS::Serverless::Function
Properties:
Role: !GetAtt LambdaRole.Arn
CodeUri: "s3://<bucket-name>/code.zip"
Handler: src/auth.handler
Globals:
Function:
Runtime: nodejs8.10
Outputs:
ApiURL:
Description: "OUR API URL"
Value: !Sub "https://${GreetingsApiGateway}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
I am not very sure if I completely understood what you want, but here's a Cloudformation template to create api-gateway resources with & without authorization enabled. I am using Cognito User Pool authorization method but it can be just as easily be a custom authorizer.
RestAPI:
Type: AWS::ApiGateway::RestApi
DeletionPolicy: Delete
Properties:
Name: {"Ref": "AWS::StackName"}
ApiKeySourceType: HEADER
EndpointConfiguration:
Types:
- EDGE
ApiAuthorizer:
Type: AWS::ApiGateway::Authorizer
DeletionPolicy: Retain
DependsOn: UserPoolList
Properties:
Name: !Join ["-", [{"Ref": "AWS::StackName"}, "authorizer"]]
RestApiId: !Ref RestAPI
Type: COGNITO_USER_POOLS
AuthType: cognito_user_pools
IdentitySource: "method.request.header.Authorization"
ProviderARNs: <User Pool ARN>
ResourceSignin:
Type: AWS::ApiGateway::Resource
DeletionPolicy: Delete
Properties:
RestApiId: !Ref RestAPI
ParentId: !GetAtt RestAPI.RootResourceId
PathPart: "signin"
SigninPostMethod:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref RestAPI
ResourceId: !Ref ResourceSignin
HttpMethod: POST
AuthorizationType: NONE
ApiKeyRequired: <true/false>
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${UserHandlerFunction.Arn}/invocations
Credentials: !GetAtt GenApiGatewayRole.Arn
ResourceUserCreate:
Type: AWS::ApiGateway::Resource
DeletionPolicy: Delete
Properties:
RestApiId: !Ref RestAPI
ParentId: !GetAtt RestAPI.RootResourceId
PathPart: "create"
CreatePostMethod:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref RestAPI
ResourceId: !Ref ResourceUserCreate
HttpMethod: POST
AuthorizationType: COGNITO_USER_POOLS
AuthorizerId: !Ref ApiAuthorizer
ApiKeyRequired: <true/false>
Integration:
Type: AWS_PROXY
IntegrationHttpMethod: POST
Uri: !Sub arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${UserHandlerFunction.Arn}/invocations
Credentials: !GetAtt UserApiGatewayRole.Arn
Here resource signin has a POST method with no authorization while create resource has a POST method with authorization enabled.
If you are planning to use API keys this might be the only way possible. I could not get API keys to work with SAM (I believe API keys with SAM is not yet supported - this was about a month back, but you can double check).
We can achieve this via swagger within API Gateway:
The World lambda is a public API and the Hello lambda resides behind the AuthLambda authorizer
OurApiGateway:
Type: AWS::Serverless::Api
Properties:
StageName: Prod
Auth:
Authorizers:
MyAuthorizer:
FunctionPayloadType: REQUEST
FunctionArn: !GetAtt AuthLambda.Arn
DefinitionBody:
swagger: 2.0
basePath: /prod
info:
title: AwsSamExample
x-amazon-apigateway-policy:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal: "*"
Action: execute-api:Invoke
Resource:
- execute-api:/*/*/*
schemes:
- https
paths:
"/hello":
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HelloLambda.Arn}/invocations
responses: {}
security:
- MyAuthorizer: []
"/world":
get:
x-amazon-apigateway-integration:
httpMethod: POST
type: aws_proxy
uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${WorldLambda.Arn}/invocations
responses: {}
security: []
Use the Serverless framework and easily manage this with just an attribute.
https://www.npmjs.com/package/serverless

CloudFormation Template for API Gateway with Lambda Proxy and MethodResponse Headers

Here is a CloudFormation puzzle I think I cannot solve without your help. I'm trying to create a template for a REST API with CloudFormation (YAML). The API has a Lambda Proxy and has to have a MethodResponse as shown in the attached image.
This is my template so far which produces the following error when building the stack:
PostMethod: Value of property ResponseParameters must be an
object
ApiGatewayAccount:
Type: "AWS::ApiGateway::Account"
Properties:
CloudWatchRoleArn: "some role"
RestApi:
Type: "AWS::ApiGateway::RestApi"
Properties:
Description: "some rest api"
EndpointConfiguration:
Types:
- REGIONAL
Name: RestApi
SomeResource:
Type: "AWS::ApiGateway::Resource"
Properties:
ParentId:
Fn::GetAtt:
- "RestApi"
- "RootResourceId"
PathPart: part
RestApiId:
Ref: "RestApi"
SomeSubResource:
Type: "AWS::ApiGateway::Resource"
Properties:
ParentId:
Ref: "SomeResource"
PathPart: count
RestApiId:
Ref: "RestApi"
SomeResponseModel:
Type: "AWS::ApiGateway::Model"
Properties:
ContentType: "text/html"
Description: "Empty text/html response."
Name: someresponse
RestApiId:
!Ref RestApi
Schema: {}
PostMethod:
Type: "AWS::ApiGateway::Method"
Properties:
HttpMethod: POST
Integration:
IntegrationHttpMethod: POST
Type: AWS_PROXY
Uri:
Fn::Join:
- ""
- - "arn:aws:apigateway:"
- "some-region"
- ":lambda:path/2015-03-31/functions/"
- "some-arn-of-lambda-function"
MethodResponses:
-
ResponseModels:
Key: "application/x-www.form-urlencoded"
Value:
!Ref SomeResponse
ResponseParameters:
- method.response.header.Content-Length: true
- method.response.header.Content-Type: true
- method.response.header.Connection: true
StatusCode: 200
OperationName: SomeName
ResourceId:
!Ref "SomeSubResource"
RestApiId:
!Ref "RestApi"
According to the documentation, it would seem that this should not be a list of key-value pairs, but instead just an object, where each entry is just another key/value.
I expect the following would work:
ResponseParameters:
method.response.header.Content-Length: true
method.response.header.Content-Type: true
method.response.header.Connection: true