LoginSignup
12
7

More than 3 years have passed since last update.

CloudFormationでAPI Gateway+LambdaなAPIを作成する

Last updated at Posted at 2019-06-10

CloudFormationを利用してlambdaとAPI Gatewayの連携をさらっとまとめてみました
今回のハマりポイントはlambdaPermissionの設定ぐらいでしょうか。
さくっと出来ちゃうのでCloudFormationはホント便利ですね!

・deploy用にS3バケットを用意
・swaggerファイルとlambdaパッケージをアップロード
・CFn実行
という手順で進めていきます

対象者

・環境構築を楽にしたい人
・サーバーレスなAPIに興味がある人

deploy用のS3バケットを作成

swaggerファイルとlambdaファイルをアップロードする先として
S3バケットとバケットポリシーを定義します

deployXXXBucket.yml
AWSTemplateFormatVersion: '2010-09-09'
Description: This CloudFormation template to create S3 Bucket

Parameters:
  DeployBucket:
    Description: deploy workspace
    Type: String

Resources:

  #==============================
  # lambda,swaggerファイルをdeploy時に参照するバケット
  #==============================

  DeployS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref DeployBucket
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: True
        BlockPublicPolicy: True
        IgnorePublicAcls: True
        RestrictPublicBuckets: True

  DeployS3BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref DeployS3Bucket
      PolicyDocument:
        Id: DeployS3BucketPolicy
        Version: '2012-10-17'
        Statement:
        - Sid: XXXS3Acl
          Effect: Allow
          Principal: {
            Service: "cloudformation.amazonaws.com"
          }
          Action:
          - "s3:GetObject"
          Resource:
          - !Sub "arn:aws:s3:::${DeployBucket}/*"

定義したymlファイルを使ってstackを作成します

deployXXXBucket.sh
#!/bin/bash
set -Ceu

BASE_DIR=$(cd $(dirname $0); pwd)
REGION="ap-northeast-1"
CFN_INIT_TEMPLATE_FILE="deployXXXBucket.yml"
STACK_NAME_DEPLOY_BUCKET="apiXXXDeployS3Bucket"
DEPLOY_BUCKET="api-xxx-deploy-bucket"

/usr/bin/aws cloudformation create-stack \
--template-body file://${BASE_DIR}/${CFN_INIT_TEMPLATE_FILE} \
--stack-name ${STACK_NAME_DEPLOY_BUCKET} \
--region ${REGION} \
--parameters ParameterKey=DeployBucket,ParameterValue=${DEPLOY_BUCKET}

lambdaを作成

index.js
exports.handler = async (event, context) => {
  context.done(null, new Response(200, JSON.stringify({data: "hello world"})));
};

class Response{
  constructor(statusCode, body){
    this.statusCode = statusCode;
    this.body = body;
    this.headers = {"Access-Control-Allow-Origin" : "*"};
  }
}

swagger.ymlを作成

swagger.yml
swagger: "2.0"
info:
  version: "2019-03-26T11:14:17Z"
  title:
    Fn::Sub: ${ApiGwName}
host: "api-xxx.hoge.me"
schemes:
- "https"
paths:
  /:
    get:
      x-amazon-apigateway-integration:
        uri:
          Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${ApiXXXFunction.Arn}/invocations
        responses:
          default:
            statusCode: "200"
        passthroughBehavior: "when_no_match"
        httpMethod: "POST"
        contentHandling: "CONVERT_TO_TEXT"
        type: "aws_proxy"
      produces:
      - "application/json"
      responses:
        200:
          description: "200 response"
          schema:
            $ref: "#/definitions/Empty"
          headers:
            Access-Control-Allow-Origin:
              type: "string"

definitions:
  Empty:
    type: "object"
    title: "Empty Schema"

x-amazon-apigateway-policy:
  Version: "2012-10-17"
  Statement:
  - Effect: "Allow"
    Principal: "*"
    Action: "execute-api:Invoke"
    Resource:
      Fn::Sub: "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}*"

