Microsoft Sentinel のインシデントを Tenant A から CSV で書き出したものの、Tenant B 側にそのまま取り込めず困っていませんか?本記事では「CSV をインシデントとして移行したい」を、現実的に実現できる形(再作成/見える化/レポート化)に分解し、REST API・PowerShell・Python・Azure Lighthouse を使った具体策を整理します。
Microsoft Sentinel のインシデントは「CSVインポートで移行」できない理由
結論から言うと、Sentinel のインシデントは単なる一覧データではなく、ワークスペース(Log Analytics)・分析ルール・アラート・エンティティ・調査の文脈と結びついた「ケース管理の対象」です。CSV エクスポートは便利ですが、CSV を別テナントの Sentinel にインポートして、同一インシデントとして復元するための標準機能は用意されていません。
また、CSV 内に「インシデントへのリンク(ポータル deep link)」が含まれていても、リンク先のワークスペースや Azure リソースは Tenant A 側に存在するため、Tenant B 側ではアクセスできない/意味を成さないケースが多くなります(権限・テナント境界・参照先リソースの問題)。
そのため実務では、目的を以下のどれに寄せるかで解が変わります。
目的別に解を選ぶ:再作成・見える化・レポート化
| やりたいこと(目的) | おすすめの方針 | メリット | 注意点(割り切り) |
|---|---|---|---|
| Tenant B に「監査・報告用として」インシデントを残したい | API / PowerShell / Python で “再作成” | Tenant B にデータが残る。検索・レポートの基盤が作れる。 | Tenant A のアラート、証跡、関連エンティティなどの“調査文脈”は基本的に引き継げない。 |
| 移さなくてよいので、Tenant B から Tenant A の Sentinel を横断的に監視したい | Azure Lighthouse | データ移動なしで集中管理が可能。運用として自然。 | あくまで“見える化/管理”であり、Tenant B に複製されない。 |
| 複数テナント/複数ワークスペースを 1 画面で見たい | 複数ワークスペースビュー(Multiple workspace view)、Defender ポータルの統合ビュー | 画面上で横断監視できる。運用導線が分かりやすい。 | これも移行ではない。権限とテナント選択(ディレクトリ・サブスク選択)が前提。 |
| インシデントとして再作成せず、一覧の監査レポートを作れればよい | CSV を Log Analytics / Power BI に取り込み、Workbook で可視化 | データ整形と分析が柔軟。運用コストが低い場合が多い。 | Sentinel の「インシデント」機能としては扱わない(ケース管理の導線が別物)。 |
方式1:REST API で Tenant B にインシデントを“再作成”する
「Tenant B に同等のインシデントを作り直して残す」場合、最も確実なのは Microsoft Sentinel の Incidents REST API を使う方法です。Incidents API には Create/Update(PUT)があり、スクリプトで 1 件ずつ作成できます。
再作成でできること/できないこと
- できること:タイトル、重大度、状態、説明、発生時刻(first/last activity)、ラベル、担当者(owner)など、ケース管理としての「箱」を Tenant B に作る。
- できないこと:Tenant A のインシデントに紐づくアラートやエンティティ、証跡、タイムラインなどの“調査の中身”を完全に引き継ぐ(別テナントで同一IDとして復元する)こと。
- 現実的な落としどころ:監査・レポート・集中監視のために「メタデータ+原本参照(URL/番号)」を残し、調査が必要な場合は Tenant A 側に切り替えて追う。
Incidents API の要点(必須項目と列挙値)
Incidents – Create Or Update は、ワークスペース配下の Incident リソースに対して PUT します。必須は title / severity / status です。
| 項目 | API 側の値 | CSV からの変換ポイント |
|---|---|---|
| Severity(重大度) | High / Medium / Low / Informational | CSV が「高・中・低・情報」など日本語なら、英語列挙値にマッピングする。 |
| Status(状態) | New / Active / Closed | CSV の「新規・対応中・クローズ」などをマッピング。 |
| Owner(担当者) | objectId / email / UPN / assignedTo / ownerType | Tenant B に存在するユーザー/グループの情報が必要。特に objectId は別テナントでは一致しない。 |
| First/Last Activity Time | firstActivityTimeUtc / lastActivityTimeUtc | 監査用途なら CSV の「発生時刻」を first/last に入れ、原本の作成/更新時刻は説明欄にも残すと追跡しやすい。 |
| Labels(ラベル) | labels: [{labelName, labelType}] | 「MigratedFromTenantA」「OriginalSeverity:High」など、後で検索できる設計にする。 |
MITRE ATT&CK 戦術(tactics)をどう扱うか
CSV に「MITRE 戦術」が入っている場合、最初に確認したいのはそれを Tenant B の“インシデントの標準フィールド”として保持できるかです。
Incidents の REST API 定義上、戦術は “Attack Tactic” の列挙値として定義されており、Reconnaissance / InitialAccess / Execution… などの値が用意されています。
ただし、インシデントの戦術が「アラート由来で自動付与される性質」を持つケースでは、手動/再作成したインシデントに同じ形で入らないことがあります。実務の安全策としては、次のどれかに寄せるのが堅いです。
- 説明(description)に戦術を明記:「Tactics: Execution, LateralMovement」
- ラベルで戦術を表現:「Tactic:Execution」「Tactic:LateralMovement」
- コメントで原本の戦術を保存(後述の Incident Comments API / PowerShell で追記)
日本語→列挙値の変換が必要な場合は、次のようなマッピングが扱いやすいです。
| CSV 側(例) | MITRE 戦術(列挙値) | 補足 |
|---|---|---|
| 偵察 | Reconnaissance | ラベル化するなら「Tactic:Reconnaissance」 |
| 初期アクセス | InitialAccess | 複数戦術はカンマ区切り→配列化 |
| 実行 | Execution | 値の正規化(空白・全角半角)を先に行う |
| 永続化 | Persistence | CSV が略語の場合は辞書を用意 |
| 権限昇格 | PrivilegeEscalation | 表記揺れに注意 |
必要な権限(Tenant B 側)
Tenant B にインシデントを作成・更新するには、Sentinel の RBAC が必要です。Microsoft Learn のロール定義では、インシデント管理を行うには Microsoft Sentinel Responder 以上が推奨されます。
| ロール | 用途 | この移行(再作成)での目安 |
|---|---|---|
| Microsoft Sentinel Reader | 閲覧のみ | 作成は不可。検証用に読むだけなら可。 |
| Microsoft Sentinel Responder | インシデント管理 | インシデントの作成/更新・担当者変更などを行う役。 |
| Microsoft Sentinel Contributor | Sentinel 資産全般 | 大規模運用や自動化(アプリ/サービスプリンシパル)ならこれが無難。 |
また、Azure ポータルからの手動作成・API 作成は Sentinel Responder または Contributor が必要とされています。
設計のコツ:再作成インシデントに「原本トレーサビリティ」を埋め込む
再作成は「別物のインシデント」になるため、監査・調査の導線を壊さない設計が重要です。おすすめは、Tenant A の情報を Tenant B の説明/ラベル/コメントに必ず残すことです。
- 説明(description)冒頭に、原本の Tenant / Workspace / Incident 番号 / URL を記録
- ラベルに「MigratedFrom:TenantA」「OriginalStatus:Closed」などを付与
- コメントに「移行日時」「CSV の出典(レポート名)」を残す
コメントは Incident Comments の Create Or Update で PUT できます(message が必須)。
実装ステップ(REST API / PowerShell / Python 共通)
- CSV の列定義を確定:タイトル、重大度、状態、発生時刻、担当者、戦術、原本 URL(できれば)など。
- Tenant B 側の“格納先”を決める:どの Sentinel ワークスペースに再作成するか(監査専用ワークスペースを用意する運用も多い)。
- マッピング辞書を用意:Severity/Status、担当者(A→B)、戦術(日本語→列挙値、またはラベル化)
- 重複防止の設計:incidentId を固定(後述)し、同じ CSV を再投入しても “更新” になるようにする。
- 投入(作成)→コメント追記→検証:作成が成功したか、タイトル/状態/担当者/ラベルが期待通りか確認。
CSV→API のマッピング例(テンプレ)
| CSV列(例) | Tenant B に保存する場所 | 理由 |
|---|---|---|
| Title | properties.title | 一覧性を維持するため必須 |
| Severity | properties.severity | 必須。High/Medium/Low/Informational のいずれかに正規化。 |
| Status | properties.status | 必須。New/Active/Closed に正規化。 |
| FirstSeen / OccurredAt | properties.firstActivityTimeUtc / lastActivityTimeUtc | 監査の時系列を残すため |
| Assignee(担当者) | properties.owner(Tenant B の objectId 等) | Tenant A のユーザー情報はそのまま入らないので、B のユーザーにマッピングが必要。 |
| MITRE Tactics | labels または description / comments | “検索できる形”で保持するのがポイント |
| Original Incident URL | description と comments | 監査・調査で原本へ戻る導線を確保 |
重複投入を防ぐ最大のコツ:incidentId を「原本由来」で固定する
Incidents API は URL に incidentId(リソース名)を含めて PUT する形式です。つまり、同じ incidentId で PUT すれば “作成” ではなく “更新” になるため、移行を繰り返しても二重化を抑えられます。
おすすめは次のどちらかです。
- CSV に原本の incidentId が入っている:それをそのまま Tenant B の incidentId に使う(最も安定)
- CSV に原本 URL が入っている:URL の末尾に含まれる GUID(incidentId)をパースして使う(安定+トレーサビリティ)
原本 URL 自体は Tenant B で開けなくても、「IDとして使う」だけなら価値があります。これをやると、再投入時に “同じインシデントを更新して整合させる” 運用にしやすくなります。
PowerShell で実現する方法:Az.SecurityInsights で再作成する
PowerShell なら、REST API を直叩きする以外に、Az.SecurityInsights の cmdletを使う方法が実務的です。New-AzSentinelIncident / New-AzSentinelIncidentComment などが提供されています。
以下は「CSV を読み込み、Tenant B の Sentinel ワークスペースにインシデントを作成し、原本 URL をコメントに残す」骨子です(列名は環境に合わせてください)。
# 必要モジュール(例)
# Install-Module Az -Scope CurrentUser
# Install-Module Az.SecurityInsights -Scope CurrentUser
# Tenant B にログイン(必要なら -Tenant を指定)
Connect-AzAccount
$rg = "RG_Sentinel_TenantB"
$ws = "LAW_Sentinel_TenantB"
$csv = "C:\temp\sentinel_incidents_tenantA.csv"
# 任意:担当者マッピング(例:メール→UPN)
$assigneeMap = @{
"[email protected]" = "[email protected]"
"[email protected]" = "[email protected]"
}
Import-Csv $csv | ForEach-Object {
# Severity/Status の正規化(例)
$severity = switch ($_.Severity) {
"高" { "High" }
"中" { "Medium" }
"低" { "Low" }
default { "Informational" }
}
$status = switch ($_.Status) {
"新規" { "New" }
"対応中" { "Active" }
"クローズ" { "Closed" }
default { "New" }
}
# incidentId を固定する(CSV に OriginalIncidentId がある想定)
$incidentId = if ($_.OriginalIncidentId) { $_.OriginalIncidentId } else { (New-Guid).Guid }
# 説明に原本情報を埋め込む
$desc = @"
[MIGRATED] SourceTenant=TenantA
OriginalUrl=$($_.OriginalIncidentUrl)
OriginalNumber=$($_.OriginalIncidentNumber)
Tactics=$($_.Tactics)
---
$($_.Description)
"@
# Owner(担当者)は Tenant B のユーザーに合わせる
$ownerUpn = $null
if ($_.Assignee -and $assigneeMap.ContainsKey($_.Assignee)) {
$ownerUpn = $assigneeMap[$_.Assignee]
}
# 作成(New-AzSentinelIncident は “作成 or 更新” になる)
if ($ownerUpn) {
New-AzSentinelIncident `
-ResourceGroupName $rg `
-WorkspaceName $ws `
-Id $incidentId `
-Title $_.Title `
-Severity $severity `
-Status $status `
-Description $desc `
-OwnerUserPrincipalName $ownerUpn | Out-Null
} else {
New-AzSentinelIncident `
-ResourceGroupName $rg `
-WorkspaceName $ws `
-Id $incidentId `
-Title $_.Title `
-Severity $severity `
-Status $status `
-Description $desc | Out-Null
}
# 原本 URL をコメントとして追加(検索・監査用)
if ($_.OriginalIncidentUrl) {
New-AzSentinelIncidentComment `
-ResourceGroupName $rg `
-WorkspaceName $ws `
-IncidentId $incidentId `
-Message ("Original incident (Tenant A): " + $_.OriginalIncidentUrl) | Out-Null
}
}
Az.SecurityInsights は API を抽象化してくれるため、トークン取得や URL 組み立ての事故を減らせます。一方で「より細かいフィールド制御」や「特殊な運用要件」がある場合は、次の REST API 直叩きの方がコントロールしやすいです。
REST API を直叩きする場合の要点(Create / Update)
Incidents – Create Or Update は、次の形式で PUT します(management.azure.com の ARM API です)。
- PUT: /subscriptions/SUBSCRIPTION_ID/resourceGroups/RESOURCE_GROUP/providers/Microsoft.OperationalInsights/workspaces/WORKSPACE/providers/Microsoft.SecurityInsights/incidents/INCIDENT_ID?api-version=2025-09-01
- Body(必須):properties.title / properties.severity / properties.status
コメントを残すなら、Incident Comments の Create Or Update を使います。
Python で実現する方法:CSV→Incidents API に PUT
Python なら「CSV→マッピング→PUT」のバッチが書きやすく、CI/CD やスケジューラ(Azure Automation、GitHub Actions 等)に乗せるのも容易です。以下は設計の要点を押さえた雛形です。
import csv
import json
import uuid
import subprocess
import requests
from datetime import datetime
SUBSCRIPTION_ID = "SUBSCRIPTION_ID"
RESOURCE_GROUP = "RESOURCE_GROUP"
WORKSPACE_NAME = "WORKSPACE_NAME"
API_VERSION = "2025-09-01"
CSV_PATH = r"C:\temp\sentinel_incidents_tenantA.csv"
def get_arm_token():
# Azure CLI で ARM トークンを取得(事前に az login --tenant TENANT_B を実施)
cmd = ["az", "account", "get-access-token", "--resource", "https://management.azure.com/", "--query", "accessToken", "-o", "tsv"]
return subprocess.check_output(cmd, text=True).strip()
def normalize_severity(s: str) -> str:
s = (s or "").strip()
return {"高":"High","中":"Medium","低":"Low","情報":"Informational"}.get(s, "Informational")
def normalize_status(s: str) -> str:
s = (s or "").strip()
return {"新規":"New","対応中":"Active","クローズ":"Closed"}.get(s, "New")
token = get_arm_token()
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
with open(CSV_PATH, newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
# incidentId を固定(CSV に OriginalIncidentId がない場合は新規GUID)
incident_id = row.get("OriginalIncidentId") or str(uuid.uuid4())
url = (
f"https://management.azure.com/subscriptions/{SUBSCRIPTION_ID}"
f"/resourceGroups/{RESOURCE_GROUP}"
f"/providers/Microsoft.OperationalInsights/workspaces/{WORKSPACE_NAME}"
f"/providers/Microsoft.SecurityInsights/incidents/{incident_id}"
f"?api-version={API_VERSION}"
)
payload = {
"properties": {
"title": row.get("Title") or "Migrated incident",
"severity": normalize_severity(row.get("Severity")),
"status": normalize_status(row.get("Status")),
"description": (
"[MIGRATED] SourceTenant=TenantA\n"
f"OriginalUrl={row.get('OriginalIncidentUrl','')}\n"
f"OriginalNumber={row.get('OriginalIncidentNumber','')}\n"
f"Tactics={row.get('Tactics','')}\n"
"---\n"
f"{row.get('Description','')}"
),
# 必要なら first/lastActivityTimeUtc を ISO 8601 (UTC) で設定
# "firstActivityTimeUtc": "2025-01-01T00:00:00Z",
# "lastActivityTimeUtc": "2025-01-01T01:00:00Z",
}
}
resp = requests.put(url, headers=headers, data=json.dumps(payload))
if resp.status_code not in (200, 201):
raise RuntimeError(f"Failed: {resp.status_code} {resp.text}")
上のサンプルは「インシデント作成」に絞っていますが、実務では次の拡張を入れると運用品質が上がります。
- スロットリング対策:一定件数ごとにスリープ、リトライ(指数バックオフ)
- 投入ログ:成功/失敗を別 CSV または JSON に保存し、再開可能にする
- 二重化対策:incidentId 固定に加え、ラベルで「MigrationBatch=YYYYMMDD」などを付与
補足:手動作成・API作成のインシデントと Defender ポータルの関係
Microsoft Sentinel を Microsoft Defender ポータルにオンボードして運用している場合、手動で作成したインシデントは Defender ポータルと同期されない旨の注意があります。集中監視の画面を Defender ポータルに寄せている組織は、再作成インシデントの見え方を事前に検証してください。
方式1の現実解:再作成は「監査・レポート用途に強い」
Tenant B に作る再作成インシデントは、次の用途に特に向きます。
- 監査で「いつ」「どんなインシデントが」「どの担当で」「どうクローズされたか」を Tenant B 側に保存したい
- グループ会社・子会社の SOC を Tenant B 側で統制し、一定形式の記録を残したい
- 原本は Tenant A 側に保持しつつ、Tenant B では “台帳(ケース記録)” を持ちたい
方式2:Azure Lighthouse でクロステナント運用(移行せず集中管理)
「そもそも移行しなくていい。Tenant B の SOC から Tenant A の Sentinel を見て運用できればよい」という場合、Azure Lighthouse が自然です。
Azure Lighthouse を使うと、複数テナントの Microsoft Sentinel ワークスペースを横断的に管理でき、クエリやワークブックによる可視化などを “データ移動なし” で実現しやすくなります。
また、Microsoft Learn のクロステナント管理の整理でも、Microsoft Sentinel は Lighthouse 経由で「顧客テナントの Sentinel 管理」「複数テナントの攻撃追跡やアラート参照」「複数ワークスペースのインシデント参照」などのシナリオが挙げられています。
Azure Lighthouse を選ぶべきケース
- 集中監視・集中運用が目的で、データ複製(移行)を必須としていない
- MSSP 的な運用(複数テナントの運用代行)や、グループ企業の横断 SOC を構築したい
- 「Tenant A の Sentinel を Tenant B から直接扱える」導線を重視したい
運用設計のポイント(ハマりどころ)
- 委任設計(どのロールをどのグループに渡すか):Sentinel のロール(Reader/Responder/Contributor)ごとにグループを作って委任すると運用が整理しやすい。
- ディレクトリ+サブスクリプション選択:Azure ポータル側で複数テナント/サブスクを選べる状態にしないと、横断のワークスペース選択に出てこない。
方式3:複数ワークスペースビュー/統合ビューで“移さずに見える化”する
「移行ではなく、運用者の画面を統合したい」場合は、Microsoft Sentinel の複数ワークスペースビュー(Multiple workspace view)が強力です。複数ワークスペースを同時に選んで、インシデントを横断的に一覧化して扱えます。テナントを跨いだ可視化にも触れられています。
さらに、Microsoft Learn の整理では、Azure ポータルと Defender ポータルの「インシデントビュー」は、複数ワークスペースのインシデントを中央で管理・監視でき、必要に応じて元のワークスペース文脈にドリルダウンできる、とされています。
複数ワークスペースビューの基本イメージ
- アクセス可能なワークスペースを複数選択 → 「View incidents」
- 横断のインシデント一覧でフィルタ・トリアージ
- 必要なものだけ元ワークスペースにドリルダウン
この方式は「コピーを作らない」ため、データ二重化や整合性の問題が起きにくく、集中監視の目的に合うことが多いです。
監査・報告が主目的なら:CSV を“インシデント”にせずレポート基盤へ
「監査で必要なのは、インシデント一覧のメタデータが残っていること」「集計・可視化・出力ができること」であれば、Sentinel のインシデントとして再作成するより、次の方がハマりが少ない場合があります。
- CSV を Tenant B の Log Analytics(カスタムテーブル)に取り込む
- Workbook や Power BI でレポート化し、監査に必要な粒度で出力
この方法だと、担当者や戦術などの項目も “列” として保持でき、API の列挙値制約に縛られにくくなります。反面、Sentinel のインシデント管理機能(担当割り当てやクローズ操作など)とは別の導線になる点は割り切りです。
実務でハマりやすい点と対処(チェックリスト)
| ハマりどころ | 起きがちな症状 | 対処の考え方 |
|---|---|---|
| 担当者(Owner)の不一致 | Tenant A の担当者をそのまま入れられない/エラーになる | Tenant B のユーザー/グループにマッピングし、無理なら「未割当」にして説明/コメントに原本担当者を残す。 |
| Severity/Status の値が通らない | 400 Bad Request など | High/Medium/Low/Informational と New/Active/Closed に正規化。CSV の表記揺れを先に吸収。 |
| 時刻の形式 | 日付が入らない/ズレる | UTC の ISO 8601 形式(例:2025-01-01T00:00:00Z)に整形し、元のタイムゾーン情報も説明に残す。 |
| Defender ポータルに表示されない | 再作成したインシデントが統合画面に出てこない | 手動作成インシデントの同期仕様を事前確認し、運用画面を Azure ポータル側に寄せるなど設計で吸収。 |
| 大量件数の投入 | 途中で失敗/再実行が怖い | incidentId 固定+投入ログ+リトライ設計。PUT の “更新” を活用して冪等にする。 |
最短で決めるための判断フレーム
- Tenant B にデータを“複製して残す”必要がある → 方式1(再作成:REST API / PowerShell / Python)
- 複製は不要、運用を一箇所に寄せたい → 方式2(Azure Lighthouse)または方式3(複数ワークスペースビュー)
- 監査レポートが主で、インシデント機能は不要 → CSV をレポート基盤へ(Log Analytics / Power BI)
まとめ
Microsoft Sentinel のインシデントは CSV を直接インポートして別テナントに移行する形が取りづらい一方で、API/PowerShell/Python による“再作成”、または Azure Lighthouse/複数ワークスペースビューによる“見える化”で、目的(監査・報告・集中監視)に合わせた落としどころを作れます。
特に「再作成」を選ぶなら、incidentId の固定(冪等化)と、原本トレーサビリティ(URL/番号/担当/戦術)を Tenant B 側に必ず残す設計が、後から効いてきます。運用要件に合わせて、最適な方式を選んでください。

コメント