Reputation: 395
I've been all over the web searching for an answer to this.
Essentially, we're spinning up an API using Swagger, which is awesome and works great, but one thing doesn't work... When we make a call to an Endpoint, we get a 500 error (it's not a 500 error that we're providing either it's one from AWS). The error states "Execution failed due to configuration error: Invalid permissions on Lambda function" (https://youtu.be/H4LM_jw5zzs <- This is a video, from another user, of the error I'm getting).
I've gone down many ratholes, and have found an answer... It involves using the AWS CLI and looks a bit like this:
aws lambda add-permission \
--function-name FUNCTION_NAME \
--statement-id STATEMENT_ID \
--action lambda:InvokeFunction \
--principal apigateway.amazonaws.com \
--source-arn "arn:aws:execute-api:us-east-1:ACCOUNT_ID:API_ID/*/METHOD/ENDPOINT"
This is great and all, but we are using CloudFormation to spin up everything and we want this to be automated. Is there an easier way to go about this? Is there something in CloudFormation that will give us the resource policy that we need?
I'm hitting a bit of a wall with this, but I've been working on it for a few hours today and it's a bit of a blocker for our API release, so any help would be much appreciated. :)
Upvotes: 28
Views: 33607
Reputation: 4267
Thanks https://twitter.com/edjgeek for helping me get this straight in my head.
This GIST shows how to use AWS::Serverless:Function with Events to automatically generate the needed AWS::Lambda::Permission to allow APIGateway (for a given route) to invoke your Lambda:
https://gist.github.com/rainabba/68df1567cbd0c4930d428c8953dc2316
Both of the following approaches assume an api such as (many fields omitted for readability):
MyApi:
Type: 'AWS::Serverless::Api'
Properties:
DefinitionBody:
Fn::Transform:
Name: AWS::Include
Parameters:
Location: openapi.yaml
The most relevant bit (I've omitted many required fields):
MyLambdaFunction:
Type: 'AWS::Serverless::Function'
Properties:
Events:
MyRouteEventToProxy:
Type: Api
Properties:
Method: POST
Path: '/some-route/{pathParm}'
RestApiId: !Ref MyApi # ResourceName of AWS::Serverless::Api
Auth:
Authorizer: NONE
If you'd rather declare the binding in the openapi.yaml, then see the following project (no Lambda/Events required). This approach requires an explict role to allow invoke.
template.yaml relevant bits:
MyLambdaFunction:
Type: 'AWS::Serverless::Function'
Properties:
# Events: # No need for Events when binding from openapi.yaml
MyHttpApiRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service: "apigateway.amazonaws.com"
Action:
- "sts:AssumeRole"
openapi.yaml relevant bits:
paths:
post:
x-amazon-apigateway-integration:
httpMethod: POST
uri:
Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyLambdaFunction.Arn}:live/invocations"
contentHandling: "CONVERT_TO_TEXT"
type: aws_proxy
credentials:
Fn::GetAtt: [MyHttpApiRole, Arn]
https://github.com/aws-samples/sessions-with-aws-sam/tree/master/http-api-direct-integration
Upvotes: 5
Reputation:
For the invoke permissions:
"APIInvokePermission": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": {
"Ref": "YOUR_LAMBDA_FUNCTION_RESOURCE_NAME"
},
"Action": "lambda:InvokeFunction",
"Principal": "apigateway.amazonaws.com",
"SourceArn": {
"Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${YOUR_REST_API_RESOURCE_NAME}/*/*/*"
}
}
},
Upvotes: 6
Reputation: 7122
There is a CloudFormation
solution to this problem. See the following CloudFormation
snippet:
"Permission": {
"Type": "AWS::Lambda::Permission",
"Properties": {
"FunctionName": { "Fn::GetAtt": [ "Lambda", "Arn" ] },
"Action": "lambda:InvokeFunction",
"Principal": "apigateway.amazonaws.com",
"SourceArn": { "Fn::Join": [ "", [
"arn:aws:execute-api:",
{ "Ref": "AWS::Region" }, ":",
{ "Ref": "AWS::AccountId" }, ":",
{ "Ref": "API" },
"/*/*/*"
] ] }
}
}
This grants API Gateway
permissions to launch your Lambda
function. Variables in this snippet you need to change are Lambda
(line 4) and API
(line 11).
Upvotes: 32