0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Terraform StateをAWS S3とDynamoDBで安全に管理するリモートバックエンド設計と移行手順

0
Posted at

Terraformを複数人のチームで運用する際、Stateファイル(terraform.tfstate)の管理方法は極めて重要です。Stateファイルをローカル環境で管理していると、競合によるインフラの破損や、機密情報の漏洩リスクが高まります。

この記事では、AWS環境においてS3とDynamoDBを組み合わせたセキュアなリモートバックエンドを構築し、既存のローカルStateを安全に移行する具体的な手順と設計テンプレートを解説します。

読者が抱える課題

  • 複数人で同時に terraform apply を実行した際、Stateの競合や先祖返りが発生する懸念がある。
  • Stateファイルに含まれるパスワードやAPIキーなどの機密情報が、ローカル環境やGitリポジトリに混入するリスクを排除したい。
  • 既存のローカルStateファイルを、本番環境に影響を与えずにリモートバックエンドへ移行する方法が分からない。

この記事で分かること

  • S3(暗号化・バージョニング)とDynamoDB(ロック制御)を用いたリモートバックエンドの設計・設定方法
  • ローカルStateからリモートバックエンドへの安全な移行手順
  • チーム運用におけるState管理のチェックリスト

対象読者・前提条件

  • Terraformの基本的な操作(init, plan, apply)を理解している方
  • AWSアカウントを保有し、適切なIAM権限(S3、DynamoDBの作成・操作権限)を持っている方
  • Terraform v1.0.0以降を使用している環境(本記事のコード例はTerraform v1.5.x以降を想定していますが、バージョンごとの公式ドキュメントも併せて参照してください)

リモートバックエンドの設計構成

安全なリモートバックエンドを構築するためには、以下の要素が必須です。

  1. S3バケット(Stateの保存先)
    • バージョニングの有効化: 誤ってStateを破損・削除した場合に過去のバージョンに復元できるようにします。
    • 暗号化(SSE-S3またはSSE-KMS): State内の機密情報を保護するため、保存時の暗号化を強制します。
    • パブリックアクセスのブロック: 外部からの不正アクセスを完全に遮断します。
  2. DynamoDBテーブル(排他制御・ロック用)
    • パーティションキー: LockID(文字列型)として定義します。これにより、同時に実行される apply 操作の競合を防ぎます。

実装コード例

1. バックエンド用リソースの作成(S3 & DynamoDB)

まず、Stateを保存するためのS3バケットと、ロック制御用のDynamoDBテーブルを作成します。これらは、管理対象のインフラとは別のライフサイクルで管理するか、手動または専用の初期化コードで作成することを推奨します。

# backend-resources.tf
provider "aws" {
  region = "ap-northeast-1"
}

# S3バケットの定義
resource "aws_s3_bucket" "terraform_state" {
  bucket        = "my-company-terraform-state-bucket" # 世界で一意なバケット名に変更してください
  force_destroy = false

  lifecycle {
    prevent_destroy = true
  }
}

# バージョニングの設定
resource "aws_s3_bucket_versioning" "state_versioning" {
  bucket = aws_s3_bucket.terraform_state.id
  versioning_configuration {
    status = "Enabled"
  }
}

