背景
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やコンテナに保持されるため、外部に埋め込んだりすることがありません。
ワークフロー
Terraform Pull Request Automation | Atlantis にある通りです。
- PRを送る
- Atlantisが自動で
terraform plan
を実行し、結果がコメントとして返る - チームメンバーがレビューしてapproveする
atlantis apply
とコメントする- Atlantisが
terraform apply
を実行し、結果がコメントとして返る - マージする
terraform plan
に失敗した場合はコードを修正して2
を繰り返せばよく、terraform apply
に失敗した場合は4
を繰り返して再実行したり、.tf
ファイルを修正してやり直す形になります。
こうしてapplyに失敗して不整合を持った状態でマージされる、といったことがなくなります。
導入してみる
チュートリアル
こちらのチュートリアルを一度実行すると流れがつかめるため、環境を構築する前に試すと良いです。
ローカルに構築する
今回実行する環境はローカルとします。
に則って進めます。
各種インストール
- 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はそれらの問題を解決してくれるツールとしてオススメです。