🔖

Terraformプロジェクトにおけるドリフト検知とテストリソースのクリーンアップに関する調査

2024/06/12に公開

調査結果の報告とアイディアの提案だけで、何一つ問題の解決を行っていない内容となっている。

ドリフト検知

最近はConftestによるポリシーテストの話題を頻繁に扱ってきたが、クラウド上に手動でリソースを作成するなどして発生するドリフトは、リソースの本当の状態がソースコード上に記述されていない状況であるため、ポリシーテストをすり抜けてしまうといった問題を引き起こしてしまう。

ドリフト対策として、以前Terraform Cloud(現HCP Terraform)のDrift Detection機能の調査を行なった際に、以下のようなスクリプトを実装することで最低限のドリフト検知が可能になることは説明した。

$ terraform plan -refresh-only --out /tmp/tfplan.binary
$ terraform show -json /tmp/tfplan.binary > /tmp/tfplan.json
$ cat /tmp/tfplan.json | jq .resource_drift

しかしこのスクリプトではTerraformのstate上で管理されているリソースに対してはドリフト検知が可能なものの、新規に手動で追加されたリソースの検知までは出来ないといった課題がある。

なお、新規に手動でリソースを追加した場合のドリフト検知も可能なTerraform向けのツールとしてはdriftctlがある。

driftctlではAWSだけでなくGCPやAzureのリソースの検知もそれなりにサポートしているなど非常に機能が充実しているが、残念ながら現在はメンテナンスモードとなっている。

その他のドリフト検知の候補としてtfactionDiggerの利用も検討はしたが、これらCI向けのフレームワークは既にCIをオレオレ設計で構築済みである自分のプロジェクトとは相性が悪かった。

AWSのCloudFormationで環境を構築しているのであれば標準機能のドリフト検知を使用できるが、残念ながら自分のプロジェクトはGCP上にTerraformを使用してインフラを構築しているためこちらも利用することは出来ない。

以上からドリフト検知の導入は自分のプロジェクトでは一筋縄では解決できない問題となってしまっているが、個人的に実現したいドリフト検知の方向性としてはdriftctlが最も近いため、メンテナンスモード中ではあるがその機能について調査と検証を行ってるみることにした。

driftctl

現在機能開発が停止してはいるものの、driftctlのドリフト検知機能は現在においても十分役立つものであるため、様々なリスクと相談の上ではあるが導入を検討しても良いのではないかと考えている。

(検知可能なGCPサービスの一覧はこちら)

driftclは導入のコストが低いため、以下のように自分の環境で手軽に試せる。

Macのhomebrewを使用している場合、driftctlは以下のコマンドでインストールできる。

$ brew install driftctl

その他のインストール手順はこちら

GCPのリソースに対してドリフト検知を行うにあたって、まずCloud Asset Inventory APIとCloud Resource Manager APIの有効化と、driftctlコマンドの実行の際にIAMアカウントへのroles/cloudasset.viewerの付与が必要になる。

いつものinfra-testing-google-sampleプロジェクトのサンドボックス環境(sbx-e)でドリフト検知を試す場合、ownerロールを持つ自分のIAMアカウントのデフォルトクレデンシャルを使用して以下のコマンドを実行する。

$ GOOGLE_APPLICATION_CREDENTIALS=~/.config/gcloud/application_default_credentials.json \
  CLOUDSDK_CORE_PROJECT=infra-testing-google-sample-sbx-e \
  driftctl scan \
  --from tfstate+gs://infra-testing-google-sample-sbx-e-terraform/terraform/tier1-state/default.tfstate \
  --from tfstate+gs://infra-testing-google-sample-sbx-e-terraform/terraform/tier2-state/default.tfstate \
  --to gcp+tf

driftctl scanコマンドのfromオプションにはTerraformのstateのパスを指定して、GCPプロジェクトに対してスキャンを行う場合はtoオプションにgcp+tfを指定する。

これだけでdriftctlによるドリフト検知の導入は完了となる。

なおdriftctlがサポートしていないGCPの新機能のリソースについてもドリフト検知を行いたい場合はリポジトリをforkして自分で拡張していくか、何か別の方法でドリフト検知機能を自前で実装するしかない状態である。

ソースコードを確認した訳ではないものの、ドキュメントの記述などから推測するとdriftctlのドリフト検知はTerraformのstateファイルの値とCloud Asset Inventory API経由で取得したプロジェクト内のリソース一覧の突き合わせによって行なっていると考えられる。

よって以下のコマンドでGCPプロジェクト内に存在するリソース一覧を取得して、あとはTerraformのstateファイルと値の突き合わせを行うロジックを実装することでオリジナルのドリフト検知が実現できるのではないかと予想している。

$ gcloud asset list --project infra-testing-google-sample-sbx-e

なお導入コストが一番少なく済む解決方法はチーム内でリソースの手動更新禁止を徹底することだとは思うが、自分がそれを出来るかと言われるとやはりテスト時に野良のリソースを作りたいケースも実際にあるため、それも難しい話ではある。

テストリソースのクリーンアップ

テスト時に手動でリソースを作成することに関してはドリフト発生だけでなく、テストリソースをうっかり消し忘れるケースについても備える必要がある。

放置されるリソースによっては大きなコストが発生することになるため、出来れば自動的にクリーンアップを行う仕組みが欲しい。

まずGCPにはproject_cleanupというクリーンアップアプリケーションのようなものが公式から提供されているが、これはテスト環境のGCPプロジェクトごと削除するツールとなっていて、以前投稿した記事で言及したようにリソース単位でのクリーンアップを行いたい自分の設計とは相容れないものであるため選択肢からは外れてしまう。

なおリソースクリーンアップツールには慣例的にx-nukeという名前が付けられていて、GCP用にはgcp-nukeというプロジェクトがGithubに2つ存在するが、どちらも開発途中のまま長らく更新されていない状態となっている。

一方でAWSに関しては公式からaws-nukeというプロジェクト単位だけでなくリソース単位でのクリーンアップをきめ細かく指定可能なツールが提供されていて、誤削除対策もかなり練られていることから自分が調べる限りでは唯一実用に耐えうるものとなっている。

(その他にもAWS向けのcloud-nukeというOSSクリーンアップツールが存在するが、機能の充実度やサポートの観点からもAWS公式のツールであるaws-nuke使用した方がよい)

ではGCPではどのようにクリーンアップを実現するかという話だが、個人的には自前で実装するのは時間がかかる上にバグ発生時のリスクが極めて高いことから、いっそのことクリーンアップの機構を用意しない方向で考えている。

その代わりにサービスを構成する全GCPプロジェクトの課金発生状況を常にモニタリングして、異常が見られるプロジェクトに関しては通知が行われる仕組みを用意することに注力した方が、はるかに安全な運用かつコストをチームに意識させることが出来て一石二鳥の解決策なのではというのがGCPプロジェクトにおけるクリーンアップの課題に対する個人的な結論となる。

もちろんコストのモニタリングだけでは本来クリーンアップされるべきリソースがコストゼロだった場合に検知が難しくなるが、この辺りに関してはクリーンアップに何を求めるか次第の話にはなるかと思う。

おわり

ドリフト検知とクリーンアップは守備範囲が一部重複しているため、両者を同時に導入する場合はお互いの挙動が干渉し合って意図しない挙動が引き起こされないように気をつけて設計を練る必要がある。

以上、半年間続いたテスタブルなインフラプロジェクトの設計および実装のドキュメンテーション作業はこれでいったん ~ 完 ~

Discussion