ページの先頭です

ページ内を移動するためのリンク
本文へ (c)

ここから本文です。

非人間アイデンティティ

非人間アイデンティティ(Non-Human Identity:NHI)とは何か?
どう管理すべきか?整理してみました。

ライター:渥美 淳一
セキュリティアーキテクトとして活動。「ID で守り、ID を守る」がセキュリティの本質であり、未来への入口だと考えている。

目次

非人間アイデンティティとは?

私たち人間は、組織のシステムにアクセスするとき、組織の一員であることを証明するデジタルアイデンティティ(ログイン情報)を使います。

組織には人間じゃないモノ、たとえば「アプリ」「スクリプト」「AI エージェント」「サービスアカウント」もいます。これらも実は、組織のシステムにアクセスするときにデジタルアイデンティティ(非人間アイデンティティ)を使います。

組織は非人間アイデンティティを人間と同じように管理できているのでしょうか?

アプリ

たとえばスマホの銀行アプリは、口座の残高や入出金履歴を表示するために銀行システムの窓口にアクセスして情報をもらいます。この窓口を API(アプリケーション・プログラミング・インターフェース)といいます。アプリは API にアクセスし、必要な情報をもらい、画面に表示します。

このとき、API にアクセスすれば誰でも私の口座情報を表示できたら困ります。そこで銀行アプリが私の口座情報を表示するには、まず「私であることを証明する何か」が必要です。これが人間アイデンティティ、つまりログインです。

しかし実際に API にアクセスして情報をもらうのは、私ではなくアプリです。アプリが API にアクセスするには、「正しいアプリであることを証明する何か」が必要です。これが非人間アイデンティティ、たとえば以下です。

私であることを証明する何かが必要
例)パスワード、多要素認証

アプリ

正しいアプリであることを証明する何かが必要
例)API キー、アクセストークン

API キー

これはパスワードのようなものです。アプリは API にアクセスするとき、API キーをいっしょに送ることで「このアプリは正しいです」と API 側に伝えることができます。そのため API キーがアプリの中にあらかじめ埋め込まれていることがあります。たとえば次のようにコードの中に書かれていて、API にアクセスするたびに自動で送られるようになっています。

API_KEY = "AIzaSyD4x9vK8J7xZQ3eT9aLwX9gPq2bXxYzA1Bc"

ここで注意が必要です。API キーはパスワードのようなものなので、もし誰かに知られてしまうと勝手に API にアクセスされてしまう可能性があります。特に、アプリのコードをインターネット上に公開してしまった場合、API キーもいっしょに漏れてしまうことがあります。API キーは機密情報です。コードの中に直接書かず、たとえば次のように環境変数を使って安全に管理する方法が推奨されます。

import os
API_KEY = os.getenv("NETONE_API_KEY")

もし漏れても被害を最小限にするため、API キーは定期的に変更(ローテーション)し、古いキーは忘れずに無効化します。また特定の IP アドレスのみ API キーの使用を許可し、アクセスできる回数を制限し、「できること」(スコープ)を限定します。

アクセストークン

漏えいしやすい API キーだけで「このアプリは安全」と判断するのは危険です。そこで、より安全な方法として使われるようになったのがアクセストークンです。

アクセストークンの形式は決まっていません。
よく利用されるのは JSON Web Token 形式(ヘッダー.ペイロード.署名)です。

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2F1dGguZXhhbXBsZS5jb20vIiwic3ViIjoiYXBpLXVzZXIxMjMiLCJhdWQiOiJodHRwczovL2FwaS5leGFtcGxlLmNvbS8iLCJleHAiOjE2MDAwMDAwMDAsImlhdCI6MTYwMDAwMDAwMCwic2NvcGUiOiJyZWFkIHdyaXRlIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

アクセストークンも機密情報ですが、時間がたつと無効になりますので、もし漏えいしても無期限で使われ続ける心配はありません。

アクセストークンは、認可サーバーからもらいます。認可サーバーは、認可窓口(認可エンドポイント)とトークン窓口(トークンエンドポイント)を提供します。

このとき、スマホの銀行アプリのように私の個人情報にアクセスする場合は、私の同意が必要です。まず私が、認可窓口にログインし、同意して認可コードをもらいます。

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7(私が同意したらもらえる認可コード例)

次にアプリは「もらった認可コード」「正しいアプリであることを証明する何か」をトークン窓口に送信し、クライアント認証してもらいます。成功すればアクセストークンをもらえます。

