【Spanner設計レビュー】IAMとアクセス制御:なぜあなたの権限設計は「広すぎる」のか?
プロジェクトの終盤に差し掛かり、セキュリティ監査で「データベースへの過剰な権限付与」を指摘されて冷や汗をかいた――そんな経験はないだろうか。
Cloud Spannerは、その圧倒的なスケールと可用性ばかりがクローズアップされがちだが、エンタープライズグレードの厳格なアクセス制御をネイティブで備えている。GCPのIAM(Identity and Access Management)と完全に統合されており、インスタンスレベルからデータベースレベル、さらには行レベルのセキュリティまでを緻密にコントロール可能だ。
今回は、テックリードとしてコードレビューやアーキテクチャレビューの場で行っている、Cloud Spannerにおける「最小権限の原則(Principle of Least Privilege)」に基づいた堅牢なIAM設計の極意を伝授しよう。
—
1. 階層型IAMの全体像:どこに何を付与すべきか?
Cloud SpannerのIAMは、主に2つの階層構造を持つ。ここを混同すると、途端にガバナンスが崩壊する。
1. インスタンスレベル (Instance Level)
- 対象: `roles/spanner.admin`, `roles/spanner.instanceAdmin` など
- スコープ: インスタンス内の全データベース、バックアップ、インスタンス構成そのもの。
- 誰に与えるか: インフラエンジニア、SRE、データベース管理者(DBA)。アプリケーション層のサービスアカウントには絶対に与えてはならない。
2. データベースレベル (Database Level)
- 対象: `roles/spanner.databaseAdmin`, `roles/spanner.databaseUser`, `roles/spanner.viewer` など
- スコープ: 特定のデータベース内のスキーマ変更やデータ読み書き。
- 誰に与えるか: アプリケーションのランタイム、CI/CDパイプライン、データアナリスト。
レビューで見かけるアンチパターン
> 「開発効率を上げるために、アプリ用のサービスアカウントに `roles/spanner.admin` を付与しました」
一発レッドカードだ。 これをやると、万が一アプリケーションの脆弱性(SQLインジェクションやコンテナの乗っ取りなど)を突かれた際、攻撃者にDMLの実行だけでなく、データベースのドロップやスキーマの破壊まで許すことになる。アプリが必要としているのはあくまで「データの読み書き」であり、データベースの管理ではない。
—
2. 実務で使うべき最小権限のIAMロールマッピング
アプリケーション、CI/CD、アナリスト、それぞれの役割に応じた「正しいロール割り当て」の黄金律は以下の通りだ。
| アクター | 推奨IAMロール | 理由・ユースケース |
| :— | :— | :— |
| プロダクション・アプリ | `roles/spanner.databaseUser` | データの読み取り・書き込み(DML / Query)のみを許可。DDL実行権限は持たせない。 |
| CI/CDパイプライン (スキーマ適用) | `roles/spanner.databaseAdmin` (またはカスタムロール) | マイグレーションツール(Liquibase, Atlas, 自製スクリプト等)からDML/DDLを実行するため。 |
| データアナリスト / BIツール | `roles/spanner.viewer` | トランザクションをブロックしないよう、読み取り専用でアクセスさせる。 |
gcloudによる正しい権限付与の例
アプリケーション用のサービスアカウントに対して、特定のデータベースレベルのみで `databaseUser` を付与するコマンドは以下の通りだ。プロジェクト全体やインスタンス全体ではなく、必ずデータベース名までスコープを絞ること。
アプリケーション用サービスアカウントに、特定のDBの読み書き権限のみを付与する
gcloud spanner databases add-iam-policy-binding my-database \
–instance=my-instance \
–member=”serviceAccount:app-runtime-sa@my-project.iam.gserviceaccount.com” \
–role=”roles/spanner.databaseUser”
—
3. 高度なアクセス制御:行レベルセキュリティ(Fine-Grained Access Control)
「同じデータベースにアクセスするが、テナントAはテナントAのデータしか見えてはならない」
マルチテナントSaaSや、厳格なリーガルチェックが入るシステムでは、データベースレベルの権限だけでは不十分だ。ここで登場するのが 行レベルセキュリティ(Row-Level Security: RLS) である。
Spannerでは、SQLベースでポリシーを定義し、特定のユーザー(またはサービスアカウント)ごとに行の可視性を動的に制限できる。
実装パターン例
例えば、`Tenants` テーブルにおいて、各サービスアカウントが自テナントのレコードしか触れないようにするポリシーは以下のように記述する。
— 1. 行アクセス ポリシーの作成
CREATE ROW ACCESS POLICY tenant_isolation_policy
ON Orders
GRANT SELECT, UPDATE, DELETE
ON TABLE Orders
USING (TenantId = SESSION_USER());
— ※注: SESSION_USER() や組み込み関数を用いて、アクセスしているプリンシパルを判定します。
これにより、アプリケーション側で `WHERE TenantId = ?` の付け忘れによるデータ漏洩(IDOR脆弱性)が発生したとしても、データベース層が物理的・強制的に他テナントのデータを隠蔽する。ここまでやって初めて「堅牢な設計」と呼べる。
—
4. パフォーマンスとセキュリティの交差点:IAMキャッシュの罠
最後に、SpannerのIAM設計において、パフォーマンスや運用面でハマりがちな「知見」を共有しよう。
IAM変更の反映遅延
IAMポリシーを変更(`gcloud` や Terraform で付与・剥奪)した場合、その変更がグローバルに伝播し、キャッシュが無効化されるまでに数秒〜最大1分程度のタイムラグが発生することがある。
- 実務上の注意: CI/CDパイプラインで「IAMを付与した直後にテストクエリを走らせる」ようなステップを書くと、権限不足(`PERMISSION_DENIED`)で偶発的にビルドが落ちることがある。デプロイパイプラインでは、IAM変更後に数秒の `sleep` を挟むか、リトライ機構を実装するのが定石だ。
コネクションプールとIAMトークン
Cloud Spannerのクライアントライブラリは、内部的にGoogle CloudのOAuth2アクセストークン(通常1時間で有効期限切れ)を定期的に自動更新し、gRPCのメタデータに付与して通信を行っている。
- 注意点: サービスアカウントの鍵(JSONキー)の静的な運用は、ローテーションの手間や漏洩リスクの観点から完全にアンチパターンである。Google Kubernetes Engine (GKE) なら Workload Identity、Compute Engine なら デフォルトサービスアカウント(またはカスタムSA)によるメタデータサーバー経由の自動トークン取得(ADC: Application Default Credentials)を絶対に使用すること。
—
チーフアーキテクトからの総括
Cloud SpannerにおけるIAMとアクセス制御は、単なる「セキュリティチェックリストを埋めるための作業」ではない。システムの「防衛ライン」をどこに引くかというアーキテクチャそのものだ。
1. インスタンス管理権限とデータベース利用権限を完全に分離する。
2. アプリケーションには必ず `roles/spanner.databaseUser` をデータベース単位で最小限に付与する。
3. マルチテナントや高機密データには 行レベルセキュリティ(RLS) を導入し、アプリケーションコードのバグすらもデータベース層で吸収する。
次の設計レビューでは、これらのポイントがクリアされているかを厳しくチェックしてほしい。妥協したセキュリティは、必ず数ヶ月後の障害やインシデントという形で牙をむくのだから。
コメント