1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Terraform個人メモ:S3 + CloudFront + Route 53 + ACM(バージニア北部)構成を整理してみた

Posted at

はじめに

本記事では、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 を作成し、aclprivate に設定することで、直接アクセスできないようにします。タグを追加することで、環境識別が容易になります。

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 にアップロードします。aclprivate にすることで、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
  }
}

実際に完成したコード

main.tf
# 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 リソースを効率的に管理し、セキュアなシステムを構築してみましょう!

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?