概要
CloudFormationを使ってCloudFrontとS3を構築する方法について解説します
前提
- Route53にドメインを登録済み
- ACMを発行済み(リージョンはバージニア北部)
ディレクトリ構成
tree
.
└── templates
├── network
| └── cloudfront.yml
└── storages
├── s3-bucket-for-frontend.yml
└── s3-bucket-policy-for-frontend.yml
S3作成用のスタック
静的ファイルを格納するS3を作成します
AWSTemplateFormatVersion: 2010-09-09
Description: "S3 Bucket Stack"
# -------------------------------------
# Metadata
# -------------------------------------
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Project Configuration"
Parameters:
- ProjectName
- Environment
# -------------------------------------
# Parameters
# -------------------------------------
Parameters:
ProjectName:
Description: "Enter the project name (ex: my-project)"
Type: String
MinLength: 1
ConstraintDescription: "ProjectName must be enter"
Default: my-project
Environment:
Description: "Select the environment"
Type: String
AllowedValues: [dev, stg, prd]
ConstraintDescription: "Environment must be select"
# -------------------------------------
# Resources
# -------------------------------------
Resources:
# -------------------------------------
# S3
# -------------------------------------
# For Static Website Hosting
AssetsBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Join
- "-"
- - !Sub "${ProjectName}-${Environment}-assets-with-origin-access-control"
- !Select [0, !Split ["-", !Select [2, !Split ["/", !Ref AWS::StackId]]]]
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
VersioningConfiguration:
Status: Enabled
# -------------------------------------
# Outputs
# -------------------------------------
Outputs:
AssetsBucketName:
Value: !Ref AssetsBucket
AssetsBucketArn:
Value: !GetAtt AssetsBucket.Arn
AssetsBucketDomainName:
Value: !GetAtt AssetsBucket.RegionalDomainName
S3のアクセス許可の設定
今回はCloudFront経由でS3へアクセスしたいので
- BlockPublicAcls
- ストレージへのパブリックアクセスをブロック
- BlockPublicPolicy
- 指定されたバケットポリシーでパブリックアクセスが許可されている場合、S3はPUT Bucketポリシーへの呼び出しを拒否
- IgnorePublicAcls
- Amazon S3 はバケットとそれに含まれるオブジェクトのすべてのパブリックACLを無視
- RestrictPublicBuckets
- アクセスをバケット所有者のアカウントおよびアクセスポイント所有者のアカウント内のAWSのサービスプリンシパルと承認されたユーザーのみに制限
を全てTrueにします
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
S3の暗号化設定
S3バケットの暗号化設定を行います
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
S3のバージョニング
今回はバージョニングを有効にします
VersioningConfiguration:
Status: Enabled
S3のバケットポリシー作成用のスタック
CloudFrontからのアクセスを許可するためのバケットポリシーを作成します
AWSTemplateFormatVersion: 2010-09-09
Description: "S3 Bucket Policy Stack"
# -------------------------------------
# Metadata
# -------------------------------------
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "S3 Configuration"
Parameters:
- AssetsBucketName
- AssetsBucketArn
- CloudFrontAssetsDistributionID
# -------------------------------------
# Parameters
# -------------------------------------
Parameters:
AssetsBucketName:
Description: "Enter the S3 assets bucket name (ex: example-assets-with-oac-xxxxxxxx)"
Type: String
AssetsBucketArn:
Description: "Enter the S3 assets bucket ARN (ex: arn:aws:s3:::example-assets-with-oac-xxxxxxxx)"
Type: String
CloudFrontAssetsDistributionID:
Description: "Enter the CloudFront Distribution ID for assets bucket (ex: XXXXXXXXXXXXXX)"
Type: String
# -------------------------------------
# Resources
# -------------------------------------
Resources:
# -------------------------------------
# S3 Bucket Policy
# -------------------------------------
AssetsBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref AssetsBucketName
PolicyDocument:
Statement:
- Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action:
- s3:GetObject
- s3:ListBucket
Resource:
- !Sub ${AssetsBucketArn}/*
- !Ref AssetsBucketArn
Condition:
StringEquals:
AWS:SourceArn: !Sub arn:aws:cloudfront::${AWS::AccountId}:distribution/${CloudFrontAssetsDistributionID}
バケットポリシー
今回は指定したCloudFrontのディストリビューションがバケット自体をListできるポリシーとバケット内のオブジェクトをGetできるポリシーを付与します
{
"Version": "2008-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": [
"s3:GetObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::{バケット名}/*",
"arn:aws:s3:::{バケット名}"
],
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::{アカウントID}:distribution/{ディストリビューションID}"
}
}
}
]
}
CloudFrontのディストリビューション作成用のスタック
CloudFrontのディストリビューションを作成します
AWSTemplateFormatVersion: 2010-09-09
Description: "CloudFront Stack"
# -------------------------------------
# Mappings
# -------------------------------------
Mappings:
# CachePolicyIdは以下の記事を参照
# https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/using-managed-cache-policies.html
CachePolicyIds:
CachingOptimized:
Id: 658327ea-f89d-4fab-a63d-7e88639e58f6
CachingDisabled:
Id: 4135ea2d-6df8-44a3-9df3-4b5a84be39ad
CachingOptimizedForUncompressedObjects:
Id: b2884449-e4de-46a7-ac36-70bc7f1ddd6d
Elemental-MediaPackage:
Id: 08627262-05a9-4f76-9ded-b50ca2e3a84f
Amplify:
Id: 2e54312d-136d-493c-8eb9-b001f22f67d2
# ResponseHeadersPolicyIdは以下の記事を参照
# https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/using-managed-response-headers-policies.html
ResponseHeadersPolicyIds:
CORS-and-SecurityHeadersPolicy:
Id: e61eb60c-9c35-4d20-a928-2b84e02af89c
CORS-With-Preflight:
Id: 5cc3b908-e619-4b99-88e5-2cf7f45965bd
CORS-with-preflight-and-SecurityHeadersPolicy:
Id: eaab4381-ed33-4a86-88ca-d9558dc6cd63
SecurityHeadersPolicy:
Id: 67f7725c-6f97-4210-82d7-5512b31e9d03
SimpleCORS:
Id: 60669652-455b-4ae9-85a4-c4c02393f86c
# -------------------------------------
# Metadata
# -------------------------------------
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Project Configuration"
Parameters:
- ProjectName
- Environment
- Label:
default: "Route 53 Configuration"
Parameters:
- HostZoneID
- Label:
default: "CloudFront Configuration"
Parameters:
- CloudFrontHostZoneID
- ACMPublicCertificateArn
- CachePolicy
- ResponseHeadersPolicy
- AssetsBucketDomainName
# -------------------------------------
# Parameters
# -------------------------------------
Parameters:
ProjectName:
Description: "Enter the project name (ex: my-project)"
Type: String
MinLength: 1
ConstraintDescription: "ProjectName must be enter"
Default: my-project
Environment:
Description: "Select the environment"
Type: String
AllowedValues: [dev, stg, prd]
ConstraintDescription: "Environment must be select"
HostZoneID:
Description: "Select the Route 53 Hosted Zone ID"
Type: AWS::Route53::HostedZone::Id
DomainName:
Description: "Enter the Route 53 domain name"
Type: String
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-route53-recordset-aliastarget.html#cfn-route53-recordset-aliastarget-hostedzoneid
# Specify Z2FDTNDATAQYW2. This is always the hosted zone ID when you create an alias record that routes traffic to a CloudFront distribution.
CloudFrontHostZoneID:
Type: String
Description: "Select the CloudFront hosted zone ID. (fixed value: Z2FDTNDATAQYW2)"
Default: Z2FDTNDATAQYW2
AllowedValues:
- Z2FDTNDATAQYW2
ACMPublicCertificateArn:
Description: "Enter the ACM public certificate ARN for global region"
Type: String
CachePolicy:
Description: "Select the CloudFront cache policy (Recommended for S3: CachingOptimized)"
Type: String
Default: CachingOptimized
AllowedValues:
- CachingOptimized
- CachingDisabled
- CachingOptimizedForUncompressedObjects
- Elemental-MediaPackage
ResponseHeadersPolicy:
Description: "Select the CloudFront response headers policy"
Type: String
Default: SecurityHeadersPolicy
AllowedValues:
- CORS-and-SecurityHeadersPolicy
- CORS-With-Preflight
- CORS-with-preflight-and-SecurityHeadersPolicy
- SecurityHeadersPolicy
- SimpleCORS
AssetsBucketDomainName:
Description: "Enter the S3 bucket region domain name for static web hosting (ex: example-assets-bucket.s3.ap-northeast-1.amazonaws.com)"
Type: String
# -------------------------------------
# Resources
# -------------------------------------
Resources:
# -------------------------------------
# Route 53
# -------------------------------------
CloudFrontAliasRecord:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneId: !Ref HostZoneID
Name: !Ref DomainName
Type: A
# CloudFront用の設定
AliasTarget:
HostedZoneId: !Ref CloudFrontHostZoneID
DNSName: !GetAtt AssetsDistribution.DomainName
# -------------------------------------
# CloudFront Distribution
# -------------------------------------
AssetsDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: S3Origin
DomainName: !Ref AssetsBucketDomainName
S3OriginConfig:
OriginAccessIdentity: ""
OriginAccessControlId: !GetAtt CloudFrontOriginAccessControl.Id
Enabled: true
DefaultRootObject: index.html
Comment: "S3 Static Website Hosting Distribution"
CustomErrorResponses:
- ErrorCachingMinTTL: 0
ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /404/index.html
DefaultCacheBehavior:
CachePolicyId: !FindInMap [CachePolicyIds, !Ref CachePolicy , Id]
ResponseHeadersPolicyId: !FindInMap [ResponseHeadersPolicyIds, !Ref ResponseHeadersPolicy, Id]
TargetOriginId: S3Origin
ViewerProtocolPolicy: redirect-to-https
HttpVersion: http2
ViewerCertificate:
AcmCertificateArn: !Ref ACMPublicCertificateArn
MinimumProtocolVersion: TLSv1.2_2021
SslSupportMethod: sni-only
# 代替ドメイン名の設定に必要
Aliases:
- !Ref DomainName
IPV6Enabled: false
# -------------------------------------
# CloudFront OAC
# -------------------------------------
CloudFrontOriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Description: "Origin Access Control For S3 Static Website Hosting"
Name: !Sub ${ProjectName}-${Environment}-S3OAC
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
# -------------------------------------
# Outputs
# -------------------------------------
Outputs:
AssetsDistributionID:
Value: !Ref AssetsDistribution
Route53の設定
Route53内にAレコードを作成し、トラフィックのルーティング先をCloudFrontのディストリビューションに指定します
# -------------------------------------
# Route 53
# -------------------------------------
CloudFrontAliasRecord:
Type: AWS::Route53::RecordSet
Properties:
HostedZoneId: !Ref HostZoneID
Name: !Ref DomainName
Type: A
# CloudFront用の設定
AliasTarget:
HostedZoneId: !Ref CloudFrontHostZoneID
DNSName: !GetAtt AssetsDistribution.DomainName
CloudFrontのディストリビューションの設定
Origins
CloudFrontのオリジンの設定を行います
オリジンはS3に指定し、後ほど作成するOACの設定を行います
DefaultRootObject
ドメインにアクセスする際のルートページをindex.htmlに指定します
CustomErrorResponses
404を返す際はカスタムの404ページを表示させます
DefaultCacheBehavior
ビヘイビアの設定を行います
今回はビューワープロトコルポリシーをRedirect HTTP to HTTPSにします
ViewerCertificate
HTTPS通信ができるようSSL証明書の設定を行います
Aliases
代替ドメイン名の設定を行います
# -------------------------------------
# CloudFront Distribution
# -------------------------------------
AssetsDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- Id: S3Origin
DomainName: !Ref AssetsBucketDomainName
S3OriginConfig:
OriginAccessIdentity: ""
OriginAccessControlId: !GetAtt CloudFrontOriginAccessControl.Id
Enabled: true
DefaultRootObject: index.html
Comment: "S3 Static Website Hosting Distribution"
CustomErrorResponses:
- ErrorCachingMinTTL: 0
ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /404/index.html
DefaultCacheBehavior:
CachePolicyId: !FindInMap [CachePolicyIds, !Ref CachePolicy , Id]
ResponseHeadersPolicyId: !FindInMap [ResponseHeadersPolicyIds, !Ref ResponseHeadersPolicy, Id]
TargetOriginId: S3Origin
ViewerProtocolPolicy: redirect-to-https
HttpVersion: http2
ViewerCertificate:
AcmCertificateArn: !Ref ACMPublicCertificateArn
MinimumProtocolVersion: TLSv1.2_2021
SslSupportMethod: sni-only
# 代替ドメイン名の設定に必要
Aliases:
- !Ref DomainName
IPV6Enabled: false
OriginAccessControl(OAC)の設定
OACの設定を行うS3バケットを指定します
# -------------------------------------
# CloudFront OAC
# -------------------------------------
CloudFrontOriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Description: "Origin Access Control For S3 Static Website Hosting"
Name: !Sub ${ProjectName}-${Environment}-S3OAC
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
実際に作成してみよう!
S3の作成
CloudFormationのコンソールからスタックを作成します
今回はスタック名をMyS3Frontend、environmentをdevにします
以下のようにS3が作成されていたら成功です
S3を作成したらバケット内に静的ファイルをアップロードしましょう
CloudFrontのディストリビューションの作成
CloudFormationのコンソールからスタックを作成します
AssestBucketDomainNameに以下のように記載します
my-project-dev-assets-with-origin-access-control-c2fa7500.s3.ap-northeast-1.amazonaws.com
以下のようにCloudFrontのディストリビューションが作成されたら成功です
以下のようにCloudFrontのディストリビューションを紐づいたAレコードが作成されたら成功です
S3のバケットポリシーの作成
実際にディストリビューションとドメインからアクセスしてみよう!
先ほど作成したS3バケットにindex.htmlをはじめとした静的ファイルをアップロードします
今回はCloudFrontにデフォルトルートオブジェクトをindex.htmlを設定するのでindex.htmlを忘れずにアップロードします
以下のようにディストリビューションとドメイン名からアクセスした際にindex.htmlが表示されたら成功です
参考