やりたいこと
- CloudFront + S3でSPAサイトを公開したい
- そしてRoute53で独自ドメインでアクセスできるようにする
- かつCloudFrontにWAFを設定してアクセス制限したい
CloudFormationで一気に作ろうとしたらWAFを作るところで怒られてしまった...
調べてみるとWebACLのScopeをCLOUDFRONT
で作成する場合はリージョンをus-east-1
で作成する必要がありました
参考↓
ドキュメントにも書いてありました、なるほど
For CLOUDFRONT, you must create your WAFv2 resources in the US East (N. Virginia) Region, us-east-1
解決
ということでus-east-1
で作る必要があるものは別で作成してから、
CloudFrontとかS3などは後から別のテンプレートで作成します
(今回は東京リージョンに作りたかったのでそこに)
全体の流れとしては下記のような感じにしました
-
us-east-1
で作成が必要なものを作る- SSL証明書
- Route53 ホストゾーン
- WAF
-
ap-northeast-1
で他のものを作る- S3
- CloudFront
- Route53のレコード
us-east-1で作成するもの
まずはus-east-1
で作成が必要なものから先に作成します
独自ドメインは取得済みである前提です
WAFは特定のIPからだけアクセスできるようなルールにしています
また、WebACLはブロックした時に404
を返すようにしています
(デフォルトは403ですが、403の場合はCloudFrontでルートパスにリダイレクトしたいので404を返すようにしてます)
CloudFormationテンプレートは下記のような感じです
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
DomainName:
Description: Domain Name
Type: String
Resources:
# -----
# ACM
# -----
ACM:
Type: AWS::CertificateManager::Certificate
Properties:
DomainName: !Ref DomainName
ValidationMethod: DNS
DeletionPolicy: Delete
# -----
# Route53 Hosted Zone
# -----
Route53HostedZone:
Type: AWS::Route53::HostedZone
Properties:
Name: !Ref DomainName
DeletionPolicy: Delete
# -----
# WAF
# -----
##### IP Set
WAFIPSet:
Type: AWS::WAFv2::IPSet
Properties:
NAME: MyIPSet
Addresses:
- 2400:2400:2400:2400:2400:2400:2400:2400/128
IPAddressVersion: IPV6
Scope: CLOUDFRONT
DeletionPolicy: Delete
##### WAF Web ACL
WAFWebAcL:
Type: AWS::WAFv2::WebACL
Properties:
DefaultAction:
Block:
CustomResponse:
ResponseCode: 404
Name: MyWebACL
Rules:
- Name: MyRule
Action:
Allow: {}
Priority: 0
Statement:
IPSetReferenceStatement:
Arn: !GetAtt WAFIPSet.Arn
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: MyRuleMetricName
SampledRequestsEnabled: true
Scope: CLOUDFRONT
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: MyWebACLMetricName
SampledRequestsEnabled: true
DeletionPolicy: Delete
これでスタックを作成します(us-east-1で作成することを忘れずに)
ACMのSSL証明書はDNS検証が必要になります
作成したホストゾーンにDNSレコードを追加して検証が完了したらOKです
残りのもの
あとは東京リージョンで作成するものを作ります
CloudFront + S3の設定はOAIを使用して、CloudFrontを経由せずにS3へ直接アクセスすることを制限します
それと独自ドメインをCloudFrontに向かわせるためのRoute53レコードも作ります
パラメータは下記のように上で作成したリソースを指定するようにします
- CertificateArn
- 上で作成したSSL証明書のARN
- DomainName
- ドメイン
- WebACLArn
- 作成したWebACLのARN
- Route53HostedZone
- 作成したホストゾーンのID
テンプレートはこんな感じ
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
CertificateArn:
Description: Certificate Arn
Type: String
DomainName:
Description: Domain Name
Type: String
WebACLArn:
Description: Web ACL Arn for CloudFront
Type: String
Route53HostedZone:
Description: Route53 Hosted Zone Id
Type: String
Resources:
# -----
# S3
# -----
S3Bucket:
Type: AWS::S3::Bucket
Properties:
BucketName: shiotomo-vite-app-bucket
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
DeletionPolicy: Delete
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref S3Bucket
PolicyDocument:
Statement:
- Action: s3:GetObject
Effect: Allow
Resource: !Sub arn:aws:s3:::${S3Bucket}/*
Principal:
AWS: !Sub arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${CloudFrontOriginAccessIdentity}
DeletionPolicy: Delete
# -----
# CloudFront
# -----
CloudFront:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Comment: My Distribution
Enabled: true
Origins:
- Id: S3Bucket
DomainName: !GetAtt S3Bucket.DomainName
S3OriginConfig:
OriginAccessIdentity: !Sub origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}
ViewerCertificate:
AcmCertificateArn: !Ref CertificateArn
MinimumProtocolVersion: TLSv1.2_2021
SslSupportMethod: sni-only
Aliases:
- !Ref DomainName
CustomErrorResponses:
-
ErrorCode: 403
ResponsePagePath: /
ResponseCode: 200
DefaultRootObject: index.html
DefaultCacheBehavior:
TargetOriginId: S3Bucket
Compress: true
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6
ViewerProtocolPolicy: redirect-to-https
DefaultRootObject: index.html
IPV6Enabled: true
WebACLId: !Ref WebACLArn
DeletionPolicy: Delete
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: MyOAI
DeletionPolicy: Delete
# -----
# Route53 Records
# -----
Route53ARecord:
Type: AWS::Route53::RecordSet
Properties:
Name: !Ref DomainName
Type: A
AliasTarget:
DNSName: !GetAtt CloudFront.DomainName
HostedZoneId: Z2FDTNDATAQYW2
HostedZoneId: !Ref Route53HostedZone
DeletionPolicy: Delete
Route53AAAARecord:
Type: AWS::Route53::RecordSet
Properties:
Name: !Ref DomainName
Type: AAAA
AliasTarget:
DNSName: !GetAtt CloudFront.DomainName
HostedZoneId: Z2FDTNDATAQYW2
HostedZoneId: !Ref Route53HostedZone
DeletionPolicy: Delete
これでスタック作成して問題なければ
あとはS3にindex.htmlをアップするだけです
独自ドメインにアクセスして表示されれば完了!
参考
CloudFrontのOAIについて↓