Terraform

Terraform variable validationで入力値を堅牢にする: 入力値の検証ルールをAssociate/Pro視点で整理

2026-04-19
NicheeLab編集部

variable validationは、型制約では表しきれないビジネスルールをTerraform言語で宣言的に検査する機能です。エラーメッセージを明示でき、モジュールの再利用性と安全性を高めます。

Associateでは基本構文・評価タイミング、Proではコレクション/条件付き/unknownの扱いが頻出。実務でもmoduleの入口で落とせる設計が保守コストを下げます。

variable validationの基本と評価タイミング

variableブロック内のvalidationは、conditionがtrueであることを要求し、falseの場合にerror_messageの内容で失敗させます。conditionはTerraform言語の式で、var.<name>を参照します。

評価タイミングは「その変数の最終値が既知になった時点」。通常はplan時に既知で評価され、結果が偽ならplan自体がエラーで停止します。値がunknown(例: data source依存)で条件結果が不定な場合は、明確にfalseと判定できない限り適用時まで猶予されます。

  • 宣言的・副作用なし: 外部コマンド実行やリソース参照は不可
  • 型制約と併用が前提: typeで粗く、validationで細かく
  • エラーメッセージは利用者向けに具体的に(期待値と例を含める)
  • 入力ソース(-var, tfvars, 環境変数, Cloud/Enterpriseの変数)を問わず同一に適用
項目役割
type制約型・簡易制約を強制string, number, list(string), object({...})
default入力欠如時の既定値default = 443
validation型では表せないルールを宣言AMIは"ami-"で開始、ポート1..65535 など

評価パイプライン(概念図)

入力ソース(-var, tfvars, env, Cloud)値の決定とdefault適用型制約の適用/型変換custom validationtrue→続行 / false→エラーplan/apply入力 → 値決定/default → 型制約 → custom validation → plan/apply

最小構成の例

variable "image_id" {
  type = string

  validation {
    condition     = can(regex("^ami-[0-9a-f]+
NicheeLab を読み込み中…
quot;, var.image_id)) error_message = "image_id は 'ami-' で始まる有効なAMI IDを指定してください。例: ami-0123abcd"; } }

文法とベストプラクティス

validationブロックはcondition(必須)とerror_message(必須)から構成されます。conditionは純粋式であり、関数・演算子・for式を使って書けます。エラーメッセージは利用者が即修正できる粒度で短く具体的に。

正規表現や数値範囲など失敗しやすい判定はcan()でガードし、不正形式でregexがエラーになるのを防ぎます。重い計算や大きなコレクション走査は最小限に保ち、読みやすく維持しやすい表現を心がけます。

  • まずtypeで大枠を絞り、validationでビジネスルールを追加
  • regexはcan()で保護: can(regex(pattern, s))
  • 複合条件は論理積/含意(AならB)で短く: (env != "prod" || count >= 3)
  • メッセージは期待形・制約範囲・例を含める
関数用途注意点
regex, can書式・パターン検証regexは不一致時にfalse、パターン不正時はエラー→canで防御
startswith, endswith接頭/接尾の簡易検証単純なときはregexより可読
contains要素/値の包含判定セット許容値の検査と相性が良い
alltrue, anytrueブール配列の総合判定for式と組み合わせると強力
length, distinct長さ・一意性の検査重複禁止の表現によく使う

エラーメッセージ設計の観点

何が期待か期待される形式や条件許容範囲/形式境界値・パターンami-0123abcd など短く具体的なメッセージの3要素

よくあるガードの書き方

variable "account_id" {
  type = string
  validation {
    condition     = can(regex("^[0-9]{12}
NicheeLab を読み込み中…
quot;, var.account_id)) error_message = "account_id は12桁の数字で指定してください。"; } } variable "port" { type = number validation { condition = var.port >= 1 && var.port <= 65535 error_message = "port は1〜65535の範囲で指定してください。"; } }

文字列・数値の代表的な検証パターン

シンプルなパターンは可読性を重視します。接頭辞検査はstartswith、厳密な形式はregex、レンジは単純な比較で表現します。

regexはメンテナンス性を損ねやすいので、必要十分に留め、代替があればなるべくstartswithやlengthで置き換えます。

  • 接頭辞: startswith(var.id, "ami-")
  • 範囲: var.replicas >= 2 && var.replicas <= 10
  • 最小長: length(var.name) >= 3
  • 列挙: contains(["dev","stg","prod"], var.env)
