til//cloud-db-tenant-safe-writes
cloud-db-tenant-safe-writes.mdupdated 2026-08-012,953 chars

クラウドDBへの​テナント安全​書き込み —— 接続・認証・RLS を​一気通貫で​理解する

特定の​顧客​(テナント)だけを​対象に、​記事データを​クラウドDBへ​安全に​読み込ませる​作業に​ついて、​各手順の​意味から​積み上げて​理解する​ための​ノートである。

全体​像 —— 実際に​何を​しているのか

[手元 PC]
  ↓ ① Cloud SQL Auth Proxy で安全なトンネルを張る
[クラウドDB(Cloud SQL)]
  ↓ ② Secret Manager からパスワードを取り出して接続
  ↓ ③ テナントを絞り込んで(RLS または WHERE句)
  ↓ ④ 1件ずつ確認・書き込み・ログ記録

大きく​分けると、​「安全に​接続する​(①②)」​→​「正しい​相手に​だけ​書き込む​(③)」​→​「証跡を​残す​(④)」の​3段階に​なる。

クラウドDBへの​安全な​接続

Cloud SQL Auth Proxy —— 安全な​トンネル

Cloud SQL Auth Proxy は、​データベースの​接続ポートを​インターネットに​公開する​代わりに、​Google の​認証を​通過した接続だけを​通す​「安全な​トンネル​(プロキシ)」である。​データベースを​直接インターネットに​さら​さずに​済む。​通常の​データベース接続は​ポートを​開けて​ IP 許可リストで​守るが、​Auth Proxy は​そもそも​ポートを​公開しない。​ローカルで​起動すると、​データベースは​あたかも​ localhost に​存在するかのように​見える​一方、​裏側では​暗号化・認証済みの​通信を​中継している。

./cloud-sql-proxy <project>:<region>:<instance> --port <ローカルポート>

ADC —— アプリが​使う​既定の​ログイン認証情報

ADC(Application Default Credentials)は、​認証情報を​コードに​ハードコード​(=直接​埋め込むこと)する​代わりに、​実行環境に​応じた​認証を​自動で​選択する​仕組みである。​自分の​マシン上ではgcloud auth application-default loginで​設定した​ユーザー認証情報を​使う。

quota-project —— API利用枠と​課金先の​明示

quota-project は、​GCP​(Google Cloud Platform)の​ API を​呼び出す際に、​どの​プロジェクトの​利用枠と​課金を​使うかを​明示する​設定である。​これが​ずれていると​ 403 エラー​(サーバーが​「権限が​ない」と​して​拒否する​状態)に​なることがある。​ADC を​設定した​ユーザーと​呼び出し元の​プロジェクトが​一致しない​場合に​起きやすい。

gcloud auth application-default set-quota-project <project-id>

シークレットの​扱い​ —— Secret Manager

Secret Manager は、​パスワードや​ API キーなどの​シークレット​(=秘密情報)を​暗号化して​保管する​クラウドの​金庫である。​コードや​設定ファイルに​平文で​書いてはならない。

原則は​次の​とおりである。​シークレットは​実行時に​のみ​取得する​(セッション中だけ変数に​展開する)。​取得した​値を​画面・ログ・ファイルに​出力しない。​スクリプトに​直接​書き込む​(ハードコードする)​ことも​禁止である。

gcloud secrets versions access latest --secret=<secret-name> --project=<project-id>

マルチテナントと​ RLS

マルチテナント設計

マルチテナントとは、​単一の​データベースや​アプリケーションを​複数の​顧客​(テナント)で​共有する​設計を​指す。​テナントごとに​別システムを​立てるより​効率的だが、​ある​顧客の​データが​別の​顧客の​データと​混ざらないよう分離を​慎重に​設計する​必要が​ある。​通常は​各テーブルに​テナントを​識別するcustomer_id列を​持たせ、​あらゆる​操作で​この​列に​よる​フィルタリングを​徹底する。

RLS —— 行レベルセキュリティ

RLS(Row-Level Security)は、​接続している​ユーザーや​セッション変数に​応じて​「どの​行が​見える​/​書き込めるか」を​自動的に​制御する​データベースの​ポリシー機能である。​RLS が​有効な​データベースに​書き込む​場合、​ポリシーが​自動的に​テナントで​フィルタする​ため、​アプリケーション側は​通常の​ INSERT を​実行するだけで​よい。

RLS が​無効、​または​設定されていない​環境では、​アプリケーション側が​フィルタリングの​責任を​負う。​必ずWHERE customer_id = '<対象>'のような​条件を​付ける。​条件なしの​書き込みは、​他テナントの​データを​上書き・汚染する​危険が​ある。

スキーマを​把握する​ —— information_schema

スキーマとは、​データベースの​テーブル・列・型などの​設計情報を​指す。information_schema は、​データベース自身が​そのスキーマ情報を​記述する​ために​持つ​特別な​仮想テーブル群であり、​どの​テーブルに​どの​列が​あるかを​ SQL で​問い​合わせられる。

-- テーブル一覧
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public';

-- 列一覧
SELECT column_name, data_type
FROM information_schema.columns
WHERE table_name = '<テーブル名>';

本文コンテンツの​保存形式は​環境に​よって​異なり、​HTML・JSON・リッチテキスト​(ProseMirror や​ Tiptap と​いった​エディタが​出力する​構造化データ)などが​ある。​書き込む前に、​実際の​列の​型と​既存データの​形式を​必ず確認する。

安全な​書き込み手順

  1. 自己確認:​書き込む前に​ SELECT を​実行し、​対象テナント・対象テーブル・件数を​表示して​確認する。
  2. 1件テスト:まず1件だけ​書き込み、​結果が​意図どおりか​確認する。
  3. 本番は​1件ずつ、​または​小バッチで​進める:大量データを​一度に​流し込まない。
  4. 監査ログ:何を​・いつ・​何件書いたかを​自分の​マシンに​記録する。
  5. 読み取りを​先に​する:必要が​なければ​書き込まない。​まず​読み取って​確認する。

書き込む前に​必ず​この​順序で​進める。​確認を​省いた​一括​書き込みが​事故の​原因に​なる。

本番ロックダウン —— 守るべき運用規律

  • 事前承認なしに​本番データベースを​直接変更しない。
  • 破壊的操作​(DELETE・TRUNCATE・DROP)は、​内容と​影響範囲を​事前に​明示したうえで​承認を​得る。
  • git push --force(=履歴を​上書きする​強制プッシュ)は​原則と​して​禁止する。
  • パスワードや接続情報を​含むコマンドを​画面出力や​ログに​残さない。

な​ぜ​この​規律が​必要か

マルチテナント環境では、​1つの​ミスが​複数の​顧客に​同時に​波及する。​本番​データベースの​データは​削除すると​元に​戻らない​(バックアップからの​復元には​時間と​コストが​かかる)。​接続・認証・フィルタリングを​丁寧に​積み上げるのは​過剰な​慎重さではなく、​共有環境に​おける​最低限の​責任である。​手順が​多いのは、​それだけ守るべき人と​データが​多いからである。

出典・参考

元の​ノートに​外部の​出典リンクは​記載されていない。

148 notestil