R.S Mohan Aravind
R.S Mohan Aravind

Reputation: 379

AWS- Integrating Lambda with API Gateway using CFT

I'm trying to build a CFT that creates a Lambda Function and an API, and integrates both of them. I'm currently able to create the Lambda Function and the API, but I can't integrate them.

I thought of using AWS:Lambda:Permission, or specifying the Lambda Function in the AWS:RestApi resource, but both require either ARN value of the Lambda Function or the API ID- Both of which I don't have access to because I'm trying to create, deploy, and integrate Lambda and API Gateway in a SINGLE CFT.

What method or resource should I specify in my CFT that can integrate my lambda function and API Gateway, without needing the Lambda ARN or API Id, since I don't have access to those until after theyre created?

EDIT: If it helps, I'm also using Swagger in my CFT

Upvotes: 2

Views: 2466

Answers (1)

asr9
asr9

Reputation: 2768

So the first thing you have to do is to create the Lambda function.

  1. Make sure lambda is the first thing CFN does. You can do this by specifying the DependsOn attribute for AWS::ApiGateway::RestApi - but usually CFN is smart enough to figure it out. Value would be the resource name for AWS::Lambda::Function.

  2. Define your rest API. In the swagger document, you have to have the custom x-amazon-apigateway-integration section. Refer x-amazon-apigateway-integration. The uri attribute of this contains the ARN of the lambda function created earlier. This is not the ARN displayed on lambda console. It can be constructed like this (yaml example). You may need more if you have stages or versions for your lambda.

    uri: !Join ["", ["arn:aws:apigateway:", {"Ref": "AWS::Region"}, ":lambda:path/2015-03-31/functions/", !GetAtt <YourLambdaResourceName>.Arn, "/invocations"]]
    
  3. Also define a role in the credentials attribute of the x-amazon-apigateway-integration. This role needs to define permissions for API gateway to assume to call lambda. Sample role & policy in CFN yaml.

    ApiGatewayRole:
      Type: "AWS::IAM::Role"
      Properties:
        RoleName: !Join ["-", [{"Ref": "AWS::Region"}, {"Ref": "AWS::StackName"}, "apigateway_lambda_role"]]
        AssumeRolePolicyDocument:
          Version: "2012-10-17"
          Statement:
            -
              Effect: "Allow"
              Action:
                - "sts:AssumeRole"
              Principal:
                Service: 
                  - "apigateway.amazonaws.com"
        Path: "/"
    ApiGatewayPolicy:
      Type: "AWS::IAM::Policy"
      DependsOn: ApiGatewayRole
      Properties:
        PolicyName: !Join ["-", [{"Ref": "AWS::Region"}, {"Ref": "AWS::StackName"}, "apigateway_lambda_policy"]]
        PolicyDocument: 
          Version: "2012-10-17"
          Statement: 
            - 
              Effect: "Allow"
              Action: "lambda:InvokeFunction"
              Resource:
                - "*"           
        Roles: 
          - 
            Ref: ApiGatewayRole
    
  4. Finally create you lambda permission with function name as ARN of your lambda you just created (GetAtt .Arn) and principal as apigateway.amazonaws.com. Sample

    LambdaPermission1:
    Type: "AWS::Lambda::Permission"
    Properties: 
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt HandlerFunction.Arn
      Principal: apigateway.amazonaws.com
      SourceAccount: !Ref AWS::AccountId
      SourceArn: !Join ["", ["arn:aws:execute-api:", {"Ref": "AWS::Region"}, ":", {"Ref": "AWS::AccountId"}, ":", <API id>, "/<stage>/<method>/path"]]
    

API id can be retrieved by using Ref function. Hope this helps.

Upvotes: 2

Related Questions