目標
- 静的サイトをS3に用意し、CloudFrontから公開する
- S3はCloudFrontからのアクセスのみ許可する
- アクセスログをS3バケットに格納する
- 独自ドメインは使用しない
- CloudFormationで作成する
静的ウェブサイトの設定について
そもそも静的ウェブサイトの設定方法は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
参考
- https://aws.amazon.com/jp/premiumsupport/knowledge-center/cloudfront-serve-static-website/
- https://github.com/aws-samples/amazon-cloudfront-secure-static-site
- https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-http-307-response/
- https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/AWS_CloudFront.html
- https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/AWS_S3.html