26

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. :)

Jedi
  • 3,088
  • 2
  • 28
  • 47
Sam Bantner
  • 375
  • 1
  • 3
  • 9
  • For what it's worth, you can also do this via AWS SDK too. I use it for Go, so it's here: http://docs.aws.amazon.com/sdk-for-go/api/service/lambda/#Lambda.AddPermission ... What I don't see if any way to list existing permissions. So I just tolerate the errors about it already existing in my deploy tool. Weird. I mean I didn't even see anything about needing this permission either and it's not in any exported Swagger either. – Tom Nov 19 '16 at 22:27
  • I believe you can **add a role to the API Gateway with permissions to invoke the required Lambdas**. I'm still looking for how to do that but I believe this should be a better solution than continually adding these fiddly permissions policies to the Lambdas. – NeilG Aug 21 '23 at 08:09

3 Answers3

30

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).

adamkonrad
  • 6,794
  • 1
  • 34
  • 41
  • 2
    Is there any danger doing `"/*/*/*"` versus `/*/POST/example`? on the face of it, it seems like we are opening up permissions for that api end point to call any resource path – David Jul 23 '19 at 15:06
  • @David it all depends on the application - whether or not you need the API Gateway to be a filter – adamkonrad Jul 23 '19 at 15:08
  • for all FunctionName which should I use? – Vikramsinh Gaikwad Jun 29 '20 at 12:21
  • i need to give permission to all my lambda so what should I put under FunctionName?? – Vikramsinh Gaikwad Jun 29 '20 at 12:25
  • You can see it's an ARN. Inspect it and you may be able to put "*" at the end where the function name is. – adamkonrad Jun 29 '20 at 13:17
  • Anyone else feel like this resource should be automatically created in the SAM translation based on the API/Lambda-event bindings? Anyone seen the requirement for manual creation of this resource documented by AWS anywhere? – rainabba Mar 04 '21 at 17:00
  • In SAM this should be automatically handled by the Api resource. @rainabba – adamkonrad Mar 04 '21 at 18:49
6

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}/*/*/*"
    }
  }
},
5

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

Using "SAM Events"

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

Using "openapi binding"

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

rainabba
  • 3,804
  • 35
  • 35