Terraform

Terraform マルチ環境設計:dev/stg/prod を安全に分離する実装

2026-04-19
NicheeLab編集部

マルチ環境の設計で最重要なのは「状態と権限の分離」です。特に本番は事故の影響範囲が大きく、設計の粗はそのままリスクになります。

本稿では、ディレクトリ分割と共通モジュールを基本に、バックエンド、変数、Terraform Cloud/Enterprise の組合せで dev/stg/prod を安全に運用する方法を解説します。試験対策として問われやすい落とし穴も明記します。

マルチ環境の原則と分離レベル

dev/stg/prod の分離は「コード」「状態ファイル」「認証情報」「クラウドアカウント(またはサブスクリプション/プロジェクト)」「ネットワーク」の5層で考えます。最低限、状態ファイルと認証情報は環境ごとに分離し、可能であればクラウドアカウントも分けます。

Terraform のワークスペースは便利ですがセキュリティ境界ではありません。同一バックエンド内の論理的な状態分割に過ぎないため、強い隔離が必要な prod をワークスペース単独で守る設計は避けます。公式ドキュメントが推奨するのは、リモートバックエンドでの確実なロックと状態分離、アクセス制御の明確化です。

  • 最優先は状態ファイルの完全分離(環境ごとに別キー、可能なら別バケット/ストレージ/Workspace)
  • 認証情報(クレデンシャル)も環境ごとに分離(別ロール/サービスプリンシパル)
  • クラウドアカウント分離を推奨(prod は非prod と IAM を別に)
  • リモートバックエンドを利用(S3+DynamoDB ロック、GCS、AzureRM、または Terraform Cloud/Enterprise)
  • default ワークスペースは使わず、環境名を明示(dev/stg/prod)

よくある誤りチェック(試験対策)

NG: ワークスペースだけで prod を保護
NG: backend ブロックで var を参照して環境を切替(バックエンドは変数展開不可)
OK: -backend-config オプションで環境固有の backend 設定を注入
OK: 各環境で別の認証主体(例: IAM Role、SPN)を使用

推奨アーキテクチャ:ディレクトリ分割 + リモートバックエンド + 共通モジュール

実務と試験の両面で扱いやすいのは、共通モジュールを modules/ に集約し、環境ごとの差分は envs/dev|stg|prod のオーバーレイで吸収する構成です。状態はリモートバックエンドで環境ごとにキー(もしくはストレージ)を分け、ロックを有効化します。

CI/CD では環境ディレクトリごとに別ジョブを用意し、plan と apply を明確に分離。prod はレビュー必須、apply 権限も限定します。

  • コードの再利用性(modules/)と環境ごとの安全な分離(envs/)を両立
  • バックエンドは S3/GCS/AzureRM か Terraform Cloud(ロックと RBAC あり)
  • CI は環境ディレクトリ単位でトリガ、prod のみ手動承認

参照アーキテクチャ(ディレクトリ分割 + リモート状態 + TFC 連携)

Git Repo
└─ modules/
   ├─ network/
   └─ app/
└─ envs/
   ├─ dev/
   │  ├─ main.tf     -> module呼び出し(dev用変数)
   │  └─ backend.hcl -> state: s3://tfstate-nonprod/dev/...
   ├─ stg/
   │  ├─ main.tf
   │  └─ backend.hcl -> state: s3://tfstate-nonprod/stg/...
   └─ prod/
      ├─ main.tf
      └─ backend.hcl -> state: s3://tfstate-prod/prod/...(別アカウント/バケット)

CI/CD
└─ Job: plan-dev  -> envs/dev  -> Remote Backend (lock有)
└─ Job: plan-stg  -> envs/stg  -> Remote Backend (lock有)
└─ Job: plan-prod -> envs/prod -> Remote Backend (lock有, 承認必須)

Cloud Accounts/Projects
└─ nonprod-account  (dev, stg)
└─ prod-account     (prod)

代表的なファイル例(部分)

# envs/prod/backend.hcl(S3 例。backend は変数展開不可、-backend-config で渡す)
bucket         = "tfstate-prod"
key            = "proj/prod/terraform.tfstate"
region         = "ap-northeast-1"
dynamodb_table = "tf-locks-prod"
encrypt        = true

# envs/prod/main.tf(共通モジュール呼び出し)
terraform {
  required_version = ">= 1.4.0"
  backend "s3" {}
}

provider "aws" {
  region = var.region
  # prod 用のロール/プロファイルを使用
}

module "network" {
  source = "../../modules/network"
  cidr_block = var.cidr
  tags = {
    env = "prod"
  }
}

# 実行例(CIなど)
# terraform -chdir=envs/prod init -backend-config=backend.hcl -upgrade
# terraform -chdir=envs/prod plan -var-file=prod.tfvars

設計パターンの比較:ワークスペース駆動 vs ディレクトリ駆動 vs リポジトリ分割

