Serverless-application-model: Issue with Lambda-Permission for API-Gateway

Created on 11 Jan 2017  ·  37Comments  ·  Source: aws/serverless-application-model

All,

it seems to me that there is a bug with the created LAMBDA-Policy when creating a "ANY"- API-Gateway-Mapping to a Lambda-Function, see the template here:

app_spec.txt

The created Lambda policy includes (for Resource analytics the following condition), and therefore a Lambda permission Error occurs when testing the API-Gateway:

"Condition":{"ArnLike":{"AWS:SourceArn":"arn:aws:execute-api:us-east-1:310073746091:yi1i6eckj4/*/ANY/analytics/*"}}

instead of (resource manual has been created manually afterwards via API-Gateway-Gui):

"Condition":{"ArnLike":{"AWS:SourceArn":"arn:aws:execute-api:us-east-1:310073746091:yi1i6eckj4/*/*/manual/*"}}

Any Idea?

Best Regards,

Gregor
[email protected]

areserverless-api contributorgood-first-issue priorit1-critical typbug typquestion

Most helpful comment

@gpuettmann, @Squareomatic Hey, I was able to get this to work by applying permissions on the lambda. I added this config to the sam yaml:

  ConfigLambdaPermission:
    Type: "AWS::Lambda::Permission"
    DependsOn:
    - MyAwesomeApi
    - ConfigHandlerLambdaFunction
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref ConfigHandlerLambdaFunction
      Principal: apigateway.amazonaws.com

All 37 comments

Where is the actual error? Does it happen when you make HTTP request to the API, say via Curl?

...yes, the error occurs, when I test the function, Error-Message:
"Tue Jan 31 14:52:20 UTC 2017 : Execution failed due to configuration error: Invalid permissions on Lambda function
Tue Jan 31 14:52:20 UTC 2017 : Method completed with status: 500"

This error is on the APIGateway Web Console UI right? If so, I think this is a known problem

Hi, yes it seams that permissions for api gateway to call laambdas are not given to certain endpoints, I have seen it randomly in some resources of mine too

Hi @sanathkr , I'm experiencing the same problems as the others here. Hopefully I can provide some more info.

I have a SAM with an API and 3 lambdas. Everything is deployed successfully and connected using stage variables as well. My API cannot talk to the lambda because of the permissions issue mentioned above.

I was able to click to change the lambda:
image

and then this is the modal that popped:

image

After I said "OK", the lambda was reachable via API Gateway.

In addition, since I'm using a stage variable, it provided an extra message:

You defined your Lambda function as a stage variable; you must manually give permissions to all the functions you will use. You can do this by running the below AWS CLI command for each function, replacing the stage variable in the function-name parameter with the necessary function name.

aws lambda add-permission --function-name arn:aws:lambda:us-east-1:1234567890:function:${stageVariables.SignupFunctionName} --source-arn 'arn:aws:execute-api:us-east-1:1234567890:aeleq5o0z0/*/GET/v1/accounts/*/groups' --principal apigateway.amazonaws.com --statement-id 123456-96c3-4362-b900-860d14191d9f --action lambda:InvokeFunction

Is there a step missing when the AWS::Serverless::Api is created to access the lambdas?

Corresponding AWS link regarding this issue: https://forums.aws.amazon.com/thread.jspa?threadID=217143

@gpuettmann, @Squareomatic Hey, I was able to get this to work by applying permissions on the lambda. I added this config to the sam yaml:

  ConfigLambdaPermission:
    Type: "AWS::Lambda::Permission"
    DependsOn:
    - MyAwesomeApi
    - ConfigHandlerLambdaFunction
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref ConfigHandlerLambdaFunction
      Principal: apigateway.amazonaws.com

@ryanlitalien I'm trying to do the same (API GW + Lambda) but via cloudformation. Would you mind posting a sharable version of your cloudformation template ?
thnx

@ryanlitalien
I am too facing difficulties with Lambda permission for the API Gateway. Would you be able to post a complete sam yaml for the permission with a proxy-any example?

