はじめに
本記事では、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 の検証レコードを追加します。
1. S3 バケットの作成
resource "aws_s3_bucket" "my_bucket" {
bucket = "my-cloudfront-bucket-tokyo"
acl = "private"
tags = {
Name = "MyS3Bucket"
Environment = "Production"
}
}
この設定では、S3 バケット my-cloudfront-bucket-tokyo
を作成し、acl
を private
に設定することで、直接アクセスできないようにします。タグを追加することで、環境識別が容易になります。
2. 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"
}
}
この設定により、S3 のウェブサイトホスティング機能を有効にし、デフォルトの index.html
および error.html
を指定しています。
3. CloudFront オリジンアクセスアイデンティティ(OAI)の設定
resource "aws_cloudfront_origin_access_identity" "my_oai" {
comment = "OAI for S3 bucket"
}
CloudFront から S3 にアクセスするための OAI(オリジンアクセスアイデンティティ)を作成します。この OAI を S3 のバケットポリシーで使用します。
4. 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}/*"
}
]
})
}
このバケットポリシーでは、CloudFront の OAI のみが S3 からオブジェクトを取得できるように設定します。これにより、S3 への直接アクセスを防ぎ、安全性を確保できます。
5. HTML ファイルの作成とアップロード
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"
}
ローカルで index.html
を作成し、Terraform を使って S3 にアップロードします。acl
を private
にすることで、CloudFront 経由でのみアクセス可能になります。
6. CloudFront ディストリビューションの作成
resource "aws_cloudfront_distribution" "my_distribution" {
origin {
domain_name = aws_s3_bucket.my_bucket.bucket_regional_domain_name
origin_id = "S3-my-cloudfront-bucket"
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 = ["xxx.xxx"]
tags = {
Name = "MyCloudFrontDistribution"
Environment = "Production"
}
}
この設定では、CloudFront を有効化し、S3 をオリジンとして設定します。HTTPS のリダイレクトや、独自ドメイン honda333.blog
のエイリアスも指定しています。
7. Route 53 の DNS 設定
resource "aws_route53_record" "cloudfront" {
zone_id = "xxx"
name = "xxx"
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"
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 = ["xxx.xxx"]
tags = {
Name = "MyCloudFrontDistribution"
Environment = "Production"
}
}
# Route 53 に CloudFront へのエイリアスレコードを追加
resource "aws_route53_record" "cloudfront" {
zone_id = "xxx"
name = "xxx.xxx"
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
}
}
Route 53 に CloudFront のエイリアスレコードを追加し、独自ドメインでのアクセスを可能にします。
まとめ
本記事では、S3 バケットを CloudFront 経由で提供するための Terraform 設定を詳しく解説しました。
CloudFront の OAI を利用することで、S3 への直接アクセスを防ぎ、安全なウェブホスティング環境を構築できます。
Terraform を活用して AWS リソースを効率的に管理し、セキュアなシステムを構築してみましょう!