💭

Terraform初期設定の備忘録

2023/06/01に公開

新規開発でのTerraformの初期設定に手こずったのでまとめておきます。

目標

1. tfstateファイルをS3に保存する設定

2. 静的コンテンツ用のS3の作成

3. CloudFrontの作成

ディレクトリ構成

全ての設定を一つのファイルに書くことも可能ですが、可読性とメンテナンス性を考慮して、リソースごとにファイルを分けています。

terraform/
├── .gitignore/
├── common/
│   ├── cloudfront.tf
│   ├── s3.tf
│   └── variables.tf
└── envs/
    ├── dev/
    │   └── main.tf
    ├── stg/
    │   └── main.tf
    └── prd/
        └── main.tf

開発が進むにつれて、必要に応じて新たなAWSリソースの設定を追加していきますが、初期設定としては上記で問題なかったです。

1. tfstateファイルをS3に保存する設定

S3バケットを手動で作成

tfstateファイル(Terraformの状態ファイル)の保存先であるバケットは事前に存在する必要があるため、ここで使用するS3バケットはAWSのマネージメントコンソールから手動で作成します。

AWS Providerの設定

AWSをTerraformで使用するための設定です。
手動で作成したS3バケットはここで保存先に設定されます。

envs/dev/main.tf
# バックエンドとしてS3を選択。Terraformの状態管理ファイル(tfstate)がS3バケットに保存される。
terraform {
  backend "s3" {
    bucket = "手動で作成したS3バケット名"
    key    = "terraform.tfstate"
    region = "ap-northeast-1"
  }
}

# AWSをクラウドプロバイダとして指定。
provider "aws" {
  region = "ap-northeast-1"
}

# commonモジュールを作成。設定は「../../common」に格納されたTerraform設定ファイルで定義される。
module "common" {
  source   = "../../common"
  env_name = "dev"  # 変数としてモジュール内部で利用できる。環境に合わせてstg,prdに変更。
}

※おまけ

.gitignore
.terraform  # ローカルでの「terraform init」で生成されるファイル
terraform.tfstate.d  # tfstateファイルは機密情報を含む可能性あり

2. 静的コンテンツ用のS3の作成

s3.tf
resource "aws_s3_bucket" "for_client" {
  bucket_prefix = "何らかのプレフィックス"  # 指定したプレフィックスで始まるユニークなバケット名を作成
}


# バケットに対するアクセスを制御するためのポリシーを定義
resource "aws_s3_bucket_policy" "for_client" {
  bucket = aws_s3_bucket.for_client.id
  policy = data.aws_iam_policy_document.for_client.json
}


# AWS IAMポリシーのJSONドキュメントを作成する
data "aws_iam_policy_document" "for_client" {
  statement {
    sid    = "Allow CloudFront"  # ポリシーステートメントの識別子
    effect = "Allow"  # ステートメントで許可されるアクション
    # アクセス元の設定
    principals {
      type        = "AWS"
      identifiers = [aws_cloudfront_origin_access_identity.for_client.iam_arn]  # CloudFrontに適用
    }
    # バケットに対して制御するアクションを設定
    actions = ["s3:GetObject"]  # オブジェクトの読み取りアクション。
    # アクセス先の設定
    resources = [
      "${aws_s3_bucket.for_client.arn}/*"  # 作成したバケット内のすべてのオブジェクトに適用
    ]
  }
}

新しいS3バケットを作成し、そのバケットにCloudFrontを通じたオブジェクト取得のみを許可する設定をしています。

3. CloudFrontの作成

ちょっと長いです。

cloudfront.tf
resource "aws_cloudfront_distribution" "cf" {
  # Route53でCloudFrontをエイリアス先に設定することで、既に管理しているドメインでCloudFrontにアクセスできる
  # aliases = "ドメイン名"  # 未設定なのでコメントアウト

  # 配信のコンテンツ元(ここではS3バケット)を指定
  origin {
    domain_name = aws_s3_bucket.for_client.bucket_regional_domain_name
    origin_id   = aws_s3_bucket.for_client.id
    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.for_client.cloudfront_access_identity_path
    }
  }

  enabled             = true  # 配信を有効
  is_ipv6_enabled     = true  # IPv6を有効
  default_root_object = "index.html"  # デフォルトのルートオブジェクト

  # デフォルトのキャッシュ動作を定義
  default_cache_behavior {
    allowed_methods  = ["GET", "HEAD"]
    cached_methods   = ["GET", "HEAD"]
    target_origin_id = aws_s3_bucket.for_client.id

    # リクエストと一緒にオリジンサーバー(S3バケット)に送る情報を指定
    forwarded_values {
      query_string = false

      cookies {
        forward = "none"
      }
    }

    viewer_protocol_policy = "redirect-to-https"  # HTTPS通信のみ許可する。

    # キャッシュのTTL設定
    min_ttl     = 0  # 0s
    default_ttl = 86400  # Cache-Control or Expires がリクエストのヘッダーに無い時のデフォルトのTTL。1日。
    max_ttl     = 31536000  # 365日
  }


  # 地理的な制限を設定。noneなので制限なし。
  restrictions {
    geo_restriction {
      restriction_type = "none"
    }
  }

  # SSL証明書の設定
  viewer_certificate {
    cloudfront_default_certificate = true  # CloudFrontが提供するデフォルトのSSL証明書を使用
    # ACMで作成した証明書を使用する。その場合cloudfront_default_certificateはfalseにする。
    # acm_certificate_arn            = aws_acm_certificate.cert.arn  # 未設定なのでコメントアウト
    ssl_support_method       = "sni-only"
    minimum_protocol_version = "TLSv1"
  }

  # カスタムエラーレスポンス("403: Forbidden"の時に"/"に200で飛ばす)
  custom_error_response {
    error_code         = 403  # Cloudfront→S3の構成で存在しないファイルパスを叩くと403エラー
    response_code      = 200
    response_page_path = "/"
  }
}

# CloudFrontがオリジン(S3バケット)にアクセスするための特別なユーザーを作成
resource "aws_cloudfront_origin_access_identity" "for_client" {}

感想

Terraformはまだまだ設定することはありますが、とりあえず「デプロイできる環境を構築する」ことに必要な設定を今回深掘りできてよかったです。

参考

https://katsuya-place.com/terraform-cloudfront/
https://dev.classmethod.jp/articles/static-web-with-cf-s3-tf/
https://zenn.dev/redgosho/articles/13b93d2a8eac0f

GitHubで編集を提案
エックスポイントワン技術ブログ

Discussion