@BradNation4Eva @haiko Unfortunately I don't have access to the source anymore. Essentially you'll need to explicitly add and set permissions within the sam, with the DependsOn so it's run after the API GW and Lambda are created. Good luck 👍

I ran into the same issue and fixed it thanks to @ryanlitalien . You can see a simple example here: https://github.com/luebken/hello-sam

Now my question would be if this permission is always needed in an API / Lambda example. And if that is the case if it shouldn't be added to the examples.

Works for me, thanks for sharing!

If you are using APIGW Console Test button, then yes this problem still exists. But if you Curl the API or go using browser default SAM settings will work. This is a bug, and the workaround you suggested is only temporarily needed until we fix this.

If you are using separate Swagger, make sure you add the APIs to the events section as well. This will make SAM add correct Lambda::Permissions. See https://github.com/awslabs/serverless-application-model/blob/master/examples/2016-10-31/api_swagger_cors/template.yaml#L24-L35

@sanathkr
I've been experiencing the same issue with an ANY method*, when using a function name with a stage variable.
That is when using the configuration just as in the api_swagger_cors example in the documentation, and not just from the test button in the console, but when querying externally as well.

The resolution has been using the explicit ConfigLambdaPermission as described by ryanliatien above.

*no issues when using an explicit POST instead of ANY (this could be a red herring though)

I am reaching out to the relevant teams internally to see what we can do about this. Will update when more information is available.

I'm having the problem with nodejs "aws-sdk". while testing the invoking the test getting the internal server error with 500. How can we enable the permission from nodejs "aws-sdk"

I am also getting this issue when I use an ANY method for an endpoint.

Edit: My suggestion below is incorrect, please see @ryanlitalien workaround suggestion above. We are working on getting this addressed. Thanks and sorry for any trouble my suggestion caused.

All,

I spoke with the relevant team and have a path forward. If you are seeing problems calling your API Gateway endpoint (outside of the Test Button on the console), update the Method: ANY to Method: "*" until we can get out the update to this policy.

@jfuss the above didn't work for us and sadly we found that the issue still occurred when using curl. The exact scenario was:

  • We had two lambda functions (different handlers) defined
  • We didn't have an API defined (we allowed the transform to handle this)
  • We used package / deploy to deploy

@jjmschofield Looks like I didn’t test deep enough before suggesting. My fault! You are correct, that doesn’t seem to work. Looks like the only option may be to do what was suggested above by others by applying permissions manually in the template. There is an example above. I will edit my above comment to reflect that it will not work. Sorry for the troubles and thank you for pointing it out.

Regarding @ryanlitalien solution above:

  • DependsOn is not necessary: declaring the MyAwesomeApi dependency is not needed (the permission does not depend in any way on that specific API); the dependency with ConfigHandlerLambdaFunction is already implicit because you used the !Ref function with ConfigHandlerLambdaFunction as a parameter.

  • it is important to define a SourceARN property: If you add a permission without providing the source ARN, any AWS account that creates a mapping to your function ARN can send events to invoke your Lambda function.

A more correct version would look like:

  ConfigLambdaPermission:
    Type: "AWS::Lambda::Permission"
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref ConfigHandlerLambdaFunction
      Principal: apigateway.amazonaws.com
      SourceARN: arn:aws:execute-api:<region>:<accountNumber>:<restApiId>/<stage>/<method>/<path>

Sources:

Thanks for that update @lusentis - the part about SourceArn is particularly useful (and worrisome). It would be much better if this problem is solved properly within the SAM service/project, instead of us having to create a workaround to create permissions that works appropriately.

Hey all! So I am back to shed a deeper light into what is going on. This is going to be a longer post with links to....... CODE. :)

So SAM will set/create Lambda Permissions for Api Gateway in this method. The important piece is self._construct_permission call at the end of the method that will return the LambdaPermission resource that will be added to the output CloudFormation Template (the one that run in CloudFormation that creates all the resources).

