サービスアカウント
Service Account ・ さーびすあかうんと
人間ではなくプログラムに与えるID。鍵を持たせず基盤が身元を保証する鍵レス化が進む。
✦ 30秒で試す — 航海人間ではない「社員」が、クラウドにたくさん住んでいる3か月たったいま、その鍵ファイルは?予想してみる概要
サービスアカウントは、人間ではなくプログラムに与えるアカウントです。対象は、夜間のバッチ処理、CI/CD のパイプライン、サーバ上のアプリケーション、コンテナの中のワークロードなどです。人間のアカウントと同じように認証を受け、権限を割り当てられ、行動が監査ログに記録されますが、その主体はソフトウェアです。「深夜2時にデータベースをバックアップしているのは誰か」という問いに「backup-job というサービスアカウントです」と答えられるようにする仕組み、と言えます。
いまのシステムでは、API を呼ぶ回数も権限を使う回数も、人間よりプログラムのほうが圧倒的に多くなっています。クラウドの IAM(アクセス管理)のサービスアカウントやロール、Kubernetes の ServiceAccount、Active Directory のマシンアカウントなど、名前や実装は環境ごとに違っても、「機械にも一人前の ID を持たせて統制する」という考え方は共通です。人間の ID に対して、こちらはワークロードアイデンティティ、ノンヒューマンアイデンティティなどとも呼ばれます。
なぜ生まれたか
サービスアカウントがなかった時代、自動処理は誰かの個人アカウントを間借りして動いていました。担当者の ID とパスワードをバッチ処理の設定ファイルに書き込む、という運用です。これは二重に破綻します。まず、その担当者が退職してアカウントを止めた瞬間、夜間バッチが全滅します。逆に「バッチが止まるから」と退職者のアカウントを残せば、それは持ち主のいない生きた侵入口になります。監査の面でも、ログに残る「A さんの操作」が本人の操作なのか自動処理なのか区別できず、「誰が何をしたか」を追えません。
そこで、人間と自動処理の ID を分け、プログラムには専用のアカウントを発行するという原則が確立しました。サービスアカウントは特定の個人に結びつかないので退職の影響を受けません。権限はその処理に必要な分だけに絞れ(最小権限の原則)、ログの上でも人間の操作とはっきり区別できます。
ただ、ID を分けても「そのアカウントとして認証するための鍵」は残りました。鍵はどこかに置かなければならず、置かれた鍵は漏れます。2010年代後半から、クラウドや CI の基盤が「いま動いているのがどのワークロードか」を自分で証明できるようになり、長命の鍵そのものを無くす「鍵レス」化が進みました。
詳細
人間のアカウントとの違い
サービスアカウントは人間のアカウントと多くの仕組みを共有しますが、性質は対照的です。人間はパスワードと MFA で対話的にログインします。サービスアカウントに対話はなく、鍵やトークンによる非対話の認証だけを使います(対話ログインはむしろ無効にするのが定石です)。人間の ID は、入社・異動・退職という人事の出来事に合わせて管理されます。サービスアカウントの寿命は、システムの構築・変更・廃止に結びつきます。放っておくと「何に使われているか誰も知らない」孤児アカウントが溜まっていきます。数の面でも、いまの組織ではサービスアカウントが人間の ID の何倍、何十倍もあるのが普通です。攻撃者にとっては「MFA がなく、権限が強く、監視が甘い」格好の標的です。
最小権限が生命線
サービスアカウントの設計原則は最小権限の原則に尽きます。人間と違って、サービスアカウントの職務ははっきりしています。バックアップのジョブなら「特定のストレージへの書き込み」だけ、レポートの集計なら「特定のテーブルの読み取り」だけで、それ以外の権限を持つ理由がありません。それでも現実には「動かないから」と管理者権限を与えたまま放置されがちで、その資格情報が1つ漏れただけで環境全体が落ちます。用途ごとにアカウントを分ける(1ジョブ1アカウント)、RBAC のロールで職務ごとに権限を束ねる、実際の利用実績と突き合わせて使っていない権限を削る。この地道な運用が、認可の設計としてのサービスアカウント管理の中心です。
長命の鍵から「鍵レス」へ
サービスアカウントの認証は、伝統的に長命の資格情報に頼ってきました。APIキー、パスワード、クラウドのサービスアカウントの鍵ファイル(秘密鍵を入れた JSON など)です。この方式の弱点は根本的です。鍵は、それを使うサーバや CI のどこかに置かなければなりません。置かれた鍵は、設定ファイルへの書き込み、Git リポジトリへの誤コミット、デバッグ用に出力したログ、退職者の手元に残ったファイル、といった経路で漏れます。そして多くの鍵には有効期限がなく、作り直すまで何か月でも使えます。シークレット管理の基盤で保管とローテーションを自動にするのが第一の対策ですが、より根本的な解決が、長命の鍵そのものを無くす「鍵レス(keyless)」化です。
代表例がクラウドの Workload Identity です(AWS の IAM ロール、Google Cloud の Workload Identity 連携、Azure のマネージド ID など)。発想はこうです。基盤は、どの仮想マシンや、どのコンテナや、どの CI ジョブが動いているかを、自分自身で知っています。それなら、ワークロードが「私は誰か」を鍵で証明しなくても、基盤が身元を保証すればよい。クラウドはその保証を確かめて、1時間ほどで失効する一時的な資格情報を発行します。ワークロードは期限が来る前に自動で取り直します。
GitHub Actions から AWS へデプロイする場面で、流れを順に追ってみます。(1)ジョブが始まると、GitHub の IdP(ID プロバイダ)が、そのジョブ専用の OIDC の ID トークンを発行します。中身は署名つきの JWT で、「どのリポジトリの、どのブランチの、どのワークフローか」が書かれています。(2)ジョブはこの ID トークンを AWS の STS(一時的な資格情報を発行するサービス)に提示し、「このロールを使いたい」と頼みます。(3)STS は、トークンの署名が GitHub の公開鍵で検証できるか、発行元と宛先が正しいか、リポジトリ名やブランチがロールの信頼ポリシーの条件に合うかを確かめます。(4)通れば、1時間ほどで失効する一時的な資格情報を返します。ジョブはそれで API を呼び、終わればそのまま捨てます。
注意したいのは、一時資格情報も持参人型だという点です。ログに出力されたものを拾われれば、期限内は使えてしまいます。鍵レスの強さは「盗めない」ことではなく、「盗む価値のある長命の鍵がどこにも置かれず、流れるのは短命のものだけ」であることにあります。下の部品で、拾った資格情報を時間を進めながら使ってみて、両者の違いを確かめてください。
サービスアカウントの鍵ファイルの写しが、3か所に落ちています。あなたは攻撃者です。どれか1つをクラウドのリソースへドラッグして、使えるか試してください(タップでもおまかせで運べます)。
実務の落とし穴
鍵レスにも設定の落とし穴があります。いちばん多いのは、信頼ポリシーの条件を緩くしすぎることです。「GitHub が発行したトークンなら何でも受け入れる」設定にすると、他人のリポジトリのジョブまでロールを引き受けられてしまいます。リポジトリ名やブランチ、環境(本番用のデプロイだけ)まで条件に書いて絞ります。仮想マシンの場合は、基盤が用意するメタデータサービスから資格情報を取り出す仕組みなので、アプリに SSRF(サーバに任意の URL を取りに行かせる脆弱性)があると、そこ経由で資格情報を抜かれます。AWS の IMDSv2 のように、トークンを先に取らないと応答しない方式を必須にします。
Kubernetes とゼロトラストの文脈で
Kubernetes では ServiceAccount が第一級のリソースで、Pod に結びつけたアカウントのトークンが自動でマウントされます。Pod はそれを使って API サーバや外部のサービスに自分の身元を証明します。かつては期限のないトークンが Secret として作られていましたが、いまは有効期限つきで宛先を限った「projected token」が標準で、ここでも短命化の流れは一貫しています。クラウドの Workload Identity と組み合わせれば、Pod のトークンをクラウドの一時資格情報に交換でき、クラスタの中にクラウドの鍵を置かずに済みます。
さらにサービスメッシュでは、ワークロードの ID を証明書として発行し(SPIFFE の ID など)、サービス間を mTLS で相互に認証します。「ネットワークの内側だから信用する」のではなく、ワークロードの一つひとつが検証できる ID を持ってはじめて通信を許す。サービスアカウントは、ゼロトラストを機械同士の世界で成り立たせるための土台です。
試問
プログラムが使うアカウント(サービスアカウント)の資格情報の写しが、設定ファイル・デバッグログ・退職者の PC の3か所に漏れた想定です。方式は「長命のキー(鍵ファイル)」と「Workload Identity(鍵を持たず、基盤が身元を保証して1時間だけ使える一時資格情報を発行する)」から選べます。時計のつまみで漏れてからの時間を進め、写しをクラウドのリソースへ運ぶと(タップでも可)、通るか弾かれるかが分かります。
あなたはクラウドを守る側です。資格情報の写しが3か所に漏れた想定で、方式を選び、時計で「漏れてからの時間」を進め、写しをクラウドのリソースへ運んで(タップでも運べます)通るかを確かめてください。
