全体クラウド構成One-page architecture
11 個の手順で構築したリソースが、本番環境でどう連動するかを 1 枚の図にまとめました。「ユーザのアクセス → 入口(LB + WAF)→ 4 つの Cloud Run サービス → ストレージ / DB / メッセージング基盤 → Google Drive ミラー」の流れを、上から下に追えるように配置しています。
ランタイム構成Runtime topology
ユーザがブラウザでアクセスしてから、データベース・Google Drive へ届くまでの主要経路です。teal の太線は同期的な主経路、灰色の細線は非同期処理、点線はスケジュール起動を示します。
読み方: teal の太線は「ファイルが感染していないとわかった瞬間に Drive 同期を起動する」など、業務上クリティカルな同期主経路です。灰色の細線は Pub/Sub やバッチを介した非同期、点線(金茶色)はスケジュール起動を示します。matsuba-sync と matsuba-batch は需要が無いとき 0 インスタンス(課金 0 円)に縮退します。
本構築で作成したクラウドリソース一覧Resource manifest
手順 00〜10 で作成したものを、層別に並べました。それぞれの設定詳細は対応する手順ページに展開しています。
| 層 | サービス | 件数 | 役割 |
|---|---|---|---|
| 入口 / 公開境界 | Cloud Load Balancing | 1 LB / 4 バックエンド / 2 NEG | 2 ホスト振り分け、1 枚の SAN 証明書で TLS 終端 |
| 入口 / 公開境界 | Cloud Armor | 2 ポリシー × 7 ルール | OWASP 6 種 + IP ごとのレート制限(本体と共有リンクで別のポリシー) |
| 入口 / 公開境界 | Cloud DNS + Cloud Domains | 1 ゾーン / 2 A レコード | portal.example.com + inbox.portal.example.com |
| 実行基盤 | Cloud Run(Service) | 4 サービス | web / api / sync / scanner、東京リージョン |
| 実行基盤 | Cloud Run(Jobs) | 1 ジョブ + 17 スケジュール(予定) | 定期バッチ統合、アイドル時 0 円 |
| 実行基盤 | Artifact Registry | 1 リポジトリ | コンテナイメージ保管、一定期間・一定数を保持する自動掃除 |
| メッセージング | Pub/Sub | 13 主トピック + 13 DLQ / 22 サブスクリプション | 業務イベント配信 + 失敗時退避先 |
| メッセージング | Eventarc | 1 トリガ | 未検査バケットの新規 → scanner サービスへ Push |
| メッセージング | Cloud Tasks | 1 キュー | メール送信ジョブの非同期化 |
| ストレージ | Cloud Storage | 5 バケット | 未検査 / 検査済み / 隔離 / ミラー(ウイルス定義) / 共有 ZIP |
| ストレージ | Supabase Postgres | 1 プロジェクト | 東京 Pro、PITR + 3 拡張(pg_trgm / uuid-ossp / pgcrypto) |
| 認証 / アイデンティティ | サービスアカウント | 7 個 | web / api / sync / scanner / batch(Jobs)の各実行 SA・隔離読取専用 SA・デプロイ用 SA |
| 認証 / アイデンティティ | Workload Identity Federation | 1 プール / 1 プロバイダ | GitHub Actions からのキーレス認証 |
| 認証 / アイデンティティ | Google OAuth Client | 1 クライアント | Better Auth の Google ログイン |
| 認証 / アイデンティティ | Google 共有ドライブ | 1 ドライブ | 「社内アーカイブ」、sync の実行 SA を Content manager 追加 |
| シークレット | Secret Manager | 7 シークレット | DB / Better Auth / OAuth / Resend / CORS、SA 単位の最小権限 |
| 外部 SaaS | Resend | 1 API キー + 1 Webhook | ドメイン mail.example.com を再利用、件名/送信者名でブランド明示 |
| 監視 / コスト | Cloud Monitoring | 1 通知チャネル + 1 アラート | 5xx 検出を起点に Step 99 で詳細化 |
| 監視 / コスト | Cloud Billing | 1 月予算 | 予算に近づいたとき・達したとき・超えたときの 4 段階で通知 |
| 監視 / コスト | Cloud Error Reporting | 新規エラー通知 ON | Cloud Logging から自動集約 |
| CI/CD | GitHub リポジトリ + Secrets | 1 リポジトリ + 5 Secrets | <owner>/matsuba(Private) |
合計: 上記の構成要素は 主要だけで 150 以上。一見多いように見えますが、これらは全て「設計ルール(本体の設計文書)に書かれた構造をそのまま再現したもの」で、コンソール上の手作業で構築しています。
公開境界の方針Public boundary
社外取引先がアクセスする前提のため、IAP(Identity-Aware Proxy = Google アカウント縛りのアクセス制御)は使えません。代わりに 5 層の多層防御で守ります。
| 層 | 守るもの | 守り方 |
|---|---|---|
| 外側 | Cloud Armor(WAF) | OWASP 6 種(SQLi / XSS / LFI / RFI / RCE / Scanner Detection)+ IP ごとのレート制限(本体と共有リンクで別のポリシー) |
| 2 層目 | Cloud Load Balancing | HTTPS 終端、HSTS ヘッダ送出(旧クライアント保護)、ホスト名で portal.example.com と inbox.portal.example.com を振り分け |
| 3 層目 | apps/web の proxy.ts | Better Auth のセッションを毎リクエスト検証、未ログインは /sign-in に強制リダイレクト |
| 4 層目 | apps/api ミドルウェア | Cookie / Bearer 検証、Origin チェック、データベースに送る JWT を生成 |
| 最内 | Postgres RLS | 行レベルセキュリティ(DB が「あなたが見られる行か」を最終判定。アプリにバグがあっても、この判定が最後の防壁になる) |
| 用途 | ホスト | 役割 |
|---|---|---|
| 本体アプリ | portal.example.com | 認証必須の全機能(サインイン、Box 操作、管理画面、API) |
| 共有リンク受取 | inbox.portal.example.com | 受取人向け(ログイン不要)。本体 API は露出させない |
サービスアカウントの配置Service account topology
サービスアカウント(SA)は「アプリが Google Cloud にアクセスする際の身分証」です。用途別に分け、必要なリソース(バケット / トピック / シークレット単位)にだけ最小限の権限を与えています。JSON 鍵ファイルは 1 つも発行していません。
| SA | 用途 | 主な権限 |
|---|---|---|
web の実行 SA | matsuba-web(Next.js UI) | apps/api を内部呼び出し |
api の実行 SA | matsuba-api(業務 API) | GCS(未検査 / 検査済み / 共有 ZIP の各バケット)、Pub/Sub publish、Secret Manager 参照、Cloud Tasks enqueue |
sync の実行 SA | matsuba-sync(Drive 同期) | 検査済みバケット read、Pub/Sub subscribe、共有ドライブの Content manager(fileOrganizer) |
scanner の実行 SA | matsuba-scanner(ウイルス検査) | 4 バケット R/W(未検査 / 検査済み / 隔離 / ミラー(ウイルス定義))、Pub/Sub publish、Eventarc 受信 |
batch(Jobs)の実行 SA | matsuba-batch(定期処理) | GCS、Postgres、Pub/Sub、Secret Manager |
隔離読取専用 SA | 感染ファイル取り出し専用(system_admin が impersonate) | 隔離バケットのみ Viewer。誰にも紐付けず、必要時のみ手動で借りる |
デプロイ用 SA | GitHub Actions のデプロイ用 | Cloud Run admin、Artifact Registry writer、Secret Manager 参照 |
意図: api の実行 SA に 隔離バケットへの権限を与えていないのは、「業務 API が誤って感染ファイルを取り出す経路をそもそも作らない」ためです。隔離ファイルへのアクセスは専用の 隔離読取専用 SA を一時的に借りる形でしか行えません。