Skip to content

インフラ構成 (GCP リソース図)

採用構成

  • 同一 GCP project に staging と prod を同居 (リソース名で env を suffix)
  • Cloud Run v2 + Cloud SQL (Unix socket) で API ↔ DB を結ぶ
  • Workload Identity Federation で GitHub Actions から短命 token で deploy
  • Secret Manager で機密値、TF state には slot だけ作って値は外部投入
  • per-resource IAM で staging SA が prod の secret を読めない構成

依存関係

┌──────────────────────────── GCP プロジェクト ─────────────────────────────┐
│                                                                          │
│   GitHub Actions (OIDC token)                                            │
│         │                                                                │
│         ▼                                                                │
│   ┌────────────────────────┐                                             │
│   │ Workload Identity Pool │  ← assertion.repository == astyleinc/liga-mono
│   │  └─ Provider (OIDC)    │                                             │
│   └─────────┬──────────────┘                                             │
│             │ impersonate                                                │
│             ▼                                                            │
│   ┌────────────────────────┐  push image    ┌───────────────────────┐    │
│   │ SA: github-actions-X   │ ─────────────► │ Artifact Registry     │    │
│   │  run.developer (svc)   │                │ liga-images (共有)    │    │
│   │  artifactregistry.wr   │                └────────────┬──────────┘    │
│   │  cloudsql.client       │                             │ pull          │
│   │  secretmanager.acc(X)  │                             ▼               │
│   │  iam.serviceAccountUser│                ┌─────────────────────────┐  │
│   │  (cloud-run-api-X だけ)│                │  Cloud Run (api)        │  │
│   └─────────┬──────────────┘  deploy        │  liga-api-X             │  │
│             └──────────────────────────────►│  ─ allUsers / public   │  │
│                                              └──────┬──────────┬──────┘  │
│                          Unix socket /cloudsql/...  │  secret env        │
│                                       │             ▼                    │
│                                       ▼   ┌─────────────────────┐        │
│                            ┌────────────┐ │  Secret Manager     │        │
│                            │ Cloud SQL  │ │  BETTER_AUTH_SECRET │        │
│                            │ PostgreSQL │ │  STRIPE_*           │        │
│                            │ liga-X     │ │  DATABASE_URL ★    │        │
│                            └────────────┘ │  R2_*, etc.         │        │
│                                            └─────────────────────┘        │
│                                                                          │
│ X = staging / prod                                                       │
│ ★ DATABASE_URL のみ TF が組み立てて投入。他は gcloud で人間が外部投入    │
└──────────────────────────────────────────────────────────────────────────┘

リソース一覧 (Terraform 管理)

ファイル内容
main.tfprovider / GCS backend / 必須 API 有効化
cloud_sql.tfCloud SQL (PostgreSQL 17, edition=ENTERPRISE) + DB + user + 乱数 password
cloud_run.tfCloud Run v2 (Hono API) + 公開設定
artifact_registry.tfDocker image 置き場 (staging/prod 共有)
secrets.tfSecret Manager slot 群 + placeholder version + DATABASE_URL 投入
iam.tfSA × 2 + WIF Pool/Provider + bindings (per-resource scope)
outputs.tfCI / Netlify が使う値の出力

env 別の分離

stagingprod
Cloud SQLliga-staging (ZONAL, db-f1-micro)liga-prod (REGIONAL HA, db-custom-1-3840)
Cloud Runliga-api-staging (min=0)liga-api-prod (min=1 warm)
Secret*_staging*_prod
IAM SAcloud-run-api-staging / github-actions-staging同 prod
WIF Poolgithub-actions-staginggithub-actions-prod
state prefixstagingprod

ラベル (請求 / ログ集計用)

全リソースに統一ラベル:

KeyValue用途
appligaプロジェクト単位
envstaging / prod環境別 (AR / state バケットは共有なので省略)
managed-byterraform手動作成と区別
componentdatabase / api / secret / registry / tfstateリソース種別

利用例:

sql
-- BigQuery billing export で env 別月次コスト
SELECT labels.value AS env, service.description, SUM(cost) AS cost_usd
FROM `<dataset>.gcp_billing_export_v1_*`, UNNEST(labels) AS labels
WHERE labels.key = "env"
GROUP BY env, service.description
ORDER BY cost_usd DESC;
# Cloud Logging を env で絞る
resource.labels.env="staging"

セキュリティ設計

同 GCP project に staging + prod を同居させているため、SA の権限が 他環境に染み出さない よう per-resource IAM に徹底。

SA何ができるか範囲
cloud-run-api-${env}Cloud SQL connectproject (DB 認証必須)
*_${env} Secret 読取secret-level (他環境の secret 不可)
github-actions-${env}image pushliga-images repo (共有)
Cloud Run deployliga-api-${env} service-level (他環境不可)
SA 借用 (act as)cloud-run-api-${env} SA-level (他環境不可)
*_${env} Secret 読取secret-level (他環境不可)
Cloud SQL connectproject (migration 用、DB 認証必須)

残るリスクと許容理由

リスク影響許容理由 / 対策
Cloud SQL public IP (staging のみ 0.0.0.0/0 許可)DB 認証あれば任意 IP から到達可DB password は 32 文字乱数、Secret Manager のみで配布。Netlify が Unix socket 不可なため staging 限定で開く。prod は Private IP + Serverless VPC Access に切替
Cloud Run public endpoint誰でも API を叩けるBetter Auth が認証 gate (アプリ層)
state に DB password 平文state を盗まれれば DB 直接接続可GCS バケットは project Owner のみ
Artifact Registry 共有仮に staging CI が prod の image を push する可能性image tag が SHA-based で overwrite 不能

本番化前に検討する強化

  • Cloud SQL を Private IP + Serverless VPC Access に切替
  • Cloud Run に Cloud Armor で WAF / IP 制限
  • Secret Manager の値ローテーション スケジュール
  • GCS state バケットに CMEK
  • Netlify / GCP / GitHub の 2FA + recovery code 定期確認