とことんDevOps | 日本仮想化技術のDevOps技術情報メディア

DevOpsに関連する技術情報を幅広く提供していきます。

日本仮想化技術がお届けする「とことんDevOps」では、DevOpsに関する技術情報や、日々のDevOps業務の中での検証結果、TipsなどDevOpsのお役立ち情報をお届けします。
主なテーマ: DevOps、CI/CD、コンテナ開発、IaCなど
読者登録と各種SNSのフォローもよろしくお願いいたします。

tflintでTerraformのコードをいい感じにlintする

Terraformコマンドのサブコマンドにはvalidateやtestがあり、Terraformさえインストールしていればバリデーションやテストを実行できます。これで十分といえば十分なのですが、validateはコードの妥当性を検証するのみで、testは自分でテストコードを書かないといけません。例えば、存在しないインスタンスタイプを指定してしまったとしても、コードの記述方法が狂っていなければvalidateで検出できませんし、テストコードを書かなければtestでも検出できないわけです。この手のテストコードを網羅的に記述し、メンテナンスし続けるのも大変です。そこで今回はコード以外の妥当性もチェックできるtflintを紹介します。

tflint

github.com

tflintは外部からルールセットを読み込んでTerraformのコードをlintします。ルールセットはtflintのGitHub Orgで公開されているものもありますし、AWSが公開しているルールなどもあります。

設定

tflintはカレントディレクトリの./.tflint.hclか、ホーム直下の~/.tflint.hclを読み込みます。コマンドラインオプションで変更することも可能です。

設定ファイルのドキュメントはこちらです。

設定ファイルの書き方は以下のようになります。

config {
   ...
}

plugin "plugin_name" {
  ...
}

rule "rule_name" {
  ...
}

configブロック

configはtflint自体の設定を記述しておけます。ほとんどの設定はコマンドラインオプションで変更可能です。複数人で同じ設定を共有する場合にはconfigブロックを追加してリポジトリに入れておけばよさそうですね。

pluginブロック

使用するプラグインを指定します。プラグインとはルールセットのことで、これを指定しないとなんのチェックもされずにtflintが完走してしまいます。

プラグインの指定方法は以下です。

plugin "terraform" {
  enabled = true

  version = "0.5.0"
  source  = "github.com/terraform-linters/tflint-ruleset-terraform"

  preset  = "recommended"
}
  • enabled
    このプラグインを有効化・無効化するオプションです。Bool値で設定します。このオプションは必須です。

  • version
    このオプションはプラグインのバージョンを指定します。プラグインのバージョンはプラグインが公開されているリポジトリのReleasesと一致します。Releasesで設定されているバージョンの先頭のvはバージョン文字列に含めません。

  • source
    プラグインが公開されているリポジトリのURLです。github.com/org/repo-nameのフォーマットで指定します。

presetオプションはtflintのオプションではなく、プラグインの方で定義されているオプションです。今回の場合だとtflint-ruleset-terraformが入力を求めているオプションです。どういう設定ができるのかはプラグインのリポジトリにあるドキュメントを見てください。

以下はtflint-ruleset-terraformで使用できるオプションのドキュメントです。

tflint-ruleset-terraform/docs/configuration.md at main · terraform-linters/tflint-ruleset-terraform · GitHub

ruleブロック

ルールセットを適用したら過剰に反応されるのはlinterあるあるだと思います。プロジェクトに合わせてルールの有効化・無効化をして調整します。

rule "terraform_deprecated_index" {
  enabled = false
}

以下はtflint-ruleset-terraformで使用できるルールの一覧です。

tflint-ruleset-terraform/docs/rules/README.md at main · terraform-linters/tflint-ruleset-terraform · GitHub

使う

今回はTerraformとAWSのプラグインを使用したいので.tflint.htlは以下のものを使用します。

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

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

Terraformのコードはmain.tf 1つだけ用意して、内容は以下のようにしてみます。

provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_instance" "this" {
  ami           = "ami-06cd52961ce9f0d85"
  instance_type = "t1.nano"
}

この状態で一度実行してみましょう。

$ tflint
6 issue(s) found:

