LoginSignup
2
6

More than 3 years have passed since last update.

CloudFormationを使ってCloudFront+S3の静的サイトを構築

Last updated at Posted at 2020-10-31

目標

  • 静的サイトをS3に用意し、CloudFrontから公開する
  • S3はCloudFrontからのアクセスのみ許可する
  • アクセスログをS3バケットに格納する
  • 独自ドメインは使用しない
  • CloudFormationで作成する

static-site.png

静的ウェブサイトの設定について

そもそも静的ウェブサイトの設定方法は2020年10月6日時点では、以下の設定があるようです。

  • アクセスがオリジンアクセスアイデンティティ(OAI) で制限されたオリジンとして、REST API エンドポイントを使用する
  • 匿名 (パブリック) アクセスを許可して、ウェブサイトのエンドポイントをオリジンとして使用する
  • アクセスが Referer ヘッダーで制限されたオリジンとして、ウェブサイトのエンドポイントを使用する
  • AWS CloudFormation を使用して REST API エンドポイントをオリジンとしてデプロイし、OAI と CloudFront を指すカスタムドメインによってアクセスを制限する

今回はCloudFormationを使用してOAIで制限されたREST APIエンドポイント使用する感じになります。

実装

static-site.yaml
AWSTemplateFormatVersion: '2010-09-09'
Description: "aws static site sample"
Resources:
  S3BucketLogs:
    Type: AWS::S3::Bucket
    Properties:
      AccessControl: LogDeliveryWrite
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
  S3BucketWebStatic:
    Type: AWS::S3::Bucket
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      LoggingConfiguration:
        DestinationBucketName: !Ref S3BucketLogs
        LogFilePrefix: 'origin/'
  BucketPolicyWebStatic:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref S3BucketWebStatic
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Action:
              - s3:GetObject
            Effect: Allow
            Resource: !Sub '${S3BucketWebStatic.Arn}/*'
            Principal:
              CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
  CloudFrontOriginAccessIdentity:
    Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
    Properties:
      CloudFrontOriginAccessIdentityConfig:
        Comment: "CloudFront OAI for Static Web Site"
  CloudFrontDistribution:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        DefaultCacheBehavior:
          Compress: true
          DefaultTTL: 86400
          ForwardedValues:
            QueryString: true
          MaxTTL: 31536000
          TargetOriginId: 'WebStatic-S3'
          # httpの通信はhttpsにリダイレクトする
          ViewerProtocolPolicy: 'redirect-to-https'
        Enabled: true
        HttpVersion: 'http2'
        DefaultRootObject: 'index.html'
        IPV6Enabled: true
        Logging:
          Bucket: !GetAtt S3BucketLogs.DomainName
          IncludeCookies: false
          Prefix: 'cdn/'
        Origins:
          # 作成直後にStatusCode 307とならないように、Region指定の方式
          # https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-http-307-response/
          - DomainName: !Join ["", [!Ref S3BucketWebStatic, !Sub ".s3-${AWS::Region}.amazonaws.com"]]
            Id: 'WebStatic-S3'
            S3OriginConfig:
              OriginAccessIdentity:
                !Join ['', ['origin-access-identity/cloudfront/', !Ref CloudFrontOriginAccessIdentity]]
        PriceClass: 'PriceClass_All'
        ViewerCertificate:
          CloudFrontDefaultCertificate: true
Outputs:
  S3BucketLogsName:
    Description: "S3 Bucket for keeping access logs."
    Value: !Ref S3BucketLogs
  S3BucketWebStaticName:
    Description: "S3 Bucket for deploying static site."
    Value: !Ref S3BucketWebStatic
  CloudFrontDomainName:
    Description: "CloudFront DomainName."
    Value: !GetAtt  CloudFrontDistribution.DomainName

aws cliからスタックを作成します。

$ aws cloudformation create-stack --stack-name static-site-sample --template-body file://static-site.yaml

作成完了後にOutputで作成したS3のバケット名とCloudFrontのドメイン名を確認します。

$ aws cloudformation describe-stacks --stack-name static-site-sample                   {
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:xxxx:stack/static-site-sample/xxxxx",
            "StackName": "static-site-sample",
            "Description": "aws static site sample",   
...
            "Outputs": [
                {
                    "OutputKey": "S3BucketLogsName",
                    "OutputValue": "static-site-sample-s3bucketlogs-xxxxx",
                    "Description": "S3 Bucket for keeping access logs."
                },
                {
                    "OutputKey": "S3BucketWebStaticName",
                    "OutputValue": "static-site-sample-s3bucketwebstatic-xxxx",
                    "Description": "S3 Bucket for deploying static site."
                },
                {
                    "OutputKey": "CloudFrontDomainName",
                    "OutputValue": "xxxxxxx.cloudfront.net",
                    "Description": "CloudFront DomainName."
                }
            ],
...                           

作成したバケットに静的ファイルをアップロードします。仮にビルドしたファイルのアップロードを想定します。

$ aws s3 cp --recursive ./build s3://static-site-sample-s3bucketwebstatic-xxxx

以上で作成が完了しているはずです。cloudfrontからのアクセスは確認ができるが、S3のオブジェクトURLは403でエラーとなるはずです。

ソースコードはこちらです。
https://github.com/shikazuki/aws-static-site-sample

参考

2
6
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
2
6