Terraform の条件式は単独ではリソース生成を抑止できません。リソースの有無を切り替えるには count または for_each を使います。
属性レベルの ON/OFF は null を返す条件式が定番です。plan 時に値が不明 (unknown) な場合の挙動や、型整合性のルールも試験で頻出です。
Terraform の条件式は condition ? true_val : false_val の形式です。条件が true なら true_val、false なら false_val が評価されます。未選択の枝は評価されませんが、両枝の型は互換である必要があります。
試験観点では「型の整合」と「評価されない枝に未定義参照があっても良い」点がよく問われます。条件が plan 時に不明 (unknown) の場合、結果も unknown になり得ます。count/for_each の条件に unknown を与えるのは不可で、plan で決定可能である必要があります。
条件式の型整合の例
variable "env" { type = string }
locals {
is_prod = var.env == "prod"
# OK: 数値と数値
replicas = local.is_prod ? 3 : 1
# OK: リストとリスト (どちらも list(string))
cidrs = local.is_prod ? ["10.0.0.0/8"] : ["192.168.0.0/16"]
# NG 例 (型不一致): 数値 と 文字列 -> plan エラー
# bad = local.is_prod ? 1 : "1"
}Terraform はリソースブロック自体を条件式で囲めません。リソースの作成/非作成を切り替えるには meta-argument の count または for_each を使います。単一リソースの ON/OFF は count、キー安定性を保った複数作成は for_each が適しています。
count/for_each の式は plan 時に決定可能である必要があります。たとえば data ソースに依存し apply まで分からない値を条件に使うとエラーになります。
| 手段 | 主な用途 | 注意点・短所 | 典型コード |
|---|---|---|---|
| 条件式のみ | 値や式の切替 (属性/変数) | リソースの有無は切替不可 | var.enabled ? "on" : "off" |
| count | 単一リソースの ON/OFF | インデックス参照の安全化が必要 | count = var.create ? 1 : 0 |
| for_each | 複数作成・キー安定性 | キーの変動は再作成の原因 | for_each = var.create ? {"main"=true} : {} |
| null を返す | 属性の無効化 (未指定扱い) | ブロックは dynamic が必要 | tags = var.add_tags ? local.tags : null |
条件付き作成 (count) の流れ
var.create
|
v
condition ? 1 : 0 ---> count = 1 ----> resource.example[0] が作成
\
\-> count = 0 ----> インスタンスは 0 件 (作成なし)count/for_each によるリソース ON/OFF と安全な参照
variable "create" { type = bool }
# 単一の ON/OFF は count
resource "null_resource" "one" {
count = var.create ? 1 : 0
triggers = {
purpose = "demo"
}
}
# 参照は条件式または try で安全化
output "one_id" {
value = var.create ? null_resource.one[0].id : null
}
output "one_id_try" {
value = try(null_resource.one[0].id, null)
}
# キー安定性を重視するなら for_each
resource "null_resource" "named" {
for_each = var.create ? { main = true } : {}
triggers = {
name = each.key
}
}
output "named_keys" {
value = keys(null_resource.named)
}多くの引数は null を与えると「未指定」と同等になります。タグや user_data などを条件により省略したい場合、条件式の結果として null を返すのが安全です。
ブロック (versioning など) を ON/OFF する場合は dynamic ブロックと条件式/for_each の組み合わせを用います。
引数とブロックを条件で省略する例
# 属性を null で省略
variable "attach_user_data" { type = bool }
resource "aws_instance" "web" {
ami = "ami-xxxxxxxx"
instance_type = "t3.micro"
user_data = var.attach_user_data ? file("${path.module}/init.sh") : null
}
# ブロックを dynamic で ON/OFF
variable "enable_versioning" { type = bool }
resource "aws_s3_bucket" "b" {
bucket = "example-bucket-12345"
dynamic "versioning" {
for_each = var.enable_versioning ? [1] : []
content {
enabled = true
}
}
}
for_each はキーに基づいてリソースを管理するため、条件式で集合をフィルタする際はキーが安定するように設計します。キーが変わると destroy/create が発生します。
enabled フラグによる部分作成は、内包表記と if 句で自然に書けます。全体を無効化するスイッチは空マップ {} を返す条件式で包みます。
enabled フラグでサブセット作成 + 全体スイッチ
variable "manage_users" { type = bool }
variable "users" {
type = map(object({ enabled = bool, email = string }))
}
locals {
# enabled のみを抽出
enabled_users = { for k, v in var.users : k => v if v.enabled }
}
resource "example_user" "this" {
# 全体スイッチ: false なら空マップで 0 件
for_each = var.manage_users ? local.enabled_users : {}
name = each.key
email = each.value.email
}
条件式は選ばれた枝のみ評価されます。したがって、true の枝だけが参照するリソースが false のときに未定義でも、エラーにはなりません。一方で count/for_each の式は plan 時に既知でなければならず、unknown 値だとエラーになります。
optional なリソース参照は条件式 または try() で安全化します。try は引数を順に評価し、最初にエラーにならない式を返します。
条件式/try による安全な参照
variable "create" { type = bool }
resource "null_resource" "maybe" {
count = var.create ? 1 : 0
}
# 条件式で [0] の参照をガード
output "maybe_id" {
value = var.create ? null_resource.maybe[0].id : null
}
# try で評価を順次試行 (count=0 でも安全)
output "maybe_id_try" {
value = try(null_resource.maybe[0].id, null)
}
条件式は値の切替、count/for_each はリソースの有無や個数制御、null は属性の未指定化。この役割分担を守ると、plan が読みやすく安全になります。
試験では「リソースブロックを条件式で包めない」「count/for_each は plan 時既知」「未選択枝は評価されない」の3点を確実に押さえましょう。
モジュール切替の最小パターン
variable "create_subnet" { type = bool }
module "subnet" {
source = "./modules/subnet"
count = var.create_subnet ? 1 : 0
# モジュール出力の安全参照
}
output "subnet_id" {
value = try(module.subnet[0].id, null)
}
Associate
問題 1
var.create_bucket が false のときに S3 バケットを作成しない最も適切な方法はどれか。出力でバケット ID を安全に参照する必要がある。
正解: A
リソースの有無は count/for_each で制御します。参照は条件式または try() で安全化します。resource ブロック自体は条件式で包めません。lifecycle は作成の有無を制御しません。
条件式は両方の枝を評価しますか?未選択側に存在しないリソース参照を書いたらどうなりますか?
選択された枝のみ評価されます。未選択側は評価されないため、そこに count=0 のリソース参照があってもエラーになりません。ただし両枝の型は互換である必要があります。
count/for_each の条件に data ソース由来で plan 時に不明な値を使えますか?
使えません。count/for_each は計画段階で値が既知である必要があります。unknown を渡すと plan エラーになります。変数や locals で plan 時に決定できる値を使ってください。
条件式で null を返すと属性はどう扱われますか?
多くの引数では null は「未指定」と等価になり、プロバイダはその属性を送信しません。ブロックの ON/OFF は dynamic と for_each の組み合わせで行います。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
Terraform HCL 構文の基礎:Block / Attribute / Expression を正しく使い分ける
Terraform Associate で頻出の HCL 構文を、ブロック・属性・式の3視点で整理。実務で迷いがちな書き...
Terraform Authoring & Ops Pro: 上位資格の範囲と対策
上位レベルを想定したTerraformの設計・運用ドメインを整理し、実務で通用する対策を提示。モジュール設計、ステート運...
Terraform Providers の基本: プラグイン型アーキテクチャを正しく使いこなす
Associate レベルで押さえるべき Provider の基礎、インストール、バージョニング、認証、エイリアス運用を...
Terraform Resourceブロック徹底ガイド: 最小単位のリソース定義
Associateレベルで押さえるべきResourceブロックの構造、依存関係、メタ引数、ライフサイクル制御を実務目線で...
Terraform Data Source徹底理解:既存リソースの参照で壊さず足す
Terraform Associate向けに、Data Sourceを用いた既存リソース参照の基本、選択基準、評価順序、...