この記事はIaC Meetup【Finatext × YUMEMI.grow】の登壇で発表した内容になります。
目次
- CIでPlanするメリット
- CIでPlanするための設定
- Plan実行の流れ
Planするメリット
- 実行環境の再現性を向上させられる
- インフラの一貫性維持とドリフト検知が
できる - 依存関係のアップデートがしやすくなる
実行環境の再現性を向上させられる
たまにある問題: Aさんの環境ではPlanできるのに、Bさんの環境ではPlanできない
- 認証の問題
- 権限の問題
- 環境の問題
- variablesの設定値の問題
- etc…
上の図ではGitHubの認証エラーで弾かれている
Planするために必要な環境が明示されるようになる
- CI上でPlanするために必要な準備を全て行う必要がある
- そのためにはPlanするための認証、権限、環境をすべて用意し設定しているはず
実際に動く環境として、実行環境の明示がなされる。CIで設定している内容はPlanするために必須であり、個人の環境から実施する際にも必要になる。
インフラの一貫性維持とドリフト検知ができる
Terraformの内容と実際のリソースの状態が一致していることを確認する機会が増やせる
- 一致していないとApplyで設定が巻き戻ってしまう可能性
- 手動で変更していたのであれば必要な変更では?
- この状態では新規に開発することが難しい
スケジューラーが無効になっているがこれは有効にしてもOK? それとも無効のままがよい?
これを判断できないと迂闊にApplyできない
Terraform側を修正して現状維持するようにしてもいいが、間違ったインフラ変更だったという場合もある
依存関係のアップデートがしやすくなる
主な依存関係のProviderを更新させ続けられる
- Providerの更新があった際に、対応が必要かそのまま適用できるか判断できる
- PlanでNo changesであれば適用して問題ない場合が多い
- Changeがあれば仕様が変わっている可能性がある
- RenovateやDependabotで自動マージまで持っていくことも可能
renovate-approveを使用して依存関係の更新を完全自動化している。Providerの更新に対しplanで差分が検出されなければ自動でマージする設定になっている。
CIでPlanするための設定
- 実行環境の設定
- 認証の設定
- 権限の設定
実行環境の設定
Terraform
-
hashicorp/setup-terraform
のActionsでインストール可能 - バージョンの指定はお好みで…
- detailed-exitcodeのオプションとの相性が悪いようなのでterraform_wrapperは
false
に
- uses: hashicorp/setup-terraform@v3
with:
terraform_wrapper: 'false'
AWS
-
aws-actions/configure-aws-credentials
のActionを使用しOIDCによる認証を使用 - Workflowにおけるpermissionsに、
id-token: write
を設定すること -
mask-aws-account-id
をtrueにするとアカウント番号を隠してくれる
- uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: 'us-east-1'
role-to-assume: ${{ secrets.AWS_TERRAFORM_PLANNER_ROLE }}
role-session-name: 'TerraformCheck'
mask-aws-account-id: true
retry-max-attempts: 3
Google Cloud
-
google-github-actions/auth
のActionを使用しOIDCによる認証を使用 - Workflowにおけるpermissionsに、id-token: writeを設定すること
- projectIdを隠したい場合はGitHub ActionsのSecretsに登録の上、 Workflowの中でSecretを参照する必要がある
- Checkoutした直下に認証用のファイルを作成するので注意 ( gha-creds-40c829577b183395.json のようなファイル)
- このファイルが漏れても直ちに影響があるわけではない
- コミット指定なファイルが増えるのでgit diffなどで引っかかることがある
- uses: google-github-actions/auth@v2
with:
workload_identity_provider: ${{secrets.GOOGLE_CLOUD_IDENTITY_PROVIDER}}
service_account: ${{secrets.GOOGLE_CLOUD_TERRAFORM_PLANNER_SERVICE_ACCOUNT}}
GitHub
-
actions/create-github-app-token
のActionを使用しAppIdと秘密鍵でTokenを作成 - RepositoryやOrganizationの設定をしたい際に使用する
- ActionsのSecretやEnvironmentなど
- Terraform側のProviderの設定でAppを使う設定にもできるが、instalation idが必要なので注意
- id: generate-token
uses: actions/create-github-app-token@v2
with:
app-id: ${{ steps.get-secrets.outputs.app_id }} # from Secret Manager
private-key: ${{ steps.get-secrets.outputs.pem }} # from Secret Manager
owner: ${{ github.repository_owner }}
その他
- サービスによって異なるが、API Keyなどを設定
- APIKeyはActionsのSecretや、クラウドのSecret Managerなどから持ってくることになりそう
- AWSに保存していれば、ephemeralblockで引っ張ってきて、Providerの設定に使用することもできる
- GoogleCloudのSecret Managerはephemeralresourceの実装が現状ない
ephemeral "aws_ssm_parameter" "cloudflare_token" {
arn = local.cloudflare_token_arn
}
provider "cloudflare" {
api_token = ephemeral.aws_ssm_parameter.cloudflare_token.value
}
権限の設定
必要な権限
- Stateファイルの読み込み/書き込みの権限
- Applyするなら書き込みが必須。Planだけなら読み込みでOK
- KMSで暗号化しているならその関連も必要
- Lockに関する権限
- Plan時にLockしない(
-lock=false
)なら不要 - 書き込みの権限であることが多い
- AWSならS3かDynamoDB
- GoogleCloudならCloud Storage
- Plan時にLockしない(
- Planするリソースに関する権限
Planするリソースに関する権限
(最小権限の原則を守れるのであればそれが一番)
- マネージドな権限を設定するのが簡単+ アクセスさせたくないものはDenyするなど
- AWSならReadOnlyAccessのポリシー
- SSM Parameterの内容が読めるので注意
- Google Cloudなら閲覧者のロール
- どちらもSecret Managerの内容は読めない
- AWSならReadOnlyAccessのポリシー
- 実際に使う際にはよく調査してから
Plan実行の流れ
- 認証の準備
terraform init
terraform plan
認証の準備
これまでで設定した認証を使用していく
terraform init
これだけで1GB弱のProviderが設置されるので注意。AWS Providerが600MB以上を占める。Google CLoudやCloudflareは130MB未満くらい。
- Providerをダウンロードしていく
- 数百MBあるので、通信量には気を付ける
- 特にSelf Hosted Runnerを使用している場合など
- Providerをキャッシュするとダウンロード回数が減る
-
TF_PLUGIN_CACHE_DIR
の指定で使用可能
-
- 数百MBあるので、通信量には気を付ける
from shared cache directory
とあるのでキャッシュが使われている。
terraform plan
terraform plan -detailed-exitcode -lock=false
-
-detailed-exitcode
で、差分がある場合に終了コードを2にしてくれる - ファイルに書き出す場合は-no-color もつけるのがおすすめ
- privateやinternalのリポジトリでは不要だが、publicなリポジトリでやっている場合にはファイルに出力するなど簡単にはterraformの実行結果を見られないようにした方が安全
- lockする設定だと、Renovateなどで一斉にProviderが更新された際に並列でplanされ、lockの取得に失敗する
まとめ
CI組まないとRenovateやDependabotでオートマージさせられないのでPlanしよう。