Terraform

Terraformモジュール入力の設計ベストプラクティス(Associate対応)

2026-04-19
NicheeLab編集部

ハブ記事: Terraform モジュール 完全ガイド

設計・配布・運用まで Terraform モジュールの全体像を一望できるハブ記事

モジュールの入力設計は、使いやすさ・安全性・将来の拡張性を左右します。曖昧な型や雑なデフォルトは、計画外の差分や本番事故につながりやすいポイントです。

ここではTerraform公式ドキュメントの振る舞いに基づき、Associate受験でも問われやすい安定概念(型制約、validation、sensitive、tfvarsの優先順位など)を、実務に落とし込める形でまとめます。

前提と基本:入力でモジュールの境界を明確にする

入力変数は、モジュールの外部と内部の契約面です。名前・型・説明・既定値を適切に定義することで、意図せぬ値の流入を防ぎ、使い手が迷わないAPIを提供します。

Associateレベルでは、変数ブロックの基本プロパティ(type、default、description、sensitive、nullable)と、var.参照、tfvars/CLI/環境変数からの値供給、およびplan/apply時の型検証の理解が求められます。

  • 変数名は意味が一意になるようにし、環境や用途を含めない(envは別変数に分離)
  • descriptionは利用者視点で「何を渡すか」「何が無効か」を明記
  • defaultを入れるなら、実運用で安全な値に限定(曖昧なデフォルトは避ける)
  • 明確な型を必ず指定(anyは原則使わない)

最小限の読みやすいvariables.tf例

variable "name" {
  type        = string
  description = "このモジュールで作るリソース群の論理名(接頭辞)"
}

variable "environment" {
  type        = string
  description = "環境識別子(例: dev, stg, prd)"
}

variable "tags" {
  type        = map(string)
  description = "共通タグ。空マップで上書き可"
  default     = {}
}

# 呼び出し側例
module "app" {
  source      = "./modules/app"
  name        = "web"
  environment = var.environment
  tags        = merge(var.tags, { component = "frontend" })
}

型制約とvalidation:早めに不正入力を捕まえる

型を厳格にし、validationで業務制約を明示します。nullableを使ってnull許容かどうかをはっきりさせ、defaultがあるのに不正値が混ざる状況を避けます。

sensitiveは表示抑制であり暗号化ではありません。値はstateに保存されるため、バックエンドの暗号化とアクセス制御も前提に設計します。

  • string/number/bool/list/map/objectを使い分け、anyは極力回避
  • validationでホワイトリスト・範囲・CIDR形式などをチェック
  • nullable = false を必要箇所に設定し、意図しないnullを拒否
  • sensitive = true は計画出力のマスキングまで。state保護は別途必要

実用的なvalidationとnullable/sensitiveの例

variable "environment" {
  type        = string
  description = "dev/stg/prd のいずれか"
  validation {
    condition     = contains(["dev", "stg", "prd"], var.environment)
    error_message = "environment は dev, stg, prd のいずれかにしてください。"
  }
}

variable "instance_count" {
  type        = number
  description = "起動するインスタンス数(1〜10)"
  default     = 2
  nullable    = false
  validation {
    condition     = var.instance_count >= 1 && var.instance_count <= 10
    error_message = "instance_count は 1〜10 の範囲で指定してください。"
  }
}

variable "cidr_block" {
  type        = string
  description = "CIDR表記 (例: 10.0.0.0/16)"
  validation {
    condition     = can(cidrhost(var.cidr_block, 0))
    error_message = "cidr_block は有効なCIDR表記である必要があります。"
  }
}

variable "db_password" {
  type        = string
  description = "DBパスワード"
  sensitive   = true
  nullable    = false
}

オブジェクトでまとめる:関連パラメータは1つの入力に

相関の強い値(例: ネットワーク周り、スケーリング設定)は、個別変数を乱立させるより、object型で1つにまとめると誤組み合わせを防げます。

Terraform 1.3以降はobject内のoptional属性を型として表現できます。これにより、呼び出し側の指定項目を最小限にしつつ、デフォルト戦略を型レベルで明文化できます。

  • 関連する値はobjectに束ね、説明に意味論も記述
  • optional属性に安全なデフォルトを与える(1.3+)
  • list(object(...))やmap(object(...))で複数要素も表現
  • anyはデバッグ困難。将来変更に強い最小十分な型を選ぶ

