「とりあえずContributorで動かしておきますね。」
CI/CDパイプラインを構築するとき、バッチ処理の自動化を組むとき——スピードを優先するあまり、サービスアカウントの権限を広く設定したまま本番環境に放置してしまうケースは珍しくありません。
問題は、その状態が半永久的に続くことです。人のアカウントと違い、サービスアカウントは誰かがログインして使うわけではないため、「権限が強すぎる」という感覚が持ちにくい。しかしアプリケーションに脆弱性が見つかった瞬間、その広い権限がそのまま攻撃者の手に渡ります。
サービスアカウントは「人以外のID」ではなく、「攻撃者の足場になりうるID」として設計する——この記事ではその考え方と実務での設計パターンを解説します。
権限管理の全体像については「IAMとは?認証と認可の違いから学ぶアクセス管理の基本」を参照してください。
「とりあえずContributorで動かす」が招くリスク
サービスアカウントに広い権限を付与すると何が起きるか。攻撃の視点で考えると明確になります。
アプリケーションに脆弱性があった場合、攻撃者はそのアプリが持つ権限の範囲で自由に動けます。アプリが「Contributorをサブスクリプション全体に持つサービスアカウント」で動いていれば、リソースの作成・変更・削除が可能になります。新しいVMを立てて横展開の拠点にする、ストレージからデータを抜き出す、ログを改ざんして証拠を消す——これらが一気に可能になります。
横展開(Lateral Movement) 攻撃者が最初に侵害したシステムやアカウントを足掛かりに、他のリソースへアクセスを広げていく攻撃手法。
人のアカウントであれば「MFAを設定する」「ログインを監視する」という対策が取れますが、サービスアカウントは自動実行のため監視の網にかかりにくく、侵害が発覚しにくいという特性があります。
最小権限の観点でサービスアカウントのリスクを詳しく理解したい方は「最小権限の原則とは?実務での考え方と設計例」も合わせてご覧ください。
参考:Microsoft Entra のサービスプリンシパルのセキュリティ保護 | Microsoft Learn
サービスアカウントとは何か——人のIDとどう違うのか
人のID・サービスアカウント・マネージドIDの3つの違い
クラウド環境では「誰が」システムにアクセスするかを管理する上で、IDを3種類に分けて考えることが重要です。
| 種類 | 使う主体 | 認証方法 | 管理の難易度 |
|---|---|---|---|
| 人のID(ユーザーアカウント) | 人間 | パスワード+MFA | 低 |
| サービスプリンシパル | アプリ・自動処理 | クライアントシークレット・証明書 | 中 |
| マネージドID | Azureリソース | Azureが自動管理 | 低(推奨) |
サービスプリンシパル(Service Principal) アプリケーションや自動処理がAzureリソースにアクセスするためのID。クライアントシークレットまたは証明書で認証する。
マネージドID(Managed Identity) AzureがIDの作成・ローテーション・削除を自動管理する仕組み。シークレットを手動管理する必要がなく、最も安全な選択肢。
クライアントシークレット(Client Secret) サービスプリンシパルの認証に使うパスワードのようなもの。漏洩・期限切れのリスクがあり、管理コストが高い。

