AWS
CloudFormation
sam
lambda

【初心者向け】CFnでAPI Gateway+LambdaなAPI作成をまとめてみた

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