# 暗号化の設定
resource "aws_s3_bucket_server_side_encryption_configuration" "state_encryption" {
  bucket = aws_s3_bucket.terraform_state.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

# パブリックアクセスのブロック
resource "aws_s3_bucket_public_access_block" "state_public_block" {
  bucket = aws_s3_bucket.terraform_state.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

# DynamoDBテーブルの定義(ロック管理用)
resource "aws_dynamodb_table" "terraform_locks" {
  name         = "my-company-terraform-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

2. バックエンド設定の適用

上記のリソースを作成後、管理対象のTerraformコード(例: main.tfproviders.tf)に以下のバックエンド設定を追加します。

# providers.tf
terraform {
  required_version = ">= 1.5.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }

  backend "s3" {
    bucket         = "my-company-terraform-state-bucket"
    key            = "global/s3/terraform.tfstate" # プロジェクトや環境ごとにパスを分けてください
    region         = "ap-northeast-1"
    dynamodb_table = "my-company-terraform-locks"
    encrypt        = true
  }
}

注意: backend ブロック内では変数の使用(var.xxx)が制限されているため、バケット名やキーは静的な文字列で記述する必要があります。


ローカルからリモートへの移行手順

既存のローカルState(terraform.tfstate)がある状態から、上記のリモートバックエンドへ安全に移行する手順です。

ステップ1: 事前バックアップ

作業前に、現在のローカルStateファイルを安全な場所にコピーしてバックアップを作成します。

cp terraform.tfstate terraform.tfstate.backup

ステップ2: バックエンド設定の記述

providers.tf などのファイルに、前述の backend "s3" ブロックを追記します。

ステップ3: 初期化とStateのアップロード

以下のコマンドを実行します。Terraformがバックエンドの変更を検知し、移行の確認を求めてきます。

terraform init

実行すると、以下のようなプロンプトが表示されます。

Do you want to copy existing state to the new backend?
  Pre-existing state was found while migrating the previous "local" backend to the
  newly configured "s3" backend. No existing state was found in the "s3" backend.
  Do you want to copy this state to the new "s3" backend? Enter "yes" to copy and
  "no" to start with an empty state.

  Enter a value:

ここで yes と入力すると、ローカルのStateファイルが自動的にS3バケットへアップロードされ、DynamoDBによるロック管理が有効になります。

ステップ4: ローカルファイルのクリーンアップ

移行が成功すると、ローカルの terraform.tfstate は不要になります。誤操作を防ぐため、ローカルファイルを削除するか、.gitignore に追加されていることを確認してください。


運用上の注意点とトラブルシューティング

1. ロックが解除されなくなった場合(State Lock Error)

apply の途中でプロセスが強制終了された場合など、DynamoDBのロックが残ったままになり、以降の操作がブロックされることがあります。

エラー例:

Error: Error acquiring the state lock

対処法:

  1. エラーメッセージに表示される ID(Lock InfoのID)を確認します。
  2. 以下のコマンドを実行して、強制的にロックを解除します。
    terraform force-unlock <LOCK_ID>
    
    ※この操作は、他のメンバーが実際に apply を実行していないことを確実に確認した上で行ってください。

2. Stateの分割(Workspaceまたはディレクトリ分割)

1つの巨大なStateファイルですべてのリソースを管理すると、影響範囲が広がり、実行速度も低下します。システムコンポーネント(例: ネットワーク、データベース、アプリケーション)ごとにディレクトリを分割し、Stateファイルを分ける設計を推奨します。


導入・運用チェックリスト

本番運用を開始する前に、以下の項目を満たしているか確認してください。

  • S3バケットのバージョニングが「有効(Enabled)」になっているか
  • S3バケットへのパブリックアクセスがすべてブロックされているか
  • S3バケットの暗号化(SSE)が有効化されているか
  • DynamoDBテーブルのハッシュキーが LockID(文字列型)で正しく作成されているか
  • .gitignore*.tfstate*.tfstate.backup が登録され、Git管理から除外されているか
  • 開発メンバーのIAMポリシーに、S3バケットへの読込/書込権限およびDynamoDBへのアクセス権限が適切に付与されているか

まとめ

Terraform StateをS3とDynamoDBによるリモートバックエンドで管理することは、チームで安全にIaCを実践するための標準的なアプローチです。競合や紛失のリスクを最小限に抑えるためにも、プロジェクトの初期段階でこの設定を導入することをお勧めします。

※AWSの仕様変更やTerraformのバージョンアップに伴い、設定パラメータが変更される場合があります。導入の際は必ず最新の Terraform公式ドキュメント(S3 Backend) をご確認ください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?