以前の記事をバージョンアップさせてみました。
CloudFormationテンプレートサンプルとしてお使いください。
個人的にはMappingsで自動でCIDR範囲を区切ってくれるようにしたところがポイントです。
このテンプレートを使用することで、以下のリソースが作成されます。
- ネットワーク
- VPC x1
- PublicSubnet x2
- PrivateSubnet(ProtectedSubnet) x2
- NatGateway x2
- コンピューティング
- EC2(Bastion) x1
- 起動テンプレート x1
- 暗号化済みEBS
- 詳細モニタリング有効化
- UserData(Apache起動、サンプルページ表示)
- AutoScaling Group x1
- Target Tracking Policy
- オートスケーリンググループ別モニタリング有効化
- Application Load Balancer
- TargetGroup
- リスナールール(パスベースルーティング)
- AccessLogs(宛先はS3)
- Security Group
- ALB用セキュリティグループ
- サーバー用セキュリティグループ
- IAM
- インスタンス用ロール
- AmazonSSMManagedInstanceCore
- インスタンスプロファイル
- インスタンス用ロール
AWSTemplateFormatVersion: 2010-09-09
Parameters:
VPCCidrBlock:
Description: The primary IPv4 CIDR block for the VPC.
Type: String
MinLength: '9'
MaxLength: '18'
Default: 10.0.0.0/16
AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})'
SubnetCidrBits:
Description: Subnet CidrBits, alowed bitween 8 and 30.
Type: String
MinLength: '1'
MaxLength: '2'
Default: '24'
AllowedPattern: '(\d{1,2})'
PJPrefix:
Type: String
Default: base
AMIID:
Type: String
Default: ami-0c8e23f950c7725b9
AccessLogsAccountID:
Type: String
Description: This value will be used in the bucket policy for storing access logs. Change it according to the region you are deploying.
Default: 127311923021
Mappings:
CidrBits:
'30':
bit: 2
'29':
bit: 3
'28':
bit: 4
'27':
bit: 5
'26':
bit: 6
'25':
bit: 7
'24':
bit: 8
'23':
bit: 9
'22':
bit: 10
'21':
bit: 11
'20':
bit: 12
'19':
bit: 13
'18':
bit: 14
'17':
bit: 15
'16':
bit: 16
'15':
bit: 17
'14':
bit: 18
'13':
bit: 19
'12':
bit: 20
'11':
bit: 21
'10':
bit: 22
'9':
bit: 23
'8':
bit: 24
Resources:
################ Create Network ################
VPC:
Type: 'AWS::EC2::VPC'
Properties:
EnableDnsSupport: 'true'
EnableDnsHostnames: 'true'
CidrBlock: !Ref VPCCidrBlock
Tags:
- Key: Name
Value: !Sub '${PJPrefix}-VPC'
PublicSubnet1:
Type: 'AWS::EC2::Subnet'
Properties:
AvailabilityZone: !Select
- 0
- 'Fn::GetAZs': !Ref 'AWS::Region'
CidrBlock:
Fn::Select:
- 0
- Fn::Cidr:
- Fn::GetAtt:
- VPC
- CidrBlock
- 4
- Fn::FindInMap:
- CidrBits
- !Ref SubnetCidrBits
- bit
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub '${PJPrefix}-PublicSubnet1'
VpcId: !Ref VPC
PublicSubnet2:
Type: 'AWS::EC2::Subnet'
Properties:
CidrBlock:
Fn::Select:
- 1
- Fn::Cidr:
- Fn::GetAtt:
- VPC
- CidrBlock
- 4
- Fn::FindInMap:
- CidrBits
- !Ref SubnetCidrBits
- bit
AvailabilityZone: !Select
- 1
- 'Fn::GetAZs': !Ref 'AWS::Region'
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub '${PJPrefix}-PublicSubnet2'
VpcId: !Ref VPC
PrivateSubnet1:
Type: 'AWS::EC2::Subnet'
Properties:
CidrBlock:
Fn::Select:
- 2
- Fn::Cidr:
- Fn::GetAtt:
- VPC
- CidrBlock
- 4
- Fn::FindInMap:
- CidrBits
- !Ref SubnetCidrBits
- bit
AvailabilityZone: !Select
- 0
- 'Fn::GetAZs': !Ref 'AWS::Region'
Tags:
- Key: Name
Value: !Sub '${PJPrefix}-PrivateSubnet1'
VpcId: !Ref VPC
PrivateSubnet2:
Type: 'AWS::EC2::Subnet'
Properties:
CidrBlock:
Fn::Select:
- 3
- Fn::Cidr:
- Fn::GetAtt:
- VPC
- CidrBlock
- 4
- Fn::FindInMap:
- CidrBits
- !Ref SubnetCidrBits
- bit
AvailabilityZone: !Select
- 1
- 'Fn::GetAZs': !Ref 'AWS::Region'
Tags:
- Key: Name
Value: !Sub '${PJPrefix}-PrivateSubnet2'
VpcId: !Ref VPC
InternetGateway:
Type: 'AWS::EC2::InternetGateway'
DependsOn: VPC
Properties:
Tags:
- Key: Name
Value: InternetGateway
VPCGatewayAttachment:
Type: 'AWS::EC2::VPCGatewayAttachment'
DependsOn:
- VPC
- InternetGateway
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref InternetGateway
PublicRouteTable:
Type: 'AWS::EC2::RouteTable'
Properties:
Tags:
- Key: Name
Value: PublicRouteTable
VpcId: !Ref VPC
PublicRoute:
Type: 'AWS::EC2::Route'
DependsOn: VPCGatewayAttachment
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PublicSubnetRouteTableAssociation1:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
DependsOn:
- PublicSubnet1
- PublicRouteTable
Properties:
SubnetId: !Ref PublicSubnet1
RouteTableId: !Ref PublicRouteTable
PublicSubnetRouteTableAssociation2:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
DependsOn:
- PublicSubnet2
- PublicRouteTable
Properties:
SubnetId: !Ref PublicSubnet2
RouteTableId: !Ref PublicRouteTable
ElasticIP1:
Type: 'AWS::EC2::EIP'
Properties:
Domain: vpc
Tags:
- Key: Name
Value: ElasticIP1
ElasticIP2:
Type: 'AWS::EC2::EIP'
Properties:
Domain: vpc
Tags:
- Key: Name
Value: ElasticIP2
NATGateway1:
Type: 'AWS::EC2::NatGateway'
Properties:
AllocationId: !GetAtt
- ElasticIP1
- AllocationId
SubnetId: !Ref PublicSubnet1
Tags:
- Key: Name
Value: NATGateway1
NATGateway2:
Type: 'AWS::EC2::NatGateway'
Properties:
AllocationId: !GetAtt
- ElasticIP2
- AllocationId
SubnetId: !Ref PublicSubnet2
Tags:
- Key: Name
Value: NATGateway2
PrivateRoutetable1:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: PrivateRouteTable1
PrivateRoute1:
Type: 'AWS::EC2::Route'
DependsOn:
- NATGateway1
Properties:
RouteTableId: !Ref PrivateRoutetable1
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NATGateway1
PrivateSubnetRouteTableAssociation1:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
RouteTableId: !Ref PrivateRoutetable1
SubnetId: !Ref PrivateSubnet1
PrivateRoutetable2:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: PrivateRouteTable2
PrivateRoute2:
Type: 'AWS::EC2::Route'
Properties:
RouteTableId: !Ref PrivateRoutetable2
DestinationCidrBlock: 0.0.0.0/0
NatGatewayId: !Ref NATGateway2
PrivateSubnetRouteTableAssociation2:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
SubnetId: !Ref PrivateSubnet2
RouteTableId: !Ref PrivateRoutetable2
PrivateRoutetable3:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: PrivateRouteTable3
################ Create BastionServer ################
EC2Instance:
Type: 'AWS::EC2::Instance'
Properties:
ImageId: !Ref AMIID
InstanceType: t3.micro
IamInstanceProfile: !Ref EC2InstanceProfile
SubnetId: !Ref PrivateSubnet1
SecurityGroupIds:
- !Ref InstanceSecurityGroup
Tags:
- Key: Name
Value: Bastion
InstanceRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
EC2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: InstanceRole
Roles:
- !Ref InstanceRole
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow http to client host
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref ALBSecurityGroup
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
################ Create ApplicationLoadBalancer ################
ALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: alb
Scheme: internet-facing
SecurityGroups:
- !Ref ALBSecurityGroup
Subnets:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
LoadBalancerAttributes:
- Key: "access_logs.s3.enabled"
Value: true
- Key: "access_logs.s3.bucket"
Value: !Ref AccessLogsBucket
ALBSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow http to client host
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
SecurityGroupEgress:
- IpProtocol: -1
CidrIp: 0.0.0.0/0
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: target
TargetType: instance
Protocol: HTTP
Port: 80
VpcId: !Ref VPC
HTTPlistener:
Type: "AWS::ElasticLoadBalancingV2::Listener"
Properties:
DefaultActions:
- Type: forward
ForwardConfig:
TargetGroups:
- TargetGroupArn: !Ref TargetGroup
LoadBalancerArn: !Ref ALB
Port: 80
Protocol: "HTTP"
ListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: forward
ForwardConfig:
TargetGroups:
- TargetGroupArn: !Ref TargetGroup
Conditions:
- Field: path-pattern
Values:
- /main
- /main/*
ListenerArn: !Ref HTTPlistener
Priority: 10
AccessLogsBucket:
Type: AWS::S3::Bucket
SampleBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref AccessLogsBucket
PolicyDocument:
Version: 2012-10-17
Statement:
- Action:
- 's3:PutObject'
Effect: Allow
Resource: !Sub 'arn:aws:s3:::${AccessLogsBucket}/AWSLogs/${AWS::AccountId}/*'
Principal:
AWS: !Sub 'arn:aws:iam::${AccessLogsAccountID}:root'
################ Create AutoScalingGroup ################
LaunchTemplate:
Type: 'AWS::EC2::LaunchTemplate'
Properties:
LaunchTemplateName: ServerTemplate
LaunchTemplateData:
IamInstanceProfile:
Arn: !GetAtt
- EC2InstanceProfile
- Arn
ImageId: !Ref AMIID
InstanceType: t3.micro
BlockDeviceMappings:
- Ebs:
VolumeSize: 8
VolumeType: gp2
DeleteOnTermination: true
Encrypted: true
DeviceName: /dev/xvda
Monitoring:
Enabled: true
MetadataOptions:
InstanceMetadataTags: enabled
SecurityGroupIds:
- !Ref InstanceSecurityGroup
TagSpecifications:
- ResourceType: instance
Tags:
- Key: Name
Value: Server
UserData:
Fn::Base64: |
#!/bin/bash
yum update -y
yum install -y httpd
echo "<h1>Hello World</h1>" > /var/www/html/index.html
systemctl start httpd
AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
VPCZoneIdentifier:
- !Ref PrivateSubnet1
- !Ref PrivateSubnet2
LaunchTemplate:
LaunchTemplateId: !Ref LaunchTemplate
Version: !GetAtt LaunchTemplate.LatestVersionNumber
MaxSize: '10'
MinSize: '1'
MetricsCollection:
- Granularity: 1Minute
TargetGroupARNs:
- !Ref TargetGroup
CPUUtilicationTrackingPolicy:
Type: AWS::AutoScaling::ScalingPolicy
Properties:
AutoScalingGroupName: !Ref AutoScalingGroup
PolicyType: TargetTrackingScaling
TargetTrackingConfiguration:
PredefinedMetricSpecification:
PredefinedMetricType: ASGAverageCPUUtilization
TargetValue: 50