概要
従来のTerraformにおいて、AWS S3をバックエンドとして状態(terraform.tfstate)を管理する際、排他ロック(State Locking)機能を実現するためにはDynamoDBテーブルの作成が必須でした。
しかし、Terraform 1.10以降ではS3の条件付き書き込み(Conditional Writes)を利用したS3ネイティブのロック機能(use_lockfile = true)がサポートされました。これにより、DynamoDBを使用することなく、S3バケットのみで安全な状態管理と排他ロックが完結するようになっています。
本記事では、S3のみでTerraformの状態管理を行うための最小限のコード構成と、パブリックリポジトリ管理を意識したバックエンド設定手順を解説します。
前提条件
- Terraform
v1.10.0以上 - AWS Provider
v6.0以降(推奨)
1. 状態管理用のS3
Stateを保持するS3バケットと、事故防止のためのバージョニング設定のみを記述します。
provider "aws" {
region = var.aws_region
}
variable "aws_region" {
type = string
default = "ap-northeast-1"
}
variable "s3_bucket_name" {
type = string
description = "Terraform State保存用のS3バケット名"
}
# 1. State保存用S3バケット
resource "aws_s3_bucket" "terraform_state" {
bucket = var.s3_bucket_name
force_destroy = true # 破棄時に過去バージョン含めて一括削除を可能にする設定
}
# 2. バージョニングの有効化(必須推奨)
resource "aws_s3_bucket_versioning" "versioning" {
bucket = aws_s3_bucket.terraform_state.id
versioning_configuration {
status = "Enabled"
}
}
2. backend.tf(バックエンド定義)
use_lockfile = true を指定することで、DynamoDBなしでのS3ネイティブロックが有効化されます。バケット名やKeyなどの可変値は初期化コマンド実行時に外部から注入するため、記述を省略します。
terraform {
required_version = ">= 1.10.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
backend "s3" {
region = "ap-northeast-1"
use_lockfile = true # S3ネイティブロックを有効化(DynamoDB不要)
}
}
バックエンド用のS3バケットが未作成の状態で backend "s3" を有効にしたまま terraform init を実行するとエラーになるため、事前に状態管理用のS3を作ってから、作成したいリソースを構築します。
GitHub Actions(CI/CD)での運用
パブリックリポジトリ等でS3バケット名をコードに直接記述したくない場合は、GitHub Secretsにバケット名を登録し、terraform init 実行時に注入します。
- name: Terraform Init
run: |
terraform init \
-backend-config="bucket=${{ secrets.TF_STATE_BUCKET }}" \
-backend-config="key=envs/dev/terraform.tfstate"
運用上の留意点
-
S3バージョニングの有効化
S3単体での管理では、terraform apply失敗時や誤操作によるState破損からの回復手段としてS3のバージョニング機能が重要となります。特別な理由がない限りstatus = "Enabled"に設定することが推奨されます。 -
S3バケット名・アカウントIDの秘匿
パブリックリポジトリにおいて、S3バケット名やAWSアカウントIDを直接コードに記述することはDoS攻撃(リクエスト大量発生による課金)やセキュリティ上の情報漏洩リスクに繋がります。-backend-configオプションや環境変数を併用し、コード内から分離します。