Terraform

Terraform 条件式(ternary)で実現する条件付きリソースの実務パターン【Associate対策】

2026-04-19
NicheeLab編集部

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 で決定可能である必要があります。

  • 両枝は同じ型または同型へ暗黙変換可能であることが必要
  • 未選択の枝は評価されないため、存在しないリソース参照を書いても可
  • 条件が unknown のとき: 結果も unknown。count/for_each には使えない
  • 文字列/数値/コレクションでの型不一致は 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"
}

条件付きリソース作成: count と for_each の定番パターン

Terraform はリソースブロック自体を条件式で囲めません。リソースの作成/非作成を切り替えるには meta-argument の count または for_each を使います。単一リソースの ON/OFF は count、キー安定性を保った複数作成は for_each が適しています。

count/for_each の式は plan 時に決定可能である必要があります。たとえば data ソースに依存し apply まで分からない値を条件に使うとエラーになります。

  • 単数なら count = var.create ? 1 : 0
  • 複数・キー重視なら for_each = var.create ? {"main"=true} : {}
  • 参照時は try(...) または条件式で [0] 参照を安全化
  • count/for_each は plan 時に known であることが必須
手段主な用途注意点・短所典型コード
条件式のみ値や式の切替 (属性/変数)リソースの有無は切替不可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)
}

属性の ON/OFF は null を返す条件式で

多くの引数は null を与えると「未指定」と同等になります。タグや user_data などを条件により省略したい場合、条件式の結果として null を返すのが安全です。

ブロック (versioning など) を ON/OFF する場合は dynamic ブロックと条件式/for_each の組み合わせを用います。

  • 引数に null → その引数は未指定と同じ扱い
  • ブロックは dynamic + for_each = 条件 ? [1] : []
  • merge/map 演算と組み合わせると柔軟に ON/OFF 可能

引数とブロックを条件で省略する例

# 属性を 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 の条件分岐とキー安定性

for_each はキーに基づいてリソースを管理するため、条件式で集合をフィルタする際はキーが安定するように設計します。キーが変わると destroy/create が発生します。

enabled フラグによる部分作成は、内包表記と if 句で自然に書けます。全体を無効化するスイッチは空マップ {} を返す条件式で包みます。

  • マップのキーは永続識別子を使う (例: ユーザーID)
  • if 句で部分的に省く + 全体スイッチで {} を返す
  • キー集合が変わる影響を plan で確認する

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
}

unknown と評価順序の落とし穴

条件式は選ばれた枝のみ評価されます。したがって、true の枝だけが参照するリソースが false のときに未定義でも、エラーにはなりません。一方で count/for_each の式は plan 時に既知でなければならず、unknown 値だとエラーになります。

optional なリソース参照は条件式 または try() で安全化します。try は引数を順に評価し、最初にエラーにならない式を返します。

  • 条件式は未選択の枝を評価しない
  • count/for_each は plan で known 必須
  • 安全な参照: var.create ? res[0].id : null / try(res[0].id, null)

条件式/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点を確実に押さえましょう。

  • Do: 単一リソースの ON/OFF → count = var.flag ? 1 : 0
  • Do: 複数 + 安定キー → 条件付き for_each
  • Do: 属性の省略 → 条件式で null を返す
  • Don't: resource ブロック自体を条件で包む (文法的に不可)
  • Don't: plan 時 unknown を count/for_each に渡す
  • Don't: 変動しやすいキーで for_each する

モジュール切替の最小パターン

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 を安全に参照する必要がある。

  1. resource に count = var.create_bucket ? 1 : 0 を設定し、output で try(aws_s3_bucket.main[0].id, null) を使う
  2. resource ブロック全体を var.create_bucket ? resource {} : null で条件分岐する
  3. lifecycle で create_before_destroy = false を設定する
  4. output で aws_s3_bucket.main[0].id を直接参照し、plan エラーが出たら無視する

正解: 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 の組み合わせで行います。

この記事で学んだ内容を問題で確認しましょう

16,000問以上の問題で実力チェック

無料で問題を解いてみる
この記事の著者

NicheeLab編集部

データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。


関連記事
Terraform

Terraform HCL 構文の基礎:Block / Attribute / Expression を正しく使い分ける

Terraform Associate で頻出の HCL 構文を、ブロック・属性・式の3視点で整理。実務で迷いがちな書き...

Terraform

Terraform Authoring & Ops Pro: 上位資格の範囲と対策

上位レベルを想定したTerraformの設計・運用ドメインを整理し、実務で通用する対策を提示。モジュール設計、ステート運...

Terraform

Terraform Providers の基本: プラグイン型アーキテクチャを正しく使いこなす

Associate レベルで押さえるべき Provider の基礎、インストール、バージョニング、認証、エイリアス運用を...

Terraform

Terraform Resourceブロック徹底ガイド: 最小単位のリソース定義

Associateレベルで押さえるべきResourceブロックの構造、依存関係、メタ引数、ライフサイクル制御を実務目線で...

Terraform

Terraform Data Source徹底理解:既存リソースの参照で壊さず足す

Terraform Associate向けに、Data Sourceを用いた既存リソース参照の基本、選択基準、評価順序、...

Terraformの記事一覧 (101件)
© 2026 NicheeLab All rights reserved.