Tech系サービスやガジェットの使い心地、自分の作業環境、資産運用について気が向いたときに記録を残しています。

記事内のAmazonアソシエイト適格販売及び、Google Adsenseでお小遣いを得ています。

Terraformのlookup()は引数内のモジュールoutputを解決する前に動く

起きたこと

利用しているAWS WAFv2の社内モジュールでは、変数に応じてマネージドルール or IPset or regexルールをACLに登録する仕組みにしています。 ipsetやregexのルールはまた別のモジュールで指定しているので、WAFモジュール側でどのルールを渡されたかlookup()を用いて判定しようとしています。

# ipruleモジュール
resource "wafv2_iprule" {
    ...
    output = {
        name = this.name
        arn = this.arn
    }
}

# WAFv2モジュール
resource "wafv2_webacl" {
 for_each = lookup(var.iprule, "arn", false) == false ? [] : [""]
 ....
 for_each = lookup(var.regex, "arn", false) == false ? [] : [""]
 ....

こんな感じで使っています

module "huga"{
  source = "hogehoge"
...
  iprule = { # ここをregexとかmanagedに変更すると指定ルールに応じた実装になる
    rule_arn = ""
  }
}

この実装だと、managedruleのようなarnがあらかじめ定まっている場合を除き、うまく動作しません。 ipruleとregexどちらも存在するかのように判定してしまい、変数のobject構造がmoduleの期待とズレてしまいます。

原因

lookup()は引数の対象オブジェクト内にある変数の解決を待たずに動作する(undefind状態のまま評価してしまう)ので、lookup(var.regex, "arn", false) がエラーを返しており、デフォルト値であるfalseを返さないことが原因です。

map内部の変数は全部解決してから評価してほしいのに…

解決策

lookup()ではなくmoduleで変数の存在確認をするにはtry()を使いましょう。

モジュールをいじれない場合はruleのモジュールを先にapplyすると、tfstateからarnを引っ張ってきて式を評価するのでワークアラウンドとしては -target を使ってapplyするのも一つの手です。

github.com