こつつみ

コツコツ積み上げる

【Terraform】CloudFront+S3をOAIで公開する

Terraformに入門してみました。業務ではCloudFormationを使っております。 正直どちらも変わらないと思っていましたが、 Terraformの良さを身に染みて感じました。

今回はNuxt.jsで作ったTwitterCloneアプリをSinglePageApplicationとしてCloudFront+S3に公開することにしました。そのリソースをTerraformで作成したので残します。

CloudFront+S3を使うにあたって、2022年8月よりオリジンアクセスコントロール (OAC)で公開することが推奨されています。

Amazon CloudFront オリジンアクセスコントロール(OAC)のご紹介 | Amazon Web Services ブログ]

CloudFront+S3をTerraformで作成する

AWS上のProfileを使用してリソース作成を行いました。

# provider.tf

# 変数定義
variable "aws_profile" {}


# ====================
#
# Provider
#
# ====================
provider "aws" {
  profile = var.aws_profile
  region  = "ap-northeast-1"
}

var.aws_profileには環境変数が入ります。環境変数は拡張子が.tfvaars のファイルを用意すると自動で読み込まれます。

terraform.rfvars

aws_profile  = "admin"  # ご自身の使用するProfileを指定してください

CloudFrontの定義は以下になります。

# cloudfront.tf

resource "aws_cloudfront_distribution" "main" {
  enabled = true
  default_root_object = "index.html"

  origin {
    origin_id                = aws_s3_bucket.main.id
    domain_name              = aws_s3_bucket.main.bucket_regional_domain_name
    origin_access_control_id = aws_cloudfront_origin_access_control.main.id
  }

  viewer_certificate {
    cloudfront_default_certificate = true
  }

  default_cache_behavior {
    target_origin_id       = aws_s3_bucket.main.id
    viewer_protocol_policy = "redirect-to-https"
    cached_methods         = ["GET", "HEAD"]
    allowed_methods        = ["GET", "HEAD"]
    forwarded_values {
      query_string = false
      headers      = []
      cookies {
        forward = "none"
      }
    }
  }

  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }
}

resource "aws_cloudfront_origin_access_control" "main" {
  name                              = "twitter-clone-oac"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

S3は以下で定義します。

# s3.tf 


resource "aws_s3_bucket" "main" {
  bucket = "twitter-clone.uesho.com"

  tags = {
    Name = "twitter-clone"
  }
}

resource "aws_s3_bucket_acl" "main" {
  bucket = aws_s3_bucket.main.id
  acl    = "private"
}

resource "aws_s3_bucket_public_access_block" "main" {
  bucket                  = aws_s3_bucket.main.id
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_s3_bucket_policy" "main" {
  bucket = aws_s3_bucket.main.id
  policy = data.aws_iam_policy_document.s3_main_policy.json
}

data "aws_iam_policy_document" "s3_main_policy" {
  statement {
    principals {
      type        = "Service"
      identifiers = ["cloudfront.amazonaws.com"]
    }
    actions   = ["s3:GetObject"]
    resources = ["${aws_s3_bucket.main.arn}/*"]
    condition {
      test     = "StringEquals"
      variable = "aws:SourceArn"
      values   = [aws_cloudfront_distribution.main.arn]
    }
  }
}

ここまで作成できたら、以下のコマンドを打つことでAWS上にリソースが作成されます。

# 初期化
$ terraform init    

# フォーマットをかける (必要なら行なってください)
$ terraform fmt

# 変更の差分を確認する
$ terraform plan

# リソースの作成を行う
$ terraform apply

実際にリソースが作成されていることが確認できると思います。 Terraformはコマンド1発で作ってくれるのは非常に良いですね。また、細かいオプション等を覚えなくて良いのが非常に体験として良かったです。

業務ではCloudFormationですが、業務外ではTerraformを積極的に使っていきたいと思います。