TerraformのDynamic Blocksには、sensitiveなvalueを使用できない

2024/09/16に公開

TL;DR

  • TerraformのDynamic Blocksには、sensitiveなvalueを使用できない
  • エラーメッセージでそのことに言及してくれないため、調査の時にハマりやすい

※ v1.9.5時点での情報です。

Dynamic Blocksとは

Terraformには Dynamic Blocks という機能があり、listやmapを元に繰り返しblock定義することができます。

例えば kubernetes_deployment でenvを複数指定する際は、以下のように env blockを複数定義します。

terraform {
  required_providers {
    kubernetes = {
      source  = "hashicorp/kubernetes"
      version = "~> 2.0"
    }
  }
}

provider "kubernetes" {
  config_path = "~/.kube/config"
}

resource "kubernetes_deployment" "example" {
  metadata {
    name = "terraform-example"
  }

  spec {
    replicas = 2

    selector {
      match_labels = {
        app = "example"
      }
    }

    template {
      metadata {
        labels = {
          app = "example"
        }
      }

      spec {
        container {
          image = "nginx:latest"
          name  = "example"

          env {
            name  = "APP_ENV"
            value = "production"
          }

          env {
            name  = "DEBUG_MODE"
            value = "false"
          }
        }
      }
    }
  }
}

これをDynamic Blocksを使用すると以下のように書き換えることができます。

(省略...)

variable "env_variables" {
  description = "環境変数のマップ"
  type        = map(string)
  default = {
    "APP_ENV"    = "production"
    "DEBUG_MODE" = "false"
  }
}

resource "kubernetes_deployment" "example" {
  metadata {
    name = "terraform-example"
  }

(省略...)

      spec {
        container {
          image = "nginx:latest"
          name  = "example"

          dynamic "env" {
            for_each = var.env_variables
            content {
              name  = env.key
              value = env.value
            }
          }
        }
      }
    }
  }
}

これにより環境変数の増減があっても、blockを都度書き換える必要がなくなります。

sensitiveなvalue使用によるエラー

Terraformのvariableには sensitive というフラグがあります。

https://developer.hashicorp.com/terraform/tutorials/configuration-language/sensitive-variables

パスワードやapi token等にはこのフラグを設定することで、plan時に値が出力されなくなります。
しかしこのフラグをDynamic Blocksのvariableに使用すると、plan/apply時にエラーになってしまいます。

variable "env_variables" {
  description = "環境変数のマップ"
  type        = map(string)
  default = {
    "APP_ENV"    = "production"
    "DEBUG_MODE" = "false"
  }
+ sensitive = true
}
% terraform plan
╷
│ Error: Invalid dynamic for_each value
│
│   on main.tf line 41, in resource "kubernetes_deployment" "example":41:             for_each = var.env_variables
│
│ Cannot use a map of string value in for_each. An iterable collection is required.
╵

Cannot use a map of string value in for_each. An iterable collection is required.

この時のエラーメッセージがsensitive valueの使用について言及してくれません。
特にaws_ssm_parameterなど、暗黙的にsensitiveフラグが有効になるresourceもあるため、より注意が必要です。

原因

この件についてissueが作成されています。
そのやりとりによるとterraformが依存しているhashicorp/hcl がsensitiveデータによるループに対応していないそうです。

https://github.com/hashicorp/terraform/issues/29744#issuecomment-942356358

The cause is that we haven't added support for sensitive for_each values in the hcl/dynblock package. Doing so seems possible, but not trivial. Sensitive collections are not iterable, and removing the sensitivity without later reapply it to the individual values is not an acceptable solution to that.

エラーメッセージを修正すべきという議論もされてますが、まだ対応はされてなさそうです。

対策

対策としては以下の二択になりそうです。

  • Dynamic Blocksの使用を避ける
  • 対象のvariableに sensitive = false を設定する

しかし後者についてはplan時に秘匿情報が出力される可能性があるため注意が必要です。

Discussion