CFnテンプレートを作成します

template.cfn.yml
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Description: This CloudFormation template to create ApiXXX

Parameters:
  DeployBucket:
    Description: to use swagger file, lambda package at build
    Type: String
  GwStage:
    Description: API Gateway deploy stage
    Type: String
    AllowedValues:
    - v1
  ApiXXXGwRole:
    Description: API Gateway role name
    Type: String
  LambdaName:
    Description: lambda function name
    Type: String
  LambdaRoleName:
    Description: lambda function role
    Type: String

Resources:
  #==============================
  # apigateway
  #==============================
  ApiXXX:
    Properties:
      DefinitionBody:
        Fn::Transform:
          Name: AWS::Include
          Parameters:
            Location: !Sub "s3://${DeployBucket}/swagger.yml"
      StageName:
        Fn::Sub: ${GwStage}
    Type: AWS::Serverless::Api
    Role:
      Fn::GetAtt:
        - ApiXXXApiGwRole
        - Arn
    DependsOn:
      - ApiXXXApiGwRole
      - ApiXXXFunction

  #==============================
  # lambda(SAM管理)
  #==============================
  ApiXXXFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: !Ref LambdaName
      Handler: index.handler
      Runtime: nodejs10.x
      CodeUri: src/function
      MemorySize: 128
      Timeout: 60
      Role:
        Fn::GetAtt:
          - LambdaExecutionRole
          - Arn

  ApiXXXApiGwRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Ref ApiXXXGwRole
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - apigateway.amazonaws.com
          Action:
          - sts:AssumeRole
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Ref LambdaRoleName
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - lambda.amazonaws.com
          Action:
          - sts:AssumeRole
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole

  LambdaPermissionxxxx:
    Type: "AWS::Lambda::Permission"
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !Ref ApiXXXFunction
      Principal: apigateway.amazonaws.com

定義したymlファイルを使って変更セットを作成します

deployXXX.sh
#!/bin/bash
set -Ceu

BASE_DIR=$(cd $(dirname $0); pwd)
REGION="ap-northeast-1"
SWAGGER_FILE="swagger.yml"
DEPLOY_BUCKET="api-xxx-deploy-bucket"
CFN_TEMPLATE_FILE="template.cfn.yml"
CFN_TEMPLATE_OUTPUT_FILE="output-template.cfn.yml"
STACK_NAME="apiXXXDeploy"

/usr/bin/aws s3 cp ./${SWAGGER_FILE} s3://${DEPLOY_BUCKET}/

/usr/bin/aws cloudformation package \
--template-file ${CFN_TEMPLATE_FILE} \
--output-template-file ${CFN_TEMPLATE_OUTPUT_FILE} \
--s3-bucket ${DEPLOY_BUCKET}

GwStage="v1"
DeployBucket=$DEPLOY_BUCKET
ApiGwName="apiXXX"
ApiXXXGwRole="apiXXXGwRole"
LambdaName="apiXXXLambda"
LambdaRoleName="apiXXXLambdaRole"
/usr/bin/aws cloudformation deploy \
--template-file ${BASE_DIR}/${CFN_TEMPLATE_OUTPUT_FILE} \
--stack-name ${STACK_NAME} \
--region ${REGION} \
--parameter-overrides GwStage=${GwStage} DeployBucket=${DeployBucket} ApiGwName=${ApiGwName} ApiXXXGwRole=${ApiXXXGwRole} LambdaName=${LambdaName} LambdaRoleName=${LambdaRoleName}  \
--capabilities CAPABILITY_NAMED_IAM

CFn変更セットを実行

ビルドを実行します
変更セットにステータスがCREAE_IN_PROGRESSで作成されている様子が確認できますね
スクリーンショット 2019-06-10 10.53.51.png

ステータスがCREATE_COMPLETEになると、
変更セット詳細ページから作成リソースを確認できます
実行すると用意したリソースが作成されています。簡単ですね
スクリーンショット 2019-06-10 10.50.59.png

12
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
7