💡

Terraformで別リソースに関連付けられたリソースの再作成を行うための備忘録

2022/12/27に公開

はじめに

みなさん、こんにちは。良いタイトルが思いつかずリソースを連呼する人になりました。

本題ですが、Terraform でリソースを作成する際、以下のようなケースに直面することがあるのではないでしょうか(ありますよね…?

  • リソース作成時、とあるArgument の値を間違えて作成してしまった(ちゃんと確認しましょう
  • そのArgument の値を変更すると新しいリソースが強制的に作成されるとドキュメントに記載されている。
  • terraform plan は通ったので実行すると、関連付けられたリソースがいるため、再作成できずエラーとなってしまう
  • GUIで関連付けを解除してtfstate ファイルを直接変更するといった手法は取らず、Terraform 上で完結させたい

Terraform に慣れた方ならすぐ解法が浮かぶと思いますが、私は「どうしようかな」となったので、備忘も兼ねて記事を書いてみようと思います。

結論:一時的に別リソースを作成して対処しました

例として、以下のようなケースを考えます(今の案件がAzure のためAzure を例示しますが、AWS やGCP でも同様かと…

  1. Application Gateway (L7のロードバランサー)にWAFポリシーを関連付けて作成。
  2. 上記WAFポリシーの名前を間違えて作成したため、terraform.tfvarsに記載された値を修正。
  3. plan を実行し、destroy とcreate により再作成が行われることを確認。
  4. apply 実行後、「WAFポリシーを削除できませんでした」というエラーが発生して終了。

なぜ起きるのか

これは例の3と4にあるとおりですが、リソース再作成の際にはTerraform がdestroy→create を行うため、削除に失敗するとcreate も出来ないというのが理由となります。
ではなぜ削除に失敗するかというと、1にあるロードバランサーがWAFを必須とするタイプのものであり、関連付けを行ったあとにWAFポリシーのみ削除することが出来ない、という仕様が原因でした。(このあたりは関連付けしているサービスの仕様を抑えないといけないなと感じました)

そのため、結論に書いたとおり、一時的に新しいWAFポリシーを作成し、ロードバランサーに関連付けを行うとともに、間違えて作成したWAFポリシーの名前を変更後、再度関連付けを行うという手法を取りました。最後に一時的に作成したリソースを削除して完了です。

具体的なイメージは以下のとおりです(途中のapplyはまとめることが出来ると思います)

1.初期状態:誤った名前で作成したWAFポリシー"CORRECT"の名前を変更したいが、関連付けによりWAFポリシー削除不可の状態

Application Gateway FIXED : WAFポリシー"CORRECT"が関連付けられた状態
WAFポリシー CORRECT : Application Gateway"FIXED"に関連付けられた状態

main.tf
# WAF_v2 で作成したApplication Gateway
resource "azurerm_application_gateway" "FIXED" {
  name                = "NAME_FIXED"
  # 1.WAFポリシー"CORRECT"と関連付け
  firewall_policy_id  = azurerm_web_application_firewall_policy.CORRECT.id
}

# 誤った名称で作成したWAFポリシー
resource "azurerm_web_application_firewall_policy" "CORRECT" {
  # 1.誤った名称"NAME_WRONG"
  name                = "NAME_WRONG"
}

2.新しいWAFポリシー"TMP"を仮作成してapply

Application Gateway FIXED : WAFポリシー"CORRECT"が関連付けられた状態
WAFポリシー CORRECT : Application Gateway"FIXED"に関連付けられた状態
WAFポリシー TMP : 独立した状態

main.tf
# WAF_v2 で作成したApplication Gateway
resource "azurerm_application_gateway" "FIXED" {
  name                = "NAME_FIXED"
  firewall_policy_id  = azurerm_web_application_firewall_policy.CORRECT.id
}

# 誤った名称で作成したWAFポリシー
resource "azurerm_web_application_firewall_policy" "CORRECT" {
  name                = "NAME_WRONG"
}

# 2.WAFポリシーを仮作成
resource "azurerm_web_application_firewall_policy" "TMP" {
  name                = "NAME_TMP"
}

3.仮作成したWAFポリシー"TMP"をApplication Gateway に関連付けてapply

Application Gateway FIXED : WAFポリシー"TMP"が関連付けられた状態
WAFポリシー CORRECT : 関連付けが外れて独立した状態
WAFポリシー TMP : Application Gateway"FIXED"に関連付けられた状態

main.tf
# WAF_v2 で作成したApplication Gateway
resource "azurerm_application_gateway" "FIXED" {
  name                = "NAME_FIXED"
  # 3.仮作成したWAFポリシー"TMP"と関連付け
  firewall_policy_id  = azurerm_web_application_firewall_policy.TMP.id
}

# 誤った名称で作成したWAFポリシー
resource "azurerm_web_application_firewall_policy" "CORRECT" {
  name                = "NAME_WRONG"
}

# WAFポリシーを仮作成
resource "azurerm_web_application_firewall_policy" "TMP" {
  name                = "NAME_TMP"
}

4.WAFポリシー"CORRECT"の名前を変更してapply(再作成)

Application Gateway FIXED : WAFポリシー"TMP"が関連付けられた状態
WAFポリシー CORRECT : name = "NAME_WRONG" で作成されたWAFポリシーを削除(destroy)後、name="CORRECT" のWAFポリシー"CORRECT"を再作成
WAFポリシー TMP : Application Gateway"FIXED"に関連付けられた状態

main.tf
# WAF_v2 で作成したApplication Gateway
resource "azurerm_application_gateway" "FIXED" {
  name                = "NAME_FIXED"
  firewall_policy_id  = azurerm_web_application_firewall_policy.TMP.id
}

# 誤った名称で作成したWAFポリシー
resource "azurerm_web_application_firewall_policy" "CORRECT" {
  # 4.この名前を変更してapplyすることでリソースが再作成(destroy→create)される
  # name                = "NAME_WRONG"
  name                = "NAME_CORRECT"
}

# WAFポリシーを仮作成
resource "azurerm_web_application_firewall_policy" "TMP" {
  name                = "NAME_TMP"
}

5.WAFポリシー"CORRECT"とApplication Gateway"FIXED" を関連付けしてapply

Application Gateway FIXED : WAFポリシー"CORRECT"が関連付けられた状態
WAFポリシー CORRECT : Application Gateway"FIXED"に関連付けられた状態
WAFポリシー TMP : 関連付けが外れて独立した状態

main.tf
# WAF_v2 で作成したApplication Gateway
resource "azurerm_application_gateway" "FIXED" {
  name                = "NAME_FIXED"
  # 5.WAFポリシー"CORRECT"と再度関連付けを行う
  firewall_policy_id  = azurerm_web_application_firewall_policy.CORRECT.id
}

# 誤った名称で作成したWAFポリシー
resource "azurerm_web_application_firewall_policy" "CORRECT" {
  # この名前を変更することでリソースが再作成(destroy→create)される
  # name                = "NAME_WRONG"
  name                = "NAME_CORRECT"
}

# WAFポリシーを仮作成
resource "azurerm_web_application_firewall_policy" "TMP" {
  name                = "NAME_TMP"
}

6.仮作成したWAFポリシー"TMP"の記述を削除してapply

Application Gateway FIXED : WAFポリシー”CORRECT”が関連付けられた状態
WAFポリシー CORRECT : Application Gateway”FIXED”に関連付けられた状態
WAFポリシー TMP : 削除された状態

main.tf
# WAF_v2 で作成したApplication Gateway
resource "azurerm_application_gateway" "FIXED" {
  name                = "NAME_FIXED"
  firewall_policy_id  = azurerm_web_application_firewall_policy.CORRECT.id
}

# 誤った名称で作成したWAFポリシー
resource "azurerm_web_application_firewall_policy" "CORRECT" {
  # name                = "NAME_WRONG"
  name                = "NAME_CORRECT"
}

# 6.仮作成のWAFポリシーは記述自体を削除(Terraform がdestory してくれる)

長くなりましたが、ここまで対応することで、誤った名称で作成したWAFポリシーの名称を変更し、元のロードバランサーに関連付けを行うことができました。

まとめ

今回はtfstate ファイルに手を加えたくない、そもそもAzure にそこまで明るくない()というのもあって、このような少し冗長な手法を取りました。一番はレビューでしっかりと確認することですが、どうしても抜け漏れは出てしまうと思います。そのような場合でも、Terraform の管理内でリソースを上手く更新していくために、色々なパターンに遭遇して知見を貯めておきたいな、と改めて感じました。

他にもっと良い方法をご存知の方がいらっしゃれば、ぜひコメントいただけたら幸いです。
最後までお読みいただき、ありがとうございました!

Discussion