optional属性つきobjectの例(Terraform 1.3+)

variable "network" {
  description = "VPCとサブネット構成"
  type = object({
    cidr_block      = string
    private_subnets = list(string)
    public_subnets  = optional(list(string), [])
    dns_hostnames   = optional(bool, true)
  })
}

# 利用側(モジュール内部)
locals {
  all_subnets = concat(var.network.private_subnets, var.network.public_subnets)
}

# サブネット数の整合をvalidationで防ぐ例(必要に応じて)
variable "az_count" {
  type        = number
  description = "利用するAZの数"
  default     = 2
  validation {
    condition     = length(var.network.private_subnets) >= var.az_count
    error_message = "private_subnets は az_count 以上必要です。"
  }
}

値の供給方法と優先順位:tfvars/環境変数/CLIの使い分け

同じ変数に複数の供給源があるときは、Terraformの優先順位で最終値が決まります。試験ではこの順序の理解が問われやすいです。実務では、環境ごとtfvarsを標準化し、必要時のみCLIで一時上書きにするのが堅実です。

自動読み込みファイル(terraform.tfvars, *.auto.tfvars)はチーム標準の入口として便利です。長期的に残すべき値はtfvars側、短命な一時値はCLIや環境変数を使い分けます。

  • 優先順位(高→低):CLI引数(-var/-var-file) > tfvars(.auto含む) > 環境変数TF_VAR_* > 変数ブロックのdefault
  • terraform.tfvars / *.auto.tfvars は自動読み込み。ファイル名規約を決める
  • 機密は環境変数や外部Secret連携(Vault/SSM等)+sensitiveで扱う
  • 本番は固定tfvarsをコミットし、CLI上書きを最小化
供給方法優先度(1=最高)適用範囲実務の使い所
-var1コマンド都度一時的な上書き・緊急回避。恒久運用は避ける
-var-file=PATH1コマンド都度環境固有ファイルを明示指定。CIでの切替に有効
terraform.tfvars / *.auto.tfvars2カレントディレクトリ標準の環境設定。チームで共有しやすい
環境変数 TF_VAR_name3シェル/CIのプロセス環境機密やCIの注入。ログ残しを抑制
変数ブロックのdefault4モジュール定義安全な既定のみ(曖昧なデフォルトは入れない)

入力供給と解決の流れ(高優先→低優先)

CLI引数 (-var / -var-file)
           |
           v  (最優先で上書き)
自動読み込み tfvars (terraform.tfvars / *.auto.tfvars)
           |
           v
環境変数 TF_VAR_*
           |
           v
変数ブロック default
           |
           v
root module の var へ束ねられる
           |
           v
module 呼び出しの引数として渡る
           |
           v
各 resource の属性に反映され plan/apply

現場での使い分け例

# 自動読み込みファイル(チーム標準)
# terraform.tfvars
environment = "stg"
name        = "web"

# 本番のみ明示指定(CI)
terraform apply -var-file=envs/prd.tfvars

# 機密は環境変数から注入(CIやローカル)
TF_VAR_db_password="s3cr3t" terraform plan

# 一時上書き(デバッグ用途)
terraform apply -var instance_count=3

enableフラグ依存を減らす:合成しやすい入力にする

createやenableのboolフラグは便利ですが、増えすぎると挙動の組み合わせ爆発が起きます。将来の拡張性とテスト容易性を考えると、具体的な集合(map/list/object)で明示する設計の方がメンテナンス性が高いです。

どうしてもフラグにするなら、count/for_eachでリソース生成を完全に切る、依存関係が循環しないことを確認する、といった消し方を徹底します。

  • フラグ乱立より map/object で具体値を渡す
  • count/for_eachで「作らない」状態をゼロ件にする
  • enable_* は上位モジュール(統合)でのみ許容し、下位は明示集合入力に
  • 検討順序:具体入力 > 合成 > 最後にフラグ

フラグ方式と集合方式の対比

# フラグ方式(最小限にとどめる)
variable "create_iam_role" {
  type    = bool
  default = true
}