grant_type=authorization_code(認可コードフローでよろしく)※後述
&code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7
&client_id=正しいアプリであることを証明するID
&client_secret=正しいアプリであることを証明するパスワード

アプリは API にアクセスするとき、HTTP ヘッダーに「Authorization: Bearer もらったアクセストークン」を入れて送ります。Bearer(ベアラー)とは「持っている人なら誰でもアクセスできる」という意味です。

Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3M(以下略)

これにより、正しい人間とアプリだけがアクセストークンをもらって API にアクセスできます。このしくみを OAuth 2.0 の「認可コードフロー」といいます。

OAuth 2.0 とは?

  • アクセストークンをもらうためのしくみ

  • アクセストークンをもらう方法は主に 2 つ
    • 人間が同意する「認可コードフロー」(authorization_code)
    • 人間の同意不要「クライアント資格情報フロー」(client_credentials)

  • HTTPS 通信が必須(アクセストークンの盗聴を防ぐため)

  • スマホアプリにも対応(OAuth 1.0 は Web アプリ向け)

スクリプト

人間が関与しない処理、たとえばバックグラウンドで動作するスクリプト(バッチ処理)も API を利用します。この場合は OAuth 2.0 の「クライアント資格情報フロー」でアクセストークンをもらいます。

人間が関与しない(人間の同意がいらない)ため、スクリプトは認可窓口にはアクセスしません。トークン窓口にアクセスし、クライアント認証だけでアクセストークンをもらい、API にアクセスします。そのため正しいスクリプトであることの証明がよりいっそう重要になります。

その証明に client_secret(パスワードのようなもの)が使われてきましたが、漏えいリスクが高いため推奨されません。代わりに、証明書を使ったクライアント認証が推奨されます。具体的には、スクリプトは client_secret ではなく client_assertion(要求トークン)を送ってクライアント認証してもらい、アクセストークンをもらいます。

grant_type=client_credentials(クライアント資格情報フローでよろしく)
&client_id=正しいスクリプトであることを証明するID
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=要求トークン

証明書を使ったクライアント認証とは?

  1. 認可サーバーに証明書(公開鍵)をあらかじめ登録

  2. スクリプトはそのペアとなる秘密鍵で署名した要求トークンを送信

  3. 認可サーバーは証明書(公開鍵)を使ってその署名を検証

  4. 要求トークンの検証に成功すればアクセストークンをもらえる

要求トークンのつくりかた

スクリプトは、まず JSON Web Token 形式のヘッダーとペイロードをつくります。

ヘッダー例

{
"alg": "RS256", (中身をSHA-256でハッシュ化してRSA秘密鍵で署名しました)
"typ": "JWT" (トークンはJSON Web Token形式です)
}

ペイロード例

{
  "aud": "https://api.example.com/oauth2/v2.0/token",   (トークン窓口)
  "iss": "your-client-id",      (正しいスクリプトであることを証明するID)
  "sub": "your-client-id",      (正しいスクリプトであることを証明するID)
  "jti": "unique-id-987654321", (盗まれて再利用されるのを防ぐためのID)
  "exp": 1732100000,            (有効期限)
  "iat": 1732099700             (発行時刻)
}

ヘッダーとペイロードをそれぞれ Base64URL エンコードした値を「.」でつなぎます。

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJodHRwczovL2FwaS5leGFtcGxlLmNvbS9vYXV0aDIvdjIuMC90b2tlbiIsImlzcyI6InlvdXItY2xpZW50LWlkIiwic3ViIjoieW91ci1jbGllbnQtaWQiLCJqdGkiOiJ1bmlxdWUtaWQtOTg3NjU0MzIxIiwiZXhwIjoxNzMyMTAwMDAwLCJpYXQiOjE3MzIwOTk3MDB9

これを秘密鍵で署名し Base64URL エンコードした値を、最後につけて完成です。

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJodHRwczovL2FwaS5leGFtcGxlLmNvbS9vYXV0aDIvdjIuMC90b2tlbiIsImlzcyI6InlvdXItY2xpZW50LWlkIiwic3ViIjoieW91ci1jbGllbnQtaWQiLCJqdGkiOiJ1bmlxdWUtaWQtOTg3NjU0MzIxIiwiZXhwIjoxNzMyMTAwMDAwLCJpYXQiOjE3MzIwOTk3MDB9.秘密鍵で署名しBase64URLエンコードした値

