Amazon S3でコンテンツをホストし、Amazon CloudFront、Route 53、ACMを組み合わせてHTTPS対応の安全で高速な静的サイトを作成します。
AWS CLIを使用してCloudFormationスタックをデプロイする場合は、以下のコマンドを実行します。
aws cloudformation create-stack \ --stack-name s3-static-website-stack \ --template-body file://s3-static-website.yaml \ --capabilities CAPABILITY_IAM
AWSTemplateFormatVersion: '2010-09-09'
Description: 'S3 static website hosting with CloudFront - Best Practices'
Resources:
LogBucket:
Type: AWS::S3::Bucket
Metadata:
Comment: Access logs bucket
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
VersioningConfiguration:
Status: Enabled
LifecycleConfiguration:
Rules:
- Id: DeleteOldLogs
Status: Enabled
ExpirationInDays: 90
LogBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref LogBucket
PolicyDocument:
Statement:
- Sid: S3ServerAccessLogsPolicy
Effect: Allow
Principal:
Service: logging.s3.amazonaws.com
Action: s3:PutObject
Resource: !Sub ${LogBucket.Arn}/*
- Sid: DenyInsecureTransport
Effect: Deny
Principal: '*'
Action: s3:*
Resource:
- !GetAtt LogBucket.Arn
- !Sub ${LogBucket.Arn}/*
Condition:
Bool:
aws:SecureTransport: false
ContentBucket:
Type: AWS::S3::Bucket
DependsOn: LogBucketPolicy
Properties:
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
VersioningConfiguration:
Status: Enabled
LoggingConfiguration:
DestinationBucketName: !Ref LogBucket
LogFilePrefix: content-bucket-logs/
LifecycleConfiguration:
Rules:
- Id: DeleteOldVersions
Status: Enabled
NoncurrentVersionExpirationInDays: 90
ContentBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref ContentBucket
PolicyDocument:
Statement:
- Sid: AllowCloudFrontServicePrincipal
Effect: Allow
Principal:
Service: cloudfront.amazonaws.com
Action: s3:GetObject
Resource: !Sub ${ContentBucket.Arn}/*
Condition:
StringEquals:
AWS:SourceArn: !Sub arn:${AWS::Partition}:cloudfront::${AWS::AccountId}:distribution/${CloudFrontDistribution}
- Sid: DenyInsecureTransport
Effect: Deny
Principal: '*'
Action: s3:*
Resource:
- !GetAtt ContentBucket.Arn
- !Sub ${ContentBucket.Arn}/*
Condition:
Bool:
aws:SecureTransport: false
CloudFrontOriginAccessControl:
Type: AWS::CloudFront::OriginAccessControl
Properties:
OriginAccessControlConfig:
Name: !Sub ${AWS::StackName}-OAC
OriginAccessControlOriginType: s3
SigningBehavior: always
SigningProtocol: sigv4
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Enabled: true
DefaultRootObject: index.html
HttpVersion: http2and3
IPV6Enabled: true
Origins:
- Id: S3Origin
DomainName: !GetAtt ContentBucket.RegionalDomainName
S3OriginConfig:
OriginAccessIdentity: ''
OriginAccessControlId: !Ref CloudFrontOriginAccessControl
DefaultCacheBehavior:
TargetOriginId: S3Origin
ViewerProtocolPolicy: redirect-to-https
AllowedMethods:
- GET
- HEAD
- OPTIONS
CachedMethods:
- GET
- HEAD
Compress: true
CachePolicyId: 658327ea-f89d-4fab-a63d-7e88639e58f6 # CachingOptimized
CustomErrorResponses:
- ErrorCode: 403
ResponseCode: 200
ResponsePagePath: /index.html
- ErrorCode: 404
ResponseCode: 200
ResponsePagePath: /index.html
ViewerCertificate:
CloudFrontDefaultCertificate: true
MinimumProtocolVersion: TLSv1.2_2021
Outputs:
BucketName:
Value: !Ref ContentBucket
Description: S3 bucket name for static content
DistributionId:
Value: !Ref CloudFrontDistribution
Description: CloudFront distribution ID
DistributionDomainName:
Value: !GetAtt CloudFrontDistribution.DomainName
Description: CloudFront distribution domain name
WebsiteURL:
Value: !Sub https://${CloudFrontDistribution.DomainName}
Description: Website URL