目的条件式の例エラーメッセージ例
AMI形式can(regex("^ami-[0-9a-f]+
NicheeLab を読み込み中…
quot;, var.ami))
ami は 'ami-'で始まる16進IDを指定してください。
名前の最小長length(var.name) >= 3name は3文字以上で指定してください。
副本数の範囲var.replicas >= 2 && var.replicas <= 10replicas は2〜10の範囲で指定してください。
環境の列挙contains(["dev","stg","prod"], var.env)env は dev/stg/prod のいずれかです。

パターン選択の目安

要件の種類?単純な接頭/接尾startswith/endswith厳密な書式regex + can数値範囲比較演算子許容セットcontains on list要件の種類に応じた関数選択

サンプル: ポートとAMI

variable "port" {
  type = number
  validation {
    condition     = var.port >= 1 && var.port <= 65535
    error_message = "port は1〜65535です。";
  }
}

variable "ami" {
  type = string
  validation {
    condition     = can(regex("^ami-[0-9a-f]+
NicheeLab を読み込み中…
quot;, var.ami)) error_message = "ami は 'ami-'で始まる有効なIDを指定してください。"; } }

コレクション/複合型の検証

listやmap/objectではfor式とalltrue/anytrueで各要素をまとめて検査します。重複禁止はdistinctで実現できます。

タグやキーの長さ・文字種制約などは読みやすい単位に分解して条件式を構成すると保守しやすくなります。

  • 全要素の接頭辞検査: alltrue([for s in var.subnets : startswith(s, "subnet-")])
  • 重複禁止: length(distinct(var.names)) == length(var.names)
  • 許容セット: alltrue([for e in var.envs : contains(["dev","stg","prod"], e)])
  • mapのキー/値長さ: alltrue([for k, v in var.tags : length(k) <= 128 && length(v) <= 256])
パターン条件式(抜粋)補足
要素の書式検査alltrue([for s in var.subnets : startswith(s, "subnet-")])単純書式はregexより可読
重複禁止length(distinct(var.ids)) == length(var.ids)distinctで一意性を検査
必須キー含有alltrue([for k in ["Name","Owner"] : contains(keys(var.tags), k)])keys(map)とcontainsの組合せ

for式で要素を検査する流れ

list/mapfor式で各要素をbool化bool配列alltrueすべて満たすか判定list/map → for式で各要素をbool化 → bool配列 → alltrue で判定

サンプル: サブネットIDとタグ

variable "subnets" {
  type = list(string)
  validation {
    condition     = length(var.subnets) > 0 && alltrue([for s in var.subnets : startswith(s, "subnet-")])
    error_message = "subnets は1件以上、各要素は 'subnet-'で始まるIDで指定してください。";
  }
}

variable "tags" {
  type = map(string)
  validation {
    condition     = alltrue([for k, v in var.tags : length(k) <= 128 && length(v) <= 256])
    error_message = "tags のキーは128文字以内、値は256文字以内で指定してください。";
  }
}

variable "names" {
  type = list(string)
  validation {
    condition     = length(distinct(var.names)) == length(var.names)
    error_message = "names は重複のない値で指定してください。";
  }
}

条件付き検証と未知値(unknown)の扱い

条件付き検証は「含意」で表現すると読みやすくなります。例えばprodのときだけ強い制約を課すなら、env != "prod" || 厳格条件 の形にします。

unknown値(計画時に未確定の値)が関係する場合、Terraformは条件が明確にfalseと断定できない限りエラーにしません。regexなど不正形式で式自体が評価エラーになる恐れがある箇所はcan()で包んで安全に。

  • 含意の定石: (条件Aでなければ許可) または (条件Aなら制約B)
  • unknownを誤って評価エラーにしない: can()で防御
  • 外部リソース属性やデータソース値に依存させない(そもそも参照不可)
状況Terraformの挙動対策/書き方
prodのみ厳格条件結果がtrue/falseで確定し評価env != "prod" || 厳格条件
unknownが混入結果が不明なら計画は続行、適用時に再評価can()や安全な関数でガード
不正パターン式の評価自体がエラーで停止regexなどはcan()を併用

unknownの評価イメージ

condition評価true続行falseエラーunknown適用時に再評価true/falseに確定condition評価は true/false/unknown の3分岐

prodのときだけ強い制約をかける

