社内システムとクラウドのサービスのログインの記録から普段と違うログインを拾い、確認すべき順に並べて本人への確認の文面を作る
社内システムとクラウドのサービスのログインの記録から、その社員の普段と違う時間・場所・端末・方式のログインを拾います。確認すべき順に並べ、本人に「このログインはご本人ですか」と確かめる文面の下書きを作ります。
- 生成AI
- ChatGPT/Claude/Gemini
- 連携・自動化
- Python
- 対象業界
- IT・SaaS/その他/人材/商社/金融
- 対象部門
- 情報システム/総務
- 対象業務
- 内容確認・チェック/分類・仕分け
- 主な課題
- 人手が足りない/期限・対応漏れが起きる/確認ミスが多い
- AIで行う処理
- 判定
- 主な効果
- 入力漏れ削減/対応スピード向上/工数削減
- 導入難易度
- ★★★★☆
- 実装レベル
- 本格構成
- 費用感
- RAG・個別開発(大)
- 人間の確認
- 条件付き
01導入前 / 導入後の業務フロー
- 警告の一覧を毎朝開き、前日分の警告を確かめる
- 警告ごとにサインインの記録を開き、時刻、場所、端末、アプリ、成功か失敗かを見る
- その社員の過去のサインインを検索し、普段の場所や端末と比べる
- 出張の予定や在宅勤務の申請を、勤怠や予定表で確かめる
- 判断がつかないものは、本人にチャットで「このログインはご本人ですか」と聞く
- 返事を待ち、本人でなければパスワードの変更とセッションの取り消しを行う
- 確かめた結果を表計算の記録に書く
- 自動1時間ごとに、Microsoft Graph API で直近のサインインの記録を取り、社内システムの認証の記録とあわせて取り込む
- 自動社員ごとに、過去60日の普段の型(時間帯、国と都市、端末、アプリ、認証の方式)を更新する
- 自動新しいサインインごとに、普段の型からの外れを特徴量にする
- 自動決めた規則で「必ず確かめる」ものに印を付ける(古い認証方式での成功、あり得ない移動など)
- 自動IsolationForest で、規則に当たらない外れの組み合わせに点数を付ける
- 自動規則と点数から、確認すべき順に並べ、外れの理由を添える
- 自動上位のものについて、Claude API が本人への確認の文面の下書きを作る
- 人情報システムの担当が上から理由を読み、本人に確認するか、そのまま閉じるかを決める
- 人確認の文面を直して社内のチャットで送り、返事を記録する
- 人本人でないと分かったものは、手順に沿ってパスワードの変更とセッションの取り消しを行う
- 自動返事と担当の判断を記録し、普段の型と点数の見直しに使う
各工程の詳しい説明を読む
- 警告の一覧を毎朝開き、前日分の警告を確かめる
- 警告ごとにサインインの記録を開き、時刻、場所、端末、アプリ、成功か失敗かを見る
- その社員の過去のサインインを検索し、普段の場所や端末と比べる
- 出張の予定や在宅勤務の申請を、勤怠や予定表で確かめる
- 判断がつかないものは、本人にチャットで「このログインはご本人ですか」と聞く
- 返事を待ち、本人でなければパスワードの変更とセッションの取り消しを行う
- 確かめた結果を表計算の記録に書く
(a)警告が多すぎて、見る順番が決まらない。 条件に当たったものはすべて同じ重さで並びます。出張中の社員の海外からのログインと、普段使わない古い認証方式での失敗の連続が、同じ一覧に同じ形で並びます。 担当は上から順に見るしかなく、本当に急ぐものが後回しになることがあります。
(b)その人の普段を調べるのに時間がかかる。 3番目で過去のサインインを検索し、普段の場所と端末を頭の中でまとめます。6分のうち、ここがいちばん重いところです。 担当によって、何日分さかのぼるかも違います。
(c)確認の連絡が遅れる。 本人に聞く文面を毎回その場で書き、返事が来なければ翌日に持ち越します。本人でなかった場合、聞くまでの時間がそのまま、他人がアカウントを使える時間になります。
(d)見ずに流した警告の中身が分からない。 「いつもの人」として流した警告が本当にいつもどおりだったかは、誰も確かめていません。流す判断そのものが担当の記憶に依存しています。
- 【自動】 1時間ごとに、Microsoft Graph API で直近のサインインの記録を取り、社内システムの認証の記録とあわせて取り込む
- 【自動】 社員ごとに、過去60日の普段の型(時間帯、国と都市、端末、アプリ、認証の方式)を更新する
- 【自動】 新しいサインインごとに、普段の型からの外れを特徴量にする
- 【自動】 決めた規則で「必ず確かめる」ものに印を付ける(古い認証方式での成功、あり得ない移動など)
- 【自動】 IsolationForest で、規則に当たらない外れの組み合わせに点数を付ける
- 【自動】 規則と点数から、確認すべき順に並べ、外れの理由を添える
- 【自動】 上位のものについて、Claude API が本人への確認の文面の下書きを作る
- 【人】 情報システムの担当が上から理由を読み、本人に確認するか、そのまま閉じるかを決める
- 【人】 確認の文面を直して社内のチャットで送り、返事を記録する
- 【人】 本人でないと分かったものは、手順に沿ってパスワードの変更とセッションの取り消しを行う
- 【自動】 返事と担当の判断を記録し、普段の型と点数の見直しに使う
8番目が、この設計の分かれ目です。人が見るのは全件ではありません。 点数が低く、外れの理由が出張の予定で説明できるものは一覧で流し見て閉じ、上位のものだけを開きます。 全件を開く設計にすると、90.0時間はほとんど減りません。
10番目を人の手に残しているのも、意図してのことです。 判定が誤っていたときに自動でアカウントを止めると、出張先で仕事ができなくなった社員からの問い合わせが、担当の時間を食います。 止める判断は人が行い、その手順は決めておきます。
02今回想定するシステム構成
Microsoft Entra ID のサインインの記録 社内の業務システムの認証の記録 │ GET /auditLogs/signIns │ CSVの書き出し ▼【トリガー】1時間ごとの定時実行 Python(pandas で取り込み・時刻の変換・社員ごとの普段の型) │ 時間帯/国と都市/端末/アプリ/認証の方式/失敗の回数 ▼ 規則 ── 必ず確かめるものの印(古い認証方式・あり得ない移動 など) ▼ Python(scikit-learn の IsolationForest) │ 外れの組み合わせの点数 ▼ 確認の順番と外れの理由 ── 出張・在宅の予定との突き合わせ │ ├──▶ Claude API ── 本人への確認の文面の下書き ▼ 【人が理由を読み、確認するか閉じるかを決める】 ▼ 本人の返事と担当の判断の記録 ── 普段の型と点数の見直し
| 役割 | 想定する製品 | 代替候補 |
|---|---|---|
| 実行環境 | Python(pandas・scikit-learn の IsolationForest) | Microsoft Sentinel の分析ルール |
| 連携 | Microsoft Graph API(サインインの記録の取得) | 管理画面からの書き出し |
| 生成AI | Claude API(本人への確認の文面の下書き) | OpenAI API、Gemini API |
| 通知 | 情報システム部のチャット、本人への社内チャット | メール |
| 保存 | 社内のデータベース | ログの保管の仕組み |
Microsoft Entra ID の設定には書き込みません。 この構成は記録を読むだけで、パスワードの変更やセッションの取り消しは、担当が手順に沿って行います。読み取りに要る権限は AuditLog.Read.All で、書き込みの権限をこの仕組みには与えません。
サインインの記録を API で取るには、Microsoft Entra ID P1 か P2 のライセンスが要ります。 ドキュメントでは、Microsoft Graph API でサインインの記録を取り出すにはこのどちらかが必要とされています。さらに、riskLevelDuringSignIn などの危険度の項目は P2 の場合だけ中身が入り、それ以外は hidden が返るとされています。この構成は、危険度の項目が hidden でも動くように作ります。P2 があれば、その値を規則の1つとして足します。
点数付けに IsolationForest を選ぶ理由は、「何が不正か」の答えが無くても使えることです。 ドキュメントでは、特徴量と分割の値をランダムに選んで観測を切り分けていくと、外れた観測ほど短い分割の回数で切り分けられるとされています。過去に不正なログインの記録がほとんど無い会社でも、普段からの外れの度合いは測れます。
03どうやって実装するのか
処理の起点を決める
1時間ごとの定時実行を起点にします。 毎朝まとめて見る形では、夜のあいだに起きたログインに気づくのが翌朝になります。1時間ごとに取り込み、「必ず確かめる」の印が付いたものだけは、その場で担当に通知します。 それ以外は、一覧にたまったものを担当が決まった時間に見ます。
取り込みは、時間の範囲を指定して行います。 ドキュメントでは、要求が時間切れにならないよう、$filter で時間の範囲を指定して取ることが勧められています。前回取り込んだ最後の時刻から現在までを範囲にし、重複は記録の id で除きます。
入力データを集める
| データ | 中身 | 取得元 |
|---|---|---|
| サインインの記録 | 時刻(UTC)、利用者、アプリ、IPアドレス、国と都市、端末(OS・ブラウザ・管理の有無)、クライアント、成功か失敗か | Microsoft Graph API |
| 社内システムの認証の記録 | 時刻、利用者、接続元、成功か失敗か | 業務システムの書き出し |
| 社員の情報 | 所属、勤務の形(夜勤の有無)、在籍の状態 | 人事の一覧 |
| 出張と在宅の予定 | 出張の行き先と期間、在宅勤務の申請 | 勤怠と出張の申請 |
| 自社の接続元 | 拠点とVPNの出口のIPアドレスの範囲 | 情報システム部の一覧 |
質を決めるのは、いちばん下の2つです。 出張の予定が無ければ、出張中の海外からのログインがすべて上位に来ます。VPNの出口のIPアドレスが一覧に無ければ、VPNにつないだ社員の場所が、出口のある都市として記録され、普段と違う場所に見えます。
3行目の在籍の状態も外せません。 退職した社員のアカウントでのログインは、普段の型と比べるまでもなく「必ず確かめる」ものです。
データの取得方法を決める
Microsoft Graph の GET /auditLogs/signIns を、アプリの権限 AuditLog.Read.All で呼びます。
| 取るもの | どこから | 何に使うか |
|---|---|---|
| サインインの記録 | GET /auditLogs/signIns(createdDateTime で範囲を指定) | 普段の型と、新しいサインインの判定 |
| 次のページ | 応答の @odata.nextLink | 1ページに収まらない分の取得 |
| 社内システムの記録 | 1時間ごとの書き出し | 同じ形にそろえて判定 |
| 出張と在宅の予定 | 勤怠と出張の申請の書き出し | 外れの理由の説明 |
1回の応答の上限は1,000件です。 ドキュメントでは、ページの大きさの既定と上限が1,000件で、新しい順に返るとされています。残りは @odata.nextLink をたどって取ります。 たどり忘れると、ログインの多い時間帯だけ取りこぼします。
記録は自分の側に貯めます。 ドキュメントでは、取り出せるのは Microsoft Entra ID の既定の保持期間の中のものだけとされています。普段の型に使う60日分は、取り込んだものを社内のデータベースに残して作ります。
v1.0 の一覧で取れるのは、対話型のサインインと、成功したフェデレーションのサインインです。 アプリが裏で行う非対話型のサインインは、この構成の対象から外します。サービス用のアカウントは別の一覧で管理し、普段の型を作りません。
AIへ渡す前に整形する
- 時刻の変換 …
createdDateTimeは UTC です。日本時間に直してから時間帯を数えます - 自社の接続元の印 … 拠点とVPNの出口のIPアドレスの範囲に当たるものに「社内」の印を付けます
- 端末の識別 …
deviceDetailの端末IDがあればそれを、無ければOSとブラウザの組み合わせを端末とみなします - 認証の方式 …
clientAppUsedがIMAP、POP、SMTPなどの古い方式かどうかの印を付けます - 普段の型 … 社員ごとに、過去60日の時間帯の分布、国と都市、端末、アプリの一覧を作ります
- 外れの特徴量 … 新しいサインインについて、その時間帯の過去の割合、初めての国か、初めての都市か、初めての端末か、管理外の端末か、直前のサインインの場所からの移動の速さ、直近1時間の失敗の回数を出します
- 予定との突き合わせ … 出張の行き先と期間、在宅勤務の申請に合うかの印を付けます
1番目を省くと、時間帯の判定がすべて9時間ずれます。 日本時間の朝9時のログインが、UTC では0時のログインに見えるからです。深夜の警告が急に増えたら、まずここを疑ってください。
6番目の移動の速さは、場所の精度に気をつけます。 携帯電話の回線やVPNでは、記録される都市が実際の場所と離れることがあります。同じ国の中の都市の違いだけで「あり得ない移動」とせず、国が変わった場合に限ります。
AIに処理させる
この構成の判定は、規則と点数の2段で行います。 規則は「これは必ず人が見る」ものを拾い、IsolationForest は規則に当たらない外れの組み合わせを拾います。生成AIは、判定も順番も決めません。
| 部品 | させること | させないこと |
|---|---|---|
| 規則(Python) | 古い認証方式での成功、あり得ない移動、退職者のアカウント、P2 の危険度が high のものに印 | 印の付いたものを閉じる |
| IsolationForest | 外れの特徴量の組み合わせに点数を付ける | 不正かどうかの結論 |
| 並べ替え(Python) | 印を先に、次に点数の低い順に並べ、外れの理由を添える | 出張の予定で説明できる理由の削除 |
| Claude API | 外れの理由から、本人への確認の文面を作る | 判定、順番、アカウントの扱いの判断 |
IsolationForest の点数は score_samples で取ります。 ドキュメントでは、値が低いほど異常とされています。この点数を全社の分布の中での順位に直して、上位から並べます。 点数の絶対値は学び直しのたびに動くため、順位で扱うほうが運用が安定します。
contamination には頼りません。 既定の 'auto' のまま学習し、predict の正常・異常の2分は使いません。何件を人が見るかは、点数ではなく担当の手の空き具合で決めます。 1日に見られる件数を先に決め、その件数で切ります。
国や端末のような区分の値は、数に直してから渡します。 ドキュメントには区分の値をそのまま扱う記述が無いため、「初めての国か」「その国の過去の割合」のように、その社員の普段との比較を数にしたものを特徴量にします。国の名前そのものは渡しません。
| 生成AIにさせないこと | 理由 |
|---|---|
| 「不正なログインです」と書く | 判定は人が行う。本人を疑う文面は関係を損なう |
| リンクやパスワードの入力を求める | 確認の連絡がフィッシングと見分けられなくなる |
| IPアドレスの全桁や端末IDを書く | 本人が判断するのに要らない |
| 外れの理由に無いことを書く | 担当が根拠を確かめられない |
指示内容を固定する
規則と点数の部分は次のとおりです。
from sklearn.ensemble import IsolationForest
FEATURES = ["hour_rarity", "new_country", "new_city", "new_device",
"unmanaged_device", "travel_kmh", "fail_count_1h", "new_app"]
# 過去60日の全社員のサインインで学習(社員ごとの普段との比較を数にしたもの)
iso = IsolationForest(n_estimators=200, random_state=0).fit(hist[FEATURES])
new["score"] = iso.score_samples(new[FEATURES]) # 低いほど普段から外れている
new["rank"] = new["score"].rank(method="first") # 低い順に1,2,3…
rules = (
(new["legacy_auth"] & new["success"]) | # 古い認証方式での成功
((new["travel_kmh"] > 900) & new["country_changed"]) | # 国をまたぐあり得ない移動
new["user_left"] | # 退職者のアカウント
(new["risk_during_signin"] == "high") # P2 がある場合のみ値が入る
)
new["must_review"] = rules
travel_kmh のしきい値は、旅客機の速さを目安に置いた値です。 国が変わったうえで、直前のサインインの場所からその速さを超えて移動したことになる場合に印を付けます。国内の都市の違いには使いません。
本人への確認の文面は、Claude API に次の指示で作らせます。
あなたは会社の情報システム部で、社員に自分のログインかどうかを確かめる連絡を書く立場です。
渡された情報だけを使って、社内チャットで送る短い文面を作ってください。
【渡す情報】
- ログインの日時(日本時間)
- ログインしたサービスの名前
- おおよその場所(国と都市)
- 端末の種類(OS とブラウザ)
- 普段と違う点(外れの理由の一覧)
【書き方】
- 1行目に、情報システム部からの確認の連絡であることを書いてください。
- 次に、日時・サービス・場所・端末を箇条書きで書いてください。
- 「このログインはご本人によるものですか」と聞き、
「はい」か「いいえ」で返事をもらうようお願いしてください。
- 心当たりが無い場合は、このチャットに返事をするだけでよいことを書いてください。
- 全体を200字以内にしてください。
【厳守事項】
- 「不正」「攻撃」「乗っ取り」など、本人を疑う言葉を使わないでください。
- リンクを書かないでください。パスワードや認証コードの入力を求めないでください。
- IPアドレスの全桁、端末ID を書かないでください。
- 普段と違う点の一覧に無いことを書かないでください。
- 点数や順位を書かないでください。
- 渡された情報が足りない場合は、文面を作らず missing に足りない項目を書いてください。
【ログインの情報】{signin}
【普段と違う点】{reasons}
「リンクを書かない」「パスワードを求めない」がいちばん大事な2つです。 確認の連絡が、ふだん社員に注意を呼びかけているフィッシングのメールと同じ形をしていると、本物の確認の連絡と偽物の区別を社員に求めることになります。 返事は、社内チャットに「はい」か「いいえ」と書くだけにします。
出力形式を固定する
次の形のJSONを、サインインごとに作ります。 score から reasons までは Python が埋め、message_draft を Claude API の構造化出力(output_config.format に type: "json_schema")で受け取ります。
{
"signin_id": "66ea54eb-....",
"user": "[email protected]",
"jst_time": "2026-10-06T02:14",
"app": "Office 365 Exchange Online",
"country": "SG",
"city": "Singapore",
"device": "Windows / Edge",
"managed": false,
"client": "Browser",
"success": true,
"must_review": false,
"score": -0.61,
"rank": 3,
"reasons": ["初めての国", "初めての端末", "普段ログインしない時間帯"],
"travel_plan_match": false,
"message_draft": { "text": "", "missing": [] },
"review": { "action": null, "by": "", "at": "" },
"user_reply": null
}
1つ目の理由は、reasons を判定の結果と同じ行に置けることです。 担当は理由を読むだけで、記録を開き直さずに判断できます。文面も reasons から作るので、担当が読んだ理由と本人に伝える内容が一致します。
2つ目は、travel_plan_match を別の項目にすることです。 出張の予定に合うからといって、点数や理由を消しません。予定に合っていても、初めての端末で古い認証方式なら見るべきものです。 消すかどうかは担当が決めます。
3つ目は、review と user_reply です。 担当がどう扱い、本人が何と答えたかが残るので、後から「閉じたものの中に本人でないものが無かったか」を確かめられます。
システムへ連携する
| つなぎ先 | 方式 | 内容 |
|---|---|---|
| Microsoft Graph API | API呼び出し(AuditLog.Read.All、読み取りのみ) | サインインの記録 |
| 社内の業務システム | 認証の記録の書き出し(読み取り) | 社内システムのログイン |
| 人事の一覧・勤怠と出張の申請 | 表の読み取り | 在籍、勤務の形、出張と在宅の予定 |
| Claude API | API呼び出し | 本人への確認の文面の下書き |
| 情報システム部のチャット | 通知 | 「必ず確かめる」の即時の通知、確認の一覧 |
| 本人への社内チャット | 担当が送信 | 確認の文面 |
本人への送信は担当が行います。 下書きを自動で送ると、点数の誤りで多くの社員に確認が届き、確認の連絡そのものが読まれなくなります。
生成AIに渡すのは、上位のものの日時・サービス・場所・端末の種類と理由だけです。 氏名やメールアドレス、IPアドレスは渡しません。宛先は送る段階で担当のチャットの側で決まります。
人が確認する
- 「必ず確かめる」の印から見る … 通知が来たら、その場で理由を読みます。古い認証方式での成功と退職者のアカウントは、本人の返事を待たずに対応を始めることがあります
- 上位から理由を読む … 出張の予定や在宅の申請で説明できるかを見ます
- 確認するか閉じるかを決める … 確認するものは下書きを直して送ります。閉じるときは理由を一言書きます
- 返事を記録する … 「はい」なら閉じ、「いいえ」か返事が無いものは手順に沿って対応します
3番目で閉じる理由を書くことを省かないでください。 同じ理由で閉じたものが続くなら、その理由は普段の型か規則に入れるべきものです。
目標は、900件をならして1件2分です。 下位のものは一覧で流し見て閉じ、上位と印の付いたものに時間を使います。
例外に対処する
| 起きること | 対応 |
|---|---|
| Graph API が応答しない、権限の誤り | その回は判定せず担当に知らせる。前回の結果を使い回さない |
@odata.nextLink の途中で止まる | 取れた範囲を記録し、次の回で続きから取る |
危険度の項目が hidden | 規則の1つを外して判定を続ける |
| 新しく入社した社員 | 普段の型が無い。点数を参考値にし、最初の2週間は規則だけで見る |
| 場所が取れない記録 | 場所の特徴量を欠けた値として扱い、理由に「場所不明」と書く |
| 本人から返事が無い | 決めた時間を過ぎたら、上長経由で確かめる |
| 本人が「いいえ」と答えた | 手順に沿って担当が対応する。判定の記録を消さない |
| 文面の下書きにリンクや疑う言葉が入る | 下書きを捨て、定型文で送る |
4行目の新しく入社した社員は、点数が当てにならない典型です。 過去の記録が無いため、何をしても「初めて」になります。この期間に点数で警告を出すと、新しい社員に確認の連絡が集中します。
記録を残す
- 取り込んだサインインの記録と、取り込んだ時刻の範囲
- 社員ごとの普段の型の更新の記録
- サインインごとの特徴量、規則の印、点数、順位、理由、そのときのモデルの版と規則の版
- 担当の判断(確認したか、閉じたか、閉じた理由)と、本人の返事
- 本人でなかったものへの対応の記録(いつ、誰が、何をしたか)
- 閉じたものからの抜き取りの確認 … 月に1回、閉じたものの一部を見直した結果
最後の行が、この構成を守る記録です。 閉じたものの中に本人でないものが混じっていないかを確かめないと、流す判断が正しいかどうかは誰にも分かりません。 現状の(d)と同じ状態に戻ります。
04実装レベルの3段階
半自動化で、1件6分が4分程度になります。 普段の型を調べる時間は減りますが、どれから見るかの判断と文面を書く作業が残ります。本格構成で2分になり、この段階が本記事の想定です。 差が大きいのは、理由付きで順番が決まり、文面の下書きまでそろうからです。 段階を飛ばさないでください。 半自動化の外れの理由を1か月見ると、VPNの出口や出張の予定のように、理由の側で直すべきものが先に見えます。 そこを直してから点数を入れるほうが、上位に並ぶものの質が上がります。
05工数削減シミュレーション
導入後 900件 × 2分 ÷ 60 = 30 時間/月
自社条件で導入効果を整理したい方へ
このユースケースを自社に当てはめた場合の前提値と削減見込みを、業務ヒアリングをもとに整理します。
06向いている企業・向いていない企業
- 従業員が数百名以上で、Microsoft Entra ID を入口にして Microsoft 365 や複数のクラウドのサービスにサインインしている会社。サインインの警告が月に数百件出て、情報システムの担当が1件ずつ記録を開いて本人かどうかを確かめている場合。出張や在宅勤務が多く、場所だけで判断すると警告が多すぎる場合。Microsoft Entra ID P1 以上のライセンスがあり、サインインの記録を API で取り出せる場合。
- 従業員が数十名で、担当がほぼ全員の働き方を把握している場合。サインインの記録を API で取り出せず、管理画面で見るしかない場合。すでにセキュリティ運用の専門の部署や外部の監視サービスが、同じ記録を見て本人確認まで行っている場合。なお、アカウントを止めるか、不正なアクセスとして扱うかの判断は、この構成では代替できません。
07最小構成で試す方法
- 過去1か月のサインインの記録を管理画面から書き出す(担当が本人に確認した警告を必ず含める)
- 30名分について、過去の記録から普段の時間帯・国・端末を表計算でまとめる
- 1か月の警告のうち、その30名のものに「初めての国」「初めての端末」「普段と違う時間帯」の印を手で付ける
- 印の数で並べ、担当が実際に本人に確認した警告がどこに来るかを見る
- 印が付かなかったのに確認が要った警告があれば、その理由を書き出す
30名分は必ずやってください。 仕組みを組む前に、「その人の普段と比べれば、確認が要るものが上に来るのか」を確かめます。
| 出てきた内容 | 判断 |
|---|---|
| 確認が要った警告が上位に集まる | API での取り込みと点数付けに進む |
| 上位に出張中の社員が多い | 出張の予定との突き合わせで直る。構成は有効 |
| 場所が実際と違う記録が多い | VPNの出口の一覧が先。 AIの問題ではない |
3行目が出ることは珍しくありません。 VPNにつないだ社員の場所は、出口のある都市として記録されます。自社の接続元の一覧を作るだけで、警告の数が大きく減ることがあります。
08実装時につまずきやすいポイント
| 問題 | 対策 |
|---|---|
| 深夜の警告が急に増えた | createdDateTime は UTC。日本時間に直してから時間帯を数える |
| ログインの多い時間帯だけ取りこぼす | 1ページの上限は1,000件。@odata.nextLink をたどる |
| 要求が時間切れになる | $filter で時間の範囲を指定して取る |
危険度の項目がすべて hidden | P2 が無い場合の仕様。無くても動く設計にする |
| VPNの社員が普段と違う場所に見える | 自社の接続元の一覧を作り「社内」の印を付ける |
| 出張中の社員が上位を占める | 出張の予定と突き合わせ、理由に添える |
| 国内の都市の違いで「あり得ない移動」になる | 移動の判定は国が変わった場合に限る |
| 新しく入社した社員に確認が集中する | 最初の2週間は規則だけで見る |
| 確認の連絡がフィッシングに似る | リンクとパスワードの入力を求めない。返事はチャットに書くだけ |
| 判定で自動的にアカウントを止めたくなる | 止めない。 対応は担当が手順に沿って行う |
| 閉じたものの中身を誰も見ない | 月に1回、閉じたものを抜き取って見直す |
上の3行が、取り込みの失敗のほとんどです。 どれも記録は取れているように見えるので、警告の数や時間帯の偏りで初めて気づきます。 取り込んだ件数を管理画面の件数と毎日比べると、早く気づけます。
09セキュリティ・AIガバナンス上の注意点
この構成で扱うデータ: 社員のサインインの記録(時刻、場所、IPアドレス、端末)、出張と在宅の予定、そして社員ごとの普段の行動の型です。
- 普段の型を監視の目的に使わない … 型はログインが本人かどうかを確かめるためのもので、勤務の時間や働きぶりの評価には使いません。 使う目的と見られる担当の範囲を、社内の規程に書いて社員に知らせます
- 読み取りの権限だけを与える … この仕組みに与えるのは
AuditLog.Read.Allで、アカウントの変更の権限は与えません。 仕組みの認証情報が漏れても、アカウントを止めたり変えたりできないようにします - 生成AIに個人を特定する情報を渡さない … 渡すのは日時、サービス、国と都市、端末の種類、理由だけです。氏名、メールアドレス、IPアドレスは渡しません
- 確認の連絡の形を社内に知らせておく … 情報システム部からの確認は「社内チャットで、リンクなしで、はい・いいえを聞く」形だと周知します。この形から外れた連絡は偽物だと社員が判断できます
- 対応の判断は人が行う … 本人でないと分かったときの対応は、担当が手順に沿って行います。判定の誤りでアカウントを止めると、業務が止まります
- 記録の保存期間を決める … 普段の型に使う60日分と、判断の記録の保存期間を決め、過ぎたものは消します
誤りが起きた場合のリスクは、本人でないログインを「いつもの人」として閉じることと、本人のログインを疑って業務を止めることの2つです。 前者は閉じたものの抜き取りの確認で、後者は人が判断する設計と、疑う言葉を使わない文面で守ります。
10まず何から始めるか
1週目:ライセンスと接続元の一覧を確かめる
Microsoft Entra ID のライセンスが P1 以上か、P2 があるかを確かめます。あわせて、拠点とVPNの出口のIPアドレスの範囲を一覧にします。 この一覧が、警告の数をいちばん大きく減らします。
2週目:30名分で試す
過去1か月の記録を書き出し、30名分の普段の型を表計算で作って、担当が実際に確認した警告が上に来るかを見ます。
3週目:規則と確認の手順を決める
「必ず確かめる」の規則と、本人でなかったときの対応の手順を、情報システム部で決めます。 確認の連絡の形(社内チャット、リンクなし、はい・いいえ)も決め、社員に周知します。
4週目:Graph API で取り込む
アプリの権限 AuditLog.Read.All で、1時間ごとにサインインの記録を取り込み、社員ごとの普段の型と外れの理由を出すところまで作ります。この時点では点数を付けず、理由の一覧だけを見ます。
2か月目: 規則の印と IsolationForest の点数を足し、確認の順番を出します。出張の予定との突き合わせを入れます。3か月目以降: 確認の文面の下書きを足し、1件6分が何分になったかを実測します。閉じたものの抜き取りの確認で、本人でないものが混じっていないことを確かめられた時点で、この構成は完成です。
11関連ユースケース
12この仕組みを理解するための記事
13技術仕様の確認日・参考情報
| 確認した内容 | 情報源 | 確認日 |
|---|---|---|
GET /auditLogs/signIns でテナントのサインインを取り出せること。対話型のサインインと成功したフェデレーションのサインインが含まれること。ページの大きさの既定と上限が1,000件で、新しい順に返ること。既定の保持期間の中のものだけが取れること。最小の権限が AuditLog.Read.All であること。時間切れを避けるため $filter で時間の範囲を指定することが勧められていること。応答に @odata.nextLink が付くこと | Microsoft Learn: List signIns | 2026-10-06 |
Graph API でサインインの記録を取り出すには Microsoft Entra ID P1 か P2 のライセンスが必要なこと。createdDateTime が UTC であること。clientAppUsed で IMAP、POP、SMTP などの古い認証方式が分かること。location に都市・州・国、deviceDetail に端末ID・OS・ブラウザが入ること。riskLevelDuringSignIn などの危険度の項目は P2 の場合だけ中身が入り、それ以外は hidden が返ること | Microsoft Learn: signIn resource type | 2026-10-06 |
IsolationForest が特徴量と分割の値をランダムに選んで観測を切り分け、外れた観測ほど短い分割の回数で切り分けられること。score_samples の値が低いほど異常であること。contamination の既定が 'auto'、n_estimators の既定が100であること | scikit-learn: IsolationForest | 2026-10-06 |
構造化出力で output_config.format に type: "json_schema" を指定して応答をJSONスキーマに沿わせられること | Claude Docs: Structured outputs | 2026-10-06 |
本人でないログインへの対応の手順と、社員の記録を扱う範囲は、情報システム部と社内の規程で決めてください。 本記事は製品の公開ドキュメントで確認できた範囲だけを扱っています。社内の業務システムの認証の記録の形式は個別に確かめる必要があり、本記事では扱っていません。
実装ステータス:構成例。 公開仕様に基づいて設計した構成であり、当社で実際に構築・検証したものではありません。工数の数値はモデル条件による試算です。
自社の業務に使えるAI活用候補を整理します
このユースケース(UC-0581)についてのご相談はこちらから。
