はじめに
AWS の S3 バケットを CloudFront 経由で公開することで、セキュリティを強化しつつ、高速なコンテンツ配信を実現できます。
本記事では、Terraform を用いて S3 と CloudFront を連携し、静的サイトをホスティングする方法を解説します。
事前準備
この設定を行う前に、以下の準備が必要です。
1. バージニア北部(us-east-1)で ACM 証明書の取得
CloudFront で HTTPS を利用するためには、証明書を バージニア北部(us-east-1) で取得する必要があります。
2. Route 53 の設定
※ACM 証明書の DNS 検証や CloudFront のエイリアス設定には、Route 53 にドメインを登録しておく必要があります。
ドメインのホストゾーンを作成後、続いて、ACM の検証レコードを追加します。
3. GitHub Actions の設定
フロントエンドのプロジェクトを効率的にデプロイするために、GitHub Actions を活用して AWS S3 への自動デプロイを実現しています。
S3 バケットの作成
まず、CloudFront 経由でアクセスするための S3 バケットを作成します。S3 のアクセスコントロールリスト(ACL)は private
に設定し、直接のアクセスを防ぎます。
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-cloudfront-bucket-tokyo"
acl = "private"
tags = {
Name = "MyS3Bucket"
Environment = "Production"
}
}
S3 のウェブホスティング設定
index.html
と error.html
を定義し、S3 での静的サイトホスティングを有効化します。
resource "aws_s3_bucket_website_configuration" "my_bucket_website" {
bucket = aws_s3_bucket.my_bucket.id
index_document {
suffix = "index.html"
}
error_document {
key = "error.html"
}
}
CloudFront 用オリジンアクセスアイデンティティ(OAI)の作成
CloudFront から S3 にセキュアにアクセスするために、OAI を作成します。
resource "aws_cloudfront_origin_access_identity" "my_oai" {
comment = "OAI for S3 bucket"
}
S3 バケットポリシーの設定
S3 のポリシーを設定し、CloudFront OAI のみがアクセスできるようにします。
resource "aws_s3_bucket_policy" "my_bucket_policy" {
bucket = aws_s3_bucket.my_bucket.id
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Principal = {
AWS = aws_cloudfront_origin_access_identity.my_oai.iam_arn
},
Action = "s3:GetObject",
Resource = "${aws_s3_bucket.my_bucket.arn}/*"
}
]
})
}
静的 HTML ファイルの作成とアップロード
サンプルとして index.html
を作成し、S3 にアップロードします。
resource "local_file" "index_html" {
content = "<html><body><h1>React in S3</h1></body></html>"
filename = "index.html"
}
resource "aws_s3_object" "index_file" {
bucket = aws_s3_bucket.my_bucket.id
key = "index.html"
source = local_file.index_html.filename
content_type = "text/html"
acl = "private"
}
CloudFront ディストリビューションの作成
CloudFront の設定を行い、S3 をオリジンとして利用します。
resource "aws_cloudfront_distribution" "my_distribution" {
origin {
domain_name = aws_s3_bucket.my_bucket.bucket_regional_domain_name
origin_id = "S3-my-cloudfront-bucket"
origin_path = "/build/client"
s3_origin_config {
origin_access_identity = aws_cloudfront_origin_access_identity.my_oai.cloudfront_access_identity_path
}
}
enabled = true
is_ipv6_enabled = true
comment = "CloudFront Distribution for S3 bucket in Tokyo region"
default_root_object = "index.html"
default_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "S3-my-cloudfront-bucket"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
viewer_protocol_policy = "redirect-to-https"
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
price_class = "PriceClass_100"
viewer_certificate {
acm_certificate_arn = "arn:aws:acm:us-east-1:881490128743:certificate/5ea024fe-07e4-4083-b3a6-0285be3d24a7"
ssl_support_method = "sni-only"
minimum_protocol_version = "TLSv1.2_2021"
}
aliases = ["honda333.blog"]
tags = {
Name = "MyCloudFrontDistribution"
Environment = "Production"
}
}
Route 53 の設定
最後に、CloudFront を指す Route 53 のエイリアスレコードを作成します。
resource "aws_route53_record" "cloudfront" {
zone_id = "Z0931404175J5ID8KD7I5"
name = "honda333.blog"
type = "A"
alias {
name = aws_cloudfront_distribution.my_distribution.domain_name
zone_id = aws_cloudfront_distribution.my_distribution.hosted_zone_id
evaluate_target_health = false
}
}
実際に完成したコード
# S3 バケットの定義(CloudFront 経由でアクセスするためのバケット)
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-cloudfront-bucket-tokyo"
acl = "private" # バケットは非公開に設定(CloudFront からのアクセスのみ許可)
tags = {
Name = "MyS3Bucket"
Environment = "Production"
}
}
# S3 バケットのウェブホスティング設定(index.html と error.html を指定)
resource "aws_s3_bucket_website_configuration" "my_bucket_website" {
bucket = aws_s3_bucket.my_bucket.id
index_document {
suffix = "index.html"
}
error_document {
key = "error.html"
}
}
# CloudFront 用オリジンアクセスアイデンティティ(OAI)の定義(S3 へのセキュアなアクセスを許可)
resource "aws_cloudfront_origin_access_identity" "my_oai" {
comment = "OAI for S3 bucket"
}
# S3 バケットポリシーの設定(CloudFront OAI のみ S3 へのアクセスを許可)
resource "aws_s3_bucket_policy" "my_bucket_policy" {
bucket = aws_s3_bucket.my_bucket.id
policy = jsonencode({
Version = "2012-10-17",
Statement = [
{
Effect = "Allow",
Principal = {
AWS = aws_cloudfront_origin_access_identity.my_oai.iam_arn
},
Action = "s3:GetObject",
Resource = "${aws_s3_bucket.my_bucket.arn}/*"
}
]
})
}
# 簡易的な HTML ファイル(index.html)の作成
resource "local_file" "index_html" {
content = "<html><body><h1>React in S3</h1></body></html>"
filename = "index.html"
}
# index.html を S3 バケットにアップロード
resource "aws_s3_object" "index_file" {
bucket = aws_s3_bucket.my_bucket.id
key = "index.html"
source = local_file.index_html.filename
content_type = "text/html"
acl = "private" # オブジェクトは非公開(CloudFront 経由でのみアクセス可能)
}
# CloudFront ディストリビューションの定義(S3 バケットをオリジンとする)
resource "aws_cloudfront_distribution" "my_distribution" {
origin {
domain_name = aws_s3_bucket.my_bucket.bucket_regional_domain_name
origin_id = "S3-my-cloudfront-bucket"
origin_path = "/client" # 🔹 ここを追加
s3_origin_config {
origin_access_identity = aws_cloudfront_origin_access_identity.my_oai.cloudfront_access_identity_path
}
}
enabled = true
is_ipv6_enabled = true
comment = "CloudFront Distribution for S3 bucket in Tokyo region"
default_root_object = "index.html"
default_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "S3-my-cloudfront-bucket"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
viewer_protocol_policy = "redirect-to-https"
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
price_class = "PriceClass_100"
viewer_certificate {
acm_certificate_arn = "arn:aws:acm:us-east-1:xxx"
ssl_support_method = "sni-only"
minimum_protocol_version = "TLSv1.2_2021"
}
aliases = ["honda333.blog"]
tags = {
Name = "MyCloudFrontDistribution"
Environment = "Production"
}
}
# Route 53 に CloudFront へのエイリアスレコードを追加
resource "aws_route53_record" "cloudfront" {
zone_id = "xxx"
name = "xxx.blog"
type = "A"
alias {
name = aws_cloudfront_distribution.my_distribution.domain_name
zone_id = aws_cloudfront_distribution.my_distribution.hosted_zone_id
evaluate_target_health = false
}
}
まとめ
本記事では、Terraform を用いて S3 と CloudFront を組み合わせた静的サイトホスティングの設定手順を解説しました。
CloudFront を活用することで、S3 への直接アクセスを防ぎながら、安全かつ効率的なコンテンツ配信が可能になります。
おまけ
独自ドメインを使い、ブラウザからアクセスするとこんな感じになります!