やあ、現場で戦うアーキテクト諸君。
今日は、Cloud Spannerを単なる「スケーラブルなDB」としてではなく、「Google Cloudのエコシステムにおける信頼の起点(Root of Trust)」としてどう扱うかという話をしよう。
テーマは「サービスアカウントのなりすまし(Impersonation)と権限委譲」だ。
多くのエンジニアが、サービスアカウントのJSONキーを環境変数に突っ込んで「接続できました!」と喜んでいる。だが、私のチームでそんなコードを書いたら、即座にリジェクトだ。なぜか? それは、静的な秘密鍵の運用が、分散システムのセキュリティにおける最大の単一障害点(SPOF)であり、現代のクラウドネイティブな設計思想から最も遠いからだ。
Spannerが他のサービス(BigQueryやGCS)と連携する際、内部で何が起きているのか。その「権限のバトンパス」の裏側を解剖する。
—
1. 「静的なキー」を捨て、なりすまし(Impersonation)を選べ
まず大前提だ。SpannerへのアクセスにJSONキーを使うのは、令和の設計ではない。我々が採用すべきは、Service Account Impersonationだ。
これは、呼び出し元のエンティティ(開発者の個人アカウントや、GKE上のWorkload Identity)が、ターゲットとなるサービスアカウントの「権限を一時的に借りる」仕組みだ。
なぜこれが重要か
SpannerのようなミッションクリティカルなDBでは、権限は「固定」されるべきではなく、「文脈(Context)に応じて動的に生成」されるべきだからだ。
悪い例: JSONキーを直接使う
export GOOGLE_APPLICATION_CREDENTIALS=”path/to/dangerous-key.json”
良い例: なりすましによる短寿命トークンの生成
gcloud auth print-access-token \
–impersonate-service-account=”spanner-reader@my-project.iam.gserviceaccount.com”
このコマンドの裏側では、IAMの `iam.serviceAccounts.getAccessToken` 権限が検証されている。この「検証プロセス」こそが、Spannerの堅牢なエコシステムの門番だ。
—
2. Spanner Service Agent:権限委譲の真の主役
Spannerは単体で動いているわけではない。例えば、Cloud StorageからデータをImportしたり、BigQueryからFederated Queryを投げたりする際、「Spanner自身が他のサービスにアクセスする」シーンが登場する。
ここで暗躍するのが Spanner Service Agent だ。
プロジェクトを有効にすると、`service-{PROJECT_NUMBER}@gcp-sa-spanner.iam.gserviceaccount.com` という形式のアカウントが自動生成される。これがSpannerという「システム」の化身だ。
権限委譲の内部シーケンス
SpannerがGCSからAvroファイルを読み込む際の、内部的な検証プロセスを想像してほしい。
1. リクエストの受信: ユーザーがSpanner APIに `Import` をリクエストする。
2. Identityの検証: Spannerは、リクエストを送ってきたユーザーが「Spannerを操作する権限」を持っているか確認する。
3. 権限の委譲(Delegation): ここが肝だ。Spannerはユーザーの権限をそのままGCSに持っていくのではない。Spanner Service Agent が GCSバケットに対して `storage.objects.get` を持っているかをIAMが検証する。
設計のポイント:
実務では、この Service Agent に対して「必要最小限(Least Privilege)」の権限を付与する設計を徹底せよ。GCS全体への `Storage Admin` ではなく、特定のバックアップ用バケットへの `Storage Object Viewer` だけを与える。これが極限の設計だ。
—
3. Federated Queries(外部データソース連携)の深淵
SpannerからBigQueryのデータを参照する「Federated Queries」を例に、高度な権限委譲を見てみよう。
Spannerで `EXTERNAL_QUERY` を実行する際、認証のホップが一段階増える。
— SpannerからBigQueryを叩く
SELECT FROM EXTERNAL_QUERY(
“projects/my-project/locations/us-central1/connections/my-bq-conn”,
“SELECT customer_id FROM customers WHERE status = ‘active'”
);
この時、Spannerは Connection Resource を介してBigQueryを呼び出す。内部的には以下の検証が走る。
1. Spanner内部で、指定された `connection` オブジェクトへのアクセス権があるか。
2. その `connection` に紐付けられたサービスアカウント(多くの場合、BigQuery Connection Service Agent)が、BigQueryのデータセットへの読み取り権限を持っているか。
パフォーマンス上の注意点:
この権限検証は、クエリ実行のオーバーヘッドになる。特に多数の小さなクエリを外部ソースに投げる設計は、IAMの検証コスト(レイテンシ)を直撃する。バルク処理として設計するのが定石だ。
—
4. 堅牢な設計パターン:短寿命トークンと条件付きIAM
私がリードするプロジェクトでは、以下の「黄金律」を適用している。
A. Workload Identityの徹底
GKE上でSpannerを動かすなら、K8sのServiceAccountとIAMのServiceAccountを1:1で紐付けろ。これにより、ポッド内のアプリケーションは「自分が誰か」を知ることなく、自動的にSpannerへの短寿命アクセストークンを手に入れる。
B. IAM Conditionsによる「時間」と「場所」の制約
「なりすまし」を許可する際も、無条件に許してはならない。
IAMポリシーの例
- members:
- “user:lead-engineer@example.com”
role: “roles/iam.serviceAccountTokenCreator”
condition:
title: “Working Hours Only”
expression: “request.time < timestamp('2023-12-31T23:59:59Z') && request.auth.claims.email_verified == true"
このように、「なりすまし権限自体に有効期限を設ける」。これが、万が一端末が盗難に遭った際の爆発半径(Blast Radius)を最小化する。
—
5. アーキテクトとしての結論
Cloud Spannerの権限設計の本質は、「誰が」ではなく「どの文脈で、どの鍵(Token)が、いつまで有効か」を制御することにある。
サービスアカウントのなりすましと権限委譲を理解することは、単なるセキュリティ設定ではない。それは、複雑な分散システムにおいて、コンポーネント間の「信頼の連鎖」を設計することそのものだ。
JSONキーを捨てろ。
Service Agentに魂を込めろ。
そして、すべての権限に「理由(Condition)」を与えろ。
これが、世界最高峰のインフラを、世界最高峰のまま使いこなす唯一の道だ。
諸君の健闘を祈る。
コメント