👋

Terraform 1.9.0 のリリースを読んでみた (1.9.1 と 1.9.2 もあるよ)

2024/07/11に公開

こんにちは、クラウドエース SRE 部の阿部です。
この記事では、2024 年 6 月 26 日にリリースされた Terraform 1.9.0 の変更点についてざっくり説明します。
また、合わせて 2024 年 7 月 3 日にリリースされた Terraform 1.9.1 と 2024 年 7 月 10 日にリリースされた Terraform 1.9.2 の変更点も簡単に紹介したいと思います。

Terraform 1.9.0 の更新内容

Terraform 1.9.0 のリリースノートの内容を記載します。

新機能

  • Input Variable のバリデーションルール(validate ブロック)において、他の Variable 等のオブジェクトを参照できるようになりました。
  • templatestring 関数が追加されました。これは、 templatefile 関数の変数版です。

機能強化

  • terraform plan で HCP Terraform リモート実行における OPA および Sentinel ポリシー評価の表示が改善されました。
  • terraform init-json オプションが追加され、JSON 形式のメッセージ出力が可能になりました。
  • terraform test で sensitive 属性の変数の取り扱いが可能になりました。以前は sensitive = true が明示された変数のみ sensitive 属性の保持が可能でした。
  • リソース数が非常に多い場合のグラフ構築処理の性能が改善されました。
  • moved ブロックを使用して null プロバイダの null_resource から terraform_data へのリファクタリングが可能になりました。
  • Terraform Cloud 使用時における terraform output の出力処理でデータ損失の可能性を示唆するエラーメッセージを出力しなくなりました。
  • terraform console で複数行入力をサポートしました。
  • リソース数が多い場合の State コピー処理性能を改善しました。
  • removed ブロックは、関連するリソースが破棄されたときに実行する provisioner を宣言できるようになりました。

その他の変更

  • remote-exec provisioner で、リモート接続は使用後すぐ切断するよう修正しました。
  • s3 バックエンドで DynamoDB/S3 State のチェックサム不一致で表示されるダイジェスト値を修正しました。
  • terraform test で Hashicorp 以外で提供されるモジュールのテスト時に誤ったレジストリアドレスに割り当てられるバグを修正しました。
  • templatefile 関数は sensitive 属性がマークされた変数をファイルパスに渡されてもパニックエラーを返さなくなりました。代わりに出力結果も sensitive にマークされます。
  • import ブロックで存在しないリソースを参照する際、エラーが発生するべきときに無視される動作を修正しました。
  • terraform init 時、同じプレリリースバージョンの制約においてポジティブとネガティブの両方が設定されている場合、他の制約の一貫性を保つため、ネガティブな制約がポジティブな制約を上書きするようになりました。
  • import ブロックは、削除済みリソースに対して破棄操作を防ぎます。
  • 動的ブロックを含む plan 実行時に完全に不明なリソースを含む場合に表示自体が欠落することがありました。この動作を改善しました。
  • 不完全なロックファイルを使用してプロバイダーミラーを実行するとコマンドがクラッシュする問題を修正しました。
  • create_before_destroy でリソース置換を行うとき、 -refresh=false オプションを付与すると正しい順序で処理しない問題を修正しました。
  • リソースアドレスが resource. で始まるときに正しくパースできるように修正しました。

非互換

  • .tftest.hclprovider ブロックにおいて、 version 引数はサポートされません。
  • import ブロックの to 引数に存在しないモジュールを指定したときにエラーを報告します。(以前のバージョンではエラーなしで無視していました。)

非互換内容についての詳細は Upgrading to Terraform v1.9 ドキュメントに記載されていますので、そちらもご確認ください。

Terraform 1.9.1 ~ 1.9.2 の主な更新内容

  • Terraform 内部で使用している hashicorp/go-getter モジュールを v1.7.5 にアップグレードしました。これは CVE-2024-6257 の対応に伴う更新です。この修正により、terraform init または terraform get における性能に影響が出る可能性があります。
    (注記: Terraform のリリースノートでは v1.7.6 にアップグレードしたと記載されていますが、Hashicorp 社の脆弱性情報によると v1.7.5 が正しいようです。)

その他の修正については、下記リリースノートをご確認ください。

追記: リリースノートのバージョン誤記について

このブログを書いた後に気になってしまい、Terraform 1.9.1 のリリースノートについて Issue を出したところ、すぐ修正していただきました。
そのため、現在はリリースノートの表記が正しい内容になっています。

https://github.com/hashicorp/terraform/issues/35445

個人的に気になった更新内容の紹介

ここからはリリースノートに記載されていた内容から個人的に気になった部分をピックアップして細かく説明します。
といっても、 1.9.0 は比較的小さな機能改修やバグフィックスが中心で、目立った新機能は Input Variable のバリデーション機能かなと思います。