秘密鍵で署名できるスクリプトだけがアクセストークンをもらえますので、より安全に「このスクリプトは本物です」を証明できます。これが信頼できる非人間アイデンティティであり、スクリプトが安心して API とつながるための大事な一歩です。

AI エージェント

ホテルや交通手段の予約。会議のスケジュール調整。非人間の AI エージェントが従来の「チャットで答える」に加え、私たち人間のために自らいろいろやってくれます。

自らいろいろやるためには API などとつながる必要がありますが、すべてとつながる AI エージェントをつくるのは簡単ではありません。

そこで登場したのが Model Context Protocol(以下 MCP)です。AI エージェントは MCP サーバーに「この API とつないで」とお願いするだけで OK。MCP サーバーが API などの違いを吸収してくれるので、AI エージェントは難しいことを気にせず、いろいろやれるようになります。

AI エージェントは、MCP サーバーにまず「何ができるの?」と聞きます。

GET /tools HTTP/1.1
Host: mcp.example.com

この MCP サーバーは API にアクセスしてホテル予約できますが、API は OAuth で保護されているためアクセストークンが必要です。MCP サーバーは「先にアクセストークンをもらってきて」と認可サーバーの URL を伝えます。

AI エージェントはその認可サーバーの URL にアクセスします。スクリプトと同じようにアクセストークンをもらい、再度 MCP サーバーに「何ができるの?」と聞きます。

GET /tools HTTP/1.1
Host: mcp.example.com
Authorization: Bearer アクセストークン

MCP サーバーはできることを JSON 形式で応答します。

HTTP/1.1 200 OK
{ "tools": [ { "name": "hotel_booking", "description": "ホテル予約できるよ" } ] }

AI エージェントは MCP サーバーにホテル予約(hotel_booking)を「お願い」します。このときホテル予約に必要な情報を JSON 形式で送ります。

POST /tools/hotel_booking HTTP/1.1
Host: mcp.example.com
Authorization: Bearer アクセストークン
Content-Type: application/json
{ "type": "mcp-call", "tool": "hotel_booking", "args": { "checkin": "2025-12-01", "checkout": "2025-12-05", "guests": 2 } }

MCP サーバーは API にアクセスし、お願いされた通りにホテル予約します。

POST /hotel_booking HTTP/1.1
Host: api.example.com Authorization: Bearer アクセストークン Content-Type: application/json
{ "checkin": "2025-12-01", "checkout": "2025-12-05", "guests": 2 }

API は MCP サーバーにホテル予約が確定したことを応答します。

HTTP/1.1 201 Created
Content-Type: application/json
{ "status": "confirmed" }

MCP サーバーは AI エージェントにその結果を JSON 形式で送ります。

HTTP/1.1 200 OK
Content-Type: application/json
{ "result": { "status": "confirmed" } }

AI エージェントもアプリスクリプトと同じように、API を安全に利用するためには OAuth が不可欠です。

サービスアカウント

サービスアカウントは、システムが自ら動くときに必要な非人間アイデンティティです。たとえばシステムが「Windows Update やウイルススキャンを実行するとき」「Web サーバーやデータベースサーバーへのリクエストを処理するとき」に必要です。人間がログインして使うものではありません。

特に Active Directory のサービスアカウントは強い権限を持ち、パスワードが変更されないケースが多いため、攻撃対象になりやすく注意が必要です。

Active Directory のサービスアカウント例

Active Directory は従業員を Kerberos プロトコルで認証します。このとき「KRBTGT」というサービスアカウントが Kerberos チケットを発行します。従業員はそれを使って社内 Web やファイルサーバーにログイン(シングルサインオン)できます。

この KRBTGT は Active Directory を構成するタイミングで自動的につくられますが、そのパスワードは変更せず使われ続けることが多いです。攻撃者はこのパスワードのハッシュを狙い、時間をかけてでも盗もうとします。パスワードのハッシュがわかれば管理者の Kerberos チケットを偽造(ゴールデンチケット攻撃)でき、管理者としてドメイン全体を操作できるようになるため、攻撃メリットが大きいです。

攻撃方法

1. 盗んだ認証情報で VPN に接続し、組織のネットワークに侵入
2. nltest コマンドなどで Active Directory を特定して攻撃(下表)
3. 管理者権限でサーバーなどを操作

管理者ログイン