ワークスペースは軽量で便利ですが、強い隔離や権限の分離には不十分です。試験観点でも「ワークスペースはセキュリティ境界ではない」を押さえてください。実務ではディレクトリ分割+共通モジュールがバランス良好。組織の境界が明確な場合はリポジトリ分割も選択肢です。

Terraform Cloud/Enterprise を使う場合、VCS 連携で環境ディレクトリごとにワークスペースを作成し、変数セットとポリシーセットで運用ガードを掛けるのが定石です。

  • 強い隔離が必要なら、アカウント/プロジェクト単位で prod を分離
  • ワークスペースはプレビューや一時環境に有効だが prod 防御には不十分
  • レジストリ公開(Private Module Registry)でモジュール再利用を促進
パターン隔離/権限制御運用コスト適合ユースケース
ワークスペース単独で環境分割弱い(同一バックエンドの論理分割。RBAC は限定的)プレビュー、短命環境、学習
ディレクトリ分割 + 共通モジュール + 環境別状態中〜強(状態とクレデンシャル分離。CI でガード)大半のプロジェクトの標準解
リポジトリ分割 + モジュールレジストリ強(VCS/RBAC/承認も分離しやすい)中〜高組織/予算/監査が厳密な領域間の分割
Terraform Cloud: 環境ごとに Workspace + 変数/ポリシーセット強(RBAC、ポリシー、State Sharing 制御)ガバナンス重視、チーム横断運用

ワークスペースは補助的に使う(命名やタグ付けに反映)

locals {
  env = terraform.workspace
  name_prefix = "proj-${terraform.workspace}"
}

resource "aws_s3_bucket" "logs" {
  bucket = "${local.name_prefix}-logs"
  tags = { env = local.env }
}
# 注意:これだけでは prod の隔離は不十分。状態/認証/アカウントの分離が必要

変数・状態の扱いベストプラクティス

環境ごとの差分は var-file(-var-file)で与えます。terraform.tfvars や *.auto.tfvars は自動読込されますが、複数環境のファイルを同居させると意図しない適用につながるため、環境実行時は -var-file=envs/prod.tfvars のように明示指定するのが安全です。

バックエンド設定は変数参照できません。-backend-config=backend.hcl 等で環境別に注入します。シークレットは VCS に置かず、環境変数 TF_VAR_xxx、Terraform Cloud の Sensitive 変数、または外部シークレット管理(Vault など)を利用します。

スタック間連携は data.terraform_remote_state を使って出力値を参照しますが、環境を跨ぐ依存は最小化し、参照権限も最小化します。

  • var-file は明示指定。auto.tfvars は単一環境のみに限定
  • バックエンドは -backend-config で注入(変数展開不可)
  • シークレットは Sensitive 変数/環境変数/シークレット管理を使用
  • remote_state の参照は最小限、権限も最小限

環境別 tfvars と locals マップ例

# envs/stg/variables.tfvars(例)
region = "ap-northeast-1"
cidr   = "10.20.0.0/16"

# modules/app/main.tf(環境差分は var と locals で吸収)
variable "region" {}
variable "cidr" {}

locals {
  tags_common = { app = "proj" }
}

resource "aws_vpc" "this" {
  cidr_block = var.cidr
  tags = merge(local.tags_common, { env = terraform.workspace })
}

# 実行(stg)
# terraform -chdir=envs/stg init -backend-config=backend.hcl
# terraform -chdir=envs/stg plan -var-file=variables.tfvars

Terraform Cloud/Enterprise での dev/stg/prod 分離

Terraform Cloud/Enterprise では、環境ディレクトリごとに Workspace を作成し、VCS 連携で該当パスのみをトリガします。Variable Sets をタグで関連付け、prod は承認フローと厳格な RBAC を設定します。Policy Sets(Sentinel など)でタグやリージョン制限、リソース保護を行うと堅牢です。

Workspace 間の state 参照は remote backend を使った data.terraform_remote_state で行えます。必要最小限の読み取り権限だけを付与し、prod の state を dev から不用意に読み取らせないことが重要です。

  • Workspace 命名規則:proj-{env}-{stack}
  • Variable Sets をタグで適用し、prod は別セットで守る
  • Policy Sets(Sentinel/OPA)でガードレールを適用
  • Run Tasks でセキュリティ/コンプライアンス検査を自動化

remote backend を用いた Workspace 間の state 参照(TFC)

data "terraform_remote_state" "network_prod" {
  backend = "remote"
  config = {
    organization = "your-org"
    workspaces = { name = "proj-network-prod" }
  }
}

output "vpc_id" {
  value = data.terraform_remote_state.network_prod.outputs.vpc_id
}
# 注意:参照先 Workspace の state は読み取り権限が必要

デプロイ順序と依存関係管理(ステート連携)

同一環境内では、ネットワーク → セキュリティ → プラットフォーム → アプリの順に適用するのが一般的です。Terraform の depends_on は同一計画内でのみ有効で、Workspace/状態を跨ぐ順序制御は CI/CD でオーケストレーションします。

