CloudFormation入門③ ALB
はじめに
今回はALBを使用して、HTTP/HTTPSトラフィックをプライベートなEC2に接続する構成です。
目標
以下のような構成を作成します。
最終的なコード
先に最終的なコードをお見せします。
AWSTemplateFormatVersion: "2010-09-09"
Description:
Create ALB and EC2!
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "Product Name"
Parameters:
- ProductPrefix
- Label:
default: "ALB Name"
Parameters:
- ALBName
- Label:
default: "EC2Instance"
Parameters:
- KeyPairName
- EC2InstanceName
- EC2InstanceAMI
- EC2InstanceInstanceType
- EC2InstanceVolumeType
- EC2InstanceVolumeSize
- SSHAccessSourceIP
ParameterLabels:
ALBName:
default: "ALBName"
KeyPairName:
default: "KeyPairName"
EC2InstanceName:
default: "EC2 Name"
EC2InstanceAMI:
default: "EC2 AMI"
EC2InstanceInstanceType:
default: "EC2 InstanceType"
EC2InstanceVolumeType:
default: "EC2 VolumeType"
EC2InstanceVolumeSize:
default: "EC2 VolumeSize"
SSHAccessSourceIP:
default: "SSH AccessSourceIP"
################################################################
# Parameters
################################################################
Parameters:
ProductPrefix:
Type: String
#ALB
ALBName:
Type: String
Default: "web"
#EC2
KeyPairName:
Type: AWS::EC2::KeyPair::KeyName
Default: ""
EC2InstanceName:
Type: String
Default: "web"
EC2InstanceAMI:
Type: String
Default: ""
EC2InstanceInstanceType:
Type: String
Default: "t2.micro"
EC2InstanceVolumeType:
Type: String
Default: "gp2"
EC2InstanceVolumeSize:
Type: String
Default: "30"
SSHAccessSourceIP:
Type: String
################################################################
# Resources
################################################################
Resources:
# VPCの作成
TestVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
Tags:
- Key: Name
Value: TestVPC
# インターネットゲートウェイ
TestInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: TestInternetGateway
# インターネットゲートウェイをVPCにアタッチ
AttachInternetGateway:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref TestVPC
InternetGatewayId: !Ref TestInternetGateway
#パブリックサブネットの作成
TestPublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
VpcId: !Ref TestVPC
CidrBlock: 10.0.10.0/24
Tags:
- Key: Name
Value: TestPublicSubnet1
TestPublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
VpcId: !Ref TestVPC
CidrBlock: 10.0.20.0/24
Tags:
- Key: Name
Value: TestPublicSubnet2
TestPrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone:
Fn::Select:
- 0
- Fn::GetAZs: ""
VpcId: !Ref TestVPC
CidrBlock: 10.0.30.0/24
Tags:
- Key: Name
Value: TestPrivateSubnet1
TestPrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone:
Fn::Select:
- 1
- Fn::GetAZs: ""
VpcId: !Ref TestVPC
CidrBlock: 10.0.40.0/24
Tags:
- Key: Name
Value: TestPrivateSubnet2
# ルートテーブルの作成
TestRouteTableForPublicSubnet:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref TestVPC
Tags:
- Key: Name
Value: TestRouteTableForPublicSubnet
# パブリックサブネットのルーティング
RoutePublicSubnetToInternetGateway:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref TestRouteTableForPublicSubnet
GatewayId: !Ref TestInternetGateway
DestinationCidrBlock: 0.0.0.0/0
# ルートテーブルをサブネットに紐付け
AssociatePublicSubnetToRouteTable:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref TestPublicSubnet1
RouteTableId: !Ref TestRouteTableForPublicSubnet
# IAMロール
TestEC2IAMRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "${ProductPrefix}-${EC2InstanceName}-role"
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
Effect: "Allow"
Principal:
Service:
- "ec2.amazonaws.com"
Action:
- "sts:AssumeRole"
Path: "/"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess"
# EC2インスタンスプロファイル
TestEC2InstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
Path: "/"
Roles:
- Ref: TestEC2IAMRole
InstanceProfileName: !Sub "${ProductPrefix}-${EC2InstanceName}-profile"
# EC2インスタンス-1:
TestEC2Instance1:
Type: "AWS::EC2::Instance"
Properties:
Tags:
- Key: Name
Value: !Sub "${ProductPrefix}-${EC2InstanceName}-1"
ImageId: !Ref EC2InstanceAMI
InstanceType: !Ref EC2InstanceInstanceType
KeyName: !Ref KeyPairName
IamInstanceProfile: !Ref TestEC2InstanceProfile
DisableApiTermination: false # 削除保護
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
VolumeType: !Ref EC2InstanceVolumeType
VolumeSize: !Ref EC2InstanceVolumeSize
SecurityGroupIds:
- !Ref TestWebSecurityGroup
SubnetId: !Ref TestPrivateSubnet1
UserData: !Base64 |
#! /bin/bash
yum update -y
# EC2セキュリティグループ
TestWebSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: test-ec2-sg
GroupDescription: EC2SecurityGroup
VpcId: !Ref TestVPC
SecurityGroupIngress:
# HTTP
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 111.111.111.111/32
Tags:
- Key: Name
Value: !Sub "${ProductPrefix}-web-sg"
# ALB セキュリティグループ
TestALBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: test-alb-sg
GroupDescription: TestALBSecurityGroup
VpcId: !Ref TestVPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 443
ToPort: 443
CidrIp: 0.0.0.0/0
Tags:
- Key: Name
Value: !Sub "${ProductPrefix}-alb-sg"
# ALB
TestALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Type: "application"
Scheme: "internet-facing"
Name: !Sub "${ProductPrefix}-alb"
Tags:
- Key: Name
Value: !Sub "${ProductPrefix}-alb"
IpAddressType: ipv4
Subnets:
- !Ref TestPublicSubnet1
- !Ref TestPublicSubnet2
SecurityGroups:
- !Ref TestALBSecurityGroup
# ターゲットグループ
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: "tg"
Tags:
- Key: Name
Value: !Sub "${TestALB}-tg"
Port: 80
Protocol: HTTP
VpcId: !Ref TestVPC
TargetType: instance
Targets:
- Id: !Ref TestEC2Instance1
# リスナールール
ListenerRule:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
LoadBalancerArn: !Ref TestALB
Port: 80
Protocol: HTTP
解説
ここからいくつかのパートに分けて解説していきます。(過去の記事で解説した内容に関しては省略します)
Metadata
Metadata:
"AWS::CloudFormation::Interface":
ParameterGroups:
- Label:
default: "Product Name"
Parameters:
- ProductPrefix
- Label:
default: "ALB Name"
Parameters:
- ALBName
- Label:
default: "EC2Instance"
Parameters:
- KeyPairName
- EC2InstanceName
- EC2InstanceAMI
- EC2InstanceInstanceType
- EC2InstanceVolumeType
- EC2InstanceVolumeSize
- SSHAccessSourceIP
ParameterLabels:
ALBName:
default: "ALBName"
KeyPairName:
default: "KeyPairName"
EC2InstanceName:
default: "EC2 Name"
EC2InstanceAMI:
default: "EC2 AMI"
EC2InstanceInstanceType:
default: "EC2 InstanceType"
EC2InstanceVolumeType:
default: "EC2 VolumeType"
EC2InstanceVolumeSize:
default: "EC2 VolumeSize"
SSHAccessSourceIP:
default: "SSH AccessSourceIP"
MetadataセクションキーのAWS::CloudFormation::Interface
を使用することで、入力パラメータのグループ化と順序を指定できます。
このセクションキーを使用しない場合だと、論理IDのアルファベット順にソートされることになり、各パラメータの意味合い的なまとまりがなくなってしまいます。
ALB
# ALB
TestALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Type: "application"
Scheme: "internet-facing"
Name: !Sub "${ProductPrefix}-alb"
Tags:
- Key: Name
Value: !Sub "${ProductPrefix}-alb"
IpAddressType: ipv4
Subnets:
- !Ref TestPublicSubnet1
- !Ref TestPublicSubnet2
SecurityGroups:
- !Ref TestALBSecurityGroup
ALBはType:AWS::ElasticLoadBalancingV2::LoadBalancer
を使用することでリソースが作成されます。
Properties内のTypeで指定するのはロードバランサーのタイプでapplication
,network
,gateway
のいずれかを指定します。今回はHTTPおよびHTTPSトラフィック用に使う想定でapplication
を指定します。
Scheme
ではロードバランサーを内部ロードバランサーにするか、インターネット向けロードバランサーにするかを選択します。今回はリクエストをインターネット経由でターゲットにルーティングしたいのでinternet-facing
を指定します。内部ロードバランサーの場合はinternal
を指定します。
Subnets
ではALBを配置するサブネットのIDを指定します。Application LoadBalancerは少なくとも2つのAZからサブネットを指定する必要があります。
これだけではALBに到達したトラフィックをEC2に向けることができないため、ターゲットグループとリスナールールの設定をします。
ALB ターゲットグループ
# ターゲットグループ
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: "test-tg"
Tags:
- Key: Name
Value: !Sub "${TestALB}-tg"
Port: 80
Protocol: HTTP
VpcId: !Ref TestVPC
TargetType: instance
Targets:
- Id: !Ref TestEC2Instance1
TargetGroupのTypeはAWS::ElasticLoadBalancingV2::TargetGroup
で指定します。
TargetType: instance
はこのターゲットグループにターゲットを登録するときに指定する必要があるターゲットのタイプになります。instance
,ip
,Lambda
,ALB
のいずれかを指定します。
ALB リスナールール
# リスナールール
ListenerRule:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
LoadBalancerArn: !Ref TestALB
Port: 80
Protocol: HTTP
DefaultActions
でデフォルトアクションのタイプとターゲットグループを指定します。
LoadBalancerArn
でリスナールールを付与するALBのARNを指定します。
おわりに
こちらのコードでスタックを作成した結果がこちらです。
VPC/Subnet/Route Table
ALB
ALBリスナールール
想定通りできていそうです!
Discussion