VISASQ Dev Blog

ビザスク開発ブログ

GitHub ActionsにTFLintを導入しました

こんにちは、今年の10月に入社したプラットフォーム開発グループ DPEチームの酒井です。

先日 GitHub Actions に TFLint と Trivy を導入しました。
まとめて書くと長くなってしまうので、今回は TFLint 導入編です。

今回説明する部分は以下になります。

  • TFLint の設定

  • TFLint を GitHub Actions で動かす

TFLintとは?

TFLint は、Terraform ファイルの命名規則や、インスタンスタイプのエラー、非推奨の構文、未使用の宣言など、静的解析してくれるフレームワークです。 github.com

TFLint 導入

TFLint の install

ビザスクの Terraform 環境周りではCLIパッケージマネージャーとして aqua を利用しています。
TFLint は aqua registry に存在していますので、aqua.yaml に以下のように追記していきます。

registries:
  - type: standard
    ref: v4.97.0
packages:
  - name: terraform-linters/tflint@v0.49.0

※ 現状だと、Terraform v1.xに対応しているとのことなので最新を取得すれば良さそうです。
https://github.com/terraform-linters/tflint/blob/master/docs/user-guide/compatibility.md

使用できるプラグイン

AWS/Azure/GCP に関しては、ルールセットのプラグインとして既に公式で用意されているようです。
ビザスクでは主に GCP を利用していますので、こちらを使ってルールを記述していきます。

基本的な TFLint の使い方

プラグインの導入

  1. .tflint.hclファイルを作成する
  2. 使用するプラグインの記載
  3. plugin "google" {
        enabled = true
        version = "0.25.0"
        source  = "github.com/terraform-linters/tflint-ruleset-google"
    }
    
  4. 以下を実行すると、`.tflint.hcl`ファイルに記載したプラグインがインストールされる
  5. $ tflint --init   
    
  6. インストールしたプラグインは以下のコマンドで確認可能
  7. $ tflint -v
    TFLint version 0.48.0
    + ruleset.google (0.25.0)
    + ruleset.terraform (0.4.0-bundled)
    
  8. lint の実行
  9. $ tflint
    
  10. 問題の修正
  11. fixオプションを指定することで、一部は自動的に修正してくれます。
    $ tflint --fix
    

moduleの中まで再帰的にチェックする

以下を.tflint.hcl記述することで、module 内まで lint の対象にしてくれます。

config {
    module = true
}

再帰の場合には以下のコマンドで実行ができます。
下の階層をチェックする際に.tflint.hclのファイルのパスがずれてしまうようなので、絶対パスで指定してあげる必要があります。

$ tflint --recursive -c $(realpath .tflint.hcl)

fix オプションを指定することで、再帰的に自動修正してくれます。

$ tflint --recursive -c $(realpath .tflint.hcl) --fix

また、以下のようにignore-moduleオプションを指定することで特定のモジュールのみチェックを回避することもできます。

$ tflint --ignore-module=./module

その他使いそうなコマンドオプション

  • --format 出力形式の変更(json形式にできたりする)

  • --var-file Terraform 変数を設定するterraform.tfvarsファイルが存在する場合には自動的にロードされる

最終的なルールセット

config {
    module = true
}

plugin "google" {
  enabled = true
  version = "0.25.0"
  source  = "github.com/terraform-linters/tflint-ruleset-google"
}

plugin "terraform" {
  enabled = true
}

rule terraform_documented_outputs {
  enabled = false
}

rule terraform_documented_variables {
  enabled = false
}

rule terraform_naming_convention {
  enabled = false
}

rule terraform_required_version {
  enabled = false
}

rule terraform_required_providers {
  enabled = false
}

ルールを一通り有効にした後に、不要なものを無効にする形で記述しています。

どのルールを有効にして、どのルールを無効にするのかということは正直好みだと思います。
Terraform のルールセットは default が recommendのものだけ有効になりますので、運用していくなかで不要なものがあれば無効にする程度で良いと思います。

Terraform のルールセット:

github.com

TFLintをGitHubActionsで動かす

詰まった事

TFLint は動かすためにterraform initする必要があります。
どうやって GitHub Action 上でterraform initするかで少し行き詰まりました。
state ファイルは GCP の Cloud Strage に置いていたので、取れる手段は2つあります。

  • override.tfを作成し、local 上に state ファイルを作成する。

developer.hashicorp.com

  • GCPの一時的な credential を発行する。

zenn.dev

今回は init するだけで、現状のリソースがどうなっているかということは関係ないので、より簡単にできる override.tf を作成する方法を選択しました。

最終的な設定ファイル

GitHub Actionsの設定は以下になります。

  tflint:
    name: Run tflint
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.ref }}

      - name: Detect Terraform version
        run: |
          printf "TF_VERSION=%s" $(cat aqua.yaml | grep "hashicorp/terraform" | awk -F '@v' '{print $2}') >> $GITHUB_ENV

      - name: Install terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: ${{ env.TF_VERSION }}

      - name: dev terraform init
        run: |
          cd terraform/environments/dev \
          && echo -e "terraform {\n  backend \"local\" {\n    path = \"./.local-state\"\n  }\n}" | tee override.tf \
          && terraform init

      - name: stg terraform init
        run: |
          cd terraform/environments/stg \
          && echo -e "terraform {\n  backend \"local\" {\n    path = \"./.local-state\"\n  }\n}" | tee override.tf \
          && terraform init
      
      - name: prod terraform init
        run: |
          cd terraform/environments/prod \
          && echo -e "terraform {\n  backend \"local\" {\n    path = \"./.local-state\"\n  }\n}" | tee override.tf \
          && terraform init
  
      - name: Cache plugin dir
        uses: actions/cache@v3
        with:
          path: ~/.tflint.d/plugins
          key: ${{ matrix.os }}-tflint-${{ hashFiles('.tflint.hcl') }}
  
      - name: Detect TFlint version
        run: |
          printf "TFLINT_VERSION=%s" $(cat aqua.yaml | grep "terraform-linters/tflint" | awk -F '@' '{print $2}') >> $GITHUB_ENV
  
      - name: Setup TFLint
        uses: terraform-linters/setup-tflint@v4
        with:
          tflint_version: ${{ env.TFLINT_VERSION }}
          github_token: ${{ secrets.GITHUB_TOKEN }}
  
      - name: Show version
        run: tflint --version
  
      - name: Init TFLint
        run: tflint --init -c ./terraform/.tflint.hcl
  
      - name: Run TFLint
        run: tflint --recursive -c $(realpath ./terraform/.tflint.hcl) -f compact

おわりに

今回は対応しなかったですが、reviewdog という OSS を使うと修正箇所がプルリクエストのコメントとして生成されるようです。
https://github.com/reviewdog/action-tflint

TFLint を入れたことで、より効率的に Terraform の運用を行えるようになったと思います。

TFLint ではルールセット自体のバージョンアップも大事ですので、セキュリティチェックの Trivy の導入に加えバージョンアップを自動化してくれるツールである renovate の導入も進んでいますのでそちらも別の記事で紹介していきます!