Terraform state管理の設計 — チーム構築で最初に決めること

Terraformを使ったチーム構築でstate管理の設計を後回しにすると、環境が3本を超えたあたりから取り返しのつかない事故が起きます。「どこにstateを置くか」「どの粒度で分割するか」「誰がロックを解除できるか」——これらはリソースを1個作る前に決めておくべき設計上の約束事です。本記事では、チームで本番環境を構築する際に最初に固定しなければならないstate管理の設計判断を、アンチパターンと比較の両面から体系的に整理します。

stateを軽視した構築が事故る構造

ローカルstateが招くコンフリクトの実態

Terraformのstateファイル(terraform.tfstate)は、Terraformが管理するリソースの現在の状態を記録したJSONファイルです。このファイルが複数人の手元に分散している状態でapplyを繰り返すと、誰の手元のstateが「正」なのかが分からなくなります。構築を任されたある担当者は、3人のチームでローカルstateを使い続けた結果、本番VPCが二重に作成されていたことを数週間後に発見したといいます。GCPやAWSを問わず、このパターンで事故を経験した現場の話はよく聞きます。チームの人数が増えるほどコンフリクトの頻度は高まり、「最後にapplyした人のstateが正になる」という非常に危うい状態が構造的に生まれます。設計の議論よりも先にリソース作成を始めてしまったチームが、後から共通認識のなさに気づくというパターンは繰り返されています。

stateとリソースの乖離が「幽霊リソース」を生む

stateに記録されていないリソース——いわゆる「幽霊リソース」——は、Terraformの管理外となるため削除も変更も追跡もできなくなります。誰かがコンソールやCLIから手動でリソースを作成・削除した瞬間に、stateとの乖離が発生します。この乖離を放置すると、次のterraform planでドリフトが検知されるどころか、依存するリソースのapplyが失敗する事態に発展するケースもあります。規模が大きくなるほど乖離の発見が遅れ、修正コストが跳ね上がります。20台規模のサーバーを管理するプロジェクトでも、半年後には手動変更の痕跡が数十か所に及んでいた、という事例は珍しくありません。「Terraformで管理しているはずなのに実態が分からない」という状況は、最初のstate設計の甘さから始まっています。

事故パターンを先に把握して設計に活かす

state管理で起きる事故には共通したパターンがあります。①stateの上書き(2人が同時にapplyして片方の変更が消える)、②stateの紛失(ローカルファイルの誤削除やリポジトリへのコミット漏れ)、③stateの破損(apply途中の中断でpartial stateが残る)——この3つがほぼすべての原因を占めます。設計段階でこれらを「起きるもの」として前提に置き、防ぐ仕組みをバックエンド選定・ロック設計・バックアップ設計に組み込む必要があります。事故が起きてから対策を入れると、対処コストが新規設計の3〜5倍になることも珍しくありません。アンチパターンを先に知っておくことが、設計判断の精度を上げる最短経路です。

ローカルstate vs リモートstate — チームで持つなら

ローカルstateが成立する唯一の条件

ローカルstateが許容されるのは、事実上「1人が1環境を専有して管理する」場面だけです。個人の検証環境や短期のPoCで使い捨てる構成であれば問題は起きにくいです。しかしチームが2人以上になった瞬間、またはCI/CDパイプラインを通じた自動applyを仕込んだ瞬間に、ローカルstateは設計上の負債になります。「とりあえず動かす」判断でローカルstateを採用したプロジェクトは、後からリモートバックエンドへ移行する際にstateのimportやmvが必要になり、数日分の工数をそこに投入することになりがちです。初期コストを惜しんだ分の代償が、移行時に集中して返ってくる構造を理解しておく必要があります。最初にリモートバックエンドを用意する手間は、後の移行コストと比較すれば明らかに小さいです。

リモートstateバックエンドの選定基準

リモートstateバックエンドを選ぶ際の判断軸は「ロック機構の有無」「保存データの暗号化」「バージョニング」「アクセス制御の粒度」の4点です。AWS環境ならS3とDynamoDBの組み合わせが標準的な選択肢で、DynamoDBがロックを担い、S3がバージョニングと暗号化を提供します。GCP環境ならCloud Storage(GCS)が組み込みでロックをサポートし、Azure環境ではAzure Blob Storageが対応します。HashiCorp Terraform Cloudはロック・バージョニング・アクセス制御を一体で提供しますが、外部SaaSへの依存をポリシー上避けたい場合はクラウドネイティブのバックエンドを選ぶことになります。どの選択肢もそれぞれの前提条件に合致する場面があるため、チームの構成とクラウド環境を照合して決定します。

