Terraform職人のためのOpenTofu再入門2024

# はじめに
この記事は [クラウドワークスグループ Advent Calendar 2024](https://qiita.com/advent-calendar/2024/crowdworks) シリーズ1 の 2日目の記事です。

あるときはTerraform職人、またあるときはお豆腐職人の [@minamijoyo](https://qiita.com/minamijoyo) です。

2023年8月HashiCorpはこれまでMPL2のOSSライセンスで公開していた主要製品をBSL(Business Source License)に変更することを発表し、Terraformはv1.6.0からOSSではなくなりました。このライセンス変更を受けて、OSS版のTerraformを求める人たちで、MPL2時点のコードベースからforkしたOpenTofuの開発が進められています。

ちょうど1年ほど前の2023年12月に、[「Terraform職人のためのOpenTofu入門」](https://qiita.com/minamijoyo/items/16d1b5b15a60d17e350a)を書いたのですが、当時のOpenTofuのバージョンはv1.6.0-beta1で、まだ正式なリリースも出ておらず、そもそもプロジェクトとしての存続も不確かな状況でした。年明けの2024年1月に最初のリリースであるv1.6.0が無事に出て、その後も順調に開発が続いており、そろそろ改訂版を書いておこうかなと思います。

「TerraformとOpenTofuって何が違うんですか？」と聞かれることも増えてきましたが、これに対する短い答えは、「terraform init / plan / applyを、tofu init / plan / applyに読み替えれば大体同じ」です。というのも、OpenTofuはTerraform v1.6.0-alpha相当からforkされたので、ここ最近1年ぐらいで追加されたTerraform v1.6以降の新機能を使っていなければ、今のところはほぼ同じです。

OpenTofuはTerraform互換を謳っており、Terraform v1.6以降に追加された機能も需要があれば随時実装されています。また、ただのクローンではなく、OpenTofuにしかない新機能も追加されています。特にTerraformで長年未解決だったissueが、OpenTofuでも再度議論されてOpenTofu側にだけ取り込まれているものもあります。

そもそも別々のプロジェクトとして開発が進められているので、コードベースはどんどん離れていっており、細かい差分を挙げればもちろんいっぱいあります。ただ漠然とCHANGELOGを眺めてもコンテキストを理解できないと全体感が掴めないと思うので、OpenTofuの採用を検討しているTerraform職人が押さえておくべきポイントをまとめます。

本稿執筆時点のOpenTofuのバージョンはv1.8.6、Terraformのバージョンはv1.10.0です。まだ検討中の機能などに関しては、関連するissueへのリンクも貼っておきます。気になるトピックの最新の情報は、そちらも合わせてご確認下さい。

# OpenTofuプロジェクトの概要
OpenTofuはTerraformのBSLライセンス変更前のMPL2のコードベース(Terraform v1.6.0-alpha相当)からforkされた、OSSのインフラ構成管理ツールです。Linux Foundation傘下のプロジェクトとして、引き続きMPL2ライセンスで開発が進められています。

公式サイト: https://opentofu.org
リポジトリ: https://github.com/opentofu/opentofu

Terraformのdrop-in replacementを謳っており、既存のTerraformのtfファイルやtfstateがほぼそのまま使えます。Terraformとの機能面での違いについては後述します。

コミュニティベースのOSSプロジェクトですが、本稿執筆時点では、Steering CommitteeとしてSpacelift、env0、Scalr、Harness、Gruntworkの5社が中心となって開発を進めています。発足当初はGruntworkが旗を振っている印象が強かったですが、現在の開発やコミュニティの運営ではSpaceliftの存在感が大きいように感じます。（個人の感想です）

OpenTofuの開発チームはHCP Terraform(旧Terraform Cloud)の競合サービスを開発しており、お互いはライバル同士でもあります。特定の1社が強い権限を持ちすぎないように、プロジェクトの運営には一定のガバナンスが必要です。

どの機能を実装すべきかについては、コミュニティから投票を受け付けて優先順位を決めており、重要な設計上の変更には、事前にRFC(Request For Comments)という公開設計レビューを行い、最終的にSteering Committeeにより判断するというプロセスを導入しています。このようにライセンスだけではなく、オープンなスタイルで開発されているのも特徴です。

# OpenTofuプロジェクトの歴史
Terraformのライセンス変更から、forkの爆誕までの経緯などは去年書いたので、詳細は以下の記事を参照して下さい。

https://qiita.com/minamijoyo/items/16d1b5b15a60d17e350a

ここでは過去の経緯は簡単にサマリし、リリース後の開発の状況などを時系列で見ていきます。

## HashiCorpのライセンス変更
2023/08/10 HashiCorpはこれまでMPL2のOSSライセンスで公開していた主要製品をBSL(Business Source License)に変更することを発表しました。

注: ソフトウェアのメタデータの標準化を推進しているSPDX(Software Package Data Exchange)では、HashiCorpのBSLの元になったMariaDBのBSLのライセンスの識別子としてBUSL-1.1が付与されてます。一方SPDXでBSLはBoost Software Licenseを指し、こちらはOSI(Open Source Initiative)に承認されたOSSライセンスですので、区別したい場合はBUSLと表記します。この記事では、HashiCorpがBSLと呼んでいるので、特に区別せずBSLと表記します。

最新版のライセンスの全文は以下で確認できます。
https://www.hashicorp.com/bsl

ライセンス文言は厳密にはリリースバージョンごとに管理されています。
https://github.com/hashicorp/terraform/blob/v1.6.0/LICENSE

Terraformのコンテキストに限定してざっくり言うと、HCP Terraform(旧Terraform Cloud)の競合サービスには使わないでねという理解でよい認識ですが、私は法律の専門家ではないので、ライセンスの解釈については各自の責任で判断して下さい。

## OpenTofuプロジェクトの誕生
HashiCorpのライセンス変更の発表からほどなく、Terraform関連ベンダの連合がOpenTF Manifestoという文書を公開しました。これはTerraformのライセンス変更に対する反対表明で、元のOSSライセンスに戻してくれなければforkするよという内容のものでした。

しかしながら、HashiCorpから回答がもらえなかったので、ライセンス変更前のコードベース(Terraform v1.6.0-alpha相当)からforkした、OpenTFプロジェクトを公開しました。

このプロジェクトは当初OpenTFという名前でしたが、「TF」という文字列だけでも商標侵害リスクがあるとの懸念が出てきて、コミュニティで新しい名前を募集したところ、「tofuでいいんじゃない。略したらtfだし、terraformとも響きが違う」というネタなのか本気なのか分からない意見が圧倒的な支持を得て、2023/09/20 Linux Foundation傘下に入るタイミングでOpenTofuへリネームされました。

HashiCorpのBSLは、実質的に競合他社の商用利用に制限をかけたものです。ライセンス変更の直接的な影響を受けるユーザは極めて少数であるにも関わらず、Linux Foundation傘下のプロジェクトとして受け入れられ、なぜこれほどまでの支持を受けているのか不思議に思う人もいるかもしれません。それは競合かどうかを決めるのがHashiCorpである、という曖昧さの残るライセンスに依存するのはリスクであると多くの人が考えているからです。特にTerraformのライセンス変更は、クラウドコンピューティングのSPOF (Single Point Of Failure) となっており、ベンダーニュートラルなOSSの選択肢を維持することの重要性が改めて認識された結果と言えるでしょう。

## OpenTofu v1.6
2023年12月にOpenTofu Registryが完成し、2024/01/10に最初の安定版であるOpenTofu v1.6.0がリリースされました。ただリネームしただけではなく、Terraform v1.6に入ったtestフレームワークや、s3バックエンドの変更なども実装されました。

https://opentofu.org/blog/opentofu-is-going-ga/

## OpenTofu v1.7
fork直後のOpenTofu v1.6は、ほぼTerraform v1.6でしたが、2024/04/30に出たOpenTofu v1.7では、OpenTofu独自の新機能として、tfstateのクライアントサイド暗号化機能が追加されました。これはTerraformで何年も前から提案されていたものの、結局取り込まれなかったものです。

また、Terraform v1.7に追加されたremoveブロックや、importブロックのfor_each、Terraform v1.8に追加されたプロバイダ定義関数なども実装されました。

https://opentofu.org/blog/opentofu-1-7-0/

## OpenTofu v1.8
2024/07/29に出たOpenTofu v1.8では、OpenTofu独自の新機能として、backendやmodule sourceで部分的にvariableとlocal変数が利用可能になりました。また、新しく.tofu拡張子を導入し、OpenTofu独自の構文を別のファイルに分けて書くことができるようになりました。その他、Terraform v1.7に入っていたが、OpenTofu v1.7に入ってなかったtestフレームワークのモック機能などが実装されました。

https://opentofu.org/blog/opentofu-1-8-0/

## apparentlymart氏の移籍
Terraformコアチームの[apparentlymart](https://github.com/apparentlymart)氏が2024年7月にHashiCorpを退職し、10月からSpaceliftに転職し、OpenTofu陣営に移籍しました。

apparentlymart(Martin Atkins)氏が何者か知らない人のために補足しておくと、HCLとTerraformの生みの親はもちろんmitchellh(Mitchell Hashimoto)氏ですが、HCL2とTerraform v0.12以降は彼がほとんど書き直したと言っても過言ではないぐらい、現役のTerraform開発の中心人物でした。

これの意味するところは、OpenTofu陣営はその気になれば[hashicorp/hcl](https://github.com/hashicorp/hcl)もforkできるし、HCL2の基礎となっている型システムである[zclconf/go-cty](https://github.com/zclconf/go-cty)も彼の作品です。そしてgo-ctyはhashicorp/管理下にないという重要なパズルのピースを握っています。

もちろんTerraformはコアだけ成り立っているわけではなく、周辺のエコシステムは引き続きHashiCorpが握っていますし、クラウドベンダの協力なくして豊富なプラグインは維持できません。ただ少なくとも彼の移籍により、OpenTofu陣営はコードベースに知見がないのでアーキテクチャレベルの根本的な改修ができないのではないか、という技術面での懸念は晴れたと言えるでしょう。

# TerraformからOpenTofuへの移行
TerraformからOpenTofuへの公式の移行ガイドは以下にあります。移行元のTerraformのマイナーバージョンごとに整理されています。
https://opentofu.org/docs/intro/migration/

基本的にTerraform v1.5までの機能しか使っていなければ、terraform applyして差分がない状態で、tofu initしてtofu applyするだけで移行完了です。tfstateや.terraform.lock.hclが書き換わります。

もしs3バックエンドを使っている場合は、Terraform v1.6以降でいくつか破壊的変更が入っているものが、OpenTofu v1.6以降にも実装されているので、OpenTofuへの移行のタイミングで同じ問題を踏む可能性があります。これは厳密にはTerraformとOpenTofuの非互換ではないのですが、移行のタイミングでバージョンを飛ばして移行すると踏む問題なので、上記の移行ガイドでも言及があります。

また後述しますが、Terraform v1.7に入ったremovedブロックは、OpenTofu v1.7にもありますが若干異なり互換性がありません。removedブロックを書き換えるか、removedブロックはapplyすると不要になるので、先にterraformでapply済みであれば、removedブロックは削除してしまえばよいでしょう。

Terraform v1.5未満からのアップデートの場合は、tfstateのフォーマット的にはTerraform v0.14以降であれば一撃でアップデートできそうな気もしますが、Terraformのマイナーバージョン間でも若干の非互換はあるので、Terraform v1.5系の最後である1.5.7を一旦刻んだ方が無難だと思います。

tfstateは内部の実装詳細ですが、もし将来的に互換性のない変更が入ってもTerraformからOpenTofuへの移行はOpenTofu側で読み替えのルールを実装することで、最新のTerraformバージョンからの移行パスはサポートされると期待してよいでしょう。一方で、OpenTofuからTerraformへの戻しは、HashiCorpがOpenTofuを無視し続ける限りは困難で、移行直後であればtfstateのバックアップなどから戻せますが、移行してしばらくしてから戻そうとすると、全リソースをimportし直すしか正しい手段がなさそうです。まずは小さめのプロジェクトから実験的に試してみるのがよいかなと思います。

# TerraformとOpenTofuの違い
TerraformからOpenTofuへの公式の移行ガイドは主に非互換な部分についての記載はあるものの、後方互換性のある新機能などについては言及がありません。OpenTofuの新機能について、この記事でも既にいくつか言及しましたが、ここではTerraformとOpenTofuの違いについて、機能面で整理してみます。

OpenTofuの公式ドキュメントは以下にあります。
https://opentofu.org/docs/

## CLI
CLIとしてのterraformコマンドは、tofuコマンドにリネームされました。基本的な使い方はterraformコマンドと同じで、tofu init/plan/apply のように読み替えるだけで使えます。

バイナリがリネームされた影響で、3rd-partyのツールなどでterraformコマンドを内部的に呼び出しているものは、tofuコマンドに差し替えが必要です。

また標準出力やエラー出力でTerraformと表示されていた箇所が、OpenTofuにリネームされています。普通にユーザとして使う分には問題ないと思いますが、3rd-partyのツールで標準出力やエラー出力をパースしているようなものは、単にalias terraform=tofuで読み替えるだけでは意図した通りに動かない可能性があります。各ツールの対応状況を確認して下さい。

### tofu plan
tofu側にしか生えていないオプションもいくつかあります。個人的に便利かなと思うのは、tofu plan -conciseで、plan出力のrefresh表示が抑止できるようになってます。あれいらんやろってみんな思ってたはず。
https://opentofu.org/docs/cli/commands/plan/#other-options

## Language
構文レベルでいくつか変更が入っている箇所があり、Terraformと相互運用しようとすると注意が必要です。

fork直後のTerraform v1.6とOpenTofu v1.6はほぼ同じですが、リリースサイクルは同じではないので、Terraform v1.7とOpenTofu v1.7のようにマイナーバージョン間で互換性があるという意味ではなく、マイナーバージョンと機能セットは一致しません。

### .tofu拡張子
OpenTofu独自拡張の構文などは.tofu拡張子に分けて書くことができるようになりました。例えば同じファイル名で拡張子だけ異なるmain.tfとmain.tofuがある場合、main.tfは読み込まれず、main.tofuだけ読み込まれます。これによりファイル単位で上書きすることが可能です。ブロック単位でマージされるわけではなく、ファイル単位でどちらを読み込むという動作であることに注意して下さい。
https://opentofu.org/docs/language/files/

TerraformとOpenTofuで相互運用するような汎用モジュールを書いている人は、terraformブロックのrequired_versionだけでは機能セットを判断できませんが、.tfと.tofuファイルそれぞれにrequired_versionを書けばバージョン指定を区別できます。ちなみにterraformブロックに対応するopentofuブロックというのは今のところありません。

現時点で.tofu拡張子に対応しているツールは少ないですが、どんどんOpenTofuだけの独自拡張が増えていくと、明確に拡張子が分かれている方が扱いやすいとは思います。

### removedブロック
Terraform v1.7に入ったremovedブロックは、OpenTofu v1.7にもありますが若干異なり、lifecycle destroy=falseの指定が不要です。

Terraformのremovedブロック:
https://developer.hashicorp.com/terraform/language/resources/syntax#removing-resources

OpenTofuのremovedブロック:
https://opentofu.org/docs/language/resources/syntax/#removing-resources

Terraformにremovedブロックが導入されたときに、なんでこんなめんどくさいことしたんだろなって思ってた人も多いと思いますが、removedブロック使いたいときにstateではなくresourceを削除したいことなんてないはずで、lifecycleブロックは冗長としか思えませんでした。OpenTofuは素直にlifecycleブロックをなくしてしまった結果、構文レベルで非互換があり、opt-inが必要なTerraformとセマンティクスが逆になっていると言えなくもないので、removedブロックを使う場合は注意が必要です。

removedブロック自体はapplyすれば削除しても構わないので、TerraformとOpenTofuで相互運用が必要なモジュールでなけば、TerraformからOpenTofuに移行する前に削除してしまってよいでしょう。

### module
#### module source
Terraformはリソース属性を他のリソースの入力に使えたり、自由に変数参照ができて便利ですが、どこでも変数参照が使えるわけではありません。具体的にはTerraformの初期化に関する属性は変数参照できません。Terraformの実装は内部的にモジュールの読み込みフェーズとリソースグラフの構築フェーズに分かれており、前者のモジュールの読み込みフェーズでは変数参照ができませんでした。

OpenTofuでは、初期化のタイミングで静的に評価が可能な式に限定してこの制限を緩和し、variableとlocal変数が利用可能な場所がいくつか増えています。たとえばmoduleブロックのsource属性は変数が使えない場所でしたが、この仕組みでvariableとlocal変数が利用可能になってます。
https://opentofu.org/docs/language/modules/sources/#support-for-variable-and-local-evaluation

#### module variable validation
Terraform v1.9でモジュール入力変数のバリデーションで他の変数参照ができるようになりましたが、本稿執筆時点では、この機能はOpenTofuではまだ使えないことに注意が必要です。
https://developer.hashicorp.com/terraform/language/expressions/custom-conditions#input-variable-validation

これはOpenTofuの機能ではないのですが、TerraformとOpenTofuの相互運用を考えると認識しておくべき差分なのでここで言及しています。汎用モジュール書いてる人には待望の機能で、需要はあると思うし、OpenTofu v1.9のマイルストーンには載っているので、OpenTofuでも対応する予定はありそうです。
https://github.com/opentofu/opentofu/issues/1336

### function
組み込み関数はTerraformとOpenTofuで随時追加されているので、使えるものと使えないものがあります。

OpenTofuでしか使えない関数

- base64gunzip
- cidrcontains
- urldecode

Terraformでしか使えない関数

- provider::terraform::encode_tfvars
- provider::terraform::decode_tfvars
- provider::terraform::encode_expr
- ephemeralasnull
- terraform.applying

上記のTerraform v1.8で追加された組み込みのTerraformプロバイダで定義されている関数は、まだOpenTofuでは実装されていません。issueのステータスはacceptedになっていますが、実装時期は未定です。
https://github.com/opentofu/opentofu/issues/1614

この記事を書いている途中でTerraform v1.10が出てしまいましたが、組み込み関数ephemeralasnullとterraform.applyingはTerraform v1.10で追加された関数で、これもまだOpenTofuでは実装されていません。Ephemeral Valuesについては後述します。

組み込み関数の一覧もすぐに古くなりそうなので、公式ドキュメントへのリンクを張っておきます。Terraform / OpenTofu v1.6以降で追加された関数を使うときは注意しましょう。ちなみにWeb上のドキュメントは一覧が見づらいので、一覧の差分比較したい場合は、ソースコードの website/docs/language/functions/ 配下のファイル名のdiffを取った方が分かりやすいです。

Terraformの組み込み関数一覧:
https://developer.hashicorp.com/terraform/language/functions

OpenTofuの組み込み関数一覧:
https://opentofu.org/docs/language/functions/

Terraform v1.8に入ったプロバイダ定義関数の仕組みは、OpenTofuのv1.8ではなく、v1.7から使えます。
https://opentofu.org/docs/language/functions/#provider-defined-functions

プロバイダのプロトコルも同じなので、もし組み込み関数が足りなければプロバイダを自作することで、独自の関数を書けます。
https://developer.hashicorp.com/terraform/plugin/framework/functions/implementation

自作関数の実装例は、たとえば以下のリポジトリが参考になるでしょう。
https://github.com/northwood-labs/terraform-provider-corefunc

またプロバイダ自作するのもめんどくさければ、実験的な機能ではありますが、自作関数がGo言語でスクリプト風に書けます。あまり実運用で積極的に使うたぐいのものではないとは思いますが、選択肢の1つとして知っておくと、何かの小ネタに使えるかもしれません。
https://github.com/opentofu/terraform-provider-go

### backend
#### 変数参照
Terraformではbackend設定に変数が書けず、Partial Configurationを使って設定を動的に差し替えるというテクニックがありましたが、OpenTofuではbackend設定にもvariableとlocal変数が利用可能になりました。module sourceの変数化などと同様に、初期化のタイミングで静的に評価が可能な式に限定されているので、リソース参照やデータソース参照などは書けません。
https://opentofu.org/docs/language/settings/backends/configuration/#variables-and-locals

#### State Encryption
TerraformではAPIキーやパスワードなどのシークレットはsensitiveとマークすることで、標準出力上でマスクすることが可能でしたが、tfstateには平文が書かれてしまう問題がありました。この問題に対し、OpenTofuはtfstateをクライアントサイドで暗号化する機能が追加されています。暗号鍵は単純なパスワードだけではなく、AWSやGCPのKMSなどを使うことも可能です。
https://opentofu.org/docs/language/state/encryption/

## Registry
Terraform Registry (registry.terraform.io)に相当するのは、OpenTofu Registry (registry.opentofu.org)です。既存のtfファイルやtfstateをそのまま使えるように、Terraform Registryへの通信は、暗黙にOpenTofu Registryに捻じ曲げられています。

最近WebUIもできて、検索やドキュメント参照などもできるようになってます。
https://search.opentofu.org/

OpenTofu Registryが建てられた時点でTerraform Registryに存在したProviderやModuleは一括で登録されており、バージョンアップも定期的にチェックして自動反映されているので、大体メジャーどころはカバーされていると思いますが、最近Terraform Registry側に新規登録されたものは、OpenTofu Registryには登録されていない可能性があります。

OpenTofu Registryの実体はCloudflareのCDNですが、メタデータは以下のリポジトリで管理されているので、自作ProviderやModuleなど欲しいものが登録されていない場合は、登録フローを読んでissueを立てると登録してもらえます。
https://github.com/opentofu/registry

## provider
Terraform ProviderはライセンスがMPL2のまま配布されており、プロバイダのプロトコルの互換性が維持される限りは、OpenTofuでTerraform Providerがそのまま使えます。また将来的なプロトコル変更があっても、Terraform Plugin Frameworkや、gRPCのprotoファイルがMPL2のまま配布されている限りは、OpenTofuにも後追いで実装することは可能です。

Terraform Registryは実質GitHub Releaseへのリダイレクタなのですが、例外があり、Hashicorp管理の公式プロバイダは、GitHubではリリース物が配布されていないので、OpenTofuはforkして自前でソースからビルドし直しています。Goコンパイラのバージョンやコンパイルのオプションなども微妙に違いますが、これが機能レベルで問題になるケースはほとんどないとは思います。

Hashicorp管理の公式プロバイダは、required_providersにhashicorp/awsと書いても、opentofu/awsと書いても、OpenTofu Registryはgithub.com/opentofu/terraform-provider-awsのリリース物をダウンロードするので、どちらでも結果は同じですが、TerraformとOpenTofuのモジュールの互換性という意味では、hashicorp/awsと書いておいた方が無難かなと思います。

プロバイダの依存ロックファイルの名前は.terraform.lock.hclのままで、.tofu.lock.hclではありません。また、前述の通り、OpenTofu Registryのアドレスが registry.opentofu.org になっている点と、プロバイダはバイナリとしては別物なので、当然.terraform.lock.hclに記録されるハッシュ値も異なります。Terraformで作成した .terraform.lock.hcl は、移行時に削除しなくても、tofu initしたタイミングで勝手に書き換えてくれます。

## testフレームワーク
Terraform v1.6から追加されたterraform testコマンドに相当する、tofu testコマンドは実装されています。
https://opentofu.org/docs/cli/commands/test/

Terraform v1.7に入ってるモック機能が、OpenTofu v1.8に実装されたりしているので、外部仕様は揃えようとしていますが、それぞれ独自に実装されているので、細かい挙動レベルの互換性はあまり期待し過ぎない方がよいのではないかと思っています。OpenTofuのみで使う分には問題ないと思いますが、Terraform / OpenTofu両方対応のモジュールのテストを書こうとするといろいろハマりそうな気はします。あえて[Terratest](https://github.com/gruntwork-io/terratest)などの3rd-partyツールを使ったほうが、差分吸収レイヤとして同じテストを使いまわしできてよいかもしれません。

# OpenTofuの周辺のエコシステム
OpenTofuの周辺のエコシステムは、現状まだまだ未発達です。
Terraform関連ツールのOpenTofuの対応状況は、awesome-opentofuを見るか、
https://github.com/virtualroot/awesome-opentofu

OpenTofuのGitHubのDiscussionに調査スレがあるので、このへんを参考にするとよいでしょう。
https://github.com/orgs/opentofu/discussions/1104

使ってるツールがOpenTofuに対応しているかは、そのツールのリポジトリのissueなどを見たほうが最新の状況が把握できて確実です。issueがあるが未対応なら+1しておき、issueがなければ立てておくとよいでしょう。メンテナの立場では、ユーザの需要がないとなかなか対応の優先度は上がりません。

すべてのツールを網羅することはできませんが、本稿執筆時点でハマりそうなポイントをいくつか書いておきます。

## バージョン管理
Terraformのバージョンをtfenvで切り替えてた人も多いと思いますが、tfenvはOpenTofu対応しない方針です。
https://github.com/tfutils/tfenv/issues/409

結果としてTerraform/OpenTofu両方対応したtenvが爆誕しました。
https://github.com/tofuutils/tenv

私はasdf派なので、asdfのOpenTofu用のプラグインを使っています。
https://github.com/virtualroot/asdf-opentofu

## IDE
Terraformの公式VSCode拡張とLSPサーバはHashiCorpが開発していたので、OpenTofu対応は期待できません。というわけでOpenTofu用にforkしちゃった人がいるようですが、本稿執筆時点では、あまり活発に開発されているようには見えません。
https://github.com/gamunu/vscode-opentofu
https://github.com/gamunu/opentofu-ls

需要はあると思いますが、IDEとLSPは個人が片手間でメンテするには巨大です。HashiCorpも過去にコミュニティが開発していたVSCode拡張を引き取ってフルタイムのエンジニアが開発している経緯を考えると、OpenTofuのフルタイムエンジニアを増やすとかじゃないと厳しいかもです。今後の続報は以下のissueをウォッチしておくのがよいかなと思います。
https://github.com/opentofu/opentofu/issues/970

一方、IntelliJには既にOpenTofu対応が入っています。HashiCorpが開発していないIDEは、普通にFeature Requestで需要があれば、そのうち対応してくれるのではないかと思います。
https://blog.jetbrains.com/idea/2024/11/intellij-idea-2024-3/#frameworks-and-technologies

## Linter
tflintは内部実装でTerraformのコードを流用しており、OpenTofuをサポートしない方針です。
https://github.com/terraform-linters/tflint/issues/2037

OpenTofuはTerraformにない構文が追加されていたり、式の評価のセマンティクスが微妙に違うので、これもforkをメンテするのは重そうです。今のところtofu lintコマンドとしてコアに入れちゃうか、tofulintという別ツールとしてforkしちゃうかみたいな議論はあるものの方針は決まっていません。
https://github.com/opentofu/opentofu/issues/2213

当面はOpenTofu独自拡張を使う場合は、.tofuファイルに分けてパースエラーにならないようにするなどの工夫が必要そうです。

## CI/CD
HCP Terraform相当のSaaSは、OpenTofuの開発を支えている[Spacelift](https://spacelift.io/)、[env0](https://www.env0.com/)、[Scalr](https://www.scalr.com/)あたりを使ってあげるとよいんじゃないでしょうか。

OSSでは[Atlantis](https://github.com/runatlantis/atlantis)、[tfaction](https://github.com/suzuki-shunsuke/tfaction)などは既にOpenTofu対応しています。[Digger](https://github.com/diggerhq/digger)はSaaS版とOSS版があり、どちらもOpenTofu対応しています。

あと[tfmigrate](https://github.com/minamijoyo/tfmigrate)をCI/CDに組み込んで使っている人もいると思いますが、環境変数 `TFMIGRATE_EXEC_PATH=tofu` をセットすることで、tofuコマンドが使えるようにしてあります。

ここで全部のツールを取り上げることはできませんが、各自自分の使ってるツールの対応状況を確認してみて下さい。

# 今後の展望
OpenTofuプロジェクトの現状を踏まえ、今後の展望についての個人的な見解を述べます。いろいろ推測を含むので、噂話レベルの期待値で読んで下さい。

## CNCFへの参加
OpenTofuはLinux Foundation傘下のプロジェクトですが、CNCF(Cloud Native Computing Foundation)への参加も狙っています。コンテナ技術やKubernetes関連のエコシステムであるCNCFも、組織構造的にはLinux Foundation傘下で、AWS、Google、Microsoftなど主要なクラウドベンダが名を連ねています。

Terraformプロバイダのライセンスは現状MPL2ライセンスのままですが、OpenTofu陣営としては、これをHashiCorp BSLに変更されると面倒なことになります。ただHashiCorp公式のプロバイダはHashiCorpが管理しているとはいえ、これをBSLに変更してOSSではなくなるとクラウドプロバイダとの協業が難しくなるのは想像に難くありません。梯子を外されかねない諸刃の剣なので、そんなに迂闊にはできないでしょう。CNCFとの関係強化は、もしものときに、HashiCorpが管理するTerraformプロバイダと、各クラウドプロバイダがそれぞれ管理するOpenTofuプロバイダという構図に持っていくための布石です。

OpenTofu v1.6のstableなリリースが出た2024年1月に、正式にCNCFのSandBoxプロジェクトへの提案が出されました。
https://github.com/cncf/sandbox/issues/81

今のところ大きな動きはないですが、2024年3月に開催されたKubeCon + CloudNativeCon Europeや、2024年11月に開催されたKubeCon + CloudNativeCon North Americaでは、OpenTofu Dayというイベントが開催されていました。クラウドプロバイダと友好な関係を構築するため、引き続き外堀を埋める活動は続くでしょう。

## IBMによるHashiCorpの買収
OpenTofuプロジェクトのもう1つのリスク要因として影響が見えていないのが、IBMによるHashiCorpの買収です。本稿執筆時点では、IBMに買収されることにHashiCorpの経営陣は合意しているものの、まだ正式な手続きは完了していません。

https://www.hashicorp.com/blog/hashicorp-joins-ibm

IBMによる買収後、収益改善のために有料版HCP Terraformの値上げぐらいであれば、そんなにOpenTofu側には影響はないと思いますが、ライセンスをMPL2に戻すぞという話になるとまた混沌としそうです。前科一犯なので、OpenTofu陣営はガバナンスを維持できるSteering Committeeの1社としてなら歓迎しようという立場を取るはずで、単純にOpenTofuをTerraform側にマージしようという話にはならないと思います。

逆にTerraformをHashiCorpの競合は使わないでねと言ってたのが、IBMの競合は使わないでねという話になると、リスク回避でOpenTofuの勢力が拡大するかもしれません。クラウドの分野ではIBMのシェアは低く、3大クラウドから見て比較的中立な立場ではありますが、IBMが買収してどうやって相乗効果を出そうとしているのか疑問です。右手で握手しながら左手で殴り合うのがビッグテックの戦い方なので、今後の展開はイマイチ読めません。

## OpenTofuの新機能
OpenTofuでは、今後のリリースのマイルストーンも公開されているので、眺めていくつか気になるポイントを説明します。本稿執筆時点のmainブランチはv1.9.0-alphaです。
https://github.com/opentofu/opentofu/milestones

OpenTofuの開発チームは、issueで+1が多いものを優先的に検討する方針なので、issueランキングを眺めて欲しい機能があれば、+1して投票しましょう。

https://github.com/opentofu/opentofu/issues/1496

### OpenTofu v1.9
#### provider for_each
providerをregionとかでfor_eachしたいよねというやつです。これも前述のbackendの変数化などと同じ作戦で、初期化のタイミングで静的に評価が可能な式に限定して制限を緩和し、providerの設定でvariableやlocal変数の参照ができるようになる予定です。providerのエイリアスを設定して、そのままmoduleにもproviderの参照を渡せるようになります。セキュリティやガバナンス系の設定は複数リージョンにまとめてapplyしたいことが多いので捗りそうです。この機能は、OpenTofu v1.9のalpha版に既に入っており、v1.9の目玉機能になる予定です。
https://github.com/opentofu/opentofu/issues/2123

Terraform側にも同じようなFeature Requestが長年あったのですが、後述するTerraform Stacksとして実装されてしまったので、実質的にTerraform単体では使えません。
https://github.com/hashicorp/terraform/issues/24476

#### tofu apply -exclude
tofu apply -targetで特定のリソースだけピンポイントにapplyするという良い子は真似してはいけないハックが既にありますが、さらに意識の低いtofu apply -excludeというフラグが生えて、やんごとなき理由で一部の差分だけを無視して残りをapplyすることができるようになります。この機能も既にマージされており、v1.9のalpha版には入っています。
https://github.com/opentofu/opentofu/pull/1900

ちなみに、このFeature RequestはTerraformのissueに9年前からあって、本稿執筆時点で1.4k以上+1されており、Terraform側のissueランキングで現在1位です。
https://github.com/hashicorp/terraform/issues/2253

ところでTerraformでは、後述するTerraform Stacksを実現するために、参照先の値が確定するまでapplyせずに保留されるDeferred Actionsという概念が内部的に導入されています。これは現状はTerraform Stacksのための機能というかんじですが、もうちょっと汎用化されると、excludeフラグっぽいものができるのではないかと期待されています。ただすぐにというかんじではなさそうです。

Terraformで人気のFeature RequestはOpenTofu側にも提案が持ち込まれる流れが続いており、OpenTofuの開発チームもユーザ獲得のために積極的に取り込んでいます。純粋なOSSライセンスであることに興味がない人でも、欲しい機能があるならOpenTofuに移行するモチベーションになり得ます。

#### 警告の全件表示
ものすごく地味ですが、OpenTofu v1.9のalpha版では、警告を省略せずに全件表示する tofu validate -consolidate-warnings=false フラグが生えています。たとえばプロバイダのリソース属性がdeprecatedになって警告を修正したいのに、警告がサマリされてしまい、修正箇所が全件特定できなくて困ったことはないでしょうか？という伝わる人にしか伝わらない、かゆいところに手が届くフラグです。
https://github.com/opentofu/opentofu/pull/1894

#### モジュール入力変数のバリデーション
モジュールのところでも言及しましたが、Terraform v1.9のモジュール入力で他の変数が参照できる機能が、OpenTofuでもv1.9マイルストーンとして予定されています。モジュール書いてると、変数a="foo"のときだけ変数bを必須にしたいとかあるので、これはぜひとも欲しい機能です。
https://github.com/opentofu/opentofu/issues/1336

#### モジュール入力変数のdeprecated記法
モジュールの入力変数をdeprecatedとマークする構文が検討されています。issueのステータスはacceptedになっていますが、まだ構文が確定しておらず実装方法は未定です。汎用モジュールのTerraformとの互換性という意味では注意が必要そうなので、ここで言及しておきます。
https://github.com/opentofu/opentofu/issues/1005

### OpenTofu v1.10
#### リソースタイプをまたぐstate mv
Terraform v1.8に入ってるリソースタイプをまたぐstate mvの実装です。Terraform v1.9ではnull_resourceからterraform_dataにstate mvできるようになってますが、この機能自体はプロバイダ側の実装がされないと使えず、今のところあまり注目されていません。しかしながら、プロバイダのメジャーバージョンアップなど破壊的変更で、リソースタイプが変わる場合にいいかんじにtfstateを調整してくれる機能として期待されています。
https://github.com/opentofu/opentofu/issues/1369

## Terraformの新機能
最後に、Terraform側で今後追加される機能についてもチラ見しておきましょう。本稿執筆時点のmainブランチはv1.11.0-alphaです。この記事を書き始めたときは、Terraform v1.10はまだRC版でしたが、書いてる途中でTerraform v1.10がリリースされてしまったので、Terraform v1.10の話題も便宜上ここに書いています。RC版から大きな変更点はないので、ご容赦下さい。

また関連するOpenTofu側のissueも合わせて貼っておくので、欲しい機能があれば+1しておきましょう。

### HCP Terraform
HashiConf 2024でTerraform Stacksのpublic betaが公開されました。これは複数のrootモジュール間の依存を定義して一括でapplyできる[Terragrunt](https://github.com/gruntwork-io/terragrunt)のような何かです。

https://www.hashicorp.com/blog/terraform-stacks-explained

OpenTofuのprovider for_eachと違って、内部的にDeferred Actionsという概念を導入して、参照がknown valueになるまでapplyを保留することができるようになっており、provider設定にリソースの参照を書くことも可能です。ただ、これはHCP Terraform(旧Terraform Cloud)の機能なので、Terraformを単体で使っている人は残念ながら利用できません。

ちなみにTerraform Stacksのオーケストレーション相当の機能は、OpenTofuとしては今のところTerragruntを使ってくれというスタンスのようです。
https://github.com/opentofu/opentofu/issues/931

TerragruntにはもともとStacksのような機能は以前からありましたが、最近Terragrunt Stacksという新機能で概念を整理しなおしているところです。
https://github.com/gruntwork-io/terragrunt/issues/3313

Terragrunt自体は今のところTerraform v1.6以降も引き続きサポートしており、TerraformとOpenTofuの両方をサポートしています。
https://terragrunt.gruntwork.io/docs/getting-started/supported-versions/

### Terraform v1.10
#### S3-native state locking
これまでs3バックエンドでtfstateのロックを取るのにDynamoDBが必要だったのですが、最近s3にconditional writesという機能が生えて、これで実質的にファイルロックが作れます。結果として、DynamoDBなしでs3だけでtfstateのロックができるようになりました。
https://github.com/hashicorp/terraform/pull/35661

対応するOpenTofu側のissueは以下です。独立した機能で技術的なブロッカーはないと思うので、そのうちOpenTofu側にも実装されるのではないかと思ってます。
https://github.com/opentofu/opentofu/issues/599

#### Ephemeral Values / Resources
tfstateにクレデンシャルを保存したくない問題の根本的な解決策として、planとapplyの間で永続化されないEphemeral Valuesという概念が導入されました。
https://developer.hashicorp.com/terraform/language/values/variables#exclude-values-from-state

さらにresourceブロックとは別に新しくephemeralブロックが導入され、tfstateに保存されないEphemeral Resourcesを定義できるようになりました。これにより、HashiCorp VaultやAWS Secret Managerなどから取得したクレデンシャルをproviderの認証情報として渡すことが可能になります。
https://developer.hashicorp.com/terraform/language/resources/ephemeral

この機能を使うにはプロバイダ側の対応も必要ですが、たとえばAWSプロバイダv5.77.0に aws_secretsmanager_secret_version と aws_kms_secrets の実装が入っています。本稿執筆時点では、Vaultプロバイダはまだ未対応です。
https://github.com/hashicorp/terraform-provider-aws/pull/40009

対応するOpenTofu側のissueはこちらです。
https://github.com/opentofu/opentofu/issues/1996

### Terraform v1.11
#### Write only attribute
Ephemeral Valueの概念をさらに推し進めて、Write only属性という概念が導入される予定です。これはたとえば、DBのパスワードなどのリソースの属性をwrite-onlyとマークすることで、特定の属性の値だけtfstateに書き込まないという制御が可能となります。Ephemeral Resourcesと組み合わせると、パスワードは外部のSecret Managerから取得するということもできそうです。プロバイダのプロトコルファイルがmainブランチにマージされているのを観測しているので、v1.11には入る見込みです。
https://github.com/hashicorp/terraform/pull/35989

ちなみにtfstateにクレデンシャルが平文で保存されてしまう問題に対して、tfstateを暗号して保存しようというOpenTofuのアプローチに比べて、そもそもtfstateに保存するべきではないというTerraform側のアプローチの方が筋が良さそうに見えます。このEphemeral ValuesやWrite only attributeの構想とプロトタイプの設計をしてたのもapparentlymart氏でした。オリジナルの作者がいるので、そのうちOpenTofuにも実装されるのは期待してよいと思います。
https://github.com/hashicorp/terraform/pull/35077

# おわりに
この記事では、TerraformのOSS版のforkであるOpenTofuについて紹介し、OpenTofuの採用を検討しているTerraform職人が押さえておくべきポイントをまとめました。

OpenTofu界隈は現在進行系でいろんな議論が並列で進んでおり、しばらく混沌としているとは思いますが、いきなりプロジェクトがなくなることは、さすがにもうなさそうな雰囲気です。Terraformの便利機能は随時取り込んで互換性を維持しつつ、ユーザ獲得のためにOpenTofu独自機能をいろいろ追加していけると、Infrastructure as Codeツールとして独自の地位を確立するのではないかと期待しています。

現時点では周辺のエコシステムが追いついてきてない感は否めませんが、まずはユーザが増えないとエコシステムは広がっていきません。多少人柱になってもよいぞという人は、とりあえず小さいプロジェクトからでも試してみて、みんなでオープンな選択肢を育てていきましょう。