背景
TerraformはInfrastructure as Codeを実現してくれるとても素晴らしいツールである一方、運用時に以下のような問題が発生します。
- 個々人がローカルで実行する場合のオペミス
- パブリッククラウドリソースを扱うクレデンシャルの管理
そのため実行環境を統一(CIと連携など)したり、GitHubでplan結果を貼ってレビュー→問題なければマージ→(自動)applyといった運用をしているチームも多いことでしょう。
しかしTerraformはplanで成功してもapplyでコケることはちょくちょくあるため、そのPRが正しい状態かどうかは実行するまで分かりません。
またCIと連携することで神権限を持ったクレデンシャルを外部サービスに預けることとなり、漏洩リスクが増大しサービスに致命的な被害をもたらす可能性もあります。
このような諸々の課題を解決していい感じに自動化してくれるのがAtlantisです。
環境
- Atlantis v0.14.0
- Terraform v0.12.28
Atlantis
まずAtlantisについて簡単に説明します。
アーキテクチャ
Atlantisを用いたオペレーションのアーキテクチャは以下です。

GitHubなどVCSでのPRやコメントをwebhookで検知してterraformを実行します。
クレデンシャルは真ん中のセルフホスティングするVMやコンテナに保持されるため、外部に埋め込んだりすることがありません。
ワークフロー
Atlantis にある通りです。
- PRを送る
- Atlantisが自動で
terraform planを実行し、結果がコメントとして返る - チームメンバーがレビューしてapproveする
atlantis applyとコメントする- Atlantisが
terraform applyを実行し、結果がコメントとして返る - マージする
terraform planに失敗した場合はコードを修正して2を繰り返せばよく、terraform applyに失敗した場合は4を繰り返して再実行したり、.tfファイルを修正してやり直す形になります。
こうしてapplyに失敗して不整合を持った状態でマージされる、といったことがなくなります。
導入してみる
チュートリアル
こちらのチュートリアルを一度実行すると流れがつかめるため、環境を構築する前に試すと良いです。
ローカルに構築する
通常実行環境はVMやコンテナですが、今回は簡単のためローカルとします。
に則って進めます。
各種インストール
- Terraform
- Atlantis
- ngrok
をダウンロードしてpathを通しておきます。
ngrokを起動しておきます。
$ ngrok http 4141

github webhookの設定
先程のngrokのURLに/eventsを付けてPayload URLにセットします。

Secretにはランダムな文字列を入れておきます。この文字列はAtlantis側でも使います。
Let me select individual eventsを選んで
- Pull request reviews
- Pushes
- Issue comments
- Pull requests
にチェックをします。

github access tokenの生成
Personal access tokensでrepoの権限を付けます。

Atlantis起動
諸々のパラメータをセットしてサーバを起動します。
$ export URL="https://16f0f2cc4e40.ngrok.io" $ export USERNAME="jun06t" $ export TOKEN="xxx" $ export SECRET="yyy" $ export REPO_WHITELIST="github.com/jun06t/atlantis-example"
atlantis server \ --atlantis-url="$URL" \ --gh-user="$USERNAME" \ --gh-token="$TOKEN" \ --gh-webhook-secret="$SECRET" \ --repo-whitelist="$REPO_WHITELIST"
これでローカル環境の構築は完了です。
検証
PRの作成
リポジトリで適当なディレクトリ、ファイルを作成します。
$ mkdir dev $ touch main.tf
main.tfの中身はテストでnull_resourceを使います。
resource "null_resource" "example" { }
PRする
PRすると自動で変更点のある*.tfのあるディレクトリでterraform planを実行してくれます。

planの実行結果がコメントに貼り付けられます。
問題なければレビューしてもらい、atlantis applyとコメントします。

applyが完了したらマージしてロックを解除(自動)します。

鍵情報の設定
上記のようなnull_resourceでなく、実際はAWSやGCPのリソースをイジることになります。
その場合各リソースにアクセスするための鍵情報が必要になりますが、Atlantisでは
Provider Credentials | Atlantis
で解説されています。
どれも鍵発行自体しないか、発行するにしろ自分のホスティングするサービス上なので安全性が高いです。
AWS
AWSでAtlantisを起動していれば
で紹介したAssume Roleの仕組みを使うことで鍵自体を発行せずに済みます。
GCP
GCE上でAtlantisを起動していれば、Instance Service Accountを使うことでEC2のRoleのような状態を実現できます。
クロスプラットフォームの場合
環境変数(AWS_ACCESS_KEYなど)を使ったり、Hashicorp Vaultを使うと良いです。
その他
オペミスを防ぐための仕組みや設定
同じディレクトリのファイルでマージ前にPRを送るとロックでコケる
Atlantisはロックによる安全機構があり、terraformでありがちな同じファイルをいじってしまう問題を防ぐことができます。
あるディレクトリのPRがある状態で、同じディレクトリを変更してPRを送ると以下のようにロックによってコケます。

ロックが外れてからatlantis planしたり再プッシュするとplanが通ります。
applyにapprovedを必須にする
repos.yamlというファイルでより細かい設定が可能です。
実行時にオプションを付けてファイルを指定してください。
atlantis server \ --atlantis-url="$URL" \ --gh-user="$USERNAME" \ --gh-token="$TOKEN" \ --gh-webhook-secret="$SECRET" \ --repo-whitelist="$REPO_WHITELIST" \ --repo-config=repos.yaml
例えば以下のようにapply_requirementsを設定することで、apply前にレビューのapprovedを必須にすることができます。
repos: - id: /.*/ apply_requirements: - approved
approvedがない状態でapplyしようとすると、以下のようにコケます。

Branch protection rules
planもapply成功していないとマージできないようにbranch protection rulesを設定すると良いです。

すると以下のようになり、planやapplyでコケているとマージできなくなります。
↓は成功しているのでチェックが通った状態です。

terraform fmtを行う
以下のようにallow_custom_workflows: trueにして独自のstepsを登録することができます。
repos: - id: /.*/ allow_custom_workflows: true workflows: default: plan: steps: - init - run: terraform fmt -check -diff - plan apply: steps: - apply
これによりterraform fmtで差分が出るとplanがエラーになります。

ただしこれはatlantisのterraform versionに依存するので、required_versionを指定していてもそのバージョンではないfmtになるので注意が必要です。
workaroundとしては$ATLANTIS_TERRAFORM_VERSIONを使ったpath指定で実行させることで、custom commandでも期待するterraform versionで実行できます。
まとめ
Terraformは非常に便利なツールである一方、オペミスや漏洩リスクなど運用上気にしないといけない点も多いです。
Atlantisはそれらの問題を解決してくれるツールとしてオススメです。