⚠️ なぜ「準備」が最も重要なのか
Terraform で最も多いトラブルは、準備不足のまま terraform apply を実行することで起きます。
よくある失敗パターン:
- 権限不足で apply 失敗 → 中途半端なリソースが残る
- API が有効化されておらず
403 SERVICE_DISABLED - State の保存先を決めずにローカルで実行 → チームで共有できない
- 手動で作ったリソースと Terraform が衝突する
コードを書く前に、環境を整える。 これが Terraform 運用の鉄則です。
🗺️ 準備の全体像
Terraform を導入する前に、以下の 5 つを整理します。
1. クラウドアカウント設計
↓
2. 認証方式の選定
↓
3. 権限(IAM)設計
↓
4. State 管理の設計
↓
5. ディレクトリ構成の設計
順番が重要です。上から順に決めないと、後工程で手戻りが発生します。
☁️ 1. クラウドアカウント設計
環境分離の原則
本番・ステージング・開発は、プロジェクト(アカウント)レベルで分離します。
| クラウド | 分離単位 | 例 |
|---|---|---|
| Google Cloud | プロジェクト | myapp-prod, myapp-stg |
| AWS | アカウント | 本番アカウント、検証アカウント |
| Azure | サブスクリプション | 本番サブスクリプション、検証サブスクリプション |
同一プロジェクト内で環境を分けると、本番リソースを誤って削除するリスクが生まれます。
マルチクラウドの場合
クラウドごとに役割を明確にします。
例:
Google Cloud → メインクラウド(Cloud Run, Cloud SQL 等)
AWS → 認証基盤のみ(Cognito)
「両方で同じことをやる」のではなく、各クラウドの得意領域を活かす設計にします。
🔐 2. 認証方式の選定
サービスアカウントキーは使わない
Terraform の認証で最も避けるべきは、サービスアカウントキー(JSON キー)の利用です。
| 方式 | セキュリティ | 運用コスト | 推奨 |
|---|---|---|---|
| サービスアカウントキー | 漏洩リスクあり | キーのローテーション必要 | NG |
| Workload Identity Federation (WIF) | キーレス | ローテーション不要 | 推奨 |
| gcloud auth(ローカル開発) | 個人認証 | 手動ログイン | 開発のみ |
Workload Identity Federation(WIF)
CI/CD パイプラインからの認証は WIF を使います。GitLab / GitHub Actions の OIDC トークンで、キーなしに Google Cloud や AWS に認証できます。
CI/CD ランナー
↓ OIDC トークン
Workload Identity Pool
↓ トークン交換
サービスアカウント(権限あり)
↓ 認証済み
Terraform 実行
クロスクラウド認証
Google Cloud と AWS の両方を Terraform で管理する場合:
GitLab Runner
├→ GCP WIF で Google Cloud に認証
└→ GCP SA の OIDC トークン → AWS STS AssumeRoleWithWebIdentity
→ AWS IAM Role で AWS に認証
キーの受け渡しなしで、クラウド間の認証が成立します。
🛡️ 3. 権限(IAM)設計
最小権限の原則
Terraform 用のサービスアカウントには、必要最小限の権限だけを付与します。
✗ roles/owner(何でもできる → 危険)
✗ roles/editor(広すぎる)
○ 必要なロールだけを個別に付与
サービスアカウントの分離
1 つのサービスアカウントで全部やらず、用途別に分離します。
| サービスアカウント | 用途 | 権限 |
|---|---|---|
| Terraform SA | インフラ構築・変更 | リソース作成・変更権限 |
| App Deployer SA | アプリデプロイ | Cloud Run デプロイ権限のみ |
| Monitoring SA | 監視 | 読み取り専用 |
API の有効化を忘れない
Terraform でリソースを作る前に、対象の API を有効化する必要があります。
# Google Cloud の場合
gcloud services enable run.googleapis.com # Cloud Run
gcloud services enable sqladmin.googleapis.com # Cloud SQL
gcloud services enable secretmanager.googleapis.com # Secret Manager
これを忘れると 403 SERVICE_DISABLED エラーになります。新しいサービスを使う際は、必ず確認してください。
💾 4. State 管理の設計
State とは
Terraform の State は、「Terraform が管理しているリソースの一覧」 です。
State ファイル(terraform.tfstate)
├ Cloud Run サービス A → 実際の GCP リソース
├ Cloud SQL インスタンス B → 実際の GCP リソース
└ S3 バケット C → 実際の AWS リソース
State がないと、Terraform はどのリソースを自分が作ったのか判別できません。
リモートバックエンド必須
State はリモートに保存します。ローカルに置くと、チームで共有できません。
GCS に統合する
マルチクラウド構成(GCP + AWS + Azure)の場合、State の保存先をクラウドごとに分けると管理が煩雑になります。GCS(Cloud Storage)に統合すると、State の管理対象が 1 箇所にまとまり、運用がシンプルになります。
# GCP のスタックも、AWS のスタックも、同じ GCS バックエンド
terraform {
backend "gcs" {
bucket = "my-project-tfstate"
}
}
State バケットの作成
State 保存用のバケットは Terraform 管理外で作成します(鶏と卵の問題)。
gsutil mb -l asia-northeast1 gs://my-project-tfstate
gsutil versioning set on gs://my-project-tfstate
バージョニングは必ず有効化します。State を壊した場合の復旧に必要です。
📁 5. ディレクトリ構成の設計
module / envs 分離パターン
terraform/
├── modules/
│ └── infra/
│ ├── gcp/ # GCP モジュール
│ │ ├── cloud-run/
│ │ ├── cloud-sql/
│ │ ├── load-balancer/
│ │ └── dns-zone/
│ └── aws/ # AWS モジュール
│ ├── cognito/
│ └── ses/
│
└── envs/ # 環境別エントリーポイント
├── stg/
│ ├── my-app/ # GCP スタック
│ └── ec-auth/ # AWS スタック
└── prod/
├── my-app/
└── ec-auth/
設計原則
| 原則 | 説明 |
|---|---|
| 単一責任 | 各モジュールは 1 つの責務のみ |
| 環境差分は変数で | コードの重複を排除 |
| State はスタック単位 | envs/prod/my-app ごとに 1 つの State |
モジュールに環境固有の値をハードコードしてはいけません。すべて変数で渡すのが原則です。
🚫 やってはいけないこと
| 禁止事項 | 理由 |
|---|---|
| CLI で直接リソース作成 | State と実態が不一致になる |
| ローカルから本番に直接 apply | 事故のリスク、CI/CD を通すこと |
| State ファイルをコミット | 機密情報が含まれる |
| サービスアカウントキーの利用 | 漏洩リスク、WIF を使う |
本番環境で terraform destroy | 多層防御で禁止すべき |
特に CLI で直接リソースを作ると、State との不整合(State drift) が発生します。Terraform で管理すると決めたら、すべて Terraform 経由で変更してください。
📚 シリーズ記事
| # | タイトル | 内容 |
|---|---|---|
| 1 | 概要 | IaC の全体像と基本方針 |
| 2 | 準備編(本記事) | アカウント設計・認証・権限・State 管理 |
| 3 | モジュール設計編(公開予定) | 再利用可能なモジュールの設計原則 |
| 4 | CI/CD パイプライン編(公開予定) | GitLab CI/CD による自動化・WIF 認証フロー |
| 5 | 運用編(公開予定) | State drift 解消・トラブルシューティング |