コンテンツにスキップ

Reference

認証方式

どの環境変数が設定されているかで2つのモードを切り替える。

モード 条件 環境変数
app-only 3つとも設定 ENTRAADM_TENANT_ID、ENTRAADM_CLIENT_ID、ENTRAADM_CLIENT_SECRET
azure-cli 3つとも未設定 現在の az login セッションを使う

app-only 用3変数のうち1つか2つだけの設定は、起動時に設定エラーとなる (黙って別モードへフォールバックしない)。

任意: ENTRAADM_MAX_PAGES_DEFAULT(1-50、既定 50)は、ツール呼び出しで max_pages を明示しなかった場合のログ走査系ツールのページ上限既定値。

任意: ENTRAADM_DEADLINE(秒、既定 45、0 で無効)は、1 回のツール呼び出しの 持ち時間。ホスト型の MCP クライアントは約 60 秒で呼び出しを打ち切るので,走査は この時間で止まり,1 回の要求のタイムアウトも残り時間で切り,それまでに取れた分を capped=true で返す。daily_brief は 2 つの節で 1 つの持ち時間を共有する。 directory_audits は category(例: UserManagement)で Graph 側の絞り込みもできる。

必要な Graph 権限

ツール 権限
get_user(基本フィールド) User.Read.All
signin_logs、signin_failure_stats、signin_success_stats、signin_by_ip、directory_audits、get_user の sign_in_activity フィールド AuditLog.Read.All(app-only)または Reports Reader ディレクトリロール(delegated)
get_user_auth_methods UserAuthenticationMethod.Read.All(app-only 専用)

ツール

health_check()

引数なし。{service, version, status, auth_mode, graph, signin_probe} を返す。 graph は基本的な Graph 到達性(GET /users、$top=1 — User.Read.All のみで通る)を、signin_probe は サインインログ読み取り可否を追加でプローブする。status は両方成功で "healthy"、Graph到達可だがサインインログ読み取り不可で "degraded"、 Graph自体に到達不可または認証設定不備で "error"。graph/signin_probe は それぞれ {auth: "ok"|"error", detail: str|null}。

get_user(upn)

アカウントのライフサイクル状態:accountEnabled、userType、作成日時・ 最終パスワード変更日時、オンプレ同期状態、解決済みライセンス名、 (AuditLog.Read.All/Reports Reader が利用可能なら)sign_in_activity。 存在しないアカウントはエラーではなく {"found": false, "user_principal_name": upn} を返す。 licenses_capped: true は、このアカウント自身のライセンスを解決する前に SKU カタログの 走査が打ち切られた場合にのみ現れる——このキーがある場合、licenses の一部は 解決済みの名前ではなく生の skuId のまま。

signin_logs(user, hours=24, result="failure", top=25, max_pages=None)

このユーザのサインインイベント。result: "failure"(既定、最頻用途)/ "success"/"all" — Graph はサインインを status/errorCode でサーバ側 フィルタできないため、クライアント側でフィルタする。各イベントの error_code には、手作業で保守している AADSTS コード表から error_code_meaning(例:50126 →「invalid credentials(パスワード相違)」)が 注釈される。hours は 1-720(30日 — Entra ID P1 のサインインログ保持期間)に クランプ。capped=true はページ予算が尽きた(または top に到達した)ことで 窓全体を走査しきれなかったことを意味する——一致件数が少なく capped=true の 場合は「予算内で見つからなかった」のであって「存在しない」ではない。

signin_failure_stats(hours=24, max_pages=None)

テナント全体の失敗集計:AADSTS エラーコード(注釈付き)・失敗ユーザ・アプリ・ 送信元IPの上位。spray_suspects は、5人以上の異なるユーザに対して失敗している IP を列挙する——Entra のアカウント単位スマートロックアウトだけでは捉えられない パターン。hours の扱いは上記と同様。