Warning: terraform "required_version" attribute is required (terraform_required_version)

  on  line 0:
   (source code not available)

Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.5.0/docs/rules/terraform_required_version.md

Warning: Missing version constraint for provider "aws" in `required_providers` (terraform_required_providers)

  on main.tf line 5:
   5: resource "aws_instance" "this" {

Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.5.0/docs/rules/terraform_required_providers.md

Error: "t1.nano" is an invalid value as instance_type (aws_instance_invalid_type)

  on main.tf line 7:
   7:   instance_type = "t1.nano"

Warning: "t1.nano" is previous generation instance type. (aws_instance_previous_type)

  on main.tf line 7:
   7:   instance_type = "t1.nano"

Reference: https://github.com/terraform-linters/tflint-ruleset-aws/blob/v0.29.0/docs/rules/aws_instance_previous_type.md

Warning: Module should include an empty outputs.tf file (terraform_standard_module_structure)

  on outputs.tf line 1:
   (source code not available)

Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.5.0/docs/rules/terraform_standard_module_structure.md

Warning: Module should include an empty variables.tf file (terraform_standard_module_structure)

  on variables.tf line 1:
   (source code not available)

Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.5.0/docs/rules/terraform_standard_module_structure.md

6つ問題が発生しました。分割して見ていきましょう。


以下2つの警告はバージョン指定が必要だと言っています。

Warning: terraform "required_version" attribute is required (terraform_required_version)

  on  line 0:
   (source code not available)

Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.5.0/docs/rules/terraform_required_version.md

Warning: Missing version constraint for provider "aws" in `required_providers` (terraform_required_providers)

  on main.tf line 5:
   5: resource "aws_instance" "this" {

Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.5.0/docs/rules/terraform_required_providers.md

Terraformはバージョン依存の処理もあるので指定しておいた方が無難でしょう。terraform {}ブロックを追加します。

terraform {
  required_version = "~> 1.6.0"
  required_providers {
    aws = {
      source = "hashicorp/aws"
      version = "~> 5.32.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

resource "aws_instance" "this" {
  ami           = "ami-06cd52961ce9f0d85"
  instance_type = "t1.nano"
}

以下2つの警告とエラーはインスタンスタイプについて言及しています。t1.nanoというインスタンスタイプが妥当ではないというエラーと、t1は旧型のインスタンスタイプであると言う警告が出ています。

Error: "t1.nano" is an invalid value as instance_type (aws_instance_invalid_type)

  on main.tf line 7:
   7:   instance_type = "t1.nano"

Warning: "t1.nano" is previous generation instance type. (aws_instance_previous_type)

  on main.tf line 7:
   7:   instance_type = "t1.nano"

Reference: https://github.com/terraform-linters/tflint-ruleset-aws/blob/v0.29.0/docs/rules/aws_instance_previous_type.md

t3.nanoなどに変更します。


以下2つの警告はファイルが足りないと言っています。

Warning: Module should include an empty outputs.tf file (terraform_standard_module_structure)

  on outputs.tf line 1:
   (source code not available)

Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.5.0/docs/rules/terraform_standard_module_structure.md

Warning: Module should include an empty variables.tf file (terraform_standard_module_structure)

  on variables.tf line 1:
   (source code not available)

Reference: https://github.com/terraform-linters/tflint-ruleset-terraform/blob/v0.5.0/docs/rules/terraform_standard_module_structure.md

今回使用しているコードはoutputもvariableも必要としていないのでルールの方を無効化します。

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

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

rule "terraform_standard_module_structure" {
  enabled = false
}

出ていたエラーと警告の部分は修正できたのでもう一度tflintを実行してみます。

$ tflint
 

エラーも警告も消えて正常終了しました。

ちなみに、初期のコードでterraform validateを実行してみるとこうなります。

terraform validate
Success! The configuration is valid.

なんのエラーも警告も検知しません。構文に間違いはなかったので当然です。

まとめ

tflintを使うと構文以外の妥当性もチェックできます。今回はTerraformとAWSをターゲットに試してみましたが、Google CloudやAzureのルールセットもありました。GitHub Actionsでも使用しやすいようにMarketplaceに用意されていたり、reviewdogと連携したActionsが公開されていたりするので、CIに設定するのもよさそうです。