Where this goes wrong is when we create the resource

Revlevant code snippet:

resource = '${__ApiId__}/' + '${__Stage__}/' + self.Method.upper() + path

You can see that we just add the Method, which is why ANY is in the policy instead of *. This is a great first issue for anyone willing to dive into the code and contribute. Given that we are now fully Open Sourced, anyone willing to take a swing at it? I have happy to guide/help the person if they run into anything :).

@jfuss I've not been able to test this change but based on my meager understanding. This patch should work. I'll continue working out my issues with pyenv and try to get a PR sent in.

diff --git a/samtranslator/model/eventsources/push.py b/samtranslator/model/eventsources/push.py
index c155b5a..76d710a 100644
--- a/samtranslator/model/eventsources/push.py
+++ b/samtranslator/model/eventsources/push.py
@@ -396,9 +396,12 @@ class Api(PushEventSource):
         if not function:
             raise TypeError("Missing required keyword argument: function")

-        if self.Method is not None:
+        if self.Method is not None and self.Method.lower() != 'ANY'.lower():
             # Convert to lower case so that user can specify either GET or get
             self.Method = self.Method.lower()
+        elif self.Method is not None and self.Method.lower() == 'ANY'.lower():
+            # Special handling required when dealing with ANY requests
+            self.Method = '*'

         resources.extend(self._get_permissions(kwargs))

@blade2005 Send a PR!

The easiest way I have found testing these things, is to write a 'unit test' with a SAM Template and add it here. You can take the output and put it into CloudFormation and test (manually). This is how I normally test new additions before sending to CR and writing integ tests.

If you need further help, its easy to communicate through our slack channel (#samdev). Feel free to ping me there, makes this process faster instead of going back and forth on github issues for help :)

If no one picks up @blade2005 until June, I guess I'll give it a try.

Sorry got slammed with a thing at work. Not sure when I'll break free. I'll see if I can't eek out some time this weekend to work on the issue. It should be mostly writing unit tests which I'm horrible at.

I applied a similar patch and it broke several tests already (not so "unit"ary heh). Gonna spend some time fixing them before even adding a new one.

Well, I guess it's not that simple. Apparently the 'ANY' method is used elsewhere and changing it to '*' at that translation phase will break stuff. Here's what applying that patch caused in one of the tests:

304a305,314
>                 "*": {
>                   "x-amazon-apigateway-integration": {
>                     "httpMethod": "POST",
>                     "type": "aws_proxy",
>                     "uri": {
>                       "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations"
>                     }
>                   },
>                   "responses": {}
>                 },
353,362c363
<               "x-amazon-apigateway-any-method": {
<                 "x-amazon-apigateway-integration": {
<                   "httpMethod": "POST",
<                   "type": "aws_proxy",
<                   "uri": {
<                     "Fn::Sub": "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ImplicitApiFunction.Arn}/invocations"
<                   }
<                 },
<                 "responses": {}
<               }
---
>                 "x-amazon-apigateway-any-method": {}

So I guess that's not the best place to fix the issue.
Perhaps it should be fixed only in the relevant line mentioned by @jfuss:

resource = '${__ApiId__}/' + '${__Stage__}/' + self.Method.upper() + path

I believe this issue can be closed since #449 was merged.

Actually it needs to be deployed first; so once you see it merged to master
we can close this. We are working on a better local transform experience.
Once that's done you will be able to use new features sooner.

On Fri, Jun 8, 2018, 6:04 AM Victor Villas notifications@github.com wrote:

I believe this issue can be closed since #449
https://github.com/awslabs/serverless-application-model/pull/449 was
merged.


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/awslabs/serverless-application-model/issues/59#issuecomment-395754335,
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABy6l3AIjo5Wt0wUaIlYkX_p_3Tkuh9kks5t6nZQgaJpZM4Lg2d6
.

I meet this problem when using lambda authorizer,

This is my template.yml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: account

Globals:
  Function:
    Timeout: 3
    Runtime: nodejs8.10
Resources:
  AccountRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - dynamodb.amazonaws.com
                - lambda.amazonaws.com
                - apigateway.amazonaws.com
            Action:
              - sts:AssumeRole

  AccountApi:
    Type: AWS::Serverless::Api
    Properties:
      StageName: prod
      DefinitionBody:
        swagger: 2.0
        info:
          title: 帐号中心接口
        securityDefinitions:
          CustomAuthorizer:
            type: apiKey
            name: Authorization
            in: header
            x-amazon-apigateway-authtype: custom
            x-amazon-apigateway-authorizer:
              type: token
              authorizerUri: !Sub arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${AuthCheckFunction.Arn}/invocations
              authorizerCredentials: !GetAtt AccountRole.Arn
              authorizerResultTtlInSeconds: 60
        paths:
          /account/resources:
            get:
              security:
                - CustomAuthorizer: []
              x-amazon-apigateway-integration:
                httpMethod: POST
                type: aws_proxy
                uri: !Sub arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ResourceFunction.Arn}/invocations
          /account/test:
            get:
              x-amazon-apigateway-integration:
                httpMethod: POST
                type: aws_proxy
                uri: !Sub arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${TestFunction.Arn}/invocations

  AuthCheckFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: app/
      Description: 验证用户 token
      Handler: handler/authCheck.default
      Role: !GetAtt AccountRole.Arn

  TestFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: app/
      Description: 测试方法
      Handler: handler/test.default
      Role: !GetAtt AccountRole.Arn
      Events:
        TestApiEvent:
          Type: Api
          Properties:
            Path: /account/test
            Method: GET
            RestApiId: !Ref AccountApi

  ResourceFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: app/
      Description: 被保护的资源
      Handler: handler/resource.default
      Role: !GetAtt AccountRole.Arn
      Events:
        TestApiEvent:
          Type: Api
          Properties:
            Path: /account/resource
            Method: GET
            RestApiId: !Ref AccountApi