signin_success_stats(hours=24, max_pages=None, min_distinct_users=2)

テナント全体の成功したサインインを送信元IPで集計する——signin_failure_stats の対:あちらは誰が攻撃されているかを、こちらは誰かが入られたかを示す。 shared_ips は min_distinct_users 人以上の異なるアカウントで成功している IP を 共有数の多い順に列挙する(IP は 50 件まで、超えたら shared_ips_capped。IP ごとに アカウント名 25 件まで・クライアントアプリ・国・初回/最終時刻)。 legacy_auth_users はレガシー認証(Authenticated SMTP・IMAP4・POP3 など、 MFA の掛からないプロトコル)で成功したアカウントを列挙する。学内 NAT や VDI も 多数のアカウントを 1 つの IP に載せるので、自組織の出口レンジを除いてから shared_ips を読むこと。ログ走査と capped の扱いは signin_failure_stats と同じで、 対話型サインインだけを見る(レガシー認証はすべて対話型として記録されるので漏れない。 非対話型のトークン更新は数えない)。

signin_by_ip(ip, hours=24, result="all", top=50, max_pages=None)

1 つの送信元IPからの全サインイン——spray_suspects や shared_ips に出た IP の 追跡用。Graph は ipAddress でサーバ側フィルタできるので、ログ走査でなく 1 回の 軽い問い合わせで済む。users はその IP をアカウント別に要約する(成功・失敗・ 初回/最終時刻、50 件まで)。events は result("all" / "success" / "failure")に 合う最新 top 件で、各行にアカウント名と signin_logs と同じ AADSTS の注釈が付く。 events_truncated は top より多くの該当行を読んだ印(users はそれも数えている)。 ip は IPv4/IPv6 アドレスとして解釈できる文字列に限る。

directory_audits(user=None, hours=24, top=25, max_pages=None)

ディレクトリ監査証跡:誰が何を(ブロック/解除・属性編集)、いつ行ったか。 user を指定すると、そのアカウントが実行者またはターゲットのいずれかである 監査を対象にする——Graph は実行者側のみサーバ側フィルタに対応しているため、 窓全体を取得してクライアント側で両方を照合する(混雑した窓では特定の人物の 監査を見つけるために max_pages を大きくする必要がある場合がある)。

get_user_auth_methods(upn)

このアカウントの登録済み認証方式。mfa_registered は、パスワード以外の方式 (Authenticator アプリ・電話・FIDO2 セキュリティキー・Windows Hello・ 一時アクセスパス・ソフトウェア OATH・プラットフォーム資格情報/パスキー)が 1つ以上登録されていれば true。UserAuthenticationMethod.Read.All(app-only)が 必要——典型的なロール割り当てでは az login 経由の delegated 認証では利用不可。 存在しないアカウントは get_user と同様 {"found": false, "user_principal_name": upn} を返す。

daily_brief(hours=24, max_pages=None, samples=10)

signin_failure_stats と directory_audits を、コンパクトな summary を添えて 1回でまとめる。片方のセクションの権限エラーはそのセクションだけを劣化させ、 もう片方は全体が返る。両セクションを1回のツール呼び出し内で同期実行する。 samples は現状未使用(予約)。

エラー

全ツールの入口は設定エラーと Graph クライアントのエラーを捕まえて {"error": "..."} を返し、例外を投げない——呼び出し側は常に dict を受け取れる。 GraphPermissionError の場合はさらに missing_permission が、そのエンドポイントに 実際に必要な Graph 権限またはディレクトリロールの名前を持つ。ページングを伴う Graph コレクションから組み立てた結果は必ず capped: bool を持つ——ページ予算の 打ち切りが「窓を完全に走査した」と見分けがつかなくなることはない。

CLI

entraadm-mcp --version   # バージョンを表示
entraadm-mcp --check     # 認証を解決し、Graph・サインインログ到達性をプローブ。exit 0(設定エラー時は 1)