こしあん
2024-04-19

[Terraform]CloudFront+S3でホームページを作る


162{icon} {views}

CloudFrontちゃんと使ったことなかったので勉強用に、ChatGPTにTerraformを生成して、CloudFront+S3でホームページを作ってみました。

GPT Log

https://chat.openai.com/share/aa5e99ab-91c0-49a4-bc43-fc7422ea7fde

ChatGPT Plus使用

ディレクトリ構成

* index.html
* main.tf

ソース

index.html

<html>
    <body>
        <h1>Hello, World</h1>
        <h2>This is shikoan's page</h2>
    </body>
</html>

main.tf

terraform {
  backend "local" {
    path = ".cache/terraform.tfstate"
  }
}

provider "aws" {
  region  = "ap-northeast-1"
  profile = "develop"
}

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 = "*"
        Action = "s3:GetObject"
        Resource = "${aws_s3_bucket.my_bucket.arn}/*"
      }
    ]
  })
}

# S3 ACL
resource "aws_s3_bucket" "my_bucket" {
  bucket = "shikoan-homepage-bucket" # Enter your backet name
}

resource "aws_s3_bucket_ownership_controls" "bucket_ownership_control" {
  bucket = aws_s3_bucket.my_bucket.id
  rule {
    object_ownership = "BucketOwnerPreferred"
  }
}

resource "aws_s3_bucket_public_access_block" "bucket_public_access_block" {
  bucket = aws_s3_bucket.my_bucket.id

  block_public_acls       = false
  block_public_policy     = false
  ignore_public_acls      = false
  restrict_public_buckets = false
}

resource "aws_s3_bucket_acl" "my_bucket_acl" {
  depends_on = [
    aws_s3_bucket_ownership_controls.bucket_ownership_control,
    aws_s3_bucket_public_access_block.bucket_public_access_block,
  ]

  bucket = aws_s3_bucket.my_bucket.id
  acl    = "public-read"
}


resource "aws_s3_object" "index_html" {
  bucket = aws_s3_bucket.my_bucket.bucket
  key    = "index.html"
  source = "index.html" # "path/to/your/local/index.html"
#   acl    = "public-read"
  content_type = "text/html"
}

resource "aws_s3_bucket_website_configuration" "my_bucket_website" {
  bucket = aws_s3_bucket.my_bucket.id

  index_document {
    suffix = "index.html"
  }
}

# CloudFront
resource "aws_cloudfront_distribution" "s3_distribution" {
  origin {
    domain_name = aws_s3_bucket.my_bucket.bucket_regional_domain_name
    origin_id   = "S3-myBucket"

    s3_origin_config {
      origin_access_identity = "origin-access-identity/cloudfront/${aws_cloudfront_origin_access_identity.s3_oai.id}"
    }
  }

  enabled             = true
  is_ipv6_enabled     = true
  default_root_object = "index.html"

  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = "S3-myBucket"

    forwarded_values {
      query_string = false

      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "redirect-to-https"
    min_ttl                = 0
    default_ttl            = 3600
    max_ttl                = 86400
  }

  price_class = "PriceClass_100"

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }
}

resource "aws_cloudfront_origin_access_identity" "s3_oai" {
  comment = "OAI for ${aws_s3_bucket.my_bucket.bucket}"
}

output "s3_bucket_url" {
  value = "http://${aws_s3_bucket_website_configuration.my_bucket_website.website_endpoint}"
  description = "URL for the S3 bucket hosting the website"
}

output "cloudfront_distribution_url" {
  value = "https://${aws_cloudfront_distribution.s3_distribution.domain_name}"
  description = "URL for the CloudFront distribution"
}

結果

CloudFrontもS3も見ることができた(S3のバケットを全公開にしたのでそれはそう)。

ちなみにCloudFrontの画面はこんな感じ。初めて見たけど、オリジンがきちんとS3を向いている。

Terraformのコード1行で、CloudFrontでHTTP→HTTPSのリダイレクトが効いているのがいけてる。ACMなどは一切インストールしていない。

ハマりどころ

ChatGPTがdecryptedなTerraformのコードを書いてくる

例えば、最初の出してきたは、websiteもaclもDecrypted。このへんはTerraformの公式文書を見ながら書き直した

resource "aws_s3_bucket" "my_bucket" {
  bucket = "my-unique-bucket-name"
  acl    = "public-read"

  website {
    index_document = "index.html"
  }
}

バケットオブジェクトにACLを設定するとアップロードできない

resource "aws_s3_object" "index_html" {
  bucket = aws_s3_bucket.my_bucket.bucket
  key    = "index.html"
  source = "index.html" # "path/to/your/local/index.html"
#   acl    = "public-read"
  content_type = "text/html"
}

このようにかけばローカルのindex.htmlを、S3にアップロードできるが、aclを設定するとアップロードに失敗する。

出てきたホームページが403

S3のダイレクトのリンクも、CloudFrontのリンクも403を出す。

これはS3のバケットポリシーを書いていなかったためで、追加したら表示できるようになった。

感想

ChatGPT+Terraformはそんなにハマることはないけど、これは割とハマったほうかな

1回でterraform applyが通らないこともあるので、2回やるとうまくいくと思う。

勉強用なので、完了したらterraform destroy。ちゃんと使うならS3バックエンドがいいと思う。



Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内

技術書コーナー

北海道の駅巡りコーナー


One Comment

Add a Comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です