記事公開日
【Microsoft Entra】API 駆動型プロビジョニングを試してみた!独自ソースからの自動ユーザー同期を実現

この記事のポイント
- API 駆動型プロビジョニングの概要: 従来の「既製コネクタ」に頼らず、あらゆるシステムから Entra ID への自動同期が可能になる機能を解説。
- SCIM ベースの柔軟な連携: HTTP リクエスト(JSON)を送るだけで、ユーザーの作成・更新・無効化を制御できる仕組み。
- 検証結果: 実際に API を叩いて、新規作成から無効化までの動作を確認。
はじめに
こんにちは、DXソリューション営業部のID管理担当です。
Entra ID のユーザーやグループ等の作成において、
「人事システムやID管理ツールでユーザーを作成し、まずオンプレミスADへ反映。その後、Microsoft Entra Connect(旧称 Azure AD Connect)でクラウドへ同期する」
といった構成で運用されている企業も多いかと思います。
オンプレミスADへのユーザー作成は、ID管理製品であったり、スクラッチのシステムで既に人事システム等と連携し、自動化されているケースも多いかと思います。
このフローは実績もあり確実ですが、クラウドネイティブなアプリやSaaS利用が増えた現代では、「クラウドのIDを作りたいだけなのに、なぜオンプレADを経由しなければならないのか?」という運用コストやタイムラグの問題が浮き彫りになるケースもあります。
今回ご紹介する「API 駆動型プロビジョニング」は、この「オンプレAD → Entra Connect」という中間層をバイパスし、外部システムから Entra ID へダイレクトに情報を届けるための強力な解決策の一つです。
API 駆動型プロビジョニングとは
API 駆動型プロビジョニングは、人事システムや独自のデータソースから Entra ID およびオンプレミス Active Directory (AD) へユーザー情報を自動連携するための仕組みです。
主な特徴とメリット
-
ハイブリッド対応の柔軟性: クラウド上の Entra ID への同期はもちろん、ドメインコントローラーにインストールしたエージェントと連携し、オンプレミス AD ユーザーの作成・更新も一元管理できます。
-
SCIM 標準による標準化: Microsoft Graph API の
/bulkUploadエンドポイントを介し、標準化された JSON フォーマットでデータを送信します。 -
更新の自動判定: 自前で「差分チェック」や「作成/更新の条件分岐」をコードに書く必要はありません。最新の情報を JSON形式データとして送るだけで、Entra 側のプロビジョニングエンジンがターゲット(クラウド または オンプレミス)に対して最適な処理(新規追加/変更/無効化)を自動実行します。
事前準備
実施にあたって、以下の設定が必要となります。
1. 有効なライセンスの用意
API 駆動型プロビジョニング機能を実行するには、Microsoft Entra ID P1 または P2 のライセンスが必要です。
2. アプリの作成
「エンタープライズ アプリケーション」の「API-driven provisioning to Microsoft Entra ID」からアプリを作成します。

3. プロビジョニングの構成
「プロビジョニング」を構成します。「作成」ボタンをクリックするだけで、既定の構成が用意されます。

4. アクセス許可
API クライアントが、プロビジョニングのAPI(/bulkUpload)を実行できるようにするため、アプリを登録し、アクセス許可を付与します。

