エラーの内容
バックエンド設定に変数参照を追加する — ごく普通の操作に思えますが、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に近いため、括弧の不一致や不正なネストをすぐに検出できます。すべてブラウザ内で処理され、データはアップロードされません。

