🏸

【Terraform】lifecycleのprevent_destroyでリソースの意図しない削除を防ぐ

に公開

概要

https://developer.hashicorp.com/terraform/tutorials/state/resource-lifecycle#prevent-resource-deletion

Terraformのlifecycleブロックのprevent_destroyというオプションについての記事です。

このオプションを設定することで、重要なリソースが意図せず削除されるのを防ぐことができます。

設定を変更するとリソースが作り直される場合がある

リソース属性の変更内容によっては、既存のリソースを直接更新することができない場合があります。このようなケースでは、Terraformはクラウドプロバイダーの仕様に従い、現在のリソースを削除して新しいリソースを作り直します。

例えば、AzureのパブリックIPリソースにzones属性を追加する変更を行うと、forces replacementというメッセージが表示され、リソースが作り直される計画が立てられることがあります。これは以前に以下の記事を書いているときに遭遇した事例です。

https://zenn.dev/shimiyu/articles/9beee4909aab47#インポート後の確認と差分の解消

terraform plan
# ... 略
Terraform will perform the following actions:

  # module.public_ip.azurerm_public_ip.main must be replaced
-/+ resource "azurerm_public_ip" "main" {
      + fqdn                    = (known after apply)
      ~ id                      = "/subscriptions/****/resourceGroups/terraform-sample-dev-rg/providers/Microsoft.Network/publicIPAddresses/pip-terraform-import-test" -> (known after apply)
      ~ ip_address              = "74.***.***.56" -> (known after apply)
      - ip_tags                 = {} -> null
        name                    = "pip-terraform-import-test"
      - tags                    = {} -> null
      - zones                   = [ # forces replacement
          - "1",
          - "2",
          - "3",
        ] -> null
        # (9 unchanged attributes hidden)
    }

Plan: 1 to add, 0 to change, 1 to destroy.

zonesという項目にforces replacementと表示されていることやPlan: 1 to add, 0 to change, 1 to destroy.とあることから、既存リソースが削除され、再作成されようとしていることが分かります。

しかし、場合によっては再作成されると困るケースもあります。今回の例で言えば、パブリックIPの再作成によりIPアドレスが変更されてしまい、関連するシステムやサービスに影響を及ぼす可能性があります。

こういった問題を防ぐには、plan実行時に変更内容をちゃんと確認することが大事です。ですが、変更内容が多い場合は重要な変更点を見落とす可能性も高く、plan時の出力内容を確認するだけでは心許ないです。

対策: prevent_destroyを設定する

上に書いたような問題への対処法の1つがlifecycleprevent_destroyです。

意図せぬ削除を防ぎたいリソースのresourceブロックにlifecycleprevent_destroyを設定します。

resource "azurerm_public_ip" "main" {
  name                     = var.name
  resource_group_name      = var.resource_group_name
  location                 = var.location
  allocation_method        = "Static"

# リソースが再作成される変更
+  zones                    = ["1", "2", "3"]
  
+  lifecycle {
+    prevent_destroy = true
+  }
}

この状態でリソースが再作成されてしまうような変更を行い、planを実行すると、「このインスタンスは削除できない(Error: Instance cannot be destroyed)」というエラーになります。

terraform plan
# ...略
Terraform planned the following actions, but then encountered a problem:
# ...略

 Error: Instance cannot be destroyed
 
   on ../../modules/public_ip/main.tf line 1:
    1: resource "azurerm_public_ip" "main" {
 
 Resource module.public_ip.azurerm_public_ip.main has
 lifecycle.prevent_destroy set, but the plan calls for this resource to be
 destroyed. To avoid this error and continue with the plan, either disable
 lifecycle.prevent_destroy or reduce the scope of the plan using the -target
 option.

このように、lifecycle.prevent_destroyを使うことで、設定変更による意図しないリソース削除を防ぐことができます。

最後に

以上です!

大した内容ではないのですが、「リソースを作成し直されたら困る!」と分かっているものには確実にprevent_destroyを設定しておきたいですね。

Discussion