バックエンド別の特性比較

各バックエンドの特性を横断的に比較すると、選定の判断軸が整理しやすくなります。特にロック機構の有無と暗号化の設定方式は、セキュリティ要件と直結するため最優先で確認すべき項目です。

バックエンド ロック機構 バージョニング 暗号化 主な採用場面
ローカル(tfstate) なし なし なし 個人検証・使い捨てPoCのみ
S3 + DynamoDB DynamoDBで実現 S3バージョニング SSE-S3 / SSE-KMS AWS中心のチーム構築
GCS(Cloud Storage) 組み込み オブジェクト世代管理 Google管理鍵 / CMEK GCP中心のチーム構築
Azure Blob Storage 組み込み(Leaseベース) Blobバージョニング Azure管理鍵 / BYOK Azure中心のチーム構築
Terraform Cloud 組み込み 状態履歴・UI閲覧可 Transit Encryption SaaS依存を許容できるチーム

state分割の粒度をどこで切るか(環境/コンポーネント)

環境軸での分割(dev/stg/prod)

最もシンプルな分割単位は「環境」です。dev・stg・prodをそれぞれ別のstateファイルに分離することで、prod環境へのapplyがdev環境のstateに影響を与えるリスクをゼロにできます。ディレクトリ構造では環境ごとにbackend設定ファイルを持たせ、各環境が独立したstateバケットまたはプレフィックスを参照する形にするのが一般的です。ただし環境間で共有するリソース(VPC・IAMポリシー・Route53ゾーンなど)をどのstateに置くかは、最初に明示的に決めておかないと後から整理が困難になります。「共有リソース専用state」を設けて下位環境から参照させる構成が、依存関係の明確化という点では設計としてすっきりします。この共有stateをどの環境が「所有」するかも、変更の権限管理と合わせて初期設計で固めておく必要があります。

コンポーネント軸での分割(レイヤー分割)

環境軸だけでは不十分な場合、コンポーネント(レイヤー)軸を加えます。ネットワーク層・セキュリティ層・データ層・アプリ層のように責任範囲でstateを分けると、変更の影響範囲が明確になり、意図しないリソースへの変更を構造的に防げます。たとえばVPCを管理するstateとEC2を管理するstateを分離すれば、アプリ層の変更がネットワーク設定に波及するリスクを排除できます。この構造では`terraform_remote_state`データソースを使って上位レイヤーのアウトプットを下位レイヤーで参照する形になるため、依存関係が単方向になっているかを設計段階で確認しておくことが重要です。依存の循環が生まれると、applyの順序が破綻してどちらも実行できない状態に陥ります。

分割粒度を間違えた場合のリスク

粒度が細かすぎると「stateをまたぐ参照」が増えすぎてapplyの順序管理が複雑になり、粒度が粗すぎるとstateファイルが肥大化してplanの実行時間が延びます。リソースが30〜50個を超えてくるとplanに数分かかることがあり、CI/CDでの待ち時間が積み重なると開発体験が著しく下がります。適切な粒度の目安として、1つのstateファイルで管理するリソースが20〜40個程度、applyが5分以内に完了する範囲を基準にする現場も多いです。この範囲を超えてきたら分割を検討し、モジュール境界を先に定義してから分割作業に入る順序を守ることが、移行作業を安全に進める前提になります。

■ この設計判断を深める一冊[PR]

実践Terraform AWSにおけるシステム設計とベストプラクティス(野村友規/NextPublishing)

本記事の設計判断を、AWS上のIaC実装に落とし込む実務書です。state設計やベストプラクティスを手を動かして確かめたい構築担当者に向いています。

Amazonで見る →

ロック・排他制御の設計(同時applyをどう防ぐか)

ロック機構の仕組みと設計上の前提

S3+DynamoDBの構成では、applyを実行するとDynamoDBにロックレコードが書き込まれ、同じstateを参照する別のapplyがそのレコードを検知してエラーで弾かれる仕組みです。この機構はTerraformのクライアントサイドで実装されているため、DynamoDBを誤って削除したりロックレコードを手動で消したりすると、排他制御が機能しない状態になります。設計上の前提として「ロックテーブル自体も保護すべき管理対象」と捉え、削除・変更の権限をIAMポリシーで厳格に制限することが求められます。ロック機構は防御の第一層であり、それだけに頼る設計は脆いという認識を持っておく必要があります。GCSやAzure Blob Storageの場合は組み込みのロック機構が動きますが、動作原理と限界を把握した上で設計に組み込むことが重要です。

CI/CDパイプラインでの排他設計

GitHub ActionsやGitLab CIでterraform applyを自動化する場合、CI側でも排他制御を組む必要があります。Terraformのロック機構だけでは「ロック取得を待つキュー」が存在しないため、同時にトリガーされたジョブが双方タイムアウトまで待ち続けるケースが起きます。GitHub Actionsのconcurrency設定やGitLab CIのresource_groupを使って、同一stateに対するジョブが同時に走らないよう制御する設計が必要です。パイプライン側のロックとTerraform側のロックを二層で持つことが、安全な自動化の基本的な設計パターンになります。この二層設計を省くと、ロック競合によるapply失敗がCI上で頻発し、手動解除の作業が定常化してしまいます。自動化の恩恵を受けるためにこそ、排他制御の設計に手を抜かないことが求められます。

ロック解除の権限設計

ロックが意図せず残った場合(apply中にプロセスが強制終了した場合など)、ロックを解除する操作が必要になります。この操作を誰でも実行できる状態にしておくと、排他制御の意味が失われます。ロック解除はインフラチームのリードや専任者に限定し、解除時は作業ログに理由・時刻・担当者を残すルールを設計段階で先に決めておきます。DynamoDBの場合はIAMポリシーでロックテーブルへの書き込み権限を制限することで、人的ミスによる不正な解除を構造的に防げます。ロックが長時間残った場合のアラート設定も合わせて検討することで、異常状態の早期発見につながります。誰がいつ解除できるかという権限設計を後回しにしているチームで、障害対応時に混乱が生じる例はよく見られます。

機密値をstateにどう扱うかの判断

stateに機密値が残る構造的な問題

Terraformはデータベースのパスワード・APIキー・証明書の秘密鍵などの機密情報を、stateファイルにプレーンテキストで書き込むことがあります。S3バックエンドでバージョニングが有効な場合、過去のすべてのstateバージョンにアクセスできるため、一度stateに書き込まれたパスワードはローテーション後も過去バージョンとして残り続けます。「stateにアクセスできる人=その機密値を読める人」という設計上の制約を最初に認識しておかないと、不用意にstateへのアクセス権限を広げたときに情報漏洩リスクが発生します。stateへのアクセス権限の設計は、機密値の扱いと一体で考える必要があります。この前提を持たずに構築を進めてしまうと、後からアクセス制御を締め直す作業が発生し、開発フローの見直しが必要になります。

機密値を分離するアーキテクチャ判断

機密値をstateに書き込まないための設計として、AWS Secrets ManagerやGCP Secret Managerを使ってTerraformの外で機密値を管理し、Terraformはリソースの「作成と参照の構造」だけを担う構成にする方法があります。データベースのパスワードであれば、Terraformではシークレットの保存先リソースだけを作成し、パスワードの値そのものはシークレットマネージャー上で管理します。この設計を採用すると、stateに残る機密値の種類を大幅に絞り込めます。ただし参照アーキテクチャが増えるため、アプリケーション側がシークレットを取得するフローの設計も同時に整理する必要があります。「Terraformで何を管理し、何を管理しないか」の境界を最初に決めておくことが、この設計判断の核心です。

stateファイル自体の暗号化設計

stateに機密値が入ることを完全に排除できない場合、ファイル自体の暗号化設計が最後の防御線になります。S3バックエンドではSSE-S3またはSSE-KMSによる暗号化を設定でき、機密レベルが高い本番環境ではKMS管理鍵(SSE-KMS)を使い、キーのローテーションポリシーとCloudTrailによるアクセスログを組み合わせる設計が推奨されます。GCSの場合はデフォルトでGoogle管理鍵による暗号化が有効になっていますが、CMEK(顧客管理鍵)への切り替えが必要かどうかは組織のセキュリティポリシーと照合して設計段階で決めます。暗号化の設定は後から変更できても、既存stateの再暗号化には作業コストがかかるため、初期設定の段階で確定させることが重要です。

state移行・リファクタの安全手順の設計思想

state移行が必要になる場面

リポジトリ構成の見直しやチームの分割、モジュール化の推進など、構築フェーズが進むとstateの移行が必要になることは珍しくありません。「最初に決めたstate分割では粒度が粗すぎた」という判断が半年後に生まれるのは、ある程度避けられない現実です。問題はそのタイミングで移行作業のコストを見誤ることで、50リソースを超えたstateの移行には1日〜数日分の工数を見込む必要があります。設計段階では「将来の移行コスト」を意識した命名規則とモジュール境界の設定も判断材料に入れておくことで、後工程での手戻りを構造的に減らせます。変更に強い構造を最初から意識しておくことが、長期的な運用の安定につながります。

state操作の安全設計思想

terraform state mvやterraform state rmなどの操作は、実行前にstateのバックアップを必ず確保する設計を徹底します。S3バックエンドならバージョニングがバックアップを担いますが、操作前後のstateバージョンIDを手元に記録しておくことで、問題が起きた場合に特定バージョンへの巻き戻しがスムーズになります。また、移行作業はCI/CDを一時停止した状態で行い、作業中に他のメンバーがapplyを走らせないよう事前にチームへ周知することが設計外のミスを防ぐ鍵になります。手を動かす手順の詳細はRunbookに落とすとして、設計段階で決めるのは「いつ・誰が・どの権限で・どの範囲で行う」という実施ルールです。このルールが存在しないまま移行作業に入った現場で、作業後に想定外のリソース削除が発生した、という話はよく聞きます。

リファクタを安全にするモジュール境界の設計

state移行のコストを下げる設計として、最初からモジュール境界をリソースの自然なライフサイクルに合わせておく方法があります。「一緒に作られて一緒に消える」リソースを同じモジュール・同じstateにまとめる原則を守ると、後からの移行範囲が小さくなります。VPCとEC2を同じstateに混在させると、EC2を差し替えるたびにVPCのplanも走るうえ、将来の分割コストも積み上がります。「捨てやすい単位」でstateとモジュールを設計する発想が、長期運用における変更コストを最小化します。モジュール境界を「どの基準で引くか」の判断は、具体的なリソース操作が始まる前の設計段階で固めるべき意思決定です。

チーム構築でstateを最初に固定するチェックリスト

以下のチェックリストは、Terraformによるチーム構築を開始する前に合意・設定しておくべき項目を整理したものです。リソース作成を開始してからでは変更コストが高くつく項目を優先して並べています。これをチームで確認し、全員が同じ判断基準を持った状態で構築を始めることが、後工程での手戻りを減らす最短経路です。

  • バックエンド決定:リモートstateバックエンドを選定し、バックエンドリソース(S3バケット・DynamoDBテーブル等)をTerraform管理外で先に作成している
  • バージョニング・暗号化:バックエンドのバージョニングと暗号化が有効になっている(S3ならバージョニングON・SSE設定済み)
  • state分割方針の合意:分割の粒度(環境軸・コンポーネント軸)をADRや設計書に記録し、チーム全員が参照できる状態にしている
  • ロック機構の確認:ロック機構が有効なバックエンドを選択し、ロック解除の権限者と手順を決定している
  • CI/CDの排他制御:パイプライン側でも同時apply防止(concurrencyまたはresource_group等)を設定している
  • 機密値の扱い方針:stateに書き込まれる機密値の種類を洗い出し、Secret Manager等への分離方針を決定している
  • バックアップルール:state操作前の手動バックアップ取得タイミングと保存場所のルールをRunbookに定めている
  • 移行・リファクタのフロー:state移行や大規模変更を行う際の事前周知・作業承認フローを決めている
  • アクセス権限の付与確認:チームメンバー全員がバックエンドへの最低限のアクセス権(read/lock)を持っていることを確認している
  • 監査ログの設定:stateへのアクセスログ・変更ログの取得設定が完了している(S3ならアクセスログ・CloudTrail連携)

▶ 手を動かして本番まで到達する

設計の型は掴めても、本番でTerraformを通しきる経験は別物です

ここまでの設計判断は、読めば腹に落ちます。ですが「自分の手で本番まで通しきる自信」は、それとは別の話になります。

2日間の集中ハンズオンで、AWS上にIaCで構築しきる経験を持ち帰れます。設計判断を、動くコードと本番環境の手応えに変える場です。

本番相当のAWS環境でstate設計を固める講座へ →

Terraformマスターセミナー|2日間ハンズオンでAWS上にIaCで本番構築