77Lifeworkベータ版

77Lifeworkベータ版

ITツール開発・インフラ構築をメインとして、その他投資等雑記用のブログです。ブログの内容が少しでも皆様の参考となれば嬉しいです。

AWS CloudFormationでAPIGatewayとLambdaを構築する方法

はじめに

こんにちは。
今回はAWS CloudFormation(CFn)のテンプレートを記述し、スタックを作成する形式でAPIGatewayとLambdaを構築する方法を書いていきます。
APIGatewayとLambdaをそれぞれ作成した後に紐づけることで、APIGatewayの特定パスにアクセスした際にLambdaを呼び出して実行するよう設定します。

事前準備

AWSアカウントの作成やIAMユーザの作成など、アカウント作成後の初期設定はあらかじめ実施しておきましょう。ここから先はAWSマネジメントコンソールにサインインして操作できる前提で進めます。

全体構成

今回CloudFormationでデプロイするのは以下の構成となります。

利用者はインターネット経由でAPIGatewayにリクエストし、バックエンドでAPIGatewayと連携するLambda functionが実行され、レスポンスを返す処理です。
ここではインフラ部分に絞って説明するため、Lambda上で動かすコードはテスト用として、リクエストに対して文字列を返却するだけの単純なものとしています。

CloudFormationのテンプレート(Lambda function)

Lambda function自体のリソースと、作成したLambda functionにアタッチする実行用IAMロールを作成するテンプレートです。

今回は実行するPythonのテストコード自体もCloudFormationテンプレートに埋め込んでいますが、実行コードをzip形式でS3に格納し、それを参照してLambda functionで実行するような構成も可能です。

Lambda実行用のIAMロールにアタッチするIAMポリシーではCloudWatchLogsへのログ書き込みに必要なActionを許可しておきます。

AWSTemplateFormatVersion: '2010-09-09'
Description: 'Lambda function'

Parameters:
  lambdaFunctionName:
    Type: String

Resources:
  LambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        ZipFile: |-
          import json
          def lambda_handler(event, context):   
            return {
              'statusCode': 200,
              'body': json.dumps('Hello from Lambda!')
            }
      FunctionName: !Ref lambdaFunctionName
      Handler: index.lambda_handler
      MemorySize: 128
      Timeout: 3
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: python3.11

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole
      Policies:
        - PolicyName: !Sub '${lambdaFunctionName}-ExeRole'
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                Resource: !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*'
              - Effect: Allow
                Action:
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${lambdaFunctionName}:*'

CloudFormationのテンプレート(APIGateway)

AWSTemplateFormatVersion: '2010-09-09'
Description: 'APIGateway'

Parameters:
  ApiName:
    Type: String
    Description: 'APIGateway Name'
  ApiStageName:
    Type: String
  ApiResourceName:
    Type: String
    Description: 'API Resource Name'
  LambdaFunctionName:
    Type: String
    Description: 'Lambda Function Name'

Resources:
  RestApi:
    Type: AWS::ApiGateway::RestApi
    Properties:
      ApiKeySourceType: HEADER
      EndpointConfiguration:
        Types:
          - REGIONAL
      Name: !Ref ApiName

  RestApiResource:
    Type: AWS::ApiGateway::Resource
    Properties:
      ParentId: !GetAtt RestApi.RootResourceId
      PathPart: !Ref ApiResourceName
      RestApiId: !Ref RestApi

  RestApiMethod:
    Type: AWS::ApiGateway::Method
    Properties:
      ApiKeyRequired: True
      AuthorizationType: NONE
      HttpMethod: GET
      Integration:
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${LambdaFunctionName}/invocations'
      ResourceId: !Ref RestApiResource
      RestApiId: !Ref RestApi

  RestApiGatewayLambdaPermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref LambdaFunctionName
      Action: lambda:InvokeFunction
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${RestApi}/*/GET/${ApiResourceName}'

  RestApiDeployment:
    Type: AWS::ApiGateway::Deployment
    Properties:
      RestApiId: !Ref RestApi
    DependsOn: RestApiMethod

  RestApiStage:
    Type: AWS::ApiGateway::Stage
    Properties:
      DeploymentId: !Ref RestApiDeployment
      RestApiId: !Ref RestApi
      StageName: !Ref ApiStageName

Outputs:
  RestApiId:
    Value: !GetAtt RestApi.RestApiId
    Export:
      Name: !Sub '${ApiName}Id'

おわりに

今回はAWS CloudFormation(CFn)のテンプレートを記述し、APIGatewayとLambdaを構築する方法を書きました。
この内容が少しでもお役に立てば幸いです。

最後まで読んでいただきありがとうございました。