サービスアカウントキーは「時限爆弾」だ。今すぐ「キーレス」へ移行せよ
現場でインシデント対応をしていると、いまだにGitHubのパブリックリポジトリや、Dockerイメージの中に埋め込まれた service-account-key.json を見つけてゾッとすることがある。
攻撃者にとって、サービスアカウントキーは「宝の地図」だ。一度流出すれば、君がどれほど複雑なパスワードをかけていようが、WAFで攻撃をブロックしていようが関係ない。そのキーさえあれば、彼らは「君自身」としてクラウド環境を自由に操作できるからだ。
今日は、なぜサービスアカウントキーを使い続けることがリスクなのか、そして、現代のクラウドエンジニアが選ぶべき「Workload Identity Federation(キーレス認証)」への移行戦略を、泥臭い実務の視点から解説する。
—
1. なぜ「キー」そのものが悪なのか?
公開鍵暗号(RSAや楕円曲線暗号)が堅牢なのは理解しているだろう。だが、どんなに強固な暗号化アルゴリズムも、その「鍵(秘密鍵)」を管理する運用プロセスが杜撰であれば無意味だ。
攻撃者が狙う盲点:キーのライフサイクル
サービスアカウントキーをJSONファイルとして管理する運用は、以下の3つの脆弱性を抱えている。
1. 永続性: 有効期限を無期限に設定している場合、一度流出するとキーを無効化するまで攻撃者は居座り続ける。
2. 静的性質: ローテーションを運用でカバーしようとしても、エンジニアの作業負荷が増え、結局「期限なし」や「更新忘れ」という人為的ミスが起きる。
3. 可視性: ソースコード、環境変数、CI/CDのログなど、あらゆるところにキーが露出するリスクがある。
PoCの視点:
攻撃者は、GitHubで filename:*.json "private_key_id" といったクエリを投げるだけで、世界中の漏洩キーを収集している。これを見つけた瞬間、彼らは gcloud auth activate-service-account コマンドで即座に君の環境を乗っ取る。
—
2. 脱・鍵管理:Workload Identity Federationの真髄
Workload Identity Federation(WIF)を使えば、GCP外部(GitHub ActionsやAWS、オンプレミスなど)から、「キーファイルを使わずに」GCPリソースにアクセスできる。
仕組みは簡単だ。君のシステムが信頼する「外部プロバイダー(GitHub等)」から発行されたOIDCトークンをGCPに提示し、GCP側でそのトークンを検証して短命なアクセストークンと交換する。これなら、そもそも「秘密鍵」を保存する必要がない。
実践:GitHub Actionsでのキーレス認証設定
まずはGCP側でワークロードIDプールとプロバイダーを作成し、GitHub ActionsがGCPリソースへアクセスできる権限を付与する。
GCPの設定(CLI例):
# ワークロードIDプールの作成
gcloud iam workload-identity-pools create "github-pool" \
--location="global"
# GitHubをプロバイダーとして追加
gcloud iam workload-identity-pools providers create-oidc "github-provider" \
--location="global" \
--workload-identity-pool="github-pool" \
--issuer-uri="https://token.actions.githubusercontent.com" \
--attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository"
# サービスアカウントへの権限付与(特定のレポジトリのみ許可)
gcloud iam service-accounts add-iam-policy-binding "my-sa@my-project.iam.gserviceaccount.com" \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/github-pool/attribute.repository/OWNER/REPO"
—
3. アプリケーション側での実装
PythonでGCPのライブラリを使う場合、環境変数にキーパスを設定する必要はもうない。google-auth ライブラリは、環境変数 GOOGLE_APPLICATION_CREDENTIALS が指定されていない場合、自動的にWorkload Identityの認証情報を探しに行く。
Pythonサンプル(GCP Storageへのアクセス):
from google.cloud import storage
# キーファイルは不要。
# 環境でWorkload Identityが正しく設定されていれば、
# ライブラリが自動的に認証情報を取得する。
def list_buckets():
try:
storage_client = storage.Client()
buckets = list(storage_client.list_buckets())
for bucket in buckets:
print(f"Bucket: {bucket.name}")
except Exception as e:
print(f"認証エラー、または権限不足: {e}")
if __name__ == "__main__":
list_buckets()
—
4. 現場の教訓:明日からやるべきこと
私の経験上、セキュリティを強固にする最大の敵は「利便性」だ。しかし、このキーレス移行に関しては、導入すれば逆に「キーの管理から解放される」という最大のメリットがある。
エンジニアへのアクションアイテム:
1. 棚卸し: gcloud iam service-accounts keys list を実行し、現在発行されているすべてのキーをリストアップせよ。
2. 期限チェック: 1年以上更新されていないキーは、即座に削除せよ。それが君のシステムを守る最短ルートだ。
3. 移行計画: CI/CDツール(GitHub Actions, GitLab CIなど)を使っているなら、最優先でWIFへの移行をバックログに入れろ。
4. 最小権限の原則: もしキーを使わざるを得ない場合でも、そのサービスアカウントには「バケットへの読み込みのみ」など、極限まで絞ったIAMロールを付与すること。
セキュリティは「完璧な防御」を目指すのではなく、「攻撃者にとって割に合わない環境」を作ることだ。鍵というアナログな資産をクラウドから追放し、アイデンティティベースの強固な認証基盤を築いてほしい。
君のコードが、明日も安全にデプロイされることを祈っている。
コメント