盗んだパスワードなどで Administrator ユーザーでのログインを試みる

Pass-the-Hash 攻撃

Mimikatz などのツールを使って LSASS プロセス(※)から盗んだハッシュでログイン

Pass-the-Ticket 攻撃

Mimikatz などのツールを使って LSASS プロセス(※)から盗んだ Kerberos チケットでログイン

Kerberoasting 攻撃

サービスの Kerberos チケットを取得し、含まれるサービスアカウントのパスワードを解析して悪用

ゴールデンチケット攻撃

KRBTGT のパスワードハッシュを盗み、管理者の Kerberos チケットを偽造してドメイン全体を操作

(※)LSASS プロセス ・・・ 認証情報をメモリで管理するプロセス

どう管理すべきか?

非人間アイデンティティの例を紹介しました。
では、これらを管理するために知っておくべきことは何でしょうか?

アプリ

クライアント認証情報は安全に保持する

クライアント認証で使う client_secret は、セキュアなストレージを使って安全に保持することが推奨されます。たとえば Azure Key Vault や AWS Secrets Manager などに暗号化した状態で保持し、アプリはその URL にアクセスして取得します。このとき誰がアクセスできるかを厳密に管理します。また client_secret を定期的に自動更新できるため、長期間同じ値を使うリスクを減らせます。こうすることで、ソースコードや公開リポジトリにクライアント認証情報が含まれるリスクを減らせます。

認可コードを盗む攻撃に備える

OAuth 2.0 の認可コードフローには認可コードを盗む攻撃があるため、OAuth 2.0 の拡張機能「PKCE」(Proof Key for Code Exchange)を実装します。これにより攻撃者は、認可コードを盗んだだけではアクセストークンをもらえません。

PKCE を実装すると?

  1. アプリはランダム文字列を作ってランダム文字列のハッシュ値を算出
  2. アプリはランダム文字列のハッシュ値も入れて認可コードを要求
  3. 認可窓口は認可コードを応答
  4. アプリはランダム文字列も入れてアクセストークンを要求
  5. トークン窓口は 4. のハッシュ値が 2. ならアクセストークンを応答

※ランダム文字列を「code_verifier」といいます
※ランダム文字列のハッシュ値を「code_challenge」といいます

アクセストークンの安全性を高める

アクセストークンはメモリで保持し、ログやエラーメッセージに出力しないようにします。アクセストークンの有効期限は短く設定し、必要なアクセス権のみを与えます。たとえば「読み取り専用」「特定の API 専用」など、できること(スコープ)を細かく設定します。認可サーバーは、アプリが要求してきたスコープが許可されているものかを確認してから、アクセストークンを発行します。

リフレッシュトークンを検討する

アクセストークンの有効期限が切れたとき、新しいアクセストークンをもらうために人間が再ログインしなければなりません。つまりアクセストークンの有効期限を短く設定するほど、人間の再ログイン回数が増えます。それを改善するのがリフレッシュトークンです。アプリはアクセストークンとリフレッシュトークンをいっしょにもらいます。アクセストークンの有効期限が切れたとき、リフレッシュトークンを送れば新しいアクセストークンをもらえるため、人間の再ログインは不要になります。

リフレッシュトークンは長期間有効であることが多いため、盗まれると大きなリスクになります。リフレッシュトークンにも有効期限を設定し、必要に応じて失効させます。OAuth 2.0 の「Refresh Token Rotation」により、アクセストークンを発行するたびにリフレッシュトークンも更新し、古いリフレッシュトークンを失効させます。

スクリプト

安全なクライアント認証を使う

前述の通り、パスワードのような client_secret よりも、証明書を使ったクライアント認証が推奨されます。有効な秘密鍵で要求トークンに署名できるスクリプトだけがアクセストークンをもらえますので、その秘密鍵の安全な保護が重要です。秘密鍵をスクリプトに直接書くのは危険です。代わりに、OS の証明書ストア(Windows や Linux にある安全な保管場所)や HSM(ハードウェアセキュリティモジュール:秘密鍵を取り出せない専用装置)を使い、署名操作だけを許可します。こうすることで、秘密鍵が外部に漏れるリスクを減らせます。また、秘密鍵と証明書の有効期限を管理し、定期的に更新(ローテーション)することも重要です。クラウド環境であれば、Azure Key Vault を使えば秘密鍵の管理やローテーションを自動化できます。

アクセストークンの安全性を高める

アプリと同様です。

リフレッシュトークンは不要

リフレッシュトークンは人間の再ログインなしにアクセストークンをもらうためのものです。スクリプトは人間が関与しませんので、リフレッシュトークンは不要です。

AI エージェント

認可サーバーが AI エージェント情報をあらかじめチェックする

正しい AI エージェントだけが組織のデータにアクセスできる必要があります。その方法として、AI エージェントの情報や証明書をまとめた URL(OAuth Client ID Metadata Document)を用意し、その URL を要求トークンに入れて、認可サーバーに送ります。認可サーバーはその URL にアクセスし、正しい AI エージェントであることをあらかじめチェックしたうえで、アクセストークンを発行します。

AI エージェントを「見える化」する

自らいろいろやる AI エージェントですが、正しい行動ばかりとは限りません。正しい行動だけを許可し、いざというときに追跡できる必要があります。そのために AI エージェントにも ID を与えて管理します。

たとえば Microsoft Entra Agent ID は、組織の AI エージェントを「ID で見える化」します。AI エージェントの行動をログから ID で追跡し、不適切な行動であれば ID を無効化してアクセス権をはく奪します。危険な AI エージェントがあれば Entra ID 保護 で自動的に発見し、条件付きアクセス機能でブロックします。

AI エージェントに必要なアクセス権だけ与える

AI エージェントにできることが増えるほど、必要なアクセス権も増えます。AI エージェントのアクセス権は必要なときだけ与え、いつでもはく奪できるのが理想です。AI エージェントがアクセスできるデータは、業務に必要な範囲に限定します。

サービスアカウント

強い権限を持ち、パスワードを変更しないサービスアカウントは、攻撃者にとって理想的な侵入口です。管理を誤ると組織全体が危険にさらされます。以下の方法で安全に管理しましょう。

サービスアカウントを「見える化」する

どのサービスがどのサービスアカウントを使っているかを把握します。サービスアカウントとその用途、権限を一覧にし、責任者を明らかにします。

サービスアカウントに必要な権限のみ与える

たとえば Active Directory のサービスアカウントに、ドメイン管理者やエンタープライズ管理者の権限は与えません。サービスアカウントにはサービスを動かすのに必要な権限のみ与えます。

サービスアカウントのパスワードを無期限にしない

サービスアカウントのパスワードは定期的に変更し、人間が管理しないのが理想です。たとえば Active Directory の場合、グループ管理サービスアカウント(gMSA)をつくって Windows サービス、IIS(Web サーバー)、SQL Server などを動かすサービスアカウントに設定すると、そのパスワードは Active Directory が自動生成・定期変更してくれるため、セキュリティが向上し、運用性も改善します。

サービスアカウントでのログインを拒否する

たとえば Active Directory の場合、グループポリシー(ユーザー権限の割り当て設定)により、サービスアカウントの「ローカルログオンを拒否」「リモート デスクトップ サービスを使ったログオンを拒否」します。

サービスアカウントでのログインを監視する

監視しやすい人間のログインと違い、サービスアカウントのログインは「システム動作」と見なされるため、異常検知が遅れやすい(攻撃者は長期間潜伏しやすい)です。サービスアカウントのログインを監視し、普段使わない端末や時間帯でのログインを見つけます。人間と区別するために、サービスアカウントの名前に svc_ をつけるなどしてログを見つけやすくします。

不要なサービスアカウントは削除する

サービスを廃止するときにサービスアカウントも削除します。サービスアカウントの責任者が異動や退職したときは、かならず棚卸しを実施します。

最後に

人間アイデンティティ、非人間アイデンティティに関わらず、「何が組織のシステムにアクセスしているのか」を知ることが重要です。そして乗っ取られた場合を想定して「これは必要?」「権限が多すぎない?」と常に疑問をもつようにします。使われていないもの、多すぎる権限は削除します。システム管理者やサービスアカウントの普段のログインを把握し、不審なログインを見つけられるようにします。権限は一時的に与え、自動で削除されるしくみが理想です。

非人間アイデンティティは、組織を支える ”もう一人の従業員” です。
人間と同じで、リスクに気づかないまま働き続けることもあります。

「信頼しすぎず、適切にチェックする」

これがゼロトラストの基本であり、最も効果的なセキュリティ対策です。

※本記事の内容は執筆者個人の見解であり、所属する組織の見解を代表するものではありません。

RECOMMEND