Terraform「Variables not allowed」エラー:バックエンド設定で変数を使用する場合

intermediate🏗️ Terraform2026-04-21| Terraform 0.12以降、任意のOS(Linux、macOS、Windows)、任意のバックエンド(S3、GCS、Azure、Consul)

Error Message

Error: Variables not allowed: Variables may not be used here.
#terraform#backend#変数#設定

エラーの内容

バックエンド設定に変数参照を追加する — ごく普通の操作に思えますが、Terraformはこのエラーを投げます:

Error: Variables not allowed

  on main.tf line 4, in terraform:
   4:   bucket = var.state_bucket

Variables may not be used here.

特に共有モジュールやマルチ環境構成で、バックエンドのバケット・プレフィックス・リージョンをデプロイごとに切り替えたい場合に、このエラーは頻繁に発生します。

なぜこうなるのか

Terraformはbackendブロックを最初に処理します — 変数、ローカル値、データソース、その他の式より先に評価されます。バックエンドが初期化されて初めて、Terraformはステートの読み書き先を把握できます。他のすべてが読み込まれる時点では、var.*local.*data.*はまだ解決されていません。

これはバグではなく、意図的な設計です。バックエンドブロックが受け付けるのはリテラル値のみ — 文字列、数値、ブール値だけです。補間は一切使えません。

よくあるトリガーパターン

多くの人がはまる構成がこちらです:

variable "environment" {
  type = string
}

variable "state_bucket" {
  type = string
}

terraform {
  backend "s3" {
    bucket = var.state_bucket        # ❌ Not allowed
    key    = "${var.environment}/terraform.tfstate"  # ❌ Not allowed
    region = "ap-southeast-1"
  }
}

どちらの行も失敗します。バックエンドブロック内では${}構文による文字列補間も使えません。

修正方法1:-backend-configフラグを使う(手軽な方法)

バックエンドブロックから動的な値を完全に取り除きます。静的な値だけを残すか、空のスケルトンにしてください:

terraform {
  backend "s3" {
    region = "ap-southeast-1"  # static values only
  }
}

init実行時に-backend-configで動的な値を渡します:

terraform init \
  -backend-config="bucket=my-tfstate-prod" \
  -backend-config="key=prod/terraform.tfstate"

または環境ごとに別の設定ファイルを用意します:

# backends/prod.hcl
bucket = "my-tfstate-prod"
key    = "prod/terraform.tfstate"
region = "ap-southeast-1"
terraform init -backend-config=backends/prod.hcl

多くのCI/CDパイプラインでは、ENVをパイプライン変数として設定し、対応する環境の.hclファイルを指定してterraform initを呼び出す方法が一般的です。

修正方法2:部分的なバックエンド設定(チーム向け推奨)

本当に静的な部分だけをバックエンドブロック内に書きます。動的なフィールドは空のままにしておけば、Terraformがinit時にプロンプトで確認するか、フラグで受け取ります。

terraform {
  backend "s3" {
    # Only what never changes goes here
    region         = "ap-southeast-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}

initスクリプトで組み合わせます:

#!/bin/bash
ENV=${1:-staging}

terraform init \
  -backend-config="bucket=myapp-tfstate-${ENV}" \
  -backend-config="key=${ENV}/terraform.tfstate"

環境ごとにバックエンドブロックを重複させる必要はありません — 1つのmain.tfと環境別の.hclファイルだけで管理できます。

修正方法3:Terragruntを使う(複雑なマルチ環境向け)

多数の環境でバックエンドの変動が激しい場合、Terragruntがネイティブにこの問題を解決します。TerraformがバックエンドブロックをみるよりもBefore前に、バックエンド設定を動的に生成します:

# terragrunt.hcl
remote_state {
  backend = "s3"
  config = {
    bucket = "myapp-tfstate-${local.environment}"
    key    = "${path_relative_to_include()}/terraform.tfstate"
    region = "ap-southeast-1"
  }
}

TerragruntはTerraformがバックエンドブロックをみる前に動的生成を処理します。クリーンな分離で、回避策は不要です。

確認方法

修正後、terraform initを再実行して出力を確認します:

terraform init -backend-config=backends/prod.hcl

# Expected output:
# Initializing the backend...
# Successfully configured the backend "s3"!

ステートバックエンドの接続を確認します:

terraform state list

既存のワークスペースではリソースの一覧が返ります。新しいワークスペースでは空のリストが返ります。いずれにしてもエラーが出なければ、バックエンドは正常に動作しています。

解決済みのバックエンド設定を直接確認するには:

cat .terraform/terraform.tfstate | python3 -m json.tool | grep -A10 '"backend"'

バックエンドファイルの構成

マルチ環境のバックエンドには、以下のようなレイアウトがスケールしやすいです:

infra/
├── main.tf            # backend block with static values only
├── variables.tf
├── backends/
│   ├── dev.hcl
│   ├── staging.hcl
│   └── prod.hcl
└── scripts/
    └── init.sh        # wrapper: terraform init -backend-config=backends/$ENV.hcl

.hclファイルには環境固有のバックエンド値を記述します。バケット名やキーパスのみで、シークレットは含まれないため、バージョン管理にコミットして問題ありません。

修正後によくあるミス

  • terraform planを実行する前にinitを再実行しない:バックエンド設定のアプローチを変更した場合は、必ず先にterraform initを再実行してください。
  • バックエンドを切り替える際に-reconfigureを忘れる:既存のワークスペースを新しいバックエンド場所に移行するには、terraform init -reconfigureが必要です。
  • バックエンド設定ソースを混在させる:同じキーをbackendブロックと-backend-configファイルの両方に指定しないでください。フラグで指定した値が優先されますが、混乱を避けるためにも責務を明確に分離してください。

ヒント:initの前にHCLファイルを検証する

.hcl.tfvarsファイルを手動編集するとミスが起きやすいです。構文ミスでterraform initを無駄に実行する前に、構造を事前確認しましょう。ToolCraftのYAML ↔ JSONコンバーターが便利です — HCLの構造はJSONに近いため、括弧の不一致や不正なネストをすぐに検出できます。すべてブラウザ内で処理され、データはアップロードされません。

Related Error Notes