API Gateway Stage Variable Rejected in IntegrationUri (Error: Invalid lambda function)

0

I am using CloudFormation to attempt to set up "stage" and "prod" API Gateway stages with Lambda integration (one lambda per stage to simplify deployment) to URLs as follows:

  • stage: https://<api_id>.execute-api.us-east-1.amazonaws.com/stage/mfl-scoring
  • prod: https://<api_id>.execute-api.us-east-1.amazonaws.com/prod/mfl-scoring

The relevant parts of my CF template are as follows:

  MflScoringStageFunction:
    Type: AWS::Lambda::Function
    Properties:
      Role: !GetAtt MflScoringStagedFunctionIamRole.Arn
      Code: 
        S3Bucket: !Sub ${BuildBucket}
        S3Key: builds/bootstrap.zip
        # S3ObjectVersion: TODO
      Handler: bootstrap
      Runtime: provided.al2
      MemorySize: 128
      Timeout: 5

  MflScoringProdFunction:
    Type: AWS::Lambda::Function
    Properties:
      Role: !GetAtt MflScoringStagedFunctionIamRole.Arn
      Code: 
        S3Bucket: !Sub ${BuildBucket}
        S3Key: builds/bootstrap.zip
        # S3ObjectVersion: TODO
      Handler: bootstrap
      Runtime: provided.al2
      MemorySize: 128
      Timeout: 5

  MflScoringFunctionStageAlias:
    Type: AWS::Lambda::Alias
    Properties:
      FunctionName:
        Ref: MflScoringStageFunction
      FunctionVersion: "$LATEST"
      Name: STAGE
      
  MflScoringFunctionProdAlias:
    Type: AWS::Lambda::Alias
    Properties:
      FunctionName:
        Ref: MflScoringProdFunction
      FunctionVersion: "$LATEST"
      Name: PROD

  MflScoringFunctionStagePermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:invokeFunction
      FunctionName: !Ref MflScoringFunctionStageAlias
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:MflScoringApi/*"

  MflScoringFunctionProdPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:invokeFunction
      FunctionName: !Ref MflScoringFunctionProdAlias
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:MflScoringApi/*"

  MflScoringStageFunctionPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:invokeFunction
      FunctionName: !GetAtt MflScoringStageFunction.Arn
      Principal: apigateway.amazonaws.com
      SourceArn:
        !Sub 
          - "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MflScoringApi}/*"
          - MflScoringApi: !Ref MflScoringApi

  MflScoringProdFunctionPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:invokeFunction
      FunctionName: !GetAtt MflScoringProdFunction.Arn
      Principal: apigateway.amazonaws.com
      SourceArn:
        !Sub 
          - "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${MflScoringApi}/*"
          - MflScoringApi: !Ref MflScoringApi

  MflScoringApi:
    Type: AWS::ApiGatewayV2::Api
    Properties:
      Name: MFL Scoring API
      ProtocolType: HTTP

  MflScoringIntegration:
    Type: AWS::ApiGatewayV2::Integration
    DependsOn:
      - MflScoringStageFunction
      - MflScoringProdFunction
      - MflScoringApiStageStage
      - MflScoringApiStageProd
    Properties:
      ApiId: !Ref MflScoringApi
      Description: Lambda proxy integration
      IntegrationType: AWS_PROXY
      IntegrationMethod: POST
      PayloadFormatVersion: "2.0"
      IntegrationUri: !Sub 'arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${!stageVariables.LambdaFunction}:${!stageVariables.LambdaAlias}/invocations'

  MflScoringApiRoute:
    Type: AWS::ApiGatewayV2::Route
    Properties:
      ApiId: !Ref MflScoringApi
      RouteKey: "GET /mfl-scoring"
      Target: !Join
        - /
        - - integrations
          - !Ref MflScoringIntegration

  MflScoringApiStageStage:
    Type: AWS::ApiGatewayV2::Stage
    Properties:
      ApiId: !Ref MflScoringApi
      DefaultRouteSettings:
        DetailedMetricsEnabled: True
      StageName: stage
      StageVariables:
        LambdaAlias: STAGE
        LambdaFunction: !GetAtt MflScoringStageFunction.Arn
      AutoDeploy: true

  MflScoringApiStageProd:
    Type: AWS::ApiGatewayV2::Stage
    Properties:
      ApiId: !Ref MflScoringApi
      DefaultRouteSettings:
        DetailedMetricsEnabled: True
      StageName: prod
      StageVariables:
        LambdaAlias: PROD
        LambdaFunction: !GetAtt MflScoringProdFunction.Arn
      AutoDeploy: true

Stage variables appear in the console as follows:

Stage "stage":

  • Key | Value
  • LambdaAlias | STAGE
  • LambdaFunction | arn:aws:lambda:us-east-1:123412341234:function:mfl-scoring-http-MflScoringStageFunction-cgdT1EMOrMbd

Stage "prod":

  • Key | Value
  • LambdaAlias | PROD
  • LambdaFunction | arn:aws:lambda:us-east-1:123412341234:function:mfl-scoring-http-MflScoringProdFunction-vZajLTdguZE7

The CloudTrail record for the failure is as follows:

{
    "eventVersion": "1.08",
    "userIdentity": {
        "type": "IAMUser",
        "principalId": "xxxx",
        "arn": "arn:aws:iam::xxxx:user/sam-user",
        "accountId": "xxxx",
        "accessKeyId": "xxxx",
        "userName": "sam-user",
        "sessionContext": {
            "sessionIssuer": {},
            "webIdFederationData": {},
            "attributes": {
                "creationDate": "2023-10-17T19:51:06Z",
                "mfaAuthenticated": "false"
            }
        },
        "invokedBy": "cloudformation.amazonaws.com"
    },
    "eventTime": "2023-10-17T19:51:11Z",
    "eventSource": "apigateway.amazonaws.com",
    "eventName": "UpdateIntegration",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "cloudformation.amazonaws.com",
    "userAgent": "cloudformation.amazonaws.com",
    "errorCode": "BadRequestException",
    "requestParameters": {
        "integrationMethod": "POST",
        "requestTemplates": {},
        "integrationType": "AWS_PROXY",
        "requestParameters": {},
        "integrationId": "xxxx",
        "description": "Lambda proxy integration",
        "payloadFormatVersion": "2.0",
        "integrationUri": "arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/${stageVariables.LambdaFunction}:${stageVariables.LambdaAlias}/invocations",
        "apiId": "xxxx"
    },
    "responseElements": {
        "message": "Invalid lambda function"
    },
    "requestID": "05af4104-df20-4916-a615-358084301c05",
    "eventID": "61184f3d-c578-45f9-b4b7-2ac71d8b5f8f",
    "readOnly": false,
    "eventType": "AwsApiCall",
    "managementEvent": true,
    "recipientAccountId": "xxxx",
    "eventCategory": "Management"
}

The error in the CloudFormation console is:

Invalid lambda function (Service: AmazonApiGatewayV2; Status Code: 400; Error Code: BadRequestException; Request ID: fa527627-91b7-4e0e-900a-2ca4ae50e9f7; Proxy: null)

What do I need to do to make ApiGatewayV2 recognize that IntegrationURI as legitimate per the AWS docs (https://docs.aws.amazon.com/apigateway/latest/developerguide/aws-api-gateway-stage-variables-reference.html#stage-variables-in-integration-lambda-functions)?

1 Answer
0

Turns out it was a syntax issue with variable replacement. This fixed it:

        - ''
        - - 'arn:aws:apigateway:'
          - !Ref "AWS::Region"
          - ':lambda:path/2015-03-31/functions/arn:aws:lambda:'
          - !Ref "AWS::Region"
          - ':'
          - !Ref "AWS::AccountId"
          - ':function:${stageVariables.LambdaFunction}:${stageVariables.LambdaAlias}/invocations'

Of course now I get "message "Internal Server Error"" without the lambda being invoked and no way to effectively troubleshoot due to HTTP APIs having no internal tracing. Good times. (not)

answered 7 months ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions