🐙

tfaction導入のお話

2022/12/18に公開2

※この記事は、Luup Advent Calendar の18日目の記事です。

最初に

こんにちは、Luup SREチームの中西(@sonic883b)です。
今回は Github Action 上で terraform Workflow を行う tfactionを導入したお話となります。

背景

LUUP でのインフラはAWS、GCPを利用しています。
SREチームの設立以来からインフラのコード化(IaC)を目標として掲げており
各メンバーが terraform による新規リソースの構築と既存リソースのインポートを実施しています。

この時、複数人が terraform による操作、変更する場合は以下の懸念点があります。

  • 各個人環境で terraform plan / apply を実行する必要がある
    • 作業タイミングによっては terraform の state と実際のリソース設定の乖離 Configuration Driftが発生する
  • AWS、GCPの認証情報もメンバの作業端末で設定する必要がある(認証情報の漏れ等のリスク)

チーム内での相談の結果、解決策として CI/CDでのワークフローの導入をすることとなりました。

DesignDoc の作成

まずは要件や運用方針をまとめた DesignDoc を作成しチーム内に共有しました。

以下は一部抜粋となります。

要件

  • CI/CDワークフローを導入して手動デプロイによるヒューマンエラーを防止する
  • terrform の変更履歴の記録や参照ができている
  • 以下のような Gitops でのworkflow を実行する

運用方針

  • terrform の remote state ファイルは各クラウドベンダのストレージで保管する
  • s3 またはGCSに設定するバケット名や prefix は以下とする
    • Bucket:terraform-backend-<AWS_account_number,GCP_project>
    • prefix(保存ファイル名): state/{dev,prod}/<project-name>/terraform.tfstate

tfaction について

suzuki-shunsukeさんが作成なさった OSS となります。

https://github.com/suzuki-shunsuke/
https://zenn.dev/shunsuke_suzuki/articles/tfaction-introduction

以前から terraform での CI/CD実行ができるツールについて調査は行っていて
個人的にも利用してみたいこともあり、SREチームに提案、相談を行って導入させて頂く事となりました。

導入、選定の理由としては tfaction の要件が Luup での terraform workflow の要件(Monorepo,Github Actions)に最適であった為です

tfaction-introduction より抜粋

tfaction の要件

  • GitHub Flow
    • branch は default branch と feature branch だけ
      default branch から feature branch を作成し、 feature branch から default branch に PR を作成
      Pull Request の CI で terraform plan などを実行
      Pull Request を default branch にマージしたら terraform apply が実行される
  • Monorepo
    • 一つのリポジトリで複数の Terraform Working Directory (State) を管理
  • GitHub Actions
    • GitHub Actions で Terraform を実行する
  • AWS Account
    • S3 に plan file や tfmigrate の history を保存
    • 依存するツールは aqua で管理
  • tfaction は tflint や tfsec, Conftest など様々なツールに依存しているが、それらは aqua でバージョン管理する
    Renovate による継続的 update

導入前の検証

大変ありがたいことに tfaction-getting-started というチュートリアルを用意されてます。
https://github.com/suzuki-shunsuke/tfaction-getting-started

また、tfaction-example というサンプルレポジトリに導入ガイドドキュメントもあります。

https://github.com/suzuki-shunsuke/tfaction-example
https://zenn.dev/shunsuke_suzuki/articles/tfaction-setup
https://suzuki-shunsuke.github.io/tfaction/docs/

上記の資料を元に検証環境(GitHubレポジトリ、AWS、GCP)で設定方法の理解や動作確認ができました。
PR01

LUUPでのtfactionの構成

基本的に tfaction-getting-started のディレクトリー構成を参考にしています。

  • 各環境のtfファイルは terraform 配下に配置
  • AWS、GCP と分けてProduction 、Devのプロダクトのステージ毎に分ける
  • tfmigrate は各環境毎に配置
  • tfaction-root.yaml で環境ごとの設定を記入
    • template に関しては設定したが現状は機能しておらず今後確認をしていく予定
.
├── aqua
├── aqua.yaml
├── templates
│   ├── aws
│   │   ├── dev
│   │   └── prod
│   └── gcp
│       ├── dev
│       └── prod
├── terraform
│   ├── aws
│   │    |── dev
│   │    |   ├── project-A
│   │    |   └── project-B
│   │    └── prod
│   │       ├── project-A
│   │       └── project-B
|   │           └── tfmigrate
│   └── gcp
│       |── dev
│       |   ├── project-A
│       |   └── project-B
│       └── prod
│           ├── project-A
│           └── project-B
|               └── tfmigrate
└── tfaction-root.yaml

tfmigrate について

minamijoyoさんが作成したOSSになります。
terraform の state 操作の作業が楽になるのとgithub 上でのコミットの管理ができます。
https://qiita.com/minamijoyo/items/670eb100552b0834dd5e

tfaction は tfmigrate の実行に対応してるので各環境で tfmigrate のファイルを保存して
ドキュメントの通り Pull Request で Label を設定すれば
workflow 上で tfmigrate の plan/apply が実行されるようになります。

  • tfmigrate.hcl のサンプル
migration "state" "mv_gcs_test01_to_02" {
  dir = "../gcs-test"
  actions = [
    "mv google_storage_bucket.test07 google_storage_bucket.test02"
  ]
}

PR02

導入で苦労した点

AWSに関してはドキュメント等にも設定事例があり特に躓いた点はありませんでした。
GCP に関しては自分の設定の不備や workflow でのエラーが発生していたので調査、対応しました。

GCPの 認証周りについて

現状は Service Account の設定を Github secret に設定しています。
PR03

導入当初からworkload identity の設定はしたのですが state ファイルがGCSにアップロードできない
エラーが発生していて一旦 Service Account を設定する方針としました。

gsutil authentication
If you configure gcs_bucket_name_plan_file, tfaction stores Terraform Plan files at Google Cloud Storage with gsutil. gsutil doesn't support Workload Identity Federation yet, so you have to use traditional service account key authentication.

https://cloud.google.com/storage/docs/authentication
https://github.com/google-github-actions/auth#authenticating-via-workload-identity-federation
The bq and gsutil tools do no currently support Workload Identity Federation! You will need to use traditional service account key authentication for now.

原因は導入当初 tfactionv0.5.7を使用しており gsutil が workload identity
をサポートしていないことでした。

https://suzuki-shunsuke.github.io/tfaction/docs/config/gcp/

v0.5.15 以降だと gcloud sdk の最新版をインストールするとの事で
tfaction のバージョンアップと workload identity の設定の対応する予定です。

tfmigrate での設定追加

以下の内容で対応しました。

  1. aqua で tfmigrate v0.3.7以上をインストール

v0.3.7 から Support GCS as a history storage となったので v0.3.9 をインストールする様に aqua の設定ファイルに追加しました。

aqua/tfmigrate.yaml

packages:
- name: minamijoyo/tfmigrate@v0.3.9
  1. tfmigrate-plan / apply に GCP認証の step を追加

tfaction での Github Actions の設定でGCP の認証設定が必要でしたので追加しました。
※別途対応方法があるかもしれませんが現状は以下の設定で行ってます

.gitnub/workflows/test.yaml

tfmigrate-plan:
(**snip**)

- uses: suzuki-shunsuke/tfaction/test@v0.5.18
  with:
    github_app_token: ${{ steps.generate_token.outputs.token }}

### 追加    
- name: Authenticate to google cloud platform
  if: ${{ env.GOOGLE_CREDENTIALS != '' }}
  uses: google-github-actions/auth@v0
  with:
    credentials_json: ${{ env.GOOGLE_CREDENTIALS }}
    create_credentials_file: 'true'
### 追加

- uses: suzuki-shunsuke/tfaction/tfmigrate-plan@v0.5.18
  with:
    github_app_token: ${{ steps.generate_token.outputs.token }}

最後に

tfaction を導入することによってterraform workflow の構築ができました。
また tfmigrate によって terraform import や state の作業が無事にできるようになりました。

お陰様で開発効率が上がり、今後のインフラリソース追加や既存リソースのimport作業がスムーズに行えそうです。

素晴らしいツールを作成して頂いた作者の皆様にお礼申し上げます。

最後までお読み頂き、ありがとうございました。

Luup Developers Blog

Discussion

Shunsuke SuzukiShunsuke Suzuki

どうも。 tfaction の作者です。 tfaction を導入・ご紹介いただきありがとうございます。
開発効率が上がったとのことで何よりです。
tfaction に関してなにかわからない点などありましたら気軽に聞いてください。

template に関しては設定したが現状は機能しておらず今後確認をしていく予定

これは何でしょうね?調べてもわからなかったら聞いてください。

tfaction での Github Actions の設定でGCP の認証設定が必要でしたので追加しました。

最新の tfaction であれば内部で google-github-actions/auth を実行しているので不要な気がします。

https://github.com/suzuki-shunsuke/tfaction/blob/60e770c88d644f59138bf1cf969ceb24ea7b16c2/setup/action.yaml#L68-L72

sonic883bsonic883b

コメントありがとうございます。
お陰様でメンバ間での terraform のやりとりが楽になりました。
template に関しては自分の設定の不備な気がするので確認していきますね

ありがとうございます。template の件も併せて tfaction を最新にしてから修正していこうと思います