なぜサービスアカウントは見落とされやすいのか
サービスアカウントがセキュリティ上の盲点になりやすい理由は3つあります。
誰も日常的に使っていない。 人のアカウントは毎日ログインするため異常に気づきやすいですが、サービスアカウントは自動処理が静かに動き続けるだけです。権限が強すぎても誰も気づかない。
作ったら作りっぱなしになりやすい。 プロジェクト終了後もサービスアカウントが削除されず、気づいたら「誰が何のために作ったか分からない」アカウントが大量に残っているケースは現場で頻繁に起きています。
MFAが適用できない。 人のアカウントに対してMFAで認証を強化できても、自動処理には適用できません。MFA記事で触れた通り、これがサービスアカウント固有のリスクになります。詳しくは「MFAとは?多要素認証の仕組みと実務での導入・運用ガイド」を参照してください。
Azureにおけるサービスアカウントの種類と使い分け
サービスプリンシパル——アプリケーションのID
サービスプリンシパルはAzure AD(Entra ID)に登録したアプリケーションのIDです。CI/CDパイプライン・外部ツール・サードパーティアプリケーションなど、Azureの管理外から接続する場合に使います。
認証方式はクライアントシークレットまたは証明書の2択です。クライアントシークレットはパスワードに近い概念で、漏洩リスクと有効期限の管理が必要になります。証明書の方がセキュリティ強度が高く、期限管理も自動化できるため推奨されます。
参考:アプリケーションとサービス プリンシパル オブジェクト | Microsoft Learn
マネージドID——Azureが管理する自動認証
マネージドIDはAzureリソース(VM・Functions・Container Appsなど)に割り当てるIDで、シークレットや証明書を一切管理せずにAzureリソース間の認証を実現できます。
システム割り当てマネージドID 特定のAzureリソースに紐づいたID。そのリソースが削除されると自動的に削除される。
ユーザー割り当てマネージドID 複数のAzureリソースで共有できる独立したID。リソースのライフサイクルに依存しない。
サービスプリンシパルとマネージドIDはどちらを使うべきか
判断の型はシンプルです。
Azureリソースから別のAzureリソースにアクセスする場合→マネージドIDを使う。 VMからKey Vaultにアクセス、FunctionsからStorageにアクセス、といったケースはすべてマネージドIDで対応できます。シークレット管理が不要になるため、これが使える場面では必ずマネージドIDを選んでください。
Azure外部のツールやアプリからアクセスする場合→サービスプリンシパルを使う。 GitHubActionsからAzureにデプロイする、Terraformでリソースを管理するなど、Azure外部からのアクセスはサービスプリンシパルが必要です。この場合も証明書認証またはフェデレーション認証(OIDC)を使い、クライアントシークレットへの依存を極力減らします。
参考:マネージドIDを使用するタイミング | Microsoft Learn

