0
votes

I am setting up an API HTTP Gateway (V2) with lambda integrations via Cloudformation, and everything has been working so far. I have 2 working integrations, but my third integration is not working: Everything looks fine from the API Gateway side (it lists the correct route with a link to the Lambda), but the API endpoint in the lambda is listed as "https://c59boisn2k.execute-api.eu-central-1.amazonaws.com/productionnull". When I try to call the route, it says "Not Found". The odd thing is that I am using the same template for all three integrations.

I was thinking it could be a "dependsOn" issue, but I think I have all the correct dependencies. I tried re-creating the stack from scratch and now two of the three functions say "null" in their URL while the API Gateway still states the correct routes. Can this be a 'dependsOn' problem?

Here's my template for a single integration:

{
  "Resources": {
    "api": {
      "Type": "AWS::ApiGatewayV2::Api",
      "Properties": {
        "Name": { "Ref": "AWS::StackName" },
        "ProtocolType": "HTTP",
        "CorsConfiguration": {
          "AllowMethods": ["*"],
          "AllowOrigins": ["*"]
        }
      }
    },

    "stage": {
      "Type": "AWS::ApiGatewayV2::Stage",
      "Properties": {
        "Description": { "Ref": "AWS::StackName" },
        "StageName": "production",
        "AutoDeploy": true,
        "ApiId": { "Ref": "api" },
        "AccessLogSettings": {
          "DestinationArn": {
            "Fn::GetAtt": ["stageLogGroup", "Arn"]
          }
        }
      }
    },

    "getSignedS3LambdaRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "RoleName": {
          "Fn::Sub": "${AWS::StackName}-getSignedS3"
        },
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": ["lambda.amazonaws.com"]
              },
              "Action": ["sts:AssumeRole"]
            }
          ]
        },
        "Policies": [
          {
            "PolicyName": "root",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Effect": "Allow",
                  "Resource": "arn:aws:logs:*:*:*",
                  "Action": "logs:*"
                },
                {
                  "Effect": "Allow",
                  "Action": ["s3:*"],
                  "Resource": ["arn:aws:s3:::euromomo.eu/uploads/*"]
                }
              ]
            }
          }
        ]
      }
    },

    "getSignedS3Lambda": {
      "Type": "AWS::Lambda::Function",
      "DependsOn": ["getSignedS3LambdaRole"],
      "Properties": {
        "FunctionName": {
          "Fn::Sub": "${AWS::StackName}-getSignedS3"
        },
        "Code": {
          "S3Bucket": { "Ref": "operationsS3Bucket" },
          "S3Key": { "Ref": "getSignedS3S3Key" }
        },
        "Runtime": "nodejs10.x",
        "Handler": "index.handler",
        "Role": { "Fn::GetAtt": ["getSignedS3LambdaRole", "Arn"] }
      }
    },

    "getSignedS3Permission": {
      "Type": "AWS::Lambda::Permission",
      "DependsOn": ["api", "getSignedS3Lambda"],
      "Properties": {
        "Action": "lambda:InvokeFunction",
        "FunctionName": { "Ref": "getSignedS3Lambda" },
        "Principal": "apigateway.amazonaws.com",
        "SourceArn": {
          "Fn::Sub": "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/*/*"
        }
      }
    },

    "getSignedS3Integration": {
      "Type": "AWS::ApiGatewayV2::Integration",
      "DependsOn": ["getSignedS3Permission"],
      "Properties": {
        "ApiId": { "Ref": "api" },
        "IntegrationType": "AWS_PROXY",
        "IntegrationUri": {
          "Fn::Sub": "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${getSignedS3Lambda.Arn}/invocations"
        },
        "PayloadFormatVersion": "2.0"
      }
    },

    "getSignedS3Route": {
      "Type": "AWS::ApiGatewayV2::Route",
      "DependsOn": ["getSignedS3Integration"],
      "Properties": {
        "ApiId": { "Ref": "api" },
        "RouteKey": "POST /getSignedS3",
        "AuthorizationType": "NONE",
        "Target": { "Fn::Sub": "integrations/${getSignedS3Integration}" }
      }
    }
  }
}
1

1 Answers

0
votes

After spending hours debugging this, I found that the problem was in my Lambda permission. I need to use the correct path in the permission.

This does not work:

arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/*/*

This does work:

arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/*/*/getSignedS3

I believe I could scope it even more to this:

arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${api}/*/POST/getSignedS3

This fixed all my problems and shows the correct path in the lambda web console.