As you can see, I have specify the role which trust apigateway service to all the functions. /account/test works fine but /account/resource reports

Execution failed due to configuration error: Invalid permissions on Lambda function.

Hi, @beary
I got the same permission issue for the authorizer lambda function, have you got any solution yet?
Cheers

@steven-gong I found solution but I fogot it...
Now I use serverless instead of aws-sam-cli.
It looks like

functions:
  authorize:
    handler: app/authorize.fn
  resource-api:
    handler: app/resource.fn
    events:
      - http:
          path: /test
          authorizer: authorize

or

functions:
  test-fn:
    handler: app/handler.fn
    events:
      - http:
          path: /test
          method: get
          authorizer:
            arn: arn:aws:lambda:ap-southeast-1:999999999:function:account-dev-authorize

I recently had a similar issue and turned out to be a problem with my Events in AWS::Serverless::Function. My Path didn't match the one I had defined in the swagger file.

Has anyone tried to get this working with API Gateway in one region and lambda in another? I tried manually through the API Gateway console - and it works fine.

But when I try to generate the API Gateway through cloudformation, I get the following error:

Functions from 'us-west-1' are not reachable in this region ('us-west-2') (Service: AWSLambda; Status Code: 404; Error Code: ResourceNotFoundException;

The yaml in the CF template looks like this:

APIInvokePermission1:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Sub 'arn:aws:lambda:us-west-1:${AWS::AccountId}:function:dp-user-${ApiGatewayStageName}-getUser'
      Action: lambda:InvokeFunction
      Principal: apigateway.amazonaws.com
      SourceArn:
        Fn::Sub: arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGateway}/*/*/*

The cloudformation template lives in us-west-2. We have our API Gateway there since Cognito is not available in us-west-1. But we'd like to have our lambdas in us-west-1.

The solution from @lusentis is the correct one. Use FunctionName: !Ref <function> instead of a DependsOn attribute. and the dependency tree will be automatically correct.

Was this page helpful?
0 / 5 - 0 ratings