AWS CloudFormationでマルチAZのVPC Lambdaを作る
覚え書き。どうしても対外IPを固定したLambdaが必要だったので作った。
- 実際に動いた構成をブログ用にまとめたものなので、そのままだと動かないかも。
- 具体的な設定値を乗せたいので、あまりパラメータに出してない。必要ならパラメータにする。
- タグは適当。とりあえず、タグをつけられる箇所だということを示すためにつけてる。
以下の記事を参考にさせていただきました。
CloudFormationを使ってVPCを構築する - Qiita
CloudFormationを使ってNAT Gatewayを構築する - Qiita
AWS CloudFormationでAWS Lambda with VPCを作成してみた | Developers.IO
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: "example"
Parameters:
ServiceName:
Description: "サービス名"
Type: String
Resources:
#========================================
# IAM
#========================================
# Lambda実行ロール
MyVpcLambdaExecutionRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Principal:
Service:
- "lambda.amazonaws.com"
Action:
- "sts:AssumeRole"
# Lambda実行ロールのポリシー
MyVpcLambdaExecutionPolicy:
Type: "AWS::IAM::Policy"
DependsOn: MyVpcLambdaExecutionRole
Properties:
PolicyName: !Ref VpcLambdaExecutionPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: "Allow"
Action:
- "logs:CreateLogGroup"
- "logs:CreateLogStream"
- "logs:PutLogEvents"
Resource: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*"
- Effect: "Allow"
Action:
- "ec2:CreateNetworkInterface"
- "ec2:DescribeNetworkInterfaces"
- "ec2:DetachNetworkInterface"
- "ec2:DeleteNetworkInterface"
Resource: "*"
Roles:
- !Ref MyVpcLambdaExecutionRole
#========================================
# Lambda
#========================================
## ここでは AWS::Serverless::Function ではなく AWS::Lambda::Function で作成してるけど、
## AWS::Serverless::Function でも VpcConfig の書き方は同じ
# VPC Lambda
MyLambdaFunction:
Type: AWS::Lambda::Function
DependsOn: MyVpcLambdaExecutionPolicy
Properties:
# ここではとりあえずNode.jsのHelloWorldを書いてます。
FunctionName: !Ref LambdaFunctionName
Code:
ZipFile: |
exports.handler = async (event) => {
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
Handler: "index.handler"
Runtime: "nodejs12.x"
Timeout: 30
MemorySize: 128
Role: !GetAtt MyVpcLambdaExecutionRole.Arn
VpcConfig:
SecurityGroupIds:
- !Ref MyLambdaSecurityGroup
SubnetIds:
# マルチAZならここを増やす
- !Ref MyPrivateSubnet1
Tags:
- Key: "ServiceName"
Value: !Ref ServiceName
#========================================
# VPC
#========================================
# VPC (ここでは 192.168.0.0/16)
MyVpc:
Type: "AWS::EC2::VPC"
Properties:
CidrBlock: "192.168.0.0/16"
EnableDnsSupport: "true"
EnableDnsHostnames: "true"
InstanceTenancy: default
Tags:
- Key: "ServiceName"
Value: !Ref ServiceName
# Lambda用のセキュリティグループ
MyLambdaSecurityGroup:
Type: "AWS::EC2::SecurityGroup"
Properties:
VpcId: !Ref MyVpc
GroupName: "MyLambdaSecurityGroupName"
GroupDescription: "VPC Lambda"
Tags:
- Key: "ServiceName"
Value: !Ref ServiceName
# インターネットゲートウェイ
MyInternetGateway:
Type: "AWS::EC2::InternetGateway"
Properties:
Tags:
- Key: "ServiceName"
Value: !Ref ServiceName
# インターネットゲートウェイをVPCにアタッチ
MyInternetGatewayAttachment:
Type: "AWS::EC2::VPCGatewayAttachment"
Properties:
VpcId: !Ref MyVpc
InternetGatewayId: !Ref MyInternetGateway
# ついでにDynamoDBへのVPCエンドポイントをプライベートサブネットに作成 (必要なら)
MyVPCEndpointDynamoDB:
Type: "AWS::EC2::VPCEndpoint"
Properties:
VpcId: !Ref MyVpc
VpcEndpointType: "Gateway"
ServiceName: "com.amazonaws.ap-northeast-1.dynamodb"
RouteTableIds:
# プライベートサブネットの数だけ指定 (マルチAZならここを増やす)
- !Ref MyPrivateRouteTable1
#----------------------------------------------
# マルチAZにする場合はここから下を増やす
# (ここでは ap-northeast-1a)
# パブリックサブネット (ここでは 192.168.1.0/24)
MyPublicSubnet1:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1a"
CidrBlock: "192.168.1.0/24"
VpcId: !Ref MyVpc
Tags:
- Key: "ServiceName"
Value: !Ref ServiceName
# プライベートサブネット (ここでは 192.168.2.0/24)
MyPrivateSubnet1:
Type: "AWS::EC2::Subnet"
Properties:
AvailabilityZone: "ap-northeast-1a"
CidrBlock: "192.168.2.0/24"
VpcId: !Ref MyVpc
Tags:
- Key: "ServiceName"
Value: !Ref ServiceName
# NATゲートウェイ
MyNATGateway1:
Type: "AWS::EC2::NatGateway"
Properties:
AllocationId: !GetAtt MyNATGateway1Ip.AllocationId
SubnetId: !Ref MyPublicSubnet1
Tags:
- Key: "ServiceName"
Value: !Ref ServiceName
MyNATGateway1Ip:
Type: "AWS::EC2::EIP"
Properties:
Domain: "vpc"
# パブリックサブネットのルートテーブル ...
MyPublicRouteTable1:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref MyVpc
Tags:
- Key: "ServiceName"
Value: !Ref ServiceName
## ... IGWにルーティング
MyPublicRoute1:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref MyPublicRouteTable1
DestinationCidrBlock: "0.0.0.0/0"
GatewayId: !Ref MyInternetGateway
## ... ルートテーブルをサブネットに紐づけ
MyPublicSubnet1RouteTableAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref MyPublicSubnet1
RouteTableId: !Ref MyPublicRouteTable1
## プライベートサブネットのルートテーブル ...
MyPrivateRouteTable1:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref MyVpc
Tags:
- Key: "ServiceName"
Value: !Ref ServiceName
## ... NATゲートウェイにルーティング
MyPrivateRoute1:
Type: "AWS::EC2::Route"
Properties:
RouteTableId: !Ref MyPrivateRouteTable1
DestinationCidrBlock: "0.0.0.0/0"
NatGatewayId: !Ref MyNATGateway1
# ... ルートテーブルをサブネットに紐づけ
MyPrivateSubnet1RouteTableAssociation:
Type: "AWS::EC2::SubnetRouteTableAssociation"
Properties:
SubnetId: !Ref MyPrivateSubnet1
RouteTableId: !Ref MyPrivateRouteTable1