resource "aws_iam_role" "this" {
  count = var.create_iam_role ? 1 : 0
  name  = "example"
  assume_role_policy = data.aws_iam_policy_document.assume.json
}

# 集合方式(推奨)
variable "iam_roles" {
  description = "作成するIAMロールの定義マップ"
  type = map(object({
    name               = string
    assume_role_policy = string
    tags               = optional(map(string), {})
  }))
  default = {}
}

resource "aws_iam_role" "this_map" {
  for_each            = var.iam_roles
  name                = each.value.name
  assume_role_policy  = each.value.assume_role_policy
  tags                = coalesce(each.value.tags, {})
}

セキュリティ・後方互換・ドキュメントの運用

sensitiveは表示マスキングであり、状態ファイルの暗号化ではありません。リモートバックエンドの暗号化と権限制御を前提に、出力にもsensitiveを伝播させます。

変数スキーマ変更は破壊的になりがちです。既存入力を保ったまま新フィールドをoptionalで追加し、旧入力は段階的に非推奨化してから削除します。変更点はCHANGELOGと変数のdescriptionに明記しましょう。

  • 機密は variable.sensitive = true と output.sensitive = true の両方で連鎖させる
  • stateの保護(リモートバックエンドの暗号化・アクセス制限)を必須化
  • 後方互換を壊す型変更は避け、optional追加で拡張
  • 非推奨はdescriptionにDEPRECATEDを明示し、互換期間を設ける

機密の伝播と非推奨の明示例

# 機密入力と出力
variable "db_password" {
  type        = string
  description = "DBパスワード"
  sensitive   = true
}

output "db_password" {
  value     = var.db_password
  sensitive = true
}

# 非推奨の入力を段階的に廃止
variable "instance_type_legacy" {
  type        = string
  default     = null
  description = "DEPRECATED: 代わりに compute.instance.type を使用。将来のメジャー版で削除予定"
}

variable "compute" {
  description = "計算リソース設定(新スキーマ)"
  type = object({
    instance = object({
      type = string
      size = optional(number, 1)
    })
  })
}

問題で確認

Associate

問題 1

同じ変数に対し複数の供給源がある場合、Terraformが最終的に採用する値の優先順位(高→低)として正しいものはどれか?

  1. CLI引数(-var / -var-file) > tfvars(terraform.tfvars / *.auto.tfvars) > 環境変数 TF_VAR_* > 変数ブロックのdefault
  2. tfvars(terraform.tfvars / *.auto.tfvars) > CLI引数(-var / -var-file) > 変数ブロックのdefault > 環境変数 TF_VAR_*
  3. 環境変数 TF_VAR_* > CLI引数(-var / -var-file) > tfvars > 変数ブロックのdefault
  4. 変数ブロックのdefault > 環境変数 TF_VAR_* > tfvars > CLI引数(-var / -var-file)

正解: A

Terraformは、CLI引数(-var / -var-file)が最も優先され、次にtfvars(terraform.tfvars / *.auto.tfvars)、その次が環境変数 TF_VAR_*、最後が変数ブロックのdefaultです。公式ドキュメントに準拠した安定仕様です。

よくある質問

object型のoptional属性はどのTerraformバージョンから使えますか?

Terraform 1.3以降で、object内のoptional属性と既定値の表現がサポートされました。バージョンをまたぐモジュールでは、required_versionで下限を明示するか、従来どおりlocalsで補完する実装にしてください。

variableでsensitive=trueにすれば、値は完全に秘匿されますか?

いいえ。sensitiveは計画出力やUI上の表示をマスクする機能です。stateには値が保存されるため、バックエンドの暗号化(例:Terraform Cloud/Enterprise、S3+KMSなど)と厳格なアクセス制御が必須です。外部サービスに渡れば、その先のログにも注意が必要です。

defaultとnullの使い分けは? nullableはどう設定すべき?

「指定がなければ安全な既定で動かしたい」ならdefaultに安全値をセット。「値が必須で未指定を許容しない」ならnullable=falseにして明示的な入力を求めます。nullは意図的な未設定を表しますが、nullable=trueのままだと意図せぬnull流入に気づきにくくなるため、重要パラメータはnullable=falseを推奨します。

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

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の記事一覧 (102件)
© 2026 NicheeLab All rights reserved.