variable "env" {
  type = string
  validation {
    condition     = contains(["dev","stg","prod"], var.env)
    error_message = "env は dev/stg/prod のいずれかです。";
  }
}

variable "az_count" {
  type = number
  validation {
    condition     = var.env != "prod" || var.az_count >= 2
    error_message = "env=prod の場合、az_count は2以上である必要があります。";
  }
}

試験対策: 出題ポイントとアンチパターン

試験では、type制約とvalidationの役割差、precondition/postconditionとの違い、評価タイミング、unknownの扱いが問われがちです。validationは入力値に対する静的な検査であり、リソース属性やデータソース結果を参照できません。

アンチパターンは、複雑な正規表現で可読性を損なう、外部状態に依存させる、エラーメッセージが抽象的すぎる、など。まず型で絞り、シンプルな関数で十分な安全性を確保しましょう。

  • validationはvariableブロック内。resourceの状態検査はprecondition/postconditionを使う
  • resource属性やdataの参照は不可(variableスコープ外)
  • 複数条件は読みやすく分割。can()で評価エラーを未然に防ぐ
  • メッセージは修正指針を含める(期待値・範囲・例)
機能定義場所実行タイミング主な用途
type制約variable値決定時(plan前段)型・スキーマの基本制約
validationvariable値が既知になった時(主にplan時)ビジネスルールの宣言的検査
pre/postconditionresourceやmodule呼び出しplan/applyでの状態検査リソース属性・モジュール出力の検査

Do/Don'tメモ

[OK] typeで大枠 → validationで細則
[OK] envに応じた含意で条件分岐
[NG] resource属性やdataをvalidationで参照
[NG] 複雑すぎるregexで可読性を損なう

アンチパターン修正例

# 悪い例(resource属性参照は不可)
# variable "size" {
#   validation {
#     condition     = var.size <= aws_instance.example.cpu_core_count  # 参照不可
#     error_message = "...";
#   }
# }

# 良い例: 入力間の関係をvalidationで、リソース状態はpreconditionで
variable "size" {
  type = number
  validation {
    condition     = var.size >= 1 && var.size <= 64
    error_message = "size は1〜64で指定してください。";
  }
}

# (参考)resource側での状態検査はprecondition/postconditionを使用
# resource "aws_instance" "example" {
#   # ...
#   lifecycle {
#     precondition {
#       condition     = self.cpu_core_count >= var.size
#       error_message = "インスタンスタイプが size を満たしていません。";
#     }
#   }
# }

問題で確認

Associate / Pro

問題 1

モジュールに env と instance_count の2つの変数があります。env=prod のときだけ instance_count を3以上に制限し、それ以外は制限しないようにしたい。最も適切なvalidationはどれか。

  1. A. variable "instance_count" { type = number validation { condition = var.env != "prod" || var.instance_count >= 3 error_message = "env=prod の場合は3以上を指定してください。" } }
  2. B. variable "instance_count" { type = number validation { condition = var.instance_count >= 3 error_message = "常に3以上を指定してください。" } }
  3. C. variable "instance_count" { type = number validation { condition = contains(["dev","stg"], var.env) && var.instance_count >= 3 error_message = "dev/stgは3以上です。" } }
  4. D. resourceのpreconditionで env と instance_count を比較する(variableにはvalidationを書かない)

正解: A

envに応じた条件付き制約は含意で表現するのが定石。env != "prod" || var.instance_count >= 3 はprod以外を無条件に許し、prod時のみ下限を課す。Bは常に3以上で不適切、Cはdev/stgに制限がかかる誤り、Dは入力値の整合はvariable側で落とすのが適切(状態検査はpre/postcondition)。

よくある質問

validationはいつ評価されますか? planとapplyのどちらですか?

値が既知であればplanの時点で評価され、falseならplanがエラーで止まります。値がunknownで結果が不定な場合は、apply段階で再評価されます。

複数のvalidationブロックを1つの変数に定義できますか?

可能です。ただし条件が増えるほど可読性が落ちるため、関連する検査は1つの読みやすい式にまとめるか、論理的に分けた少数のブロックに留めるのが実務的です。

リソース属性やデータソースの値をvalidationで参照できますか?

いいえ。validationは入力変数の検査であり、resourceやdataの属性は参照できません。入力間の関係はvalidationで、リソース状態の整合はpre/postconditionで検査します。

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

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.