on
dev ドメイン用のブログ環境を AWS で作成する
概要
dev ドメインを取得したので、AWS でブログホスティングする環境を構築します。
一般的に、静的なサイトの場合、S3 の Website ホスティングで構築すれば良いですが、HTTPS に対応するためには前段に CloudFront を配置する必要があります。dev ドメインではウェブブラウザで HSTS プリロードされているため HTTPS が必須となります(S3 だけでは運用できません)
本記事では、CloudFront + S3 環境を一撃(ほんとは二撃)で作成する CFn を備忘録として紹介します。
前提
- 運用したい dev ドメインを Route53 でホスティングしている環境を想定しています。
テンプレート
以下、テンプレートとなります。注意点としては、
- CloudFornt は us-east-1 でしか作成できないので、テンプレート内の全てのリソースは us-east-1 となる
- ACM で証明書をリクエストしているので、検証レコードをマネジメントコンソールより追加する必要がある
作成するリソースは大体次です。
Lambda@Ege は CloudFront がサブパスの hoge/
を hoge/index.html
に保管しないために作成しています。
- CloudFront
- S3
- ACM 証明書
- Route53 のレコード
- Lambda@Edge
パラメータ
ValidationDomain
には、Route53 のホストゾーンのドメインを指定する(例: konoui.dev
)DomainName
には、Web サイトのドメインを指定する(例: www.konoui.dev
)AlternativeDomainName
には、DomainName
とは別に運用したい代替ドメインを指定する(例: konoui.dev
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
| AWSTemplateFormatVersion: 2010-09-09
Description: Static contents distribution using S3 and CloudFront.
Parameters:
ValidationDomain:
Description: The domain name which you want to validate
Type: String
DomainName:
Description: FQDN of your web sites
Type: String
AlternativeDomainName:
Description: FQDN of your web sites
Type: String
Resources:
ACMCertificate:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref DomainName
SubjectAlternativeNames:
- !Ref AlternativeDomainName
DomainValidationOptions:
- DomainName: !Ref DomainName
ValidationDomain: !Ref ValidationDomain
ValidationMethod: DNS
Tags:
- Key: Name
Value: !Ref DomainName
AssetsBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref DomainName
AssetsBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref AssetsBucket
PolicyDocument:
Statement:
- Action: s3:GetObject
Effect: Allow
Resource: !Sub "arn:aws:s3:::${AssetsBucket}/*"
Principal:
AWS: !Sub "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontOriginAccessIdentity}"
ReservedBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref AlternativeDomainName
AssetsDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Aliases:
- !Ref DomainName
- !Ref AlternativeDomainName
Origins:
- Id: S3Origin
DomainName: !GetAtt AssetsBucket.DomainName
S3OriginConfig:
OriginAccessIdentity: !Sub "origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}"
ViewerCertificate:
SslSupportMethod: sni-only
AcmCertificateArn: !Ref ACMCertificate
Enabled: true
HttpVersion: http2
# see https://aws.amazon.com/jp/cloudfront/pricing/
PriceClass: PriceClass_200
DefaultRootObject: index.html
Comment: !Sub "${AWS::StackName} Distribution"
DefaultCacheBehavior:
TargetOriginId: S3Origin
ForwardedValues:
QueryString: false
ViewerProtocolPolicy: redirect-to-https
LambdaFunctionAssociations:
- EventType: origin-request
LambdaFunctionARN: !Ref OriginRequestLambdaVersion
Tags:
- Key: Name
Value: AWS::StackName
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: !Sub "${AWS::StackName} Origin Access Identity"
OriginRequestLambda:
Type: AWS::Lambda::Function
Properties:
Code:
ZipFile: |
'use strict';
const path = require('path');
exports.handler = (event, context, callback) => {
var request = event.Records[0].cf.request;
if (!path.extname(request.uri)) {
// Rewrite URL
request.uri = request.uri.replace(/\/?$/, '\/index.html');
}
return callback(null, request);
};
Handler: index.handler
MemorySize: 128
Role: !GetAtt OriginRequestLambdaExecutionRole.Arn
Runtime: nodejs8.10
Tags:
- Key: Domain
Value: !Ref DomainName
OriginRequestLambdaVersion:
Type: AWS::Lambda::Version
Properties:
FunctionName: !GetAtt OriginRequestLambda.Arn
OriginRequestLambdaExecutionRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- edgelambda.amazonaws.com
- lambda.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
AssetsDNSRecords:
Type: AWS::Route53::RecordSetGroup
Properties:
HostedZoneName: !Sub "${ValidationDomain}."
RecordSets:
- Name: !Sub "${DomainName}."
Type: A
AliasTarget:
# see Amazon CloudFront https://docs.aws.amazon.com/ja_jp/general/latest/gr/rande.html
HostedZoneId: Z2FDTNDATAQYW2
DNSName: !GetAtt AssetsDistribution.DomainName
- Name: !Sub "${AlternativeDomainName}."
Type: A
AliasTarget:
HostedZoneId: Z2FDTNDATAQYW2
DNSName: !GetAtt AssetsDistribution.DomainName
Outputs:
URL:
Value: !Sub "https://${DomainName}"
|
デプロイ
aws cloudformation deploy --stack-name <スタック名> --template <テンプレート名> --capabilities CAPABILITY_IAM --region us-east-1
上記デプロイだけではリソースの作成は完了しません。ACM の証明書は DNS 検証としているため、ACM コンソールより DNS 検証ための DNS レコードを当該ホストゾーンに追加する必要があります。
DNS 検証終了後、CFn にて処理が継続し CloudFront 等が作成されます。