サービスアカウントキーの「持ち出し」は死を意味する。Workload Identityへの移行が急務な理由
現場でインシデント対応をしていると、決まって遭遇する光景がある。それは、GitHubのパブリックリポジトリや、開発者のローカルPCの.envファイルに放置された「.json形式のサービスアカウントキー」だ。
結論から言おう。静的なサービスアカウントキー(JSON鍵)を使っている時点で、君たちのクラウドインフラは「時限爆弾」を抱えているのと同じだ。
攻撃者は、GitHubのコミット履歴や、誤って公開されたストレージバケットを24時間体制でスキャンしている。一度でも鍵が流出したら、あとは彼らが自動化ツールを使って君たちのGCP環境を蹂躙するのを見るだけだ。今回は、この「悪夢」を終わらせるための実戦的な話をしよう。
—
なぜ「鍵」ではなく「Workload Identity」なのか
従来の認証方式であるJSON鍵は、いわば「永遠に有効なマスターキー」だ。これを紛失したり盗まれたりしても、明示的に削除するまで攻撃者は権限を使い続けられる。
一方、GCPのWorkload Identityは、「身分証明書(IAM)とアプリケーションを直結させる」仕組みだ。
Kubernetes(GKE)やCloud Run上で動くアプリケーションに対し、一時的なトークンを動的に発行する。鍵ファイルそのものが存在しないため、盗まれるリスクが物理的にゼロになる。
攻撃者が狙う「盲点」
攻撃者は、アプリケーション内の脆弱性(例えば、LFI:ローカルファイル読み込み)を突いて、サーバーOS内の /var/run/secrets/ を探索する。もしそこにJSONキーが配置されていれば、その瞬間にゲームオーバーだ。だが、Workload Identityを使っていれば、アプリケーションはOS上に鍵を持たない。攻撃者がサーバー内をどれだけ探し回っても、何も見つからないのだ。
—
【実践】Workload Identityのセキュアな実装コード
ここからは、GKE上でPythonアプリケーションを動かすと仮定した、実用的な実装例を見ていく。
1. Workload Identity の設定(Terraformの抜粋)
まずはIAMの紐付けだ。GKEのServiceAccountとGCPのIAMロールをバインドする。
# GCPのサービスアカウントを作成
resource "google_service_account" "app_sa" {
account_id = "my-app-service-account"
display_name = "App Service Account"
}
# Workload Identityの設定: K8sのSAとGCPのSAを紐付ける
resource "google_service_account_iam_member" "workload_identity_binding" {
service_account_id = google_service_account.app_sa.name
role = "roles/iam.workloadIdentityUser"
member = "serviceAccount:my-project.svc.id.goog[default/my-k8s-sa]"
}
2. アプリケーションコード(Python)
Googleのライブラリは賢い。google-authライブラリを使用すれば、環境変数にJSONキーがなくても、自動的にWorkload Identityのトークンをフェッチしてくれる。
from google.cloud import storage
from google.auth import default
# JSONキーのパスを指定する必要はない
# google-authが環境を検知し、自動的にWorkload Identityの認証情報を使用する
credentials, project_id = default()
def get_bucket_data(bucket_name):
# クライアント初期化時に認証情報を渡す
storage_client = storage.Client(credentials=credentials, project=project_id)
bucket = storage_client.get_bucket(bucket_name)
# セキュアにデータを取得
return list(bucket.list_blobs())
# 実行
if __name__ == "__main__":
# ここにJSONキーを読み込むコードは一切書かない
blobs = get_bucket_data("my-secure-bucket")
print(f"Found {len(blobs)} files.")
—
現場で守るべき「3つの鉄則」
Workload Identityに移行するだけでは不十分だ。以下の運用を徹底してほしい。
1. 「最小権限の原則」を極限まで突き詰める
roles/ownerやroles/editorなどという広すぎる権限は論外。GCPのIAM条件(IAM Conditions)を活用し、特定のバケットや特定の期間のみアクセスを許可するように設定すること。
2. 静的キーの強制無効化
- Workload Identityへ移行した後は、既存のサービスアカウントキーをすべて削除し、組織ポリシー(
iam.disableServiceAccountKeyCreation)を適用して、以後誰もJSON鍵を作成できないように制限をかけること。
3. Audit Logsの監視
- 何が起きているかを知る唯一の方法はログだ。
data_accessログを有効にし、誰がいつ認証を試みたかをCloud Loggingで追跡できるようにしておくこと。
—
最後に:セキュリティは「諦めない奴」が勝つ
「設定が面倒くさい」「今のままで動いているからいい」という思考が、大規模な情報漏洩を招く。エンジニアたるもの、楽をすることではなく、堅牢であることに快感を覚えるべきだ。
Workload Identityへの移行は、数時間の作業で済む。だが、その数時間が、将来の数億円規模の損害賠償やブランド毀損を防ぐ最大の投資になる。
さあ、今すぐGitHub上の *.json を検索し、削除し、Workload Identityへの移行計画をチケットに起こしてくれ。それが、プロのエンジニアの仕事だ。
コメント