付与する権限(Microsoft Graph API)
| 権限の種類 | アクセス許可名 | 説明 |
|---|---|---|
| アプリケーション許可 | SynchronizationData-User.Upload |
ユーザーデータを Entra ID へアップロードするために必須の権限。 |
AuditLog.Read.All |
プロビジョニングログの読み取りに使用。 |
【実践】プロビジョニングを試す
それでは、実際に API エンドポイントにリクエストを送り、Entra ID 上の挙動を確認してみます。
APIエンドポイントは、作成したエンタープライズアプリの概要ページに記載されています。
Content-Typeは、[application/scim+json] とし、トークンを設定して、bulkUpload APIを呼び出します。
トークンは、アクセス許可したAPIクライアントから取得します。
※ここでは APIを直接呼び出していますが、Microsoft の公式ドキュメントには、PowerShellスクリプトによるサンプルや Logic Apps のサンプルもあります。
1. 新規作成(Create)
新規登録データとして、以下の 2ユーザーの情報を送信します。ユーザーを一意に識別するコードは、externalId です。
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkRequest"],
"Operations": [
{
"method": "POST",
"path": "/Users",
"bulkId": "714f2abb-f9c1-4ca0-9a30-0110c13136cb",
"data": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
],
"externalId": "qes-001",
"userName": "user.ichiro@<your domain>",
"name": {
"familyName": "ユーザー",
"givenName": "一郎"
},
"displayName": "ユーザー 一郎",
"emails": [
{
"value": "user.ichiro@<your domain>",
"type": "work",
"primary": true
}
],
"active": true,
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
"employeeNumber": "9191",
"department": "営業部"
}
}
},
{
"method": "POST",
"path": "/Users",
"bulkId": "714f2abb-f9c1-4ca0-9a30-0110c13136cb",
"data": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
],
"externalId": "qes-002",
"userName": "user.jiro@<your domain>",
"name": {
"familyName": "ユーザー",
"givenName": "次郎"
},
"displayName": "ユーザー 次郎",
"emails": [
{
"value": "user.jiro@<your domain>",
"type": "work",
"primary": true
}
],
"active": true,
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
"employeeNumber": "9899",
"department": "営業部"
}
}
}
]
}
リクエスト送信後、少し待つと Entra ID 上に新しいユーザーが作成されました!
プロビジョニングの結果は、プロビジョニングログで確認できます。アクションが [Create] となっており、新規作成されたことがわかります。
※プロビジョニングログに反映されるまでは、時間がかかるようで、体感的に 5~10分程度かかっていそうです。
日付部分のリンクをクリックすると、詳細ログが確認できます。
2. 属性変更(Update)
続けて、ユーザー情報の変更を試してみます。
今回は、ユーザーの表示名を変更します。新規登録時に 2ユーザー登録しましたが、そのうち 1ユーザーを更新対象とします。API 駆動型プロビジョニングは「差分」を自動で判断するため、変更対象ユーザーの最新情報を送信するだけで、変更のあった箇所だけが更新されます。もちろん、変更がないユーザーをそのまま送信しても構いません。その場合は、変更なしと扱われますので、無視されます。
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkRequest"],
"Operations": [
{
"method": "POST",
"path": "/Users",
"bulkId": "714f2abb-f9c1-4ca0-9a30-0110c13136cb",
"data": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
],
"externalId": "qes-001",
"userName": "user.ichiro@<your domain>",
"name": {
"familyName": "ユーザー",
"givenName": "一郎"
},
"displayName": "ユーザー 一郎(変更)",
"emails": [
{
"value": "user.ichiro@<your domain>",
"type": "work",
"primary": true
}
],
"active": true,
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
"employeeNumber": "9191",
"department": "営業部"
}
}
}
]
}
対象ユーザーの表示名が変更されました。
プロビジョニングログで、アクションが [Update] となっており、更新されたことがわかります。プロビジョニングログの詳細では、変更されたプロパティも確認できます。
3. ユーザー無効化(Disable)
(1)明示的な無効化
退職、休職など明示的に無効化する場合は、"active": false を送ります。先ほどのユーザーとは別のユーザーの情報を無効化として送信します。
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkRequest"],
"Operations": [
{
"method": "POST",
"path": "/Users",
"bulkId": "714f2abb-f9c1-4ca0-9a30-0110c13136cb",
"data": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
],
"externalId": "qes-002",
"userName": "user.jiro@<your domain>",
"name": {
"familyName": "ユーザー",
"givenName": "次郎"
},
"displayName": "ユーザー 次郎",
"emails": [
{
"value": "user.jiro@<your domain>",
"type": "work",
"primary": true
}
],
"active": false,
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
"employeeNumber": "9899",
"department": "営業部"
}
}
}
]
}
リクエスト送信後、対象ユーザーが無効化されました。
プロビジョニングログで、アクションが [Update] となっており、アカウントの状態が無効(accountEnabled が True ➡ False)に更新されたことがわかります。
(2)スコープ外による無効化
あらかじめスコープを定義しておき、そこから外れた場合に無効化することができます。
例えば、「営業部」に所属しているユーザーのみ、プロビジョニングする設定の場合、所属が変更された場合に無効化できます。
スコープの設定は、属性マッピングの「ソース オブジェクト スコープ」を設定します。
ここでは、アクティブユーザーの所属を「営業部」から「業務部」に変更してみます。
{
"schemas": ["urn:ietf:params:scim:api:messages:2.0:BulkRequest"],
"Operations": [
{
"method": "POST",
"path": "/Users",
"bulkId": "714f2abb-f9c1-4ca0-9a30-0110c13136cb",
"data": {
"schemas": [
"urn:ietf:params:scim:schemas:core:2.0:User",
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"
],
"externalId": "qes-001",
"userName": "user.ichiro@<your domain>",
"name": {
"familyName": "ユーザー",
"givenName": "一郎"
},
"displayName": "ユーザー 一郎(変更)",
"emails": [
{
"value": "user.ichiro@<your domain>",
"type": "work",
"primary": true
}
],
"active": true,
"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": {
"employeeNumber": "9191",
"department": "業務部"
}
}
}
]
}
リクエスト送信後、こちらも対象ユーザーが無効化されました。
スコープ外の無効化では、プロビジョニングログのアクションが [Disable] で記録されていました。
こちらもアカウントの状態が無効(accountEnabled が True ➡ False)に更新されたことがわかります。
運用上の注意点
API 駆動型プロビジョニングを安定して運用するためには、API の呼び出し制限(スロットリング)とライセンスに基づくクォータ制限を考慮する必要があります。制限を超えると、サービスは HTTP 429 (Too Many Requests) 応答を返します。
1. API エンドポイントの調整制限(スロットリング)
/bulkUpload エンドポイントには、短時間の負荷を抑えるための制限が設けられています。
- 制限事項: 任意の 5 秒間に 40 回までの API 呼び出しに制限されます。
- 対策: このしきい値を超えないよう、クライアント側にペーシング ロジックを実装してください。送信間に遅延を入れたり、レート制限処理を追加してリクエストを分散させる必要があります。
2. テナント レベルの制限(24時間クォータ)
1 日(24 時間)あたりに実行できる API 呼び出しの総数は、保有している Entra ID のライセンスプランによって異なります。
| ライセンス | 24時間あたりのAPI呼び出し上限 |
|---|---|
| Microsoft Entra ID P1 / P2 | 2,000 回 |
| Microsoft Entra ID ガバナンス | 6,000 回 |
3. パフォーマンス最適化のポイント
上記のクォータ制限内で効率的にプロビジョニングを行うために、「API 呼び出し 1 回あたりの操作数」を意識することが重要です。
bulkUpload API は、1回のリクエスト(ペイロード)に最大 50 個の操作を含めることができます。1 ユーザーごとに 1 API 呼び出しを行うのではなく、可能な限り 50 ユーザー分を 1 つのバッチにまとめて送信することで、呼び出し回数を節約し、制限内での運用を最適化できます。
まとめ
API 駆動型プロビジョニングは、Entra ID にユーザー情報やグループ情報を同期するための重要な選択肢の一つとなりそうです。ライセンスをお持ちで無い場合は、この機能を利用するためだけに Microsoft Entra ID P1 / P2 を用意するのは現実的ではないかもしれません。Microsoft E3 / E5 を利用しているなど、すでにライセンスをお持ちの場合は、こういった機能もあることを知っておけば、選択肢が広がります。
P1 / P2 にアドオンするライセンスで Microsoft Entra ID ガバナンスというものもあります。こちらは、さらにID管理を高度化できる機能がありますので、別の機会で紹介できればと思います。
※ 本記事の内容は2026年2月時点の仕様に基づいた検証結果です。Microsoft Entra IDの仕様変更やアップデートにより、画面表示や機能、制限値が変更される可能性があります。実際に導入・設定を行う際は、必ず最新の公式ドキュメントをご確認ください。
QUICK E-Solutionsでは、AIを活用した業務効率化・システム導入のお手伝いをしております。
それ以外でも 様々なアプリケーションの開発・導入を行っております。提供するサービス・ソリューションにつきましては こちら に掲載しております。
システム開発・構築でお困りの問題や弊社が提供するサービス・ソリューションにご興味を抱かれましたら、ぜひ一度 お問い合わせ ください。
※このブログで参照されている、Microsoft、Azure、Entra ID は、米国およびその他の国におけるマイクロソフトの商標または登録商標です。
