この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
はじめに
ApacheのVirtualHostで複数の静的ウェブサイトや動的ウェブサイトを運用するEC2インスタンスからサイトを分離してみました。
分離前の構成図
分離前の構成は以下の通りです。
example.com
site1.example.com
site2.example.com
3つのウェブサイトのリクエストを処理できるようにEC2インスタンスのApacheのVirtualHostで設定されています。
<VirtualHost *:80>
ServerName example.com
DocumentRoot /var/www/html/
</VirtualHost>
<VirtualHost *:80>
ServerName site1.example.com
DocumentRoot /var/www/site1/
</VirtualHost>
<VirtualHost *:80>
ServerName site2.example.com
DocumentRoot /var/www/site2/
</VirtualHost>
Route53で3つのウェブサイトのDNSレコードのValueをALB DNS名とします。ApacheのVirtualHostがHostヘッダを見て振り分けしてくれるのでALBのリスナールールは不要です。
ウェブサイト分離の動きを見るために、CFnテンプレート site.yml
を用意しました。ウェブサイトのコンテンツは フリーホームページ.netを使わせていただきました。(ありがとうございます)
site.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: Template generated by rain
Parameters:
billingTag:
Type: String
domainName:
Type: String
domainName1:
Type: String
domainName2:
Type: String
ec2Ami:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
env:
Type: String
hostedZoneId:
Type: String
instanceClass:
Type: String
instanceType:
Type: String
masterPassword:
Type: String
NoEcho: true
sysName:
Type: String
vpcCidr:
Type: String
Resources:
Alb:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
IpAddressType: ipv4
Name: !Sub ${env}-${sysName}-alb
Scheme: internet-facing
SecurityGroups:
- !Ref AlbSG
Subnets:
- !Ref MyPublicSubnet1
- !Ref MyPublicSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-api
- Key: BillingGroup
Value: !Ref billingTag
Type: application
AlbAcm:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName
DomainValidationOptions:
- DomainName: !Ref domainName
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbAcm1:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName1
DomainValidationOptions:
- DomainName: !Ref domainName1
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm1
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbAcm2:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName2
DomainValidationOptions:
- DomainName: !Ref domainName2
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm2
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm
DefaultActions:
- FixedResponseConfig:
ContentType: text/plain
MessageBody: Unauthorized Access
StatusCode: "403"
Type: fixed-response
LoadBalancerArn: !Ref Alb
Port: 443
Protocol: HTTPS
SslPolicy: ELBSecurityPolicy-2016-08
AlbListenerCertificate1:
Type: AWS::ElasticLoadBalancingV2::ListenerCertificate
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm1
ListenerArn: !Ref AlbListener
AlbListenerCertificate2:
Type: AWS::ElasticLoadBalancingV2::ListenerCertificate
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm2
ListenerArn: !Ref AlbListener
AlbListnerRule1:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- TargetGroupArn: !Ref TargetGroup
Type: forward
Conditions:
- Field: path-pattern
PathPatternConfig:
Values:
- '*'
ListenerArn: !Ref AlbListener
Priority: 1
AlbRecordSet:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Join
- ""
- - dualstack.
- !GetAtt Alb.DNSName
EvaluateTargetHealth: false
HostedZoneId: Z14GRHDCWA56QT
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName
Type: A
AlbRecordSet1:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Join
- ""
- - dualstack.
- !GetAtt Alb.DNSName
EvaluateTargetHealth: false
HostedZoneId: Z14GRHDCWA56QT
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName1
Type: A
AlbRecordSet2:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Join
- ""
- - dualstack.
- !GetAtt Alb.DNSName
EvaluateTargetHealth: false
HostedZoneId: Z14GRHDCWA56QT
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName2
Type: A
AlbSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Application load barancer.
GroupName: !Sub ${env}-${sysName}-alb-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
FromPort: 443
IpProtocol: tcp
ToPort: 443
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-alb-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
DbInstance1:
Type: AWS::RDS::DBInstance
DeletionPolicy: Delete
Properties:
AutoMinorVersionUpgrade: false
DBClusterIdentifier: !Ref clusterAurora
DBInstanceClass: !Ref instanceClass
DBInstanceIdentifier: !Sub ${env}-${sysName}-db1
DBParameterGroupName: !Ref ParameterGroupAurora
EnablePerformanceInsights: false
Engine: aurora-mysql
MonitoringInterval: 0
PubliclyAccessible: false
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-db1
- Key: BillingGroup
Value: !Ref billingTag
DbInstance2:
Type: AWS::RDS::DBInstance
DeletionPolicy: Delete
Properties:
AutoMinorVersionUpgrade: false
DBClusterIdentifier: !Ref clusterAurora
DBInstanceClass: !Ref instanceClass
DBInstanceIdentifier: !Sub ${env}-${sysName}-db2
DBParameterGroupName: !Ref ParameterGroupAurora
EnablePerformanceInsights: false
Engine: aurora-mysql
MonitoringInterval: 0
PubliclyAccessible: false
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-db2
- Key: BillingGroup
Value: !Ref billingTag
Instance1:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: 3000
VolumeSize: 8
VolumeType: gp3
CreditSpecification:
CPUCredits: standard
IamInstanceProfile: !Ref ec2Profile
ImageId: !Ref ec2Ami
InstanceType: !Ref instanceType
SecurityGroupIds:
- !Ref ec2SG
SubnetId: !Ref MyPublicSubnet1
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-instance1
- Key: BillingGroup
Value: !Ref billingTag
UserData: !Base64
Fn::Sub: |
#!/bin/bash
yum install -y httpd
cp -p /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org
cat <<EOF >> /etc/httpd/conf/httpd.conf
<VirtualHost *:80>
ServerName ${domainName}
DocumentRoot /var/www/html/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName1}
DocumentRoot /var/www/site1/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName2}
DocumentRoot /var/www/site2/
</VirtualHost>
EOF
mkdir /var/www/{site1,site2}
cd /var/www/html/
curl -O https://free-hp.net/clinic/cl_002/clinic_002_DL.zip && unzip clinic_002_DL.zip && mv clinic_002_DL/* . && rmdir clinic_002_DL && rm clinic_002_DL.zip
cd /var/www/site1/
curl -O https://free-hp.net/restaurant/re_002/restaurant_002_DL.zip && unzip restaurant_002_DL.zip && mv restaurant_002_DL/* . && rmdir restaurant_002_DL && rm restaurant_002_DL.zip
cd /var/www/site2/
curl -O https://free-hp.net/school/sc_001/school_001_DL.zip && unzip school_001_DL.zip && mv school_001_DL/* . && rmdir school_001_DL && rm school_001_DL.zip
systemctl start httpd
Instance2:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: 3000
VolumeSize: 8
VolumeType: gp3
CreditSpecification:
CPUCredits: standard
IamInstanceProfile: !Ref ec2Profile
ImageId: !Ref ec2Ami
InstanceType: !Ref instanceType
SecurityGroupIds:
- !Ref ec2SG
SubnetId: !Ref MyPublicSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-instance2
- Key: BillingGroup
Value: !Ref billingTag
UserData: !Base64
Fn::Sub: |
#!/bin/bash
yum install -y httpd
cp -p /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org
cat <<EOF >> /etc/httpd/conf/httpd.conf
<VirtualHost *:80>
ServerName ${domainName}
DocumentRoot /var/www/html/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName1}
DocumentRoot /var/www/site1/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName2}
DocumentRoot /var/www/site2/
</VirtualHost>
EOF
mkdir /var/www/{site1,site2}
cd /var/www/html/
curl -O https://free-hp.net/clinic/cl_002/clinic_002_DL.zip && unzip clinic_002_DL.zip && mv clinic_002_DL/* . && rmdir clinic_002_DL && rm clinic_002_DL.zip
cd /var/www/site1/
curl -O https://free-hp.net/restaurant/re_002/restaurant_002_DL.zip && unzip restaurant_002_DL.zip && mv restaurant_002_DL/* . && rmdir restaurant_002_DL && rm restaurant_002_DL.zip
cd /var/www/site2/
curl -O https://free-hp.net/school/sc_001/school_001_DL.zip && unzip school_001_DL.zip && mv school_001_DL/* . && rmdir school_001_DL && rm school_001_DL.zip
systemctl start httpd
MyInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-igw
- Key: BillingGroup
Value: !Ref billingTag
MyPrivateRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyInternetGateway
RouteTableId: !Ref MyPrivateRouteTable
MyPrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-rtb
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 10
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 12
- 8
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-subnet-1
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPrivateRouteTable
SubnetId: !Ref MyPrivateSubnet1
MyPrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 11
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 12
- 8
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-subnet-2
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPrivateRouteTable
SubnetId: !Ref MyPrivateSubnet2
MyPublicRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyInternetGateway
RouteTableId: !Ref MyPublicRouteTable
MyPublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-rtb
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 0
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 2
- 8
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-subnet-1
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPublicRouteTable
SubnetId: !Ref MyPublicSubnet1
MyPublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 1
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 2
- 8
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-subnet-2
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPublicRouteTable
SubnetId: !Ref MyPublicSubnet2
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref vpcCidr
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-vpc
- Key: BillingGroup
Value: !Ref billingTag
MyVPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref MyInternetGateway
VpcId: !Ref MyVPC
ParameterGroupAurora:
Type: AWS::RDS::DBParameterGroup
Properties:
Description: !Sub ${env}-${sysName}-parametergroup
Family: aurora-mysql5.7
RdsSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Rds Instances.
GroupName: !Sub ${env}-${sysName}-rds-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- FromPort: 3306
IpProtocol: tcp
SourceSecurityGroupId: !Ref ec2SG
ToPort: 3306
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-rds-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
SubnetGroupRds:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: !Sub ${env}-${sysName}-rds-SubnetGroup
DBSubnetGroupName: !Sub ${env}-${sysName}-rds-subnetgroup
SubnetIds:
- !Ref MyPrivateSubnet1
- !Ref MyPrivateSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-rds-SubnetGroup
- Key: BillingGroup
Value: !Ref billingTag
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${env}-${sysName}-ec2
Port: 80
Protocol: HTTP
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-tg
- Key: BillingGroup
Value: !Ref billingTag
TargetType: instance
Targets:
- Id: !Ref Instance1
- Id: !Ref Instance2
VpcId: !Ref MyVPC
clusterAurora:
Type: AWS::RDS::DBCluster
DeletionPolicy: Delete
Properties:
BackupRetentionPeriod: 7
DBClusterIdentifier: !Sub ${env}-${sysName}-cluster
DBClusterParameterGroupName: !Ref clusterParameterGroupAurora
DBSubnetGroupName: !Ref SubnetGroupRds
DeletionProtection: false
EnableCloudwatchLogsExports:
- audit
- error
- general
- slowquery
Engine: aurora-mysql
EngineVersion: 5.7.mysql_aurora.2.10.0
MasterUserPassword: !Ref masterPassword
MasterUsername: root
Port: 3306
PreferredBackupWindow: 17:00-18:00
PreferredMaintenanceWindow: tue:18:00-tue:19:00
StorageEncrypted: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-cluster
- Key: BillingGroup
Value: !Ref billingTag
VpcSecurityGroupIds:
- !Ref RdsSG
clusterParameterGroupAurora:
Type: AWS::RDS::DBClusterParameterGroup
Properties:
Description: !Sub ${env}-${sysName}-cluster-parametergroup
Family: aurora-mysql5.7
Parameters:
character_set_client: utf8
character_set_connection: utf8
character_set_database: utf8
character_set_results: utf8
character_set_server: utf8
general_log: 1
server_audit_events: CONNECT,QUERY,QUERY_DCL,QUERY_DDL,QUERY_DML,TABLE
server_audit_logging: 1
slow_query_log: 1
time_zone: Asia/Tokyo
ec2Profile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref ec2Role
ec2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Version: "2012-10-17"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess
ec2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ec2 Instances.
GroupName: !Sub ${env}-${sysName}-ec2-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- FromPort: 80
IpProtocol: tcp
SourceSecurityGroupId: !Ref AlbSG
ToPort: 80
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-ec2-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
Rainを使ったデプロイで説明していきます。
rain deploy -y ./site.yml site --params \
env=prd,\
sysName=example,\
billingTag=example,\
vpcCidr=10.0.0.0/16,\
domainName=example.com,\
domainName1=site1.example.com,\
domainName2=site2.example.com,\
hostedZoneId=Z10116024XXXXXXXXXXX,\
instanceType=t3.micro,\
instanceClass=db.t3.small,\
masterPassword=Passw0rd
Rainを使わない場合は、各パラメータを参考にコンソールなどからデプロイしてください。
静的ウェブサイトの分離
site2.example.com
が静的ウェブサイトだとして、VirtualHostから分離していきます。静的ウェブサイトであればS3ホスティングの利用が考えられますが、S3ホスティングではhttpsプロトコルが利用できません。
ドキュメントにもある通り、Amazon CloudFront+S3で静的ウェブサイトをHTTPSで利用できるようにします。site2.example.com
を分離した構成図は以下です。
オリジンのS3バケットには、 site2.example.com
のコンテンツを格納します。CloudFrontのOrigin Access Identity(以下、OAI)でCloudFront DistributionのみS3バケットのアクセスを許可します。CloudFront+S3リソースが出来上がった後、Route53で site2.example.com
レコードのValueをCloudFront URL dxxxxxxxxxxxx.cloudfront.net
に書き換えます。
CloudFront+S3リソースの作成
まずは、site2.example.com
のオリジンのS3バケットを作成する為、先程の site.yml
テンプレートに site2Bucket
リソースを追記しました。
site2Bucket:
DeletionPolicy: Delete
UpdateReplacePolicy: Delete
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref domainName2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-site2-contents-bucket
- Key: BillingGroup
Value: !Ref billingTag
上記リソースを追記した site.yml
テンプレートです。
site.yml(S3バケットリソース作成)
AWSTemplateFormatVersion: "2010-09-09"
Description: Template generated by rain
Parameters:
billingTag:
Type: String
domainName:
Type: String
domainName1:
Type: String
domainName2:
Type: String
ec2Ami:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
env:
Type: String
hostedZoneId:
Type: String
instanceClass:
Type: String
instanceType:
Type: String
masterPassword:
Type: String
NoEcho: true
sysName:
Type: String
vpcCidr:
Type: String
Resources:
Alb:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
IpAddressType: ipv4
Name: !Sub ${env}-${sysName}-alb
Scheme: internet-facing
SecurityGroups:
- !Ref AlbSG
Subnets:
- !Ref MyPublicSubnet1
- !Ref MyPublicSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-api
- Key: BillingGroup
Value: !Ref billingTag
Type: application
AlbAcm:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName
DomainValidationOptions:
- DomainName: !Ref domainName
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbAcm1:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName1
DomainValidationOptions:
- DomainName: !Ref domainName1
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm1
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbAcm2:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName2
DomainValidationOptions:
- DomainName: !Ref domainName2
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm2
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm
DefaultActions:
- FixedResponseConfig:
ContentType: text/plain
MessageBody: Unauthorized Access
StatusCode: "403"
Type: fixed-response
LoadBalancerArn: !Ref Alb
Port: 443
Protocol: HTTPS
SslPolicy: ELBSecurityPolicy-2016-08
AlbListenerCertificate1:
Type: AWS::ElasticLoadBalancingV2::ListenerCertificate
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm1
ListenerArn: !Ref AlbListener
AlbListenerCertificate2:
Type: AWS::ElasticLoadBalancingV2::ListenerCertificate
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm2
ListenerArn: !Ref AlbListener
AlbListnerRule1:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- TargetGroupArn: !Ref TargetGroup
Type: forward
Conditions:
- Field: path-pattern
PathPatternConfig:
Values:
- '*'
ListenerArn: !Ref AlbListener
Priority: 1
AlbRecordSet:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Join
- ""
- - dualstack.
- !GetAtt Alb.DNSName
EvaluateTargetHealth: false
HostedZoneId: Z14GRHDCWA56QT
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName
Type: A
AlbRecordSet1:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Join
- ""
- - dualstack.
- !GetAtt Alb.DNSName
EvaluateTargetHealth: false
HostedZoneId: Z14GRHDCWA56QT
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName1
Type: A
AlbRecordSet2:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Join
- ""
- - dualstack.
- !GetAtt Alb.DNSName
EvaluateTargetHealth: false
HostedZoneId: Z14GRHDCWA56QT
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName2
Type: A
AlbSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Application load barancer.
GroupName: !Sub ${env}-${sysName}-alb-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
FromPort: 443
IpProtocol: tcp
ToPort: 443
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-alb-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
DbInstance1:
Type: AWS::RDS::DBInstance
DeletionPolicy: Delete
Properties:
AutoMinorVersionUpgrade: false
DBClusterIdentifier: !Ref clusterAurora
DBInstanceClass: !Ref instanceClass
DBInstanceIdentifier: !Sub ${env}-${sysName}-db1
DBParameterGroupName: !Ref ParameterGroupAurora
EnablePerformanceInsights: false
Engine: aurora-mysql
MonitoringInterval: 0
PubliclyAccessible: false
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-db1
- Key: BillingGroup
Value: !Ref billingTag
DbInstance2:
Type: AWS::RDS::DBInstance
DeletionPolicy: Delete
Properties:
AutoMinorVersionUpgrade: false
DBClusterIdentifier: !Ref clusterAurora
DBInstanceClass: !Ref instanceClass
DBInstanceIdentifier: !Sub ${env}-${sysName}-db2
DBParameterGroupName: !Ref ParameterGroupAurora
EnablePerformanceInsights: false
Engine: aurora-mysql
MonitoringInterval: 0
PubliclyAccessible: false
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-db2
- Key: BillingGroup
Value: !Ref billingTag
Instance1:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: 3000
VolumeSize: 8
VolumeType: gp3
CreditSpecification:
CPUCredits: standard
IamInstanceProfile: !Ref ec2Profile
ImageId: !Ref ec2Ami
InstanceType: !Ref instanceType
SecurityGroupIds:
- !Ref ec2SG
SubnetId: !Ref MyPublicSubnet1
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-instance1
- Key: BillingGroup
Value: !Ref billingTag
UserData: !Base64
Fn::Sub: |
#!/bin/bash
yum install -y httpd
cp -p /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org
cat <<EOF >> /etc/httpd/conf/httpd.conf
<VirtualHost *:80>
ServerName ${domainName}
DocumentRoot /var/www/html/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName1}
DocumentRoot /var/www/site1/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName2}
DocumentRoot /var/www/site2/
</VirtualHost>
EOF
mkdir /var/www/{site1,site2}
cd /var/www/html/
curl -O https://free-hp.net/clinic/cl_002/clinic_002_DL.zip && unzip clinic_002_DL.zip && mv clinic_002_DL/* . && rmdir clinic_002_DL && rm clinic_002_DL.zip
cd /var/www/site1/
curl -O https://free-hp.net/restaurant/re_002/restaurant_002_DL.zip && unzip restaurant_002_DL.zip && mv restaurant_002_DL/* . && rmdir restaurant_002_DL && rm restaurant_002_DL.zip
cd /var/www/site2/
curl -O https://free-hp.net/school/sc_001/school_001_DL.zip && unzip school_001_DL.zip && mv school_001_DL/* . && rmdir school_001_DL && rm school_001_DL.zip
systemctl start httpd
Instance2:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: 3000
VolumeSize: 8
VolumeType: gp3
CreditSpecification:
CPUCredits: standard
IamInstanceProfile: !Ref ec2Profile
ImageId: !Ref ec2Ami
InstanceType: !Ref instanceType
SecurityGroupIds:
- !Ref ec2SG
SubnetId: !Ref MyPublicSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-instance2
- Key: BillingGroup
Value: !Ref billingTag
UserData: !Base64
Fn::Sub: |
#!/bin/bash
yum install -y httpd
cp -p /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org
cat <<EOF >> /etc/httpd/conf/httpd.conf
<VirtualHost *:80>
ServerName ${domainName}
DocumentRoot /var/www/html/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName1}
DocumentRoot /var/www/site1/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName2}
DocumentRoot /var/www/site2/
</VirtualHost>
EOF
mkdir /var/www/{site1,site2}
cd /var/www/html/
curl -O https://free-hp.net/clinic/cl_002/clinic_002_DL.zip && unzip clinic_002_DL.zip && mv clinic_002_DL/* . && rmdir clinic_002_DL && rm clinic_002_DL.zip
cd /var/www/site1/
curl -O https://free-hp.net/restaurant/re_002/restaurant_002_DL.zip && unzip restaurant_002_DL.zip && mv restaurant_002_DL/* . && rmdir restaurant_002_DL && rm restaurant_002_DL.zip
cd /var/www/site2/
curl -O https://free-hp.net/school/sc_001/school_001_DL.zip && unzip school_001_DL.zip && mv school_001_DL/* . && rmdir school_001_DL && rm school_001_DL.zip
systemctl start httpd
MyInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-igw
- Key: BillingGroup
Value: !Ref billingTag
MyPrivateRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyInternetGateway
RouteTableId: !Ref MyPrivateRouteTable
MyPrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-rtb
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 10
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 12
- 8
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-subnet-1
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPrivateRouteTable
SubnetId: !Ref MyPrivateSubnet1
MyPrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 11
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 12
- 8
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-subnet-2
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPrivateRouteTable
SubnetId: !Ref MyPrivateSubnet2
MyPublicRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyInternetGateway
RouteTableId: !Ref MyPublicRouteTable
MyPublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-rtb
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 0
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 2
- 8
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-subnet-1
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPublicRouteTable
SubnetId: !Ref MyPublicSubnet1
MyPublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 1
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 2
- 8
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-subnet-2
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPublicRouteTable
SubnetId: !Ref MyPublicSubnet2
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref vpcCidr
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-vpc
- Key: BillingGroup
Value: !Ref billingTag
MyVPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref MyInternetGateway
VpcId: !Ref MyVPC
ParameterGroupAurora:
Type: AWS::RDS::DBParameterGroup
Properties:
Description: !Sub ${env}-${sysName}-parametergroup
Family: aurora-mysql5.7
RdsSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Rds Instances.
GroupName: !Sub ${env}-${sysName}-rds-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- FromPort: 3306
IpProtocol: tcp
SourceSecurityGroupId: !Ref ec2SG
ToPort: 3306
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-rds-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
SubnetGroupRds:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: !Sub ${env}-${sysName}-rds-SubnetGroup
DBSubnetGroupName: !Sub ${env}-${sysName}-rds-subnetgroup
SubnetIds:
- !Ref MyPrivateSubnet1
- !Ref MyPrivateSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-rds-SubnetGroup
- Key: BillingGroup
Value: !Ref billingTag
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${env}-${sysName}-ec2
Port: 80
Protocol: HTTP
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-tg
- Key: BillingGroup
Value: !Ref billingTag
TargetType: instance
Targets:
- Id: !Ref Instance1
- Id: !Ref Instance2
VpcId: !Ref MyVPC
clusterAurora:
Type: AWS::RDS::DBCluster
DeletionPolicy: Delete
Properties:
BackupRetentionPeriod: 7
DBClusterIdentifier: !Sub ${env}-${sysName}-cluster
DBClusterParameterGroupName: !Ref clusterParameterGroupAurora
DBSubnetGroupName: !Ref SubnetGroupRds
DeletionProtection: false
EnableCloudwatchLogsExports:
- audit
- error
- general
- slowquery
Engine: aurora-mysql
EngineVersion: 5.7.mysql_aurora.2.10.0
MasterUserPassword: !Ref masterPassword
MasterUsername: root
Port: 3306
PreferredBackupWindow: 17:00-18:00
PreferredMaintenanceWindow: tue:18:00-tue:19:00
StorageEncrypted: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-cluster
- Key: BillingGroup
Value: !Ref billingTag
VpcSecurityGroupIds:
- !Ref RdsSG
clusterParameterGroupAurora:
Type: AWS::RDS::DBClusterParameterGroup
Properties:
Description: !Sub ${env}-${sysName}-cluster-parametergroup
Family: aurora-mysql5.7
Parameters:
character_set_client: utf8
character_set_connection: utf8
character_set_database: utf8
character_set_results: utf8
character_set_server: utf8
general_log: 1
server_audit_events: CONNECT,QUERY,QUERY_DCL,QUERY_DDL,QUERY_DML,TABLE
server_audit_logging: 1
slow_query_log: 1
time_zone: Asia/Tokyo
ec2Profile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref ec2Role
ec2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Version: "2012-10-17"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess
ec2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ec2 Instances.
GroupName: !Sub ${env}-${sysName}-ec2-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- FromPort: 80
IpProtocol: tcp
SourceSecurityGroupId: !Ref AlbSG
ToPort: 80
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-ec2-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
site2Bucket:
DeletionPolicy: Delete
UpdateReplacePolicy: Delete
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref domainName2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-site2-contents-bucket
- Key: BillingGroup
Value: !Ref billingTag
これでデプロイしていきます。
rain deploy -y ./site.yml site --params \
env=prd,\
sysName=example,\
billingTag=example,\
vpcCidr=10.0.0.0/16,\
domainName=example.com,\
domainName1=site1.example.com,\
domainName2=site2.example.com,\
hostedZoneId=Z10116024XXXXXXXXXXX,\
instanceType=t3.micro,\
instanceClass=db.t3.small,\
masterPassword=Passw0rd
S3バケットの作成後、 /var/www/site2/
にあるコンテンツをS3にアップロードしておきます。マネジメントコンソール、AWS CLIどちらでも良いです。
CloudFront、OAI、ACMの作成
次にCloudFront Distribution、OAI、ACMを作成します。ACMを作成する意図は、CloufFrontリソースはバージニアリージョンのACMのみ割当できる為です。他のリージョンのACMとCloudFrontは割当できません。なのでCloudFront、OAI、ACMをバージニアリージョンで作成します。
site2.yml
AWSTemplateFormatVersion: "2010-09-09"
Description: Template generated by rain
Parameters:
billingTag:
Type: String
hostedZoneId:
Type: String
domainName:
Type: String
domainName2:
Type: String
domainName2Bucket:
Type: String
env:
Type: String
sysName:
Type: String
Resources:
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Aliases:
- !Sub ${domainName2}
Origins:
- ConnectionAttempts: 3
ConnectionTimeout: 10
DomainName: !Sub ${domainName2Bucket}
Id: !Sub ${domainName2Bucket}
OriginPath: ""
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontCloudFrontOriginAccessIdentity}"
OriginGroups:
Quantity: 0
DefaultCacheBehavior:
AllowedMethods:
- HEAD
- GET
CachedMethods:
- HEAD
- GET
Compress: true
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
SmoothStreaming: false
TargetOriginId: !Sub ${domainName2Bucket}
ViewerProtocolPolicy: redirect-to-https
Comment: ""
PriceClass: PriceClass_All
Enabled: true
ViewerCertificate:
AcmCertificateArn: !Ref cloudfrontAcm
MinimumProtocolVersion: TLSv1.2_2021
SslSupportMethod: sni-only
Restrictions:
GeoRestriction:
RestrictionType: none
HttpVersion: http2
DefaultRootObject: index.html
IPV6Enabled: false
CloudFrontCloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: !Sub "access-identity-${domainName2Bucket}"
cloudfrontAcm:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Sub ${domainName2}
DomainValidationOptions:
- DomainName: !Sub ${domainName}
HostedZoneId: !Sub ${hostedZoneId}
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
rainコマンドは、 -r, --retion
オプションでリージョンを指定できます。バージニアリージョン(us-east-1)を指定してスタックをデプロイします。
domainName2Bucketパラメータには site2Bucket
リソースの仮想ホスト形式(バケット名.s3.Region.amazonaws.com or バケット名.s3.amazonaws.com)の値を指定しましょう。
rain deploy -y -r us-east-1 ./site2.yml site2 --params \
env=prd,\
sysName=example,\
billingTag=example,\
domainName=example.com,\
domainName2=site2.example.com,\
hostedZoneId=Z10116024XXXXXXXXXXX,\
domainName2Bucket=site2.example.com.s3.ap-northeast-1.amazonaws.com
S3バケットポリシー、Route53レコードの更新
作成したOAIを指定して site2Bucket
のバケットポリシーを設定します。このポリシーにより、CloudFront DistributionのみS3バケットにアクセスできます。併せて site2.example.com
レコードをALBからCloudFront Distributionに変更します。
〜
AlbRecordSet2:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Sub ${domain2Cloudfront} # CloudFront URL
EvaluateTargetHealth: false
HostedZoneId: Z2FDTNDATAQYW2 # cloudfront.netのHostedZoneID
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName2
Type: A
〜
site2BucketPolicy: # バケットポリシー追加
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref site2Bucket
PolicyDocument:
Statement:
- Action: s3:GetObject
Effect: Allow
Resource: !Sub arn:aws:s3:::${site2Bucket}/*
Principal:
AWS: !Sub arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${site2OAI} # OAIを指定
上記リソースを追記した site.yml
テンプレートです。
site.yml(S3バケットポリシー作成、Route53レコード変更)
AWSTemplateFormatVersion: "2010-09-09"
Description: Template generated by rain
Parameters:
billingTag:
Type: String
domainName:
Type: String
domainName1:
Type: String
domainName2:
Type: String
ec2Ami:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
env:
Type: String
hostedZoneId:
Type: String
instanceClass:
Type: String
instanceType:
Type: String
masterPassword:
Type: String
NoEcho: true
sysName:
Type: String
vpcCidr:
Type: String
domain2Cloudfront:
Type: String
site2OAI:
Type: String
Resources:
Alb:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
IpAddressType: ipv4
Name: !Sub ${env}-${sysName}-alb
Scheme: internet-facing
SecurityGroups:
- !Ref AlbSG
Subnets:
- !Ref MyPublicSubnet1
- !Ref MyPublicSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-api
- Key: BillingGroup
Value: !Ref billingTag
Type: application
AlbAcm:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName
DomainValidationOptions:
- DomainName: !Ref domainName
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbAcm1:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName1
DomainValidationOptions:
- DomainName: !Ref domainName1
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm1
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbAcm2:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName2
DomainValidationOptions:
- DomainName: !Ref domainName2
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm2
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm
DefaultActions:
- FixedResponseConfig:
ContentType: text/plain
MessageBody: Unauthorized Access
StatusCode: "403"
Type: fixed-response
LoadBalancerArn: !Ref Alb
Port: 443
Protocol: HTTPS
SslPolicy: ELBSecurityPolicy-2016-08
AlbListenerCertificate1:
Type: AWS::ElasticLoadBalancingV2::ListenerCertificate
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm1
ListenerArn: !Ref AlbListener
AlbListenerCertificate2:
Type: AWS::ElasticLoadBalancingV2::ListenerCertificate
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm2
ListenerArn: !Ref AlbListener
AlbListnerRule1:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- TargetGroupArn: !Ref TargetGroup
Type: forward
Conditions:
- Field: path-pattern
PathPatternConfig:
Values:
- '*'
ListenerArn: !Ref AlbListener
Priority: 1
AlbRecordSet:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Join
- ""
- - dualstack.
- !GetAtt Alb.DNSName
EvaluateTargetHealth: false
HostedZoneId: Z14GRHDCWA56QT
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName
Type: A
AlbRecordSet1:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Join
- ""
- - dualstack.
- !GetAtt Alb.DNSName
EvaluateTargetHealth: false
HostedZoneId: Z14GRHDCWA56QT
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName1
Type: A
AlbRecordSet2:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Sub ${domain2Cloudfront}
EvaluateTargetHealth: false
HostedZoneId: Z2FDTNDATAQYW2
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName2
Type: A
AlbSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Application load barancer.
GroupName: !Sub ${env}-${sysName}-alb-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
FromPort: 443
IpProtocol: tcp
ToPort: 443
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-alb-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
DbInstance1:
Type: AWS::RDS::DBInstance
DeletionPolicy: Delete
Properties:
AutoMinorVersionUpgrade: false
DBClusterIdentifier: !Ref clusterAurora
DBInstanceClass: !Ref instanceClass
DBInstanceIdentifier: !Sub ${env}-${sysName}-db1
DBParameterGroupName: !Ref ParameterGroupAurora
EnablePerformanceInsights: false
Engine: aurora-mysql
MonitoringInterval: 0
PubliclyAccessible: false
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-db1
- Key: BillingGroup
Value: !Ref billingTag
DbInstance2:
Type: AWS::RDS::DBInstance
DeletionPolicy: Delete
Properties:
AutoMinorVersionUpgrade: false
DBClusterIdentifier: !Ref clusterAurora
DBInstanceClass: !Ref instanceClass
DBInstanceIdentifier: !Sub ${env}-${sysName}-db2
DBParameterGroupName: !Ref ParameterGroupAurora
EnablePerformanceInsights: false
Engine: aurora-mysql
MonitoringInterval: 0
PubliclyAccessible: false
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-db2
- Key: BillingGroup
Value: !Ref billingTag
Instance1:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: 3000
VolumeSize: 8
VolumeType: gp3
CreditSpecification:
CPUCredits: standard
IamInstanceProfile: !Ref ec2Profile
ImageId: !Ref ec2Ami
InstanceType: !Ref instanceType
SecurityGroupIds:
- !Ref ec2SG
SubnetId: !Ref MyPublicSubnet1
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-instance1
- Key: BillingGroup
Value: !Ref billingTag
UserData: !Base64
Fn::Sub: |
#!/bin/bash
yum install -y httpd
cp -p /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org
cat <<EOF >> /etc/httpd/conf/httpd.conf
<VirtualHost *:80>
ServerName ${domainName}
DocumentRoot /var/www/html/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName1}
DocumentRoot /var/www/site1/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName2}
DocumentRoot /var/www/site2/
</VirtualHost>
EOF
mkdir /var/www/{site1,site2}
cd /var/www/html/
curl -O https://free-hp.net/clinic/cl_002/clinic_002_DL.zip && unzip clinic_002_DL.zip && mv clinic_002_DL/* . && rmdir clinic_002_DL && rm clinic_002_DL.zip
cd /var/www/site1/
curl -O https://free-hp.net/restaurant/re_002/restaurant_002_DL.zip && unzip restaurant_002_DL.zip && mv restaurant_002_DL/* . && rmdir restaurant_002_DL && rm restaurant_002_DL.zip
cd /var/www/site2/
curl -O https://free-hp.net/school/sc_001/school_001_DL.zip && unzip school_001_DL.zip && mv school_001_DL/* . && rmdir school_001_DL && rm school_001_DL.zip
systemctl start httpd
Instance2:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: 3000
VolumeSize: 8
VolumeType: gp3
CreditSpecification:
CPUCredits: standard
IamInstanceProfile: !Ref ec2Profile
ImageId: !Ref ec2Ami
InstanceType: !Ref instanceType
SecurityGroupIds:
- !Ref ec2SG
SubnetId: !Ref MyPublicSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-instance2
- Key: BillingGroup
Value: !Ref billingTag
UserData: !Base64
Fn::Sub: |
#!/bin/bash
yum install -y httpd
cp -p /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org
cat <<EOF >> /etc/httpd/conf/httpd.conf
<VirtualHost *:80>
ServerName ${domainName}
DocumentRoot /var/www/html/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName1}
DocumentRoot /var/www/site1/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName2}
DocumentRoot /var/www/site2/
</VirtualHost>
EOF
mkdir /var/www/{site1,site2}
cd /var/www/html/
curl -O https://free-hp.net/clinic/cl_002/clinic_002_DL.zip && unzip clinic_002_DL.zip && mv clinic_002_DL/* . && rmdir clinic_002_DL && rm clinic_002_DL.zip
cd /var/www/site1/
curl -O https://free-hp.net/restaurant/re_002/restaurant_002_DL.zip && unzip restaurant_002_DL.zip && mv restaurant_002_DL/* . && rmdir restaurant_002_DL && rm restaurant_002_DL.zip
cd /var/www/site2/
curl -O https://free-hp.net/school/sc_001/school_001_DL.zip && unzip school_001_DL.zip && mv school_001_DL/* . && rmdir school_001_DL && rm school_001_DL.zip
systemctl start httpd
MyInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-igw
- Key: BillingGroup
Value: !Ref billingTag
MyPrivateRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyInternetGateway
RouteTableId: !Ref MyPrivateRouteTable
MyPrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-rtb
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 10
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 12
- 8
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-subnet-1
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPrivateRouteTable
SubnetId: !Ref MyPrivateSubnet1
MyPrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 11
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 12
- 8
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-subnet-2
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPrivateRouteTable
SubnetId: !Ref MyPrivateSubnet2
MyPublicRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyInternetGateway
RouteTableId: !Ref MyPublicRouteTable
MyPublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-rtb
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 0
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 2
- 8
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-subnet-1
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPublicRouteTable
SubnetId: !Ref MyPublicSubnet1
MyPublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 1
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 2
- 8
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-subnet-2
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPublicRouteTable
SubnetId: !Ref MyPublicSubnet2
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref vpcCidr
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-vpc
- Key: BillingGroup
Value: !Ref billingTag
MyVPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref MyInternetGateway
VpcId: !Ref MyVPC
ParameterGroupAurora:
Type: AWS::RDS::DBParameterGroup
Properties:
Description: !Sub ${env}-${sysName}-parametergroup
Family: aurora-mysql5.7
RdsSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Rds Instances.
GroupName: !Sub ${env}-${sysName}-rds-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- FromPort: 3306
IpProtocol: tcp
SourceSecurityGroupId: !Ref ec2SG
ToPort: 3306
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-rds-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
SubnetGroupRds:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: !Sub ${env}-${sysName}-rds-SubnetGroup
DBSubnetGroupName: !Sub ${env}-${sysName}-rds-subnetgroup
SubnetIds:
- !Ref MyPrivateSubnet1
- !Ref MyPrivateSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-rds-SubnetGroup
- Key: BillingGroup
Value: !Ref billingTag
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${env}-${sysName}-ec2
Port: 80
Protocol: HTTP
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-tg
- Key: BillingGroup
Value: !Ref billingTag
TargetType: instance
Targets:
- Id: !Ref Instance1
- Id: !Ref Instance2
VpcId: !Ref MyVPC
clusterAurora:
Type: AWS::RDS::DBCluster
DeletionPolicy: Delete
Properties:
BackupRetentionPeriod: 7
DBClusterIdentifier: !Sub ${env}-${sysName}-cluster
DBClusterParameterGroupName: !Ref clusterParameterGroupAurora
DBSubnetGroupName: !Ref SubnetGroupRds
DeletionProtection: false
EnableCloudwatchLogsExports:
- audit
- error
- general
- slowquery
Engine: aurora-mysql
EngineVersion: 5.7.mysql_aurora.2.10.0
MasterUserPassword: !Ref masterPassword
MasterUsername: root
Port: 3306
PreferredBackupWindow: 17:00-18:00
PreferredMaintenanceWindow: tue:18:00-tue:19:00
StorageEncrypted: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-cluster
- Key: BillingGroup
Value: !Ref billingTag
VpcSecurityGroupIds:
- !Ref RdsSG
clusterParameterGroupAurora:
Type: AWS::RDS::DBClusterParameterGroup
Properties:
Description: !Sub ${env}-${sysName}-cluster-parametergroup
Family: aurora-mysql5.7
Parameters:
character_set_client: utf8
character_set_connection: utf8
character_set_database: utf8
character_set_results: utf8
character_set_server: utf8
general_log: 1
server_audit_events: CONNECT,QUERY,QUERY_DCL,QUERY_DDL,QUERY_DML,TABLE
server_audit_logging: 1
slow_query_log: 1
time_zone: Asia/Tokyo
ec2Profile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref ec2Role
ec2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Version: "2012-10-17"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess
ec2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ec2 Instances.
GroupName: !Sub ${env}-${sysName}-ec2-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- FromPort: 80
IpProtocol: tcp
SourceSecurityGroupId: !Ref AlbSG
ToPort: 80
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-ec2-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
site2Bucket:
DeletionPolicy: Delete
UpdateReplacePolicy: Delete
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref domainName2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-site2-contents-bucket
- Key: BillingGroup
Value: !Ref billingTag
site2BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref site2Bucket
PolicyDocument:
Statement:
- Action: s3:GetObject
Effect: Allow
Resource: !Sub arn:aws:s3:::${site2Bucket}/*
Principal:
AWS: !Sub arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${site2OAI}
domain2Cloudfront、site2OAIパラメータを追加してデプロイします。
rain deploy -y ./site.yml site --params \
env=prd,\
sysName=example,\
billingTag=example,\
vpcCidr=10.0.0.0/16,\
domainName=example.com,\
domainName1=site1.example.com,\
domainName2=site2.example.com,\
hostedZoneId=Z10116024XXXXXXXXXXX,\
instanceType=t3.micro,\
instanceClass=db.t3.small,\
masterPassword=Passw0rd,\
domain2Cloudfront=dxxxxxxxxxxxx.cloudfront.net,\
site2OAI=E36GW62SYZ8RPJ
site2.example.com
にhttpsでアクセスできることを確認できたらOKです。
動的ウェブサイトの分離
site1.example.com
が動的ウェブサイトの場合(例えばhttpd,tomcat)の分離先として、別のEC2インスタンスもしくはECSなど選択肢があります。今回はsite1.example.com
を動的ウェブサイトに見立てて、ECS(Fargate)に分離してみます。
ECSサービス作成前の事前準備
事前準備としてECRプライベートリポジトリ、コンテナログを出力する為のCloudwatchロググループとタスク実行ロールを作成し、タスク定義で指定します。
site1Ecr:
Type: AWS::ECR::Repository
Properties:
RepositoryName: site1
ImageScanningConfiguration:
ScanOnPush: "true"
LifecyclePolicy:
LifecyclePolicyText: |
{
"rules": [
{
"rulePriority": 1,
"description": "Delete images",
"selection": {
"tagStatus": "any",
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": {
"type": "expire"
}
}
]
}
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-site1-ecr
- Key: BillingGroup
Value: !Ref billingTag
ecsLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/ecs/logs/${env}/${sysName}"
ecsTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${env}-${sysName}-ecs-task-exec-role
Path: /
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
site1TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Essential: true
Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/site1:latest"
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref ecsLogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: site1
Name: site1
PortMappings:
- ContainerPort: 80
HostPort: 80
Protocol: tcp
Family: site1
ExecutionRoleArn: !GetAtt ecsTaskExecutionRole.Arn
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: "256"
Memory: "512"
上記リソースを追記した site.yml
テンプレートです。
site.yml(ECR、CloudWatch LogGroup、IAMロール、ECSタスク定義の追加)
AWSTemplateFormatVersion: "2010-09-09"
Description: Template generated by rain
Parameters:
billingTag:
Type: String
domainName:
Type: String
domainName1:
Type: String
domainName2:
Type: String
ec2Ami:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
env:
Type: String
hostedZoneId:
Type: String
instanceClass:
Type: String
instanceType:
Type: String
masterPassword:
Type: String
NoEcho: true
sysName:
Type: String
vpcCidr:
Type: String
domain2Cloudfront:
Type: String
site2OAI:
Type: String
Resources:
Alb:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
IpAddressType: ipv4
Name: !Sub ${env}-${sysName}-alb
Scheme: internet-facing
SecurityGroups:
- !Ref AlbSG
Subnets:
- !Ref MyPublicSubnet1
- !Ref MyPublicSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-api
- Key: BillingGroup
Value: !Ref billingTag
Type: application
AlbAcm:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName
DomainValidationOptions:
- DomainName: !Ref domainName
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbAcm1:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName1
DomainValidationOptions:
- DomainName: !Ref domainName1
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm1
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbAcm2:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName2
DomainValidationOptions:
- DomainName: !Ref domainName2
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm2
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm
DefaultActions:
- FixedResponseConfig:
ContentType: text/plain
MessageBody: Unauthorized Access
StatusCode: "403"
Type: fixed-response
LoadBalancerArn: !Ref Alb
Port: 443
Protocol: HTTPS
SslPolicy: ELBSecurityPolicy-2016-08
AlbListenerCertificate1:
Type: AWS::ElasticLoadBalancingV2::ListenerCertificate
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm1
ListenerArn: !Ref AlbListener
AlbListenerCertificate2:
Type: AWS::ElasticLoadBalancingV2::ListenerCertificate
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm2
ListenerArn: !Ref AlbListener
AlbListnerRule1:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- TargetGroupArn: !Ref TargetGroup
Type: forward
Conditions:
- Field: path-pattern
PathPatternConfig:
Values:
- '*'
ListenerArn: !Ref AlbListener
Priority: 1
AlbRecordSet:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Join
- ""
- - dualstack.
- !GetAtt Alb.DNSName
EvaluateTargetHealth: false
HostedZoneId: Z14GRHDCWA56QT
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName
Type: A
AlbRecordSet1:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Join
- ""
- - dualstack.
- !GetAtt Alb.DNSName
EvaluateTargetHealth: false
HostedZoneId: Z14GRHDCWA56QT
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName1
Type: A
AlbRecordSet2:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Sub ${domain2Cloudfront}
EvaluateTargetHealth: false
HostedZoneId: Z2FDTNDATAQYW2
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName2
Type: A
AlbSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Application load barancer.
GroupName: !Sub ${env}-${sysName}-alb-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
FromPort: 443
IpProtocol: tcp
ToPort: 443
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-alb-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
DbInstance1:
Type: AWS::RDS::DBInstance
DeletionPolicy: Delete
Properties:
AutoMinorVersionUpgrade: false
DBClusterIdentifier: !Ref clusterAurora
DBInstanceClass: !Ref instanceClass
DBInstanceIdentifier: !Sub ${env}-${sysName}-db1
DBParameterGroupName: !Ref ParameterGroupAurora
EnablePerformanceInsights: false
Engine: aurora-mysql
MonitoringInterval: 0
PubliclyAccessible: false
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-db1
- Key: BillingGroup
Value: !Ref billingTag
DbInstance2:
Type: AWS::RDS::DBInstance
DeletionPolicy: Delete
Properties:
AutoMinorVersionUpgrade: false
DBClusterIdentifier: !Ref clusterAurora
DBInstanceClass: !Ref instanceClass
DBInstanceIdentifier: !Sub ${env}-${sysName}-db2
DBParameterGroupName: !Ref ParameterGroupAurora
EnablePerformanceInsights: false
Engine: aurora-mysql
MonitoringInterval: 0
PubliclyAccessible: false
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-db2
- Key: BillingGroup
Value: !Ref billingTag
Instance1:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: 3000
VolumeSize: 8
VolumeType: gp3
CreditSpecification:
CPUCredits: standard
IamInstanceProfile: !Ref ec2Profile
ImageId: !Ref ec2Ami
InstanceType: !Ref instanceType
SecurityGroupIds:
- !Ref ec2SG
SubnetId: !Ref MyPublicSubnet1
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-instance1
- Key: BillingGroup
Value: !Ref billingTag
UserData: !Base64
Fn::Sub: |
#!/bin/bash
yum install -y httpd
cp -p /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org
cat <<EOF >> /etc/httpd/conf/httpd.conf
<VirtualHost *:80>
ServerName ${domainName}
DocumentRoot /var/www/html/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName1}
DocumentRoot /var/www/site1/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName2}
DocumentRoot /var/www/site2/
</VirtualHost>
EOF
mkdir /var/www/{site1,site2}
cd /var/www/html/
curl -O https://free-hp.net/clinic/cl_002/clinic_002_DL.zip && unzip clinic_002_DL.zip && mv clinic_002_DL/* . && rmdir clinic_002_DL && rm clinic_002_DL.zip
cd /var/www/site1/
curl -O https://free-hp.net/restaurant/re_002/restaurant_002_DL.zip && unzip restaurant_002_DL.zip && mv restaurant_002_DL/* . && rmdir restaurant_002_DL && rm restaurant_002_DL.zip
cd /var/www/site2/
curl -O https://free-hp.net/school/sc_001/school_001_DL.zip && unzip school_001_DL.zip && mv school_001_DL/* . && rmdir school_001_DL && rm school_001_DL.zip
systemctl start httpd
Instance2:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: 3000
VolumeSize: 8
VolumeType: gp3
CreditSpecification:
CPUCredits: standard
IamInstanceProfile: !Ref ec2Profile
ImageId: !Ref ec2Ami
InstanceType: !Ref instanceType
SecurityGroupIds:
- !Ref ec2SG
SubnetId: !Ref MyPublicSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-instance2
- Key: BillingGroup
Value: !Ref billingTag
UserData: !Base64
Fn::Sub: |
#!/bin/bash
yum install -y httpd
cp -p /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org
cat <<EOF >> /etc/httpd/conf/httpd.conf
<VirtualHost *:80>
ServerName ${domainName}
DocumentRoot /var/www/html/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName1}
DocumentRoot /var/www/site1/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName2}
DocumentRoot /var/www/site2/
</VirtualHost>
EOF
mkdir /var/www/{site1,site2}
cd /var/www/html/
curl -O https://free-hp.net/clinic/cl_002/clinic_002_DL.zip && unzip clinic_002_DL.zip && mv clinic_002_DL/* . && rmdir clinic_002_DL && rm clinic_002_DL.zip
cd /var/www/site1/
curl -O https://free-hp.net/restaurant/re_002/restaurant_002_DL.zip && unzip restaurant_002_DL.zip && mv restaurant_002_DL/* . && rmdir restaurant_002_DL && rm restaurant_002_DL.zip
cd /var/www/site2/
curl -O https://free-hp.net/school/sc_001/school_001_DL.zip && unzip school_001_DL.zip && mv school_001_DL/* . && rmdir school_001_DL && rm school_001_DL.zip
systemctl start httpd
MyInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-igw
- Key: BillingGroup
Value: !Ref billingTag
MyPrivateRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyInternetGateway
RouteTableId: !Ref MyPrivateRouteTable
MyPrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-rtb
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 10
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 12
- 8
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-subnet-1
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPrivateRouteTable
SubnetId: !Ref MyPrivateSubnet1
MyPrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 11
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 12
- 8
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-subnet-2
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPrivateRouteTable
SubnetId: !Ref MyPrivateSubnet2
MyPublicRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyInternetGateway
RouteTableId: !Ref MyPublicRouteTable
MyPublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-rtb
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 0
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 2
- 8
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-subnet-1
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPublicRouteTable
SubnetId: !Ref MyPublicSubnet1
MyPublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 1
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 2
- 8
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-subnet-2
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPublicRouteTable
SubnetId: !Ref MyPublicSubnet2
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref vpcCidr
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-vpc
- Key: BillingGroup
Value: !Ref billingTag
MyVPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref MyInternetGateway
VpcId: !Ref MyVPC
ParameterGroupAurora:
Type: AWS::RDS::DBParameterGroup
Properties:
Description: !Sub ${env}-${sysName}-parametergroup
Family: aurora-mysql5.7
RdsSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Rds Instances.
GroupName: !Sub ${env}-${sysName}-rds-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- FromPort: 3306
IpProtocol: tcp
SourceSecurityGroupId: !Ref ec2SG
ToPort: 3306
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-rds-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
SubnetGroupRds:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: !Sub ${env}-${sysName}-rds-SubnetGroup
DBSubnetGroupName: !Sub ${env}-${sysName}-rds-subnetgroup
SubnetIds:
- !Ref MyPrivateSubnet1
- !Ref MyPrivateSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-rds-SubnetGroup
- Key: BillingGroup
Value: !Ref billingTag
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${env}-${sysName}-ec2
Port: 80
Protocol: HTTP
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-tg
- Key: BillingGroup
Value: !Ref billingTag
TargetType: instance
Targets:
- Id: !Ref Instance1
- Id: !Ref Instance2
VpcId: !Ref MyVPC
clusterAurora:
Type: AWS::RDS::DBCluster
DeletionPolicy: Delete
Properties:
BackupRetentionPeriod: 7
DBClusterIdentifier: !Sub ${env}-${sysName}-cluster
DBClusterParameterGroupName: !Ref clusterParameterGroupAurora
DBSubnetGroupName: !Ref SubnetGroupRds
DeletionProtection: false
EnableCloudwatchLogsExports:
- audit
- error
- general
- slowquery
Engine: aurora-mysql
EngineVersion: 5.7.mysql_aurora.2.10.0
MasterUserPassword: !Ref masterPassword
MasterUsername: root
Port: 3306
PreferredBackupWindow: 17:00-18:00
PreferredMaintenanceWindow: tue:18:00-tue:19:00
StorageEncrypted: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-cluster
- Key: BillingGroup
Value: !Ref billingTag
VpcSecurityGroupIds:
- !Ref RdsSG
clusterParameterGroupAurora:
Type: AWS::RDS::DBClusterParameterGroup
Properties:
Description: !Sub ${env}-${sysName}-cluster-parametergroup
Family: aurora-mysql5.7
Parameters:
character_set_client: utf8
character_set_connection: utf8
character_set_database: utf8
character_set_results: utf8
character_set_server: utf8
general_log: 1
server_audit_events: CONNECT,QUERY,QUERY_DCL,QUERY_DDL,QUERY_DML,TABLE
server_audit_logging: 1
slow_query_log: 1
time_zone: Asia/Tokyo
ec2Profile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref ec2Role
ec2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Version: "2012-10-17"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess
ec2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ec2 Instances.
GroupName: !Sub ${env}-${sysName}-ec2-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- FromPort: 80
IpProtocol: tcp
SourceSecurityGroupId: !Ref AlbSG
ToPort: 80
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-ec2-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
site2Bucket:
DeletionPolicy: Delete
UpdateReplacePolicy: Delete
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref domainName2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-site2-contents-bucket
- Key: BillingGroup
Value: !Ref billingTag
site2BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref site2Bucket
PolicyDocument:
Statement:
- Action: s3:GetObject
Effect: Allow
Resource: !Sub arn:aws:s3:::${site2Bucket}/*
Principal:
AWS: !Sub arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${site2OAI}
site1Ecr:
Type: AWS::ECR::Repository
Properties:
RepositoryName: site1
ImageScanningConfiguration:
ScanOnPush: "true"
LifecyclePolicy:
LifecyclePolicyText: |
{
"rules": [
{
"rulePriority": 1,
"description": "Delete images",
"selection": {
"tagStatus": "any",
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": {
"type": "expire"
}
}
]
}
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-site1-ecr
- Key: BillingGroup
Value: !Ref billingTag
ecsLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/ecs/logs/${env}/${sysName}"
ecsTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${env}-${sysName}-ecs-task-exec-role
Path: /
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
site1TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Essential: true
Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/site1:latest"
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref ecsLogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: site1
Name: site1
PortMappings:
- ContainerPort: 80
HostPort: 80
Protocol: tcp
Family: site1
ExecutionRoleArn: !GetAtt ecsTaskExecutionRole.Arn
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: "256"
Memory: "512"
デプロイしていきます。
rain deploy -y ./site.yml site --params \
env=prd,\
sysName=example,\
billingTag=example,\
vpcCidr=10.0.0.0/16,\
domainName=example.com,\
domainName1=site1.example.com,\
domainName2=site2.example.com,\
hostedZoneId=Z10116024XXXXXXXXXXX,\
instanceType=t3.micro,\
instanceClass=db.t3.small,\
masterPassword=Passw0rd,\
domain2Cloudfront=dxxxxxxxxxxxx.cloudfront.net,\
site2OAI=E36GW62SYZ8RPJ
次にECRリポジトリにイメージをアップロードします。site1.example.com
コンテンツ(https://free-hp.net/restaurant/re_002/restaurant_002_DL.zip)を含むコンテナイメージをhttpd公式イメージをベースに作成します。
FROM httpd:2.4
COPY ./school_001_DL/ /usr/local/apache2/htdocs/
コンテナイメージのpushはドキュメントを参照してください。
ECSサービスの実行
事前準備ができたのでECSサービスを設定します。併せてALBのリスナールールで site1.example.com
のリクエストを振り分けるルールと振り分け先のターゲットグループを設定します。
site1EcsSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: site1 ecs.
GroupName: !Sub ${env}-${sysName}-site1-ecs-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- FromPort: 80
IpProtocol: tcp
SourceSecurityGroupId: !Ref AlbSG
ToPort: 80
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-site1-ecs-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
site1TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${env}-${sysName}-site1-ecs-tg
Port: 80
Protocol: HTTP
TargetType: ip
VpcId: !Ref MyVPC
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-site1-ecs-tg
- Key: BillingGroup
Value: !Ref billingTag
cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Sub ${env}-${sysName}-cluster
ClusterSettings:
- Name: containerInsights
Value: enabled
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-cluster
- Key: BillingGroup
Value: !Ref billingTag
site1ServiceDefinition:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref cluster
DesiredCount: 0
LaunchType: FARGATE
LoadBalancers:
- TargetGroupArn: !Ref site1TargetGroup
ContainerPort: 80
ContainerName: site1
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- !Ref site1EcsSG
Subnets:
- !Ref MyPublicSubnet1
- !Ref MyPublicSubnet2
ServiceName: !Sub ${env}-${sysName}-site1
TaskDefinition: !Sub ${site1TaskDefinition}
上記リソースを追記した site.yml
テンプレートです。
site.yml(ECSサービス、ターゲットグループ、ALBリスナールールの変更)
AWSTemplateFormatVersion: "2010-09-09"
Description: Template generated by rain
Parameters:
billingTag:
Type: String
domainName:
Type: String
domainName1:
Type: String
domainName2:
Type: String
ec2Ami:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
env:
Type: String
hostedZoneId:
Type: String
instanceClass:
Type: String
instanceType:
Type: String
masterPassword:
Type: String
NoEcho: true
sysName:
Type: String
vpcCidr:
Type: String
domain2Cloudfront:
Type: String
site2OAI:
Type: String
Resources:
Alb:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
IpAddressType: ipv4
Name: !Sub ${env}-${sysName}-alb
Scheme: internet-facing
SecurityGroups:
- !Ref AlbSG
Subnets:
- !Ref MyPublicSubnet1
- !Ref MyPublicSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-api
- Key: BillingGroup
Value: !Ref billingTag
Type: application
AlbAcm:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName
DomainValidationOptions:
- DomainName: !Ref domainName
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbAcm1:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName1
DomainValidationOptions:
- DomainName: !Ref domainName1
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm1
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbAcm2:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref domainName2
DomainValidationOptions:
- DomainName: !Ref domainName2
HostedZoneId: !Ref hostedZoneId
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-albacm2
- Key: BillingGroup
Value: !Ref billingTag
ValidationMethod: DNS
AlbListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm
DefaultActions:
- FixedResponseConfig:
ContentType: text/plain
MessageBody: Unauthorized Access
StatusCode: "403"
Type: fixed-response
LoadBalancerArn: !Ref Alb
Port: 443
Protocol: HTTPS
SslPolicy: ELBSecurityPolicy-2016-08
AlbListenerCertificate1:
Type: AWS::ElasticLoadBalancingV2::ListenerCertificate
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm1
ListenerArn: !Ref AlbListener
AlbListenerCertificate2:
Type: AWS::ElasticLoadBalancingV2::ListenerCertificate
Properties:
Certificates:
- CertificateArn: !Ref AlbAcm2
ListenerArn: !Ref AlbListener
AlbListnerRule1:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- TargetGroupArn: !Ref TargetGroup
Type: forward
Conditions:
- Field: path-pattern
PathPatternConfig:
Values:
- '*'
ListenerArn: !Ref AlbListener
Priority: 1
AlbRecordSet:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Join
- ""
- - dualstack.
- !GetAtt Alb.DNSName
EvaluateTargetHealth: false
HostedZoneId: Z14GRHDCWA56QT
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName
Type: A
AlbRecordSet1:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Join
- ""
- - dualstack.
- !GetAtt Alb.DNSName
EvaluateTargetHealth: false
HostedZoneId: Z14GRHDCWA56QT
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName1
Type: A
AlbRecordSet2:
Type: AWS::Route53::RecordSet
Properties:
AliasTarget:
DNSName: !Sub ${domain2Cloudfront}
EvaluateTargetHealth: false
HostedZoneId: Z2FDTNDATAQYW2
HostedZoneId: !Ref hostedZoneId
Name: !Ref domainName2
Type: A
AlbSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Application load barancer.
GroupName: !Sub ${env}-${sysName}-alb-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- CidrIp: 0.0.0.0/0
FromPort: 443
IpProtocol: tcp
ToPort: 443
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-alb-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
DbInstance1:
Type: AWS::RDS::DBInstance
DeletionPolicy: Delete
Properties:
AutoMinorVersionUpgrade: false
DBClusterIdentifier: !Ref clusterAurora
DBInstanceClass: !Ref instanceClass
DBInstanceIdentifier: !Sub ${env}-${sysName}-db1
DBParameterGroupName: !Ref ParameterGroupAurora
EnablePerformanceInsights: false
Engine: aurora-mysql
MonitoringInterval: 0
PubliclyAccessible: false
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-db1
- Key: BillingGroup
Value: !Ref billingTag
DbInstance2:
Type: AWS::RDS::DBInstance
DeletionPolicy: Delete
Properties:
AutoMinorVersionUpgrade: false
DBClusterIdentifier: !Ref clusterAurora
DBInstanceClass: !Ref instanceClass
DBInstanceIdentifier: !Sub ${env}-${sysName}-db2
DBParameterGroupName: !Ref ParameterGroupAurora
EnablePerformanceInsights: false
Engine: aurora-mysql
MonitoringInterval: 0
PubliclyAccessible: false
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-db2
- Key: BillingGroup
Value: !Ref billingTag
Instance1:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: 3000
VolumeSize: 8
VolumeType: gp3
CreditSpecification:
CPUCredits: standard
IamInstanceProfile: !Ref ec2Profile
ImageId: !Ref ec2Ami
InstanceType: !Ref instanceType
SecurityGroupIds:
- !Ref ec2SG
SubnetId: !Ref MyPublicSubnet1
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-instance1
- Key: BillingGroup
Value: !Ref billingTag
UserData: !Base64
Fn::Sub: |
#!/bin/bash
yum install -y httpd
cp -p /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org
cat <<EOF >> /etc/httpd/conf/httpd.conf
<VirtualHost *:80>
ServerName ${domainName}
DocumentRoot /var/www/html/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName1}
DocumentRoot /var/www/site1/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName2}
DocumentRoot /var/www/site2/
</VirtualHost>
EOF
mkdir /var/www/{site1,site2}
cd /var/www/html/
curl -O https://free-hp.net/clinic/cl_002/clinic_002_DL.zip && unzip clinic_002_DL.zip && mv clinic_002_DL/* . && rmdir clinic_002_DL && rm clinic_002_DL.zip
cd /var/www/site1/
curl -O https://free-hp.net/restaurant/re_002/restaurant_002_DL.zip && unzip restaurant_002_DL.zip && mv restaurant_002_DL/* . && rmdir restaurant_002_DL && rm restaurant_002_DL.zip
cd /var/www/site2/
curl -O https://free-hp.net/school/sc_001/school_001_DL.zip && unzip school_001_DL.zip && mv school_001_DL/* . && rmdir school_001_DL && rm school_001_DL.zip
systemctl start httpd
Instance2:
Type: AWS::EC2::Instance
Properties:
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
DeleteOnTermination: true
Encrypted: true
Iops: 3000
VolumeSize: 8
VolumeType: gp3
CreditSpecification:
CPUCredits: standard
IamInstanceProfile: !Ref ec2Profile
ImageId: !Ref ec2Ami
InstanceType: !Ref instanceType
SecurityGroupIds:
- !Ref ec2SG
SubnetId: !Ref MyPublicSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-instance2
- Key: BillingGroup
Value: !Ref billingTag
UserData: !Base64
Fn::Sub: |
#!/bin/bash
yum install -y httpd
cp -p /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org
cat <<EOF >> /etc/httpd/conf/httpd.conf
<VirtualHost *:80>
ServerName ${domainName}
DocumentRoot /var/www/html/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName1}
DocumentRoot /var/www/site1/
</VirtualHost>
<VirtualHost *:80>
ServerName ${domainName2}
DocumentRoot /var/www/site2/
</VirtualHost>
EOF
mkdir /var/www/{site1,site2}
cd /var/www/html/
curl -O https://free-hp.net/clinic/cl_002/clinic_002_DL.zip && unzip clinic_002_DL.zip && mv clinic_002_DL/* . && rmdir clinic_002_DL && rm clinic_002_DL.zip
cd /var/www/site1/
curl -O https://free-hp.net/restaurant/re_002/restaurant_002_DL.zip && unzip restaurant_002_DL.zip && mv restaurant_002_DL/* . && rmdir restaurant_002_DL && rm restaurant_002_DL.zip
cd /var/www/site2/
curl -O https://free-hp.net/school/sc_001/school_001_DL.zip && unzip school_001_DL.zip && mv school_001_DL/* . && rmdir school_001_DL && rm school_001_DL.zip
systemctl start httpd
MyInternetGateway:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-igw
- Key: BillingGroup
Value: !Ref billingTag
MyPrivateRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyInternetGateway
RouteTableId: !Ref MyPrivateRouteTable
MyPrivateRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-rtb
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 10
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 12
- 8
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-subnet-1
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPrivateRouteTable
SubnetId: !Ref MyPrivateSubnet1
MyPrivateSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 11
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 12
- 8
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-private-subnet-2
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPrivateSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPrivateRouteTable
SubnetId: !Ref MyPrivateSubnet2
MyPublicRoute:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref MyInternetGateway
RouteTableId: !Ref MyPublicRouteTable
MyPublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-rtb
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 0
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 0
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 2
- 8
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-subnet-1
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet1RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPublicRouteTable
SubnetId: !Ref MyPublicSubnet1
MyPublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select
- 1
- !GetAZs
Ref: AWS::Region
CidrBlock: !Select
- 1
- !Cidr
- !GetAtt MyVPC.CidrBlock
- 2
- 8
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-public-subnet-2
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
MyPublicSubnet2RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref MyPublicRouteTable
SubnetId: !Ref MyPublicSubnet2
MyVPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref vpcCidr
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-vpc
- Key: BillingGroup
Value: !Ref billingTag
MyVPCGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref MyInternetGateway
VpcId: !Ref MyVPC
ParameterGroupAurora:
Type: AWS::RDS::DBParameterGroup
Properties:
Description: !Sub ${env}-${sysName}-parametergroup
Family: aurora-mysql5.7
RdsSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Rds Instances.
GroupName: !Sub ${env}-${sysName}-rds-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- FromPort: 3306
IpProtocol: tcp
SourceSecurityGroupId: !Ref ec2SG
ToPort: 3306
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-rds-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
SubnetGroupRds:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: !Sub ${env}-${sysName}-rds-SubnetGroup
DBSubnetGroupName: !Sub ${env}-${sysName}-rds-subnetgroup
SubnetIds:
- !Ref MyPrivateSubnet1
- !Ref MyPrivateSubnet2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-rds-SubnetGroup
- Key: BillingGroup
Value: !Ref billingTag
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${env}-${sysName}-ec2
Port: 80
Protocol: HTTP
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-tg
- Key: BillingGroup
Value: !Ref billingTag
TargetType: instance
Targets:
- Id: !Ref Instance1
- Id: !Ref Instance2
VpcId: !Ref MyVPC
clusterAurora:
Type: AWS::RDS::DBCluster
DeletionPolicy: Delete
Properties:
BackupRetentionPeriod: 7
DBClusterIdentifier: !Sub ${env}-${sysName}-cluster
DBClusterParameterGroupName: !Ref clusterParameterGroupAurora
DBSubnetGroupName: !Ref SubnetGroupRds
DeletionProtection: false
EnableCloudwatchLogsExports:
- audit
- error
- general
- slowquery
Engine: aurora-mysql
EngineVersion: 5.7.mysql_aurora.2.10.0
MasterUserPassword: !Ref masterPassword
MasterUsername: root
Port: 3306
PreferredBackupWindow: 17:00-18:00
PreferredMaintenanceWindow: tue:18:00-tue:19:00
StorageEncrypted: true
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-cluster
- Key: BillingGroup
Value: !Ref billingTag
VpcSecurityGroupIds:
- !Ref RdsSG
clusterParameterGroupAurora:
Type: AWS::RDS::DBClusterParameterGroup
Properties:
Description: !Sub ${env}-${sysName}-cluster-parametergroup
Family: aurora-mysql5.7
Parameters:
character_set_client: utf8
character_set_connection: utf8
character_set_database: utf8
character_set_results: utf8
character_set_server: utf8
general_log: 1
server_audit_events: CONNECT,QUERY,QUERY_DCL,QUERY_DDL,QUERY_DML,TABLE
server_audit_logging: 1
slow_query_log: 1
time_zone: Asia/Tokyo
ec2Profile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- !Ref ec2Role
ec2Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Action:
- sts:AssumeRole
Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Version: "2012-10-17"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
- arn:aws:iam::aws:policy/AmazonSSMReadOnlyAccess
ec2SG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ec2 Instances.
GroupName: !Sub ${env}-${sysName}-ec2-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- FromPort: 80
IpProtocol: tcp
SourceSecurityGroupId: !Ref AlbSG
ToPort: 80
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-ec2-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
site2Bucket:
DeletionPolicy: Delete
UpdateReplacePolicy: Delete
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref domainName2
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-site2-contents-bucket
- Key: BillingGroup
Value: !Ref billingTag
site2BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref site2Bucket
PolicyDocument:
Statement:
- Action: s3:GetObject
Effect: Allow
Resource: !Sub arn:aws:s3:::${site2Bucket}/*
Principal:
AWS: !Sub arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${site2OAI}
site1Ecr:
Type: AWS::ECR::Repository
Properties:
RepositoryName: site1
ImageScanningConfiguration:
ScanOnPush: "true"
LifecyclePolicy:
LifecyclePolicyText: |
{
"rules": [
{
"rulePriority": 1,
"description": "Delete images",
"selection": {
"tagStatus": "any",
"countType": "imageCountMoreThan",
"countNumber": 10
},
"action": {
"type": "expire"
}
}
]
}
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-site1-ecr
- Key: BillingGroup
Value: !Ref billingTag
ecsLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub "/ecs/logs/${env}/${sysName}"
ecsTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${env}-${sysName}-ecs-task-exec-role
Path: /
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: ecs-tasks.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
site1TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
ContainerDefinitions:
- Essential: true
Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/site1:latest"
LogConfiguration:
LogDriver: awslogs
Options:
awslogs-group: !Ref ecsLogGroup
awslogs-region: !Ref AWS::Region
awslogs-stream-prefix: site1
Name: site1
PortMappings:
- ContainerPort: 80
HostPort: 80
Protocol: tcp
Family: site1
ExecutionRoleArn: !GetAtt ecsTaskExecutionRole.Arn
NetworkMode: awsvpc
RequiresCompatibilities:
- FARGATE
Cpu: "256"
Memory: "512"
site1EcsSG:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: site1 ecs.
GroupName: !Sub ${env}-${sysName}-site1-ecs-sg
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
FromPort: 0
IpProtocol: "-1"
ToPort: 0
SecurityGroupIngress:
- FromPort: 80
IpProtocol: tcp
SourceSecurityGroupId: !Ref AlbSG
ToPort: 80
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-site1-ecs-sg
- Key: BillingGroup
Value: !Ref billingTag
VpcId: !Ref MyVPC
site1TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${env}-${sysName}-site1-ecs-tg
Port: 80
Protocol: HTTP
TargetType: ip
VpcId: !Ref MyVPC
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-site1-ecs-tg
- Key: BillingGroup
Value: !Ref billingTag
cluster:
Type: AWS::ECS::Cluster
Properties:
ClusterName: !Sub ${env}-${sysName}-cluster
ClusterSettings:
- Name: containerInsights
Value: enabled
Tags:
- Key: Name
Value: !Sub ${env}-${sysName}-cluster
- Key: BillingGroup
Value: !Ref billingTag
site1ServiceDefinition:
Type: AWS::ECS::Service
Properties:
Cluster: !Ref cluster
DesiredCount: 0
LaunchType: FARGATE
LoadBalancers:
- TargetGroupArn: !Ref site1TargetGroup
ContainerPort: 80
ContainerName: site1
NetworkConfiguration:
AwsvpcConfiguration:
AssignPublicIp: ENABLED
SecurityGroups:
- !Ref site1EcsSG
Subnets:
- !Ref MyPublicSubnet1
- !Ref MyPublicSubnet2
ServiceName: !Sub ${env}-${sysName}-site1
TaskDefinition: !Sub ${site1TaskDefinition}
最後のデプロイです。
rain deploy -y ./site.yml site --params \
env=prd,\
sysName=example,\
billingTag=example,\
vpcCidr=10.0.0.0/16,\
domainName=example.com,\
domainName1=site1.example.com,\
domainName2=site2.example.com,\
hostedZoneId=Z10116024XXXXXXXXXXX,\
instanceType=t3.micro,\
instanceClass=db.t3.small,\
masterPassword=Passw0rd,\
domain2Cloudfront=dxxxxxxxxxxxx.cloudfront.net,\
site2OAI=E36GW62SYZ8RPJ
site1.example.com
にアクセスしてレスポンスが帰ってきたらOKです。お疲れ様でした。
終わりに
VirtualHostからの分離方法を整理してみました。VirtualHostだけじゃなく、サイトのリプレースも同様の流れになるので参考にしていただければ幸いです。また、S3、ECR,ECSはCodePipelineのビルド、デプロイ先として指定できるのでCI/CDの導入も一緒にご検討ください。