Input Variable のバリデーションルール新機能

これまでの Variable の validation ブロックでは、検証式で参照できる変数はその variable 自身のみでした。

例えば、以下のような 2 つの Variable があったとします。

variable "metadata" {
  type    = map(string)
  default = {}
}

variable "metadata_startup_script" {
  type    = string
  default = null
}

この 2 つの変数は、 google_compute_engine リソースの同名の引数に使用するものです。
google_compute_engine は、 Compute Engine インスタンスリソースを管理する Terraform リソースです。
このとき、以下のような仕様があります。

  • Compute Engine インスタンスに startup-script というキーを持つメタデータ(metadata.startup-script)を設定すると、その内容はインスタンス起動時にスクリプトとして実行される。
  • google_compute_engine リソースは、この startup-script メタデータの仕様を応用し、リソース作成時(再作成含む)のみ startup-script を設定することで、 Provisioner 的な動作を実現する拡張機能がある。
  • この 2 つの引数は同じ設定を参照しておりコンフリクトするため同時に使用できない。(設定の上書き等が発生する)

そのため、この 2 つをモジュール引数として処理するときに、コンフリクトしていないかをチェックしたくなります。
例えば以下のようなバリデーションルールです。

variable "metadata" {
  type    = map(string)
  default = {}

  validation {
    error_message = "Conflict metadata.startup-script and metadata_startup_script."
    condition = (!contains(keys(var.metadata), "startup-script")
      || (contains(keys(var.metadata), "startup-script") && var.metadata_startup_script == null)
    )
  }
}

variable "metadata_startup_script" {
  type    = string
  default = null
}

しかし、Terraform 1.8 までは variable "metadata"validation ブロックのように、自分自身以外の変数を参照するような条件式はこれまで記述できませんでした。以下のようなエラーが出力されます。

│ Error: Invalid reference in variable validation
│
│   on modules/gce/variables.tf line 110, in variable "metadata":
│  110:       || (contains(keys(var.metadata), "startup-script") && var.metadata_startup_script == null)
│
│ The condition for variable "metadata" can only refer to the variable itself, using var.metadata.
╵

しかし、Terraform 1.9 からは以下のように正しく検証してエラーとして扱うことができるようになりました。

│ Error: Invalid value for variable
│
│   on main.tf line 21, in module "test_instance":
│   21:   metadata = {
│   22:     "startup-script" = "sudo apt update && sudo apt install apache2"
│   23:   }
│     ├────────────────
│     │ var.metadata is map of string with 1 element
│     │ var.metadata_startup_script is "sudo apt update && sudo apt install nginx"
│
│ Conflict metadata.startup-script and metadata_startup_script.
│
│ This was checked by the validation rule at modules/gce/variables.tf:107,3-13.
╵

似たようなことは check ブロックでもできましたが、 check ブロックは動作を止めず警告メッセージのみ出力するため、制約を強制することはできません。
また、 precondition ブロックや postcondition ブロックでも似たようなことは実装できたものの、条件の検証タイミング等や、エラーメッセージの出力箇所が分かりづらいといった難点がありました。
Terraform 1.9 の Input Variable の新機能で、こうした入力値検証の条件式がより柔軟に設定できるようになりました。

CVE-2024-6257 の脆弱性対応

Terraform 1.9.1 で修正された CVE-2024-6257 について補足します。
この脆弱性は、Terraform 内部で使用されている go-getter ライブラリの脆弱性であり、 terraform init または terraform get において、 Git リポジトリをクローンする際にリポジトリの初期化処理で任意のコマンドを実行できるというものでした。
記事執筆時点(2024 年 7 月 10 日)で CVSSv3 8.4 (High) の脆弱性であるため、 Terraform 1.9.0 を使っている方はなるべく早く 1.9.1 以降にアップグレードして頂くことをお勧めします。

なお、筆者が調べた限りでは過去の Terraform マイナーバージョンも同様に該当すると考えていますが、今のところ Terraform 1.8 等では脆弱性に対するリリースは出ていないようです。
もし 1.8 以前を使用されている場合は、1.9.1 以降にアップグレードしていただくか、マイナーバージョンで脆弱性対応版が出た際にはなるべく早めに対応いただく方がよいと思います。

まとめ

Terraform 1.9 の新機能等について紹介しました。
比較的小さな機能追加にとどまっており、バグ修正や機能改善が多かった印象です。
Terraform 1.10 のアルファ版も既にリリースされており、Ephemeral Values といったいくつかの新機能について言及されています。
こちらは新機能が多く実装されそうなため、楽しみです。

この記事が、Terraform を利用する方のお役に立ちましたら幸いです。

Discussion