1. 概要
この記事では、以下の内容を解説します。
- Terraform Stateファイル(
terraform.tfstate)の役割と構造 - StateとAWSの実際のリソースの関係
- Stateが壊れたときのリスクと対処法
terraform stateコマンドでStateを操作する方法- Stateファイルにおけるsensitiveデータのリスクと対策
- State Lockによる同時実行防止の仕組み
Terraform Stateは「Terraformが管理するインフラの現在の状態を記録したファイル」です。Stateがなければ、Terraformはどのリソースを作成済みなのかを判断できません。Stateの正しい理解と管理は、Terraformを安全に運用するうえで最も重要な知識の一つです。
2. Stateとは何か
Terraformはコードを書いたあと、以下の流れでインフラを管理します。
1. HCLコード(.tf) ← 「あるべき姿」を定義
2. State(.tfstate) ← 「前回applyした状態」を記録
3. AWSの実際のリソース ← 「現在の実態」
terraform plan = コード vs State を比較して差分を計算
terraform apply = 差分をAWSに適用してStateを更新
StateがないとTerraformは「何を作ったか」を知る方法がないため、毎回すべてのリソースを再作成しようとします。
Stateファイルの場所
| バックエンド | 保存場所 |
|---|---|
| local(デフォルト) | プロジェクトディレクトリのterraform.tfstate |
| S3バックエンド | 指定したS3バケット + key |
| Terraform Cloud | Terraform Cloudのサーバー |
チーム開発では必ずS3などのリモートバックエンドを使います(詳細は「backendの設定方法」参照)。
3. Stateファイルの構造
terraform.tfstateはJSON形式のファイルです。実際の中身を見てみます。
{
"version": 4,
"terraform_version": "1.9.0",
"serial": 5,
"lineage": "a1b2c3d4-...",
"outputs": {
"instance_id": {
"value": "i-0abc1234def56789",
"type": "string"
}
},
"resources": [
{
"mode": "managed",
"type": "aws_instance",
"name": "web",
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [
{
"schema_version": 1,
"attributes": {
"id": "i-0abc1234def56789",
"ami": "ami-0123456789abcdef0",
"instance_type": "t3.micro",
"tags": {
"Name": "web",
"Environment": "dev"
}
// ... すべての属性が記録される
}
}
]
}
]
}
⚠️ 重要: Stateファイルにはすべてのリソース属性が平文で記録されます。
sensitive = trueのoutputやパスワードも例外ではありません。Stateファイルをバージョン管理(Git)にコミットしないでください。
4. Stateとリソースの対応関係
TerraformはStaeteのresourcesセクションでリソースを管理します。リソースのアドレス(aws_instance.webなど)がStateのキーになります。
Stateのリソースアドレス
# 通常のリソース
aws_instance.web
# countを使った場合
aws_instance.servers[0]
aws_instance.servers[1]
# for_eachを使った場合
aws_instance.servers["web"]
aws_instance.servers["app"]
# モジュール内のリソース
module.vpc.aws_vpc.main
module.ec2.aws_instance.app
5. terraform stateコマンド
Stateを直接操作するコマンドです。通常の運用では使いませんが、リソースのインポートや修正作業で使います。
state list — Stateのリソース一覧
# Stateで管理しているリソースをすべて表示
terraform state list
# 出力例
aws_instance.web
aws_security_group.main
module.vpc.aws_vpc.main
module.vpc.aws_subnet.public["ap-northeast-1a"]
state show — リソースの詳細を表示
# 特定リソースの全属性を表示
terraform state show aws_instance.web
# 出力例
# aws_instance.web:
resource "aws_instance" "web" {
ami = "ami-0123456789abcdef0"
id = "i-0abc1234def56789"
instance_type = "t3.micro"
private_ip = "10.0.1.10"
tags = {
"Environment" = "dev"
"Name" = "web"
}
# ...
}
state rm — StateからリソースをState管理から外す
# リソースをStateから削除(AWSのリソース自体は消えない)
terraform state rm aws_instance.web
# for_eachリソースの一部を外す
terraform state rm 'aws_instance.servers["web"]'
⚠️ 用途: Terraform管理外に移したいとき(手動管理に戻すなど)に使います。
state rm後にそのリソースが.tfコードに残っていると、次のplanで「新規作成」と判断されます。
state mv — State内でリソースアドレスを変更
# リソースの名前変更(コードを変えたときにStateを合わせる)
terraform state mv aws_instance.old aws_instance.new
# モジュール間の移動
terraform state mv aws_instance.web module.ec2.aws_instance.web
💡 注意: Terraform 1.1以降では
state mvよりmovedブロックを使うことが推奨されています。movedブロックはコードで宣言的に管理できるため、チームでの作業に適しています。
state pull / push — Stateを直接取得・更新
# リモートバックエンドのStateをローカルに取得
terraform state pull > backup.tfstate
# ローカルのStateをリモートバックエンドに強制アップロード(危険)
# terraform state push backup.tfstate ← 通常は使わない
6. terraform import — 既存リソースをState管理下に取り込む
手動で作成したリソースをTerraform管理下に移行するにはterraform importを使います。
# HCLコードに定義したリソースに既存のAWSリソースをインポート
terraform import aws_instance.web i-0abc1234def56789
手順:
# ステップ1: まずHCLコードにリソースを定義する
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux_2023.id
instance_type = "t3.micro"
tags = {
Name = "web"
Environment = "prod"
ManagedBy = "terraform"
}
}
# ステップ2: 既存のEC2インスタンスIDを指定してインポート
terraform import aws_instance.web i-0abc1234def56789
# ステップ3: planを実行して差分がないか確認
terraform plan
# → HCLコードと実際のリソースが一致していれば "No changes"
7. Stateに関するリスクと対策
リスク1: Stateファイルのセキュリティ
⚠️ Stateには以下の機密情報が平文で含まれる可能性があります:
- RDSのマスターパスワード
- IAMアクセスキー
- random_passwordで生成したパスワード
- sensitive = true のoutput値
対策:
- Gitの
.gitignoreに<em>.tfstateと</em>.tfstate.backupを追加する - S3バックエンドで保存時暗号化(
encrypt = true)を有効にする - S3バケットのパブリックアクセスをブロックする
- IAMでStateファイルへのアクセスを最小権限に制限する
リスク2: Stateの破損・消失
⚠️ Stateが消えると、TerraformはAWSのリソースを「存在しない」と判断して
次のapply時に再作成しようとします(データが消える危険があります)。
対策:
- S3バックエンドでバージョニングを有効にする(以前のStateに戻せる)
- 作業前に
terraform state pull > backup.tfstateでバックアップを取る
リスク3: 同時実行によるState破損
⚠️ 2人が同時にapplyするとStateファイルが上書きされて壊れる可能性があります。
対策:
- DynamoDBによるState Lockを必ず設定する(S3バックエンドの
dynamodb_table指定) - CIからのapplyを一本化して並行実行を防ぐ
8. 関連記事
- backendの設定方法 — Stateのリモート管理(S3+DynamoDB)
- terraform init / plan / apply / destroyの使い方 — applyによるState更新の流れ
- output(出力値)の使い方 — sensitive outputとStateへの記録
- lifecycleブロックの使い方 —
prevent_destroyでStataから削除されないようにする - terraform state コマンド完全ガイド
- workspace — 同一コードで複数環境を管理
9. まとめ
- Stateは「前回applyした状態」を記録するJSON。Terraformはこれとコードの差分を計算する
- ローカル保存はチーム開発に不向き。S3バックエンド + DynamoDB Lockが定番
- Stateには機密情報が平文で含まれる。Gitにコミット禁止・S3暗号化が必須
terraform state list/show/rm/mvでStateを直接操作できる(通常作業では使わない)- 既存リソースのインポートは
terraform import。Terraform 1.5以降はimportブロックも使える - Stateの消失・破損に備えてS3バージョニングと作業前のバックアップを徹底する
動作確認バージョン: Terraform >= 1.9 / AWS Provider ~> 5.0 対象リージョン: ap-northeast-1(東京) 公式ドキュメント: https://developer.hashicorp.com/terraform/language/state