Terraform個人メモ：CloudFrontとS3バケットの作成からHTMLファイルのアップロード、ブラウザでのアクセスまでをコード化

## はじめに
まず、大前提として、ここから先は現在キャッチアップしているTerraformを使いながら、さまざまなコードを自分用に書いていきます。

:::note alert
**※補足事項**
***そのため、内容は完全に自分向けとなっています。***
:::

また、このブログ投稿サイトのプラットフォームについても、自分自身の備忘録としてメモを残す場として活用していきたいと考えています。***このプラットフォーム上に記録を積み重ねていく予定です。***

あらかじめ、その点をご理解いただければ幸いです。

## 実際にコードで行っていること

- AWSプロバイダー設定  
  - AWSの東京リージョン（`ap-northeast-1`）を指定。

- S3バケットの作成  
  - 名前が`my-cloudfront-bucket-tokyo`のS3バケットを非公開設定（`private`）で作成。  
  - タグ（`Name`と`Environment`）を設定。

- S3バケットのウェブホスティング設定  
  - バケットにウェブホスティングを有効化。  
  - デフォルトのインデックスファイルを`index.html`に設定。  
  - エラーファイルを`error.html`に設定。

- CloudFront用のオリジンアクセスアイデンティティ（OAI）の作成  
  - CloudFrontがS3バケットにアクセスできるためのOAIを作成。

- S3バケットポリシーの設定  
  - CloudFrontのOAIに、バケット内のオブジェクト（`s3:GetObject`）へのアクセスを許可するポリシーを作成。

- ローカルの`index.html`ファイルの作成  
  - 簡易的なHTMLファイル（`Hello from S3 Bucket via CloudFront!`を表示）をローカルに作成。

- `index.html`をS3バケットにアップロード  
  - 作成した`index.html`をS3バケットにアップロード。  
  - 非公開設定（`private`）で保存。

- CloudFrontディストリビューションの作成  
  - S3バケットをオリジンとして設定。  
  - HTTPアクセスをHTTPSにリダイレクトする設定（`viewer_protocol_policy`）。  
  - 地理的制限を設定しない（`geo_restriction: none`）。  
  - デフォルトのCloudFront証明書を使用。  
  - キャッシュの設定を簡略化（GETとHEADリクエストのみ許可、クエリやクッキーの転送はなし）。  
  - バケット内の`index.html`をルートオブジェクトに設定。


## 作ったコードについて

```main.tf
provider "aws" {
  region = "ap-northeast-1" # 東京リージョン
}

# S3バケットの作成
resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-cloudfront-bucket-tokyo"
  acl    = "private" # バケットは非公開に設定（CloudFront経由でアクセス）

  tags = {
    Name        = "MyS3Bucket"
    Environment = "Production"
  }
}

# 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）を作成
resource "aws_cloudfront_origin_access_identity" "my_oai" {
  comment = "OAI for S3 bucket"
}

# S3バケットポリシー（CloudFrontからのアクセスを許可）
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}/*"
      }
    ]
  })
}

# 簡易的なindex.htmlファイルを作成
resource "local_file" "index_html" {
  content  = "<html><body><h1>Hello from S3 Bucket via CloudFront!</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ディストリビューションを作成
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" # HTTPをHTTPSにリダイレクト
  }

  restrictions {
    geo_restriction {
      restriction_type = "none" # 地理的制限なし
    }
  }

  price_class = "PriceClass_100"

  viewer_certificate {
    cloudfront_default_certificate = true # デフォルトのCloudFront証明書を使用
  }

  tags = {
    Name        = "MyCloudFrontDistribution"
    Environment = "Production"
  }
}
```

## まとめ
この記事は、自分用の備忘録としてまとめたものです。その点をご理解いただけると幸いです。

:::note info
***もし、この記事の内容が少しでも参考になれば嬉しく思います。***
:::

今後も同様の内容を継続して投稿していきますので、温かく見守っていただけるとありがたいです。

## おまけ

CloudFrontのディストリビューションドメイン名でアクセスすると、以下のように正常に表示されていることが確認できます。

![Screenshot 2025-01-24 at 14.06.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/a199851e-3052-f2aa-9adc-c4b5b5650a92.png)

一方、S3バケットに直接アクセスしようとすると、アクセスが拒否される設定になっているため、以下のようなエラーが表示されます。これは正常な動作です。

![Screenshot 2025-01-24 at 14.08.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3662571/fb935d63-9a2d-1163-ff9d-f35b01b1953d.png)