サービスアカウントの権限設計 3つの原則
原則① 権限はRBACで必要なスコープに絞る
サービスアカウントに付与する権限は、「そのサービスが動くために最低限必要なロール」だけに限定します。
RBACのスコープ(権限の適用範囲)は管理グループ→サブスクリプション→リソースグループ→リソースの順に狭くなります。可能な限り最小のスコープで付与することが原則です。
| ❌ NG例 | ✅ OK例 |
|---|---|
| Contributor をサブスクリプション全体に付与 | Storage Blob Data Reader を対象ストレージアカウントのみに付与 |
| Owner をリソースグループに付与 | 必要な操作のみを許可するカスタムロールをリソース単位に付与 |
RBACの設計パターンについては「RBACとは?クラウド権限管理の基本とAzure RBACの仕組みをわかりやすく解説」で詳しく解説しています。
参考:Azure のロールの割り当てのベストプラクティス | Microsoft Learn
原則② 認証はマネージドID・証明書を使いシークレットに頼らない
クライアントシークレットはコードやCI/CDの環境変数に直接書かれやすく、Gitリポジトリへの誤コミットやログへの出力など、漏洩経路が多い認証方式です。
マネージドIDが使える場面では必ずマネージドIDを選ぶ。 サービスプリンシパルが必要な場面では、クライアントシークレットの代わりに証明書またはフェデレーション認証(OIDC)を使う。これだけでシークレット漏洩リスクをほぼゼロにできます。
シークレットをどうしても使う場合は、Azure Key Vaultに格納してアプリケーションから直接参照する構成にします。コードにシークレットをハードコーディングすることは絶対に避けてください。
Azure Key Vault パスワード・証明書・シークレットをセキュアに管理するAzureのサービス。アプリからは参照のみを行い、直接シークレットを持たせない設計が可能。
参考:Azure Key Vault の概要 | Microsoft Learn
原則③ 用途ごとに1アカウント・使い回しは禁止
1つのサービスアカウントを複数のアプリケーションやパイプラインで共有している状態は、次の問題を生みます。
どのアプリが何の操作をしたかが監査ログで判別できなくなります。また1つが侵害されると、共有しているすべてのシステムに影響が及びます。さらにアプリを廃止するときに「このアカウントを消して他のアプリが壊れないか」という判断が難しくなり、結果として使われていないアカウントが放置されます。
用途ごとに専用のサービスアカウントを作成し、付与する権限もそれぞれ最小限に留めることが原則です。
実務でよくある失敗パターン
① OwnerやContributorをサブスクリプション全体に付与している
「動けばいい」という発想で設定されたContributorのサブスクリプション全体付与は、実質的にそのサービスアカウントが侵害されたときに全リソースへの攻撃起点になります。「最初に広く付けて後で絞る」は現実にはほぼ行われません。最初から必要最小限で始めることを習慣にしてください。
② 複数システムで同じサービスプリンシパルを使い回している
開発チーム内で「共用のデプロイ用アカウント」として1つのサービスプリンシパルを複数のCI/CDパイプラインで使い回しているケースは非常に多いです。そのアカウントのシークレットが漏洩した場合、関連するすべてのパイプラインのアクセス権が攻撃者に渡ります。パイプラインごとに専用のサービスプリンシパルを用意し、侵害の影響範囲を限定してください。
③ クライアントシークレットをコードにハードコーディングしている
GitHubのパブリックリポジトリにシークレットを含むコードを誤ってpushしてしまうインシデントは今も頻繁に発生しています。シークレットはコードに書かない、環境変数も慎重に管理する、というルールを徹底する必要があります。既存のリポジトリに埋め込まれていないかの確認にはgit-secretsやAzureのシークレットスキャン機能が有効です。
ハードコーディング シークレットやパスワードなどの機密情報をソースコード内に直接記述すること。Gitリポジトリへの誤コミットによる漏洩リスクが高い。
④ 棚卸しがなく不要なサービスプリンシパルが残り続ける
プロジェクト終了・システム廃止後もサービスプリンシパルが削除されずに残っているケースは非常に多く、「誰が何のために作ったか分からないアカウント」が増え続けます。有効なシークレットや証明書を持ったまま放置されたサービスプリンシパルは、攻撃者に悪用される可能性があります。
定期的な棚卸しと、不要になったサービスアカウントの即時削除を仕組みとして組み込むことが重要です。IDのライフサイクル管理全体については「IDライフサイクル管理とは?入社・異動・退職で権限を正しく管理する方法」で解説しています。
参考:Azure のサービスアカウントの管理 | Microsoft Learn
サービスアカウント設計チェックリスト
設計面
- サービスアカウントは用途ごとに専用のものを作成しているか
- 付与しているロールは最小限か(Owner・Contributorを全体付与していないか)
- スコープはリソース単位・リソースグループ単位に絞られているか
- マネージドIDが使える箇所はマネージドIDを採用しているか
- サービスプリンシパルの認証は証明書またはOIDCを使っているか
運用面
- クライアントシークレットをコードにハードコーディングしていないか
- シークレットはKey Vaultに格納して参照する構成になっているか
- 不要になったサービスアカウントを即時削除するフローがあるか
- 定期的な棚卸し(誰が何のために使っているかの確認)が行われているか
- サービスアカウントの操作ログをレビューする運用があるか
設計全体の抜け漏れ確認は「クラウドIAM設計チェックリスト|抜け漏れを防ぐ実践ガイド」も合わせてご活用ください。
まとめ——サービスアカウントは「攻撃者の足場」になりうる
サービスアカウントは誰も日常的に使わないからこそ、権限設計の甘さが長期間放置されます。人のアカウントに対してはMFAや定期レビューを実施していても、サービスアカウントが野放しになっていれば、そこが侵害の起点になります。
まず今日確認すべきことは2つです。自分の環境でサービスアカウントに必要以上に広い権限が付いていないか。そして不要なサービスアカウントが放置されていないか。この2点を確認するだけで、リスクの大部分を把握できます。
特権アカウントの管理を含むIAM全体のアクセス管理については「PIMとは?Azure特権アクセス管理の実務ガイド」も合わせてご覧ください。
あわせてご覧ください


コメント