LoginSignup
0
2

More than 1 year has passed since last update.

Route 53 + CloudFront + S3 + WAFの構成をCloudFormationで作る

Posted at

やりたいこと

  • 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などは後から別のテンプレートで作成します
(今回は東京リージョンに作りたかったのでそこに)

全体の流れとしては下記のような感じにしました

  1. us-east-1で作成が必要なものを作る
    1. SSL証明書
    2. Route53 ホストゾーン
    3. WAF
  2. ap-northeast-1で他のものを作る
    1. S3
    2. CloudFront
    3. 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について↓

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2