01.はじめに
【AWS】CloudFormtionでブログサービスを構築してみた(概要編)の続きである。
過去に公開した記事は下記の通りである。
・【AWS】CloudFormtionでブログサービスを構築してみた(概要編)
・【AWS】CloudFormtionでブログサービスを構築してみた(01.Network編)
この記事で扱うものはコンポーネントは下記である。
1.EC2
2.ALB
3.RDS(スナップショットを復元する)
また、テンプレートを投入後、手作業が発生するのでこちらも対応する。
SSM経由でEC2にログインして実施する
1.こちらでスナップショットを復元したRDSの接続先が
http://localhost:500になっている(SSHポートフォワーディングした影響)のでALBのドメイン名に変更する。
2.wp-config.phpに下記を追記する(https通信するとフォントが崩れてしまうため)
if($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
$_SERVER['HTTPS'] = 'on';
$_ENV['HTTPS'] = 'on';
}
02.構成図
03.事前準備
事前準備として下記をしておく
1.Route53で登録したゾーンのNSレコードをお名前ドットコムのネームサーバー情報に記載する。
公式サイトによると設定変更が反映されるまで数時間~72時間かかるとのことだが、
筆者の環境では1時間かからず反映された。
設定変更方法
2.Wordpressの初期設定済のEC2を構築してAMI化しておく。
3.RDSのスナップショットを取得しておく。
こちらで取得したものを復元する
04.リスナールールの設計
リスナールールで下記アクセスになるように制御する
1.wp-adminは管理画面のログインURLなので、「自宅のIP/32」以外接続許可しない
2.httpアクセスはhttpsへリダイレクトする
表にすると下記。
◆自宅からのアクセス
アクセスURL | アクセス結果 |
---|---|
https://<ALBのドメイン名> | 許可(200) |
https://<ALBのドメイン名>/wp-admin | 許可(302)(認証画面にリダイレクトされるため) |
http://<ALBのドメイン名> | httpsにリダイレクト(301) |
http://<ALBのドメイン名>/wp-admin | 拒否(403) |
※自分からわざわざwp-adminにhttpアクセスしないので拒否にしている
◆自宅以外からのアクセス
アクセスURL | アクセス結果 |
---|---|
https://<ALBのドメイン名> | 許可(200) |
https://<ALBのドメイン名>/wp-admin | 拒否(403) |
http://<ALBのドメイン名> | httpsにリダイレクト(301) |
http://<ALBのドメイン名>/wp-admin | 拒否(403) |
05.テスト方法
下記観点で確認する
1.通常アクセス
ターゲットグループのテストもかねて1台EC2をシャットダウンした状態でアクセスする。
2.ヘルスチェックが想定通りになっているか確認する
3.リスナールールの機能テスト(curlでレスポンスコードをとるのみにする)
自宅のコマンドプロンプトと稼働中のEC2からそれぞれ実施する。
06.テンプレートファイル
Outputs情報
Outputs:
#サブネット
PublicSubnetA:
Value: !Ref PublicSubnetA
Export:
Name: PublicSubnetA-Outputs
PublicSubnetB:
Value: !Ref PublicSubnetB
Export:
Name: PublicSubnetB-Outputs
PrivateSubnetA1:
Value: !Ref PrivateSubnetA1
Export:
Name: PrivateSubnetA1-Outputs
PrivateSubnetA2:
Value: !Ref PrivateSubnetA2
Export:
Name: PrivateSubnetA2-Outputs
PrivateSubnetC1:
Value: !Ref PrivateSubnetC1
Export:
Name: PrivateSubnetC1-Outputs
PrivateSubnetC2:
Value: !Ref PrivateSubnetC2
Export:
Name: PrivateSubnetC2-Outputs
#セキュリティグループ
EC2SecurityGroup:
Value: !Ref EC2SecurityGroup
Export:
Name: EC2SecurityGroup-Outputs
ALBSecurityGroup:
Value: !Ref ALBSecurityGroup
Export:
Name: ALBSecurityGroup-Outputs
RDSSecurityGroup:
Value: !Ref RDSSecurityGroup
Export:
Name: RDSSecurityGroup-Outputs
#VPC
CFVPC:
Value: !Ref CFVPC
Export:
Name: CFVPC-Outputs
#Route53HostZone(ACMの証明書発行で使う)
HostZone:
Value: !Ref Route53HostedZone
Export:
Name: CFHostZone-Outputs
テンプレートファイル
AWSTemplateFormatVersion: 2010-09-09
Description: EC2-ALB
# ------------------------------------------------------------#
# パラメータ
# ------------------------------------------------------------#
Parameters:
#取得する証明書のドメイン
ACMDomainName:
Type: String
Description: Type of this ACM Domain
#事前に取得しているEC2のAMI
EC2AMI:
Type: String
Description: Type of this EC2AMI.
#自宅のグローバルIP(リスナールールで使用する)
MYip:
Type: String
Description: Type of this MYip.
#管理画面のURLパス(リスナールールで使用する)
URLPath:
Type: String
Description: URLPath.
Default: "/wp-admin/*"
# ------------------------------------------------------------#
# リソース
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
# 証明書取得
# ------------------------------------------------------------#
ACM:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Sub "${ACMDomainName}"
DomainValidationOptions:
- DomainName: !Sub "${ACMDomainName}"
HostedZoneId: !ImportValue "CFHostZone-Outputs"
Tags:
- Key: Name
Value: CF-ACM
ValidationMethod: DNS
# ------------------------------------------------------------#
# EC2
# ------------------------------------------------------------#
myEC2Instance1:
Type: AWS::EC2::Instance
Properties:
KeyName: <事前に取得しているキーペア名>
#取得したAMI
ImageId: !Sub ${EC2AMI}
InstanceType: t2.micro
Monitoring: true
IamInstanceProfile: !Ref EC2InstanceProfile
SecurityGroupIds:
- !ImportValue EC2SecurityGroup-Outputs
SubnetId: !ImportValue PrivateSubnetA1-Outputs
Tags:
- Key: Name
Value: CF-EC2-1
myEC2Instance2:
Type: AWS::EC2::Instance
Properties:
KeyName: <事前に取得しているキーペア名>
#取得したAMI
ImageId: !Sub ${EC2AMI}
InstanceType: t2.micro
Monitoring: true
IamInstanceProfile: !Ref EC2InstanceProfile
SecurityGroupIds:
- !ImportValue EC2SecurityGroup-Outputs
SubnetId: !ImportValue PrivateSubnetC1-Outputs
Tags:
- Key: Name
Value: CF-EC2-2
# ------------------------------------------------------------#
# セッションマネージャー許可のIAMロールを付与
# ------------------------------------------------------------#
EC2IAMRole:
Type: AWS::IAM::Role
Properties:
RoleName: EC2-SSM-role
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
# ------------------------------------------------------------#
# セッションマネージャー許可のIAMロールをアタッチ
# ------------------------------------------------------------#
EC2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
Path: /
Roles:
- Ref: EC2IAMRole
InstanceProfileName: EC2InstanceProfile
# ------------------------------------------------------------#
# ALB
# ------------------------------------------------------------#
# ------------------------------------------------------------#
# ALB本体
# ------------------------------------------------------------#
CFALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
IpAddressType: ipv4
Name: CF-ALB
Scheme: internet-facing
SecurityGroups:
- !ImportValue ALBSecurityGroup-Outputs
Subnets:
- !ImportValue PublicSubnetA-Outputs
- !ImportValue PublicSubnetB-Outputs
Tags:
- Key: Name
Value: CF-ALB
Type: application
# ------------------------------------------------------------#
# ターゲットグループ
# ------------------------------------------------------------#
CFTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: CF-TargetGroup
VpcId: !ImportValue CFVPC-Outputs
IpAddressType: "ipv4"
Protocol: HTTP
ProtocolVersion: HTTP1
Port: 80
TargetType: instance
Targets:
- Id: !Ref myEC2Instance1
Port: 80
- Id: !Ref myEC2Instance2
Port: 80
#httpアクセスはリダイレクトされるので301にしている
Matcher:
HttpCode: "301"
HealthCheckEnabled: true
HealthCheckIntervalSeconds: 10
HealthCheckPath: /index.php
HealthCheckPort: traffic-port
HealthCheckProtocol: HTTP
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
UnhealthyThresholdCount: 2
# ------------------------------------------------------------#
# リスナー(https)
# ------------------------------------------------------------#
#https用
CFhttpsListener:
Type: AWS::ElasticLoadBalancingV2::Listener
DependsOn: ACM
Properties:
LoadBalancerArn: !Ref CFALB
Certificates:
- !Ref ACM
DefaultActions:
- TargetGroupArn: !Ref CFTargetGroup
Type: forward
Port: 443
Protocol: HTTPS
SslPolicy: "ELBSecurityPolicy-2016-08"
#リスナールール
#wp-adminのアクセスを特定IPのみ許可する設定
CFhttpsListenerRule1:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: forward
TargetGroupArn: !Ref CFTargetGroup
Conditions:
- Field: source-ip
SourceIpConfig:
Values:
- !Sub ${MYip}
- Field: path-pattern
PathPatternConfig:
Values:
- !Sub ${URLPath}
ListenerArn: !Ref CFhttpsListener
Priority: 1
#wp-adminのアクセスを拒否する設定
CFhttpsListenerRule2:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: fixed-response
FixedResponseConfig:
ContentType: text/plain
MessageBody: "403 Forbideen"
StatusCode: 403
Conditions:
- Field: path-pattern
PathPatternConfig:
Values:
- !Sub ${URLPath}
ListenerArn: !Ref CFhttpsListener
Priority: 2
# ------------------------------------------------------------#
# リスナー(http)
# ------------------------------------------------------------#
#http用
CFhttpListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref CFALB
DefaultActions:
- Type: redirect
RedirectConfig:
Protocol: "HTTPS"
Port: 443
Host: "#{host}"
Path: "/#{path}"
Query: "#{query}"
StatusCode: "HTTP_301"
Port: 80
Protocol: HTTP
#リスナールール
#wp-adminのアクセスを拒否する設定
CFhttpListenerRule1:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: fixed-response
FixedResponseConfig:
ContentType: text/plain
MessageBody: "403 Forbideen"
StatusCode: 403
Conditions:
- Field: path-pattern
PathPatternConfig:
Values:
- !Sub ${URLPath}
ListenerArn: !Ref CFhttpListener
Priority: 1
# ------------------------------------------------------------#
# RDS SubnetGroup
# ------------------------------------------------------------#
CFDBSubnetGroup:
Type: AWS::RDS::DBSubnetGroup
Properties:
DBSubnetGroupDescription: CF-DB-SubnetGroup
SubnetIds:
- !ImportValue PrivateSubnetA2-Outputs
- !ImportValue PrivateSubnetC2-Outputs
Tags:
- Key: Name
Value: CFDBSubnetGroup
Outputs:
#ALBのDNS名の定義(Route53で使う)
ALBDomainName:
Value: !GetAtt CFALB.DNSName
Export:
Name: ALB-DNS-Outputs
#ALBのゾーンIDの定義(Route53で使う)
ALBZoneId:
Value: !GetAtt CFALB.CanonicalHostedZoneID
Export:
Name: ALB-CanonicalHostedZoneID-Outputs
#ALBのARNの定義(WAFで使う)
ALBArn:
Value: !Ref CFALB
Export:
Name: ALB-ARN-Outputs
07.RDSのスナップショット復元
RDSのスナップショットを復元する。
08.修正作業
1.RDSの接続ポイント修正
EC2にセッションマネージャーでログイン、RDSに接続して下記コマンドを実行
$ mysql -h <データベースのエンドポイント名> -u wordpress -p
MySQL [(none)]> use wordpress
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MySQL [wordpress]> SELECT * FROM wp_options WHERE option_name IN ('siteurl', 'home');
+-----------+-------------+----------------------+----------+
| option_id | option_name | option_value | autoload |
+-----------+-------------+----------------------+----------+
| 2 | home | http://localhost:500 | yes |
| 1 | siteurl | http://localhost:500 | yes |
+-----------+-------------+----------------------+----------+
2 rows in set (0.00 sec)
→下記コマンドで修正する
MySQL [wordpress]> UPDATE wp_options SET option_value = 'http://<ALBのドメイン名>' WHERE option_name IN ('siteurl', 'home');
2.EC2のwp-config.phpに下記を追記する(https通信するとフォントが崩れてしまうため)
if($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
$_SERVER['HTTPS'] = 'on';
$_ENV['HTTPS'] = 'on';
}
09.テスト
1.通常アクセス
ターゲットグループのテストもかねて1台EC2をシャットダウンした状態でアクセスする。
ALBのDNS名に対してhttpsアクセスする。
証明書はRoute53のドメインに充てているため、警告は出るがhttpsアクセス出来ている。
→想定通り
2.ヘルスチェックが想定通りになっているか確認する
→想定通り
3.リスナールールの機能テスト(curlでレスポンスコードをとるのみにする)
自宅のコマンドプロンプトと稼働中のEC2からそれぞれ実施する。
この表通りになるか確認する。
◆自宅からのアクセス
アクセスURL | アクセス結果 |
---|---|
https://<ALBのドメイン名> | 許可(200) |
https://<ALBのドメイン名>/wp-admin | 許可(302)(認証画面にリダイレクトされるため) |
http://<ALBのドメイン名> | httpsにリダイレクト(301) |
http://<ALBのドメイン名>/wp-admin | 拒否(403) |
※自分からわざわざwp-adminにhttpアクセスしないので拒否にしている
◆自宅以外からのアクセス
アクセスURL | アクセス結果 |
---|---|
https://<ALBのドメイン名> | 許可(200) |
https://<ALBのドメイン名>/wp-admin | 拒否(403) |
http://<ALBのドメイン名> | httpsにリダイレクト(301) |
http://<ALBのドメイン名>/wp-admin | 拒否(403) |
・自宅のコマンドプロンプトから
>curl -k https://CF-ALB-156526098.ap-northeast-1.elb.amazonaws.com -o /dev/null -w '%{http_code}\n' -s
'200
'
>
→通常アクセスなので想定通り
>curl -k https://CF-ALB-156526098.ap-northeast-1.elb.amazonaws.com/wp-admin/ -o /dev/null -w '%{http_code}\n' -s
'302
'
>
→ログインの認証画面に遷移するので問題なし
>curl http://CF-ALB-156526098.ap-northeast-1.elb.amazonaws.com -o /dev/null -w '%{http_code}\n' -s
'301
'
>
→httpsにリダイレクトされるので問題なし
>curl http://CF-ALB-156526098.ap-northeast-1.elb.amazonaws.com/wp-admin/ -o /dev/null -w '%{http_code}\n' -s
'403
'
>
→wp-adminへのアクセスなので403で問題なし
・EC2から
$ whoami
ec2-user
$
$ curl -k https://CF-ALB-156526098.ap-northeast-1.elb.amazonaws.com -o /dev/null -w '%{http_code}\n' -s
200
$
→通常アクセスなので想定通り
$ curl -k https://CF-ALB-156526098.ap-northeast-1.elb.amazonaws.com/wp-admin/ -o /dev/null -w '%{http_code}\n' -s
403
$
→wp-adminへのアクセスなので403で問題なし
$ curl http://CF-ALB-156526098.ap-northeast-1.elb.amazonaws.com -o /dev/null -w '%{http_code}\n' -s
301
$
→httpsへリダイレクトされるので問題なし
$ curl http://CF-ALB-156526098.ap-northeast-1.elb.amazonaws.com/wp-admin/ -o /dev/null -w '%{http_code}\n' -s
403
$
→wp-adminへのアクセスなので403で問題なし
参考文献
★次回はこちら
【AWS】CloudFormtionでブログサービスを構築してみた(03.S3,CloudFront編)