Terraform の状態ファイルはチーム開発ではリモート保管が前提です。GCP 環境なら、GCS バケットをバックエンドにするのがもっともシンプルで運用しやすい選択肢です。
本記事では、GCS バックエンドの基本、セキュリティ設計、初期化と移行、認証と CI/CD、運用とトラブル対応、試験対策チェックリストまでを実務目線で解説します。
Terraform の GCS バックエンドは、状態ファイルを Google Cloud Storage に保管し、チームでの同時編集をロックで防ぎます。GCS のオブジェクト版管理と強整合性により、安全な読み書きが可能です。
バックエンド自体は単純で、必要なのはバケット名、任意のプレフィックス、そして認証だけ。復旧性を高めるためにバケットのオブジェクトバージョニングを必ず有効化しましょう。
| バックエンド | ロック方式 | バージョニング/復旧 | 暗号化の扱い |
|---|---|---|---|
| gcs | オブジェクト世代条件によるロック | GCS オブジェクトバージョニングで復旧 | バケットのデフォルト暗号化(CMEK 可) |
| s3 | DynamoDB テーブルでロック | S3 Versioning | SSE-S3 / SSE-KMS |
| azurerm | Blob のリースでロック | スナップショット/バージョン | Storage 暗号化 + CMK |
| local | プロセス内のみ(共有ロックなし) | なし | OS 依存 |
GCS バックエンドのデータフロー(ロック含む)
最小の backend 設定例(静的定義)
terraform {
backend "gcs" {
bucket = "my-tfstate-bucket"
prefix = "envs/prod"
# credentials は省略可(ADC を利用)。鍵ファイルを使うなら以下:
# credentials = "/secure/path/sa-key.json"
}
}
状態は最重要機密のひとつです。バケット設計は環境・プロジェクト境界に沿わせ、アクセス境界を明確に分離します。一般的には環境ごと(prod/stg/dev)にバケットを分け、内部で prefix と workspace を使ってディレクトリ風に整理します。
セキュリティはバケット設定で担保します。Uniform bucket-level access を有効化し、Public Access Prevention を有効化。オブジェクトバージョニングとデフォルト CMEK を設定して復旧性と暗号化を両立します。IAM は最小権限で、Terraform 実行サービスアカウントにオブジェクトの読み書きとロック用の作成/削除ができるロールを付与します。
バケットのベース設定(例: gsutil / gcloud)
# バケット作成(リージョンはチームの実行場所に近いものを)
gsutil mb -p ${PROJECT_ID} -l ${REGION} gs://${BUCKET}
# Uniform bucket-level access を有効化
gsutil uniformbucketlevelaccess set on gs://${BUCKET}
# Public Access Prevention を有効化
gcloud storage buckets update gs://${BUCKET} --public-access-prevention
# オブジェクトバージョニングを有効化
gsutil versioning set on gs://${BUCKET}
# デフォルト CMEK を設定(事前に KMS キーを用意しておく)
# projects/PRJ/locations/LOC/keyRings/RING/cryptoKeys/KEY を指定
gcloud storage buckets update gs://${BUCKET} \
--default-encryption-key=${KMS_KEY_RESOURCE}
# IAM 付与(例: 実行 SA にオブジェクト管理権限を付与)
gsutil iam ch serviceAccount:${TF_SA}:roles/storage.objectAdmin gs://${BUCKET}
backend ブロックは Terraform の構文上、変数や参照を使えません。値の差し替えは terraform init の -backend-config で行います。部分的にコードへハードコードし、機密や環境差分のみ -backend-config で注入するのが現実的です。
既存のローカル状態からの移行は terraform init -migrate-state で安全に実施できます。初回 init 時、既存 state があればコピー確認のプロンプトが出ます。
backend の部分定義と初期化コマンド例
# main.tf(部分的に固定)
terraform {
backend "gcs" {
bucket = "my-tfstate-bucket"
prefix = "team1/appA"
# credentials は CLI 側で渡す想定(ADC 利用なら不要)
}
}
# CLI で環境差分を注入して初期化(ADC を使わない場合の例)
terraform init \
-backend-config="credentials=/secure/path/sa-key.json"
# 既存ローカル state からの移行
terraform init -migrate-state
# backend.hcl を使う場合(CI 向け)
# backend.hcl
# bucket = "my-tfstate-bucket"
# prefix = "team1/appA"
# credentials = "/secure/path/sa-key.json"
terraform init -backend-config=backend.hcl
推奨は ADC(Application Default Credentials)。ローカルでは gcloud auth application-default login、GCE/Cloud Run/Cloud Build では実行サービスアカウントに必要最小権限を付与すれば、backend の credentials を省略できます。
CI/CD で鍵ファイルを埋め込むのは避け、Workload Identity Federation もしくはサービスアカウントの直接実行を用います。やむを得ず鍵ファイルを使う場合は、保管を Secret Manager 等で行いローテーション計画を用意します。
ローカル/CI での代表的な認証例
# ローカル(ADC)
# ブラウザで認証し ADC を設定
gcloud auth application-default login
# credentials を省略して init
terraform init
# サービスアカウント鍵ファイルを使う場合(非推奨だが例示)
export GOOGLE_APPLICATION_CREDENTIALS=/secure/path/sa-key.json
terraform init -backend-config="credentials=${GOOGLE_APPLICATION_CREDENTIALS}"
# Cloud Build(サービスアカウントに権限付与済み / ADC 利用)
# cloudbuild.yaml のステップ内でそのまま実行可能
- name: hashicorp/terraform:light
entrypoint: bash
args:
- -c
- |
terraform init -backend-config=backend.hcl
terraform plan -input=false
ロックは通常自動で解放されますが、プロセス異常終了で残ることがあります。エラーにはロック ID が表示されるため、正当性を確認のうえ force-unlock を実行します。
誤更新時は GCS のオブジェクトバージョニングから過去版を取得して復旧可能です。直接上書きせず、別名へ退避してから terraform state push/pull を検討しましょう(push は通常無効化されているため、復旧は慎重に)。
ロック解除とバージョン復旧の例
# ロック解除(エラーメッセージにある ID を使用)
terraform force-unlock 12345678-90ab-cdef-1234-567890abcdef
# 既存 state の取得
terraform state pull > current.tfstate
# オブジェクトの全バージョンを確認(-a オプション)
gsutil ls -a gs://${BUCKET}/${PREFIX}/default.tfstate
# 特定世代(#NUM)を別名へコピーして比較
gsutil cp gs://${BUCKET}/${PREFIX}/default.tfstate#NUM ./recovered.tfstate
# 差分を目視確認後、慎重に復旧手順を選択(例: 手動で必要エントリを移植)
出題はバックエンドの不変性、ロック、復旧、認証の基本に集中します。設計選択肢問題では、バージョニングと最小権限、鍵レス運用(ADC/Workload Identity)を選べるかがポイントです。
移行や再初期化フラグの正誤(-migrate-state と -reconfigure)、backend で変数が使えないこと、workspaces と prefix の関係は頻出です。
再初期化と backend 構成差し替え(試験頻出)
# backend 設定を変更した場合(例: prefix 変更)は再初期化を明示
terraform init -reconfigure -backend-config=backend.hcl
# 既存ローカル state を GCS に移行
terraform init -migrate-state
Associate / Pro
問題 1
Terraform の GCS バックエンドに関する正しい説明はどれか?
正解: A
A が正しい。GCS バックエンドはロックをサポートし、GCS のオブジェクトバージョニングは復旧に有効。backend ブロックは静的で変数は使えない。B は誤り(KMS はバケット側のデフォルト暗号化で指定)。C は誤り(ADC/Workload Identity を推奨、鍵ファイル必須ではない)。D は誤り(terraform init -migrate-state で安全に移行できる)。
環境ごとにバケットを分けるべきですか?それとも prefix/workspace で分離しますか?
機密性と blast radius を小さくする観点から、prod と非 prod はバケットを分けるのが無難です。バケット内では prefix と workspace でさらに整理します。アクセス境界を IAM で確実に分けられるなら同一バケットでも構いませんが、誤権限付与のリスクを考えると環境別バケットが管理しやすいです。
サービスアカウント鍵ファイルなしで CI から実行できますか?
できます。Cloud Build/Run/GCE 等では実行サービスアカウントに必要最小権限を付与し、ADC(Application Default Credentials)で認証すれば鍵ファイルは不要です。より厳密には Workload Identity Federation を用いた鍵レス運用が推奨です。
マルチリージョンバケットを使っても問題ありませんか?
可能です。チームの実行場所・レイテンシ要件・データ所在地要件を踏まえて選択してください。GCS は強整合性のため機能面の制約は基本的にありませんが、コストとレイテンシ特性はリージョン選択で変わります。
NicheeLab編集部
データエンジニアリング・クラウド資格の専門家。Databricks・Snowflake等の認定資格を保有し、実務経験に基づいた問題作成・解説を行っています。NicheeLab運営。
Terraform HCL 構文の基礎:Block / Attribute / Expression を正しく使い分ける
Terraform Associate で頻出の HCL 構文を、ブロック・属性・式の3視点で整理。実務で迷いがちな書き...
Terraform Authoring & Ops Pro: 上位資格の範囲と対策
上位レベルを想定したTerraformの設計・運用ドメインを整理し、実務で通用する対策を提示。モジュール設計、ステート運...
Terraform Providers の基本: プラグイン型アーキテクチャを正しく使いこなす
Associate レベルで押さえるべき Provider の基礎、インストール、バージョニング、認証、エイリアス運用を...
Terraform Resourceブロック徹底ガイド: 最小単位のリソース定義
Associateレベルで押さえるべきResourceブロックの構造、依存関係、メタ引数、ライフサイクル制御を実務目線で...
Terraform Data Source徹底理解:既存リソースの参照で壊さず足す
Terraform Associate向けに、Data Sourceを用いた既存リソース参照の基本、選択基準、評価順序、...