状態の移行が必要な場合、安易な直接編集は避け、import と state rm、あるいは state mv(適切なオプション)で計画的に行います。remote backend を利用している場合はツールの制約とベストプラクティスに従い、安全な手順で移行します。

  • CI でジョブ依存関係を定義し、apply の順序を制御
  • terraform apply は環境ごとに分離、並列実行はロックと衝突に注意
  • target オプションは緊急時のみの回避策(常用しない)

CI の実行順序とロックの意識(例)

stages: [plan, approve, apply]

job plan-dev   : terraform -chdir=envs/dev  plan   -var-file=dev.tfvars
job apply-dev  : terraform -chdir=envs/dev  apply  -var-file=dev.tfvars (manual)
job plan-stg   : terraform -chdir=envs/stg  plan   -var-file=stg.tfvars (needs: apply-dev)
job approve-stg: manual approval
job apply-stg  : terraform -chdir=envs/stg  apply  -var-file=stg.tfvars
job plan-prod  : terraform -chdir=envs/prod plan   -var-file=prod.tfvars (needs: apply-stg)
job approve-prd: manual approval (RBAC: 限定)
job apply-prod : terraform -chdir=envs/prod apply  -var-file=prod.tfvars
# リモートバックエンドのロックにより同一状態の並行 apply は防止される

よくある落とし穴と試験向けチェックリスト

本番隔離にワークスペースを単独で使う、バックエンドで変数展開しようとする、複数環境の *.auto.tfvars を同居させる、といった誤りは実務でも試験でも減点対象です。変更はモジュールと var-file で吸収し、状態と権限の分離を徹底します。

  • ワークスペースはセキュリティ境界ではない(試験頻出)
  • backend ブロックは変数参照不可。-backend-config を使う
  • 複数環境の *.auto.tfvars は危険(明示 -var-file を使う)
  • prod は別アカウント/別認証主体で守る。default ワークスペースは使わない
  • remote_state 参照は最小限。不要な prod 情報を dev に流さない
  • 計画と適用を分離し、prod はレビュー必須

コマンド・チートシート

# 初期化(環境別 backend)
terraform -chdir=envs/prod init -backend-config=backend.hcl -upgrade

# 計画/適用(環境別 var-file)
terraform -chdir=envs/stg plan  -var-file=stg.tfvars
terraform -chdir=envs/stg apply -var-file=stg.tfvars

# ワークスペース(補助的に利用)
terraform workspace list
terraform workspace new dev
terraform workspace select prod

問題で確認

Pro

問題 1

次の要件をすべて満たすマルチ環境設計として最も適切なのはどれか。1) prod は dev/stg から強固に隔離、2) コードの重複は最小化、3) 計画と適用のレビューを分離、4) 将来の監査に備え RBAC を適用可能。

  1. 共通モジュールを modules/ に置き、envs/dev|stg|prod の各ディレクトリから呼び出す。環境ごとにリモートバックエンドの状態を分離し、prod は別アカウント/認証主体を使用。CI でディレクトリ単位に plan/apply を分離し、prod は承認必須にする。
  2. 単一ディレクトリと単一バックエンドで管理し、ワークスペースだけで dev/stg/prod を切り替える。RBAC は Git のレビューに任せる。
  3. *.auto.tfvars を環境ごとに3つ用意し、状況に応じて必要なファイルを残す/削除する。状態は共有してドリフトを防ぐ。
  4. prod と dev/stg で同じバックエンドバケットを共有し、key のみを分ける。適用時は terraform.workspace で条件分岐し重要なリソースをスキップする。

正解: A

強い隔離と監査性には、状態・認証の分離と CI でのガードが必須。A は共通モジュールで重複を避けつつ、バックエンド・アカウント・RBAC・レビューを組み合わせて要件を満たす。B はワークスペースのみで隔離しており不十分。C は *.auto.tfvars の使い方が危険で、状態共有も要件違反。D は同一バケットでも運用次第で許容される場合はあるが、prod の保護としては弱く、条件分岐で重要リソースをスキップする設計は推奨されない。

よくある質問

ワークスペースだけで dev/stg/prod を分離できますか?

推奨しません。ワークスペースは同一バックエンド内の論理分割であり、セキュリティ境界ではありません。prod は少なくとも状態と認証を分離し、可能ならクラウドアカウントも分けてください。

backend ブロックで変数を使って環境を切り替えられますか?

できません。バックエンドは計画前に初期化されるため変数展開の対象外です。-backend-config=... で環境別ファイルを渡すか、Terraform Cloud/Enterprise の Workspace を使い分けてください。

環境ごとの差分はどう管理するのが安全ですか?

共通モジュールを作り、環境ディレクトリから var-file(-var-file)で差分を注入します。命名やタグは terraform.workspace や locals マップで吸収し、シークレットは VCS に置かないでください。

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

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.