0

I've got an app deployed to Lambda and I'm using API Gateway to forward HTTP requests over to the app.

My problem is that it looks like API Gateway isn't forwarding requests that aren't to the base URL of the app.

In other words, the code inside my Lambda handler gets executed when there's an HTTP request to https://blabblahblah.execute-api.us-west-2.amazonaws.com/Prod/. However, an HTTP request to https://blabblahblah.execute-api.us-west-2.amazonaws.com/Prod/pong throws a 500 and no code gets executed. I've got some logging statements inside my handler and they don't log anything for non-base-URL requests.

I've narrowed the problem down to a permissions issue.

I have 2 sets of permission that aren't working well together.

  1. I need to allow the API Gateway to invoke my lambda function
  2. The lambda function needs to be able to call itself.

I thought I had both these permissions working correctly but any HTTP requests that aren't aimed at the base URL throw a 500 in the API Gateway (i.e. I see no Cloudwatch log entries for the request but the response is 500).

I think that means that there must be some error in my SAM template.

Resources:
  IAMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: ['sts:AssumeRole']
            Effect: Allow
            Principal:
              Service: [lambda.amazonaws.com]
        Version: 2012-10-17
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: lambda.handler
      Role: !GetAtt IAMRole.Arn
      Runtime: ruby2.5
      CodeUri: "./src/"
      MemorySize: 512
      Timeout: 30
      Events:
        MyAppApi:
            Type: Api
            Properties:
                Path: /
                Method: ANY
                RestApiId: !Ref MyAppAPI
  MyAppAPI:
    Type: AWS::Serverless::Api
    Properties:
      Name: MyAppAPI
      StageName: Prod
      DefinitionBody:
        swagger: '2.0'
        basePath: '/'
        info:
          title: !Ref AWS::StackName
        paths:
          /{proxy+}:
            x-amazon-apigateway-any-method:
              responses: {}
              x-amazon-apigateway-integration:
                uri:
                  !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations'
                passthroughBehavior: "when_no_match"
                httpMethod: POST
                type: "aws_proxy"
          /:
            post:
              responses: {}
              x-amazon-apigateway-integration:
                uri:
                  !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyFunction.Arn}/invocations'
                passthroughBehavior: "when_no_match"
                httpMethod: POST
                type: "aws_proxy"
  ConfigLambdaPermission:
    Type: "AWS::Lambda::Permission"
    DependsOn:
    - MyFunction
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref MyFunction
      Principal: apigateway.amazonaws.com
  ConfigLambdaPermission:
    Type: "AWS::Lambda::Permission"
    DependsOn:
    - MyFunction
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref MyFunction
      Principal: !GetAtt IAMRole.Arn

Outputs:
  MyFunction:
    Description: Lambda Function for interacting with Slack
    Value:
      Fn::GetAtt:
      - MyFunction
      - Arn
  MyAppAppUrl:
    Description: App endpoint URL
    Value: !Sub "https://${MyAppAPI}.execute-api.${AWS::Region}.amazonaws.com/"

Any idea how I can get things working right?

1 Answer 1

1

Yes, you need to add the other resource as well as a event trigger. And you lambda permissions have no use in the above template. Here's how it worked for me.

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Resources:
  IAMRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: ['sts:AssumeRole']
            Effect: Allow
            Principal:
              Service: [lambda.amazonaws.com]
        Version: 2012-10-17
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: roleTest.roleTest
      Role: !GetAtt IAMRole.Arn
      Runtime: nodejs8.10
      CodeUri: s3://apicfn/roleTest.zip
      MemorySize: 512
      Timeout: 30
      Events:
        MyAppApi1:
            Type: Api
            Properties:
                Path: /
                Method: ANY
        MyAppApi2:
            Type: Api
            Properties:
                Path: /{proxy+}
                Method: ANY
Outputs:
  MyFunction:
    Description: Lambda Function for interacting with Slack
    Value:
      Fn::GetAtt:
      - MyFunction
      - Arn

PS: do not even need the Serverless::Api section for this template.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! That fixed the issue! Adding the separate event completely makes sense. Just out of curiosity, why did the proxy stuff worked fine when the was no IAM role?
The root '\' worked as that was what was specified in function definition, so it created the permission implicitly. The other resource (proxy+) was part of the REST API definition & needed the permission explicitly. The above solution is just easier.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.