IaCを導入しても、コンソールでの手動変更ひとつでコードと実態は乖離していきます。この乖離「ドリフト」を検知し、放置せず是正し、そもそも起きにくくする仕組みを、一次情報に沿って整理します。
Infrastructure as Code(IaC)を導入すると、インフラの「あるべき姿」はコードに書かれます。ところが現実には、コンソールからの緊急対応や、別チームの手動操作によって、実際のインフラはコードから少しずつずれていきます。この乖離をドリフト(drift)と呼びます。ドリフトを放置すると、次のapplyで意図しない変更が走ったり、そもそもコードを信頼できなくなったりします。本記事では、なぜドリフトが起きるのか、どう検知し、どう是正し、そしてどう起きにくくするかを、一次情報に沿って整理します。
01なぜドリフトは起きるのか
ドリフトの発生源は、突き詰めるとほぼ一つです。IaCのワークフローを経由しない変更が加わることです。具体的には、次のような場面で起こります。
- 本番障害時にコンソール(マネジメントコンソール等)から緊急でパラメータを変更し、コードに戻し忘れる
- 別チームやベンダーが、IaCの存在を知らずにコンソールやCLIで設定を変更する
- クラウド側の自動処理(オートスケール、マネージドサービスの既定値変更など)で属性が変わる
- コードでは管理していないリソースが、手動で作成されて隣り合って存在する
HashiCorpの定義でも、ドリフト検知とは「リソースがTerraformのワークフロー外で変更されたかどうかを判定すること」とされています。つまりドリフトは事故ではなく、複数人・複数チームで運用する以上、構造的に必ず発生するものです。だからこそ「起きない前提」ではなく「起きる前提で検知・是正する」設計が要になります。
02terraform planによる検知の基本
Terraform/OpenTofuでの検知の起点はterraform planです。HashiCorpの公式ドキュメントは「既定では、Terraformはterraform planまたはterraform applyを実行するたびに、ステートファイルと実インフラを比較する」と述べています。planはまずリフレッシュ(実インフラの現状取得)を行い、そのうえでコード・ステート・実態の三者を突き合わせます。
ただし通常のplanは「コードに合わせて何を変更するか」を示すため、ドリフトと本来の差分が混在します。ドリフトだけを純粋に見たい場合はterraform plan -refresh-onlyを使います。公式チュートリアルでは、この-refresh-onlyは「ステートファイルへの変更内容を確認する」ものであり、「インフラをコードに合わせて変更しようとはせず、ステートファイル上のドリフトをレビュー・追跡する選択肢を与えるだけ」と説明されています。-refresh-onlyはTerraform 0.15.4で導入され、古いterraform refreshサブコマンドより安全な確認手段として推奨されています。
ステート管理そのものの設計は検知の前提になります。ステートの分割やロック、バックエンド選定についてはStateファイルの管理と分割戦略もあわせてご確認ください。
03定期drift検知を自動化する
手元でplanを叩くだけでは、ドリフトは「気づいたときには手遅れ」になりがちです。実務では定期的な自動検知に落とし込みます。代表的な手段は二つです。
- マネージド機能を使う:HCP Terraform(旧Terraform Cloud)のヘルスアセスメントは、対象ワークスペースに対して非破壊のrefresh-only planを定期実行し、実インフラとステートの差を検知します。公式ドキュメントによれば、この機能はStandard Edition以上で利用可能とされています(提供条件は公式で要確認)。
- CIで自作する:スケジュール実行のパイプライン(例:日次のcron)で
terraform plan -refresh-only -detailed-exitcodeを回し、終了コードで差分の有無を判定して通知する構成です。-detailed-exitcodeは差分ありのとき終了コード2を返すため、CIの分岐に使えます。
検知結果は、必ず人が気づくチャネル(チャット通知やチケット起票)に流します。アラート設計の考え方は監視とアラート設計の記事も参考になります。CIパイプライン全体の組み方はIaCのCI/CDパイプライン設計で扱っています。
04GitOpsの継続的調整と自己修復
Kubernetesの世界では、ドリフトへの向き合い方が一歩進んでいます。GitOpsツール(Argo CD、Flux)は、Gitの宣言と実クラスタの状態を継続的に調整(reconcile)し続ける仕組みだからです。
Argo CDの公式ドキュメントによれば、自動同期(automated sync)は「Gitのマニフェストとクラスタ状態に差分を検知したときに自動で同期する」機能です。さらにself-healを有効にすると「実クラスタの状態がGitで定義された状態から逸脱したとき」に自動同期がかかります。つまり、誰かがkubectlで直接クラスタを変更しても、Argo CDがドリフトを検知してGitの状態へ戻します。self-healの再試行間隔は既定で5秒で、argocd-application-controllerの--self-heal-timeout-secondsフラグで制御されます。
ただし公式が明記するとおり、自動同期は既定ではリソースを削除しません。Gitから消えたリソースまで消したい場合はpruneを明示的に有効にする必要があります。また自動同期は対象アプリがOutOfSyncのときだけ走り、Syncedやエラー状態では試行されません。GitOpsの詳細はGitOpsとArgo CD / Fluxで扱っています。
05そもそも手動変更を起こさせない(SCP/権限)
検知と是正は「起きた後」の話です。より効くのは手動変更をそもそも起こさせない上流の抑止です。AWSでは、Service Control Policies(SCP)が代表的な手段になります。
AWSの公式ドキュメントによれば、SCPは組織内のIAMユーザー・ロールが持ちうる最大の権限の範囲を中央から制御します。SCPでDenyされたアクションは、そのアカウント内のどのエンティティも実行できず、個別のIAMポリシーでAllowされていても覆せません。この性質を使い、次のような設計が可能です。
- IaC実行専用ロール以外からの、特定リソースの変更・削除アクションを
Denyする - 本番アカウントでのコンソール経由の危険な操作を、条件付きで制限する
- タグやリージョンなどの条件を組み合わせ、ガードレールを細かく効かせる(SCPのIAMポリシー言語のサポート範囲は公式で要確認)
ここでの狙いは「人間が手で変えられる余地を、意図的に狭める」ことです。IaC実行ロールにのみ変更権限を集約すれば、変更は必ずコードとパイプラインを通ります。SCPを使ったガードレール設計はマルチアカウント統制やOrganizations SCPによるガードレールで詳しく扱っています。最小権限の実務的な落とし込みはIAM最小権限の現実解もご覧ください。
06検知後の是正フロー
ドリフトを検知したら、機械的にapplyで潰すのは危険です。HashiCorpも「ドリフトの修正は手動プロセスである。なぜならTerraform外で加えられた変更を残すのか、上書きするのかを判断する必要があるから」と明言しています。是正は判断を伴う分岐です。検知した差分ごとに、次のいずれかを選びます。
- 変更を破棄して戻す:手動変更が不要なら、通常の
terraform applyでコードの状態に戻します(GitOpsのself-healはこれを自動化した形です)。 - 変更を正として取り込む:手動変更が正しい対応だった場合、コード側を修正して差分を消し、必要なら
apply -refresh-onlyでステートを更新します。「実態が正しい」ときにコードを追随させる方向です。 - 管理外リソースを取り込む:手動で作られた既存リソースは
terraform import(またはimportブロック)でステートに取り込み、コードで管理下に置きます。
重要なのは、この分岐判断を属人化させず記録に残すことです。ドリフト検知チケットに「破棄/取り込み/import」のどれを選び、なぜそうしたかを書く。これを積み重ねると、頻発するドリフトの発生源が可視化され、上流(SCPやモジュール設計)の改善につながります。
07組織能力としてのドリフト対策
ドリフト対策は、ツール導入だけで完結しません。バージョン管理された宣言をソース・オブ・トゥルースとして維持できるか、という組織能力の問題でもあります。DORA(State of DevOps)は、バージョン管理を「再現性とトレーサビリティを担保し、変更速度が上がるほど重要になるセーフティネット」と位置づけています。ドリフト検知は、まさにこのセーフティネットが破れていないかの継続的な点検にあたります。
実務への落とし込みとしては、次の順序をおすすめします。まず(1)検知を定期自動化してドリフトを可視化する。次に(2)是正フローを分岐判断込みで運用に定着させる。そのうえで(3)上流の抑止(SCP・権限集約・GitOpsのself-heal)で発生頻度そのものを下げていく。この順で進めると、現場に無理なく定着します。
—まとめ
ドリフトは、複数チームで運用する以上、構造的に必ず発生します。だからこそ「起きない前提」ではなく、terraform plan -refresh-onlyによる検知、定期自動化、GitOpsの継続的調整、そしてSCPによる上流の抑止を組み合わせ、「起きても素早く気づき、判断して是正する」設計に落とし込むことが要になります。是正では機械的な上書きを避け、破棄・取り込み・importの判断を記録に残すことで、コードを一次情報として維持し続けられます。EMWでは、この検知・是正・抑止のフローを、既存の運用体制に無理なく組み込むところまで伴走します。関連する導入事例もあわせてご覧ください。