Business Problem
IDSentinel Solutions' SOC had no centralized visibility into identity-based threats. Sign-in risk events, MFA failures, legacy auth attempts, and privileged role activations were siloed across five separate Entra ID portal blades — analysts were checking them manually with no correlation, no alerting, and no audit trail proving events were reviewed.
A tabletop exercise surfaced the gap: when a simulated MFA fatigue attack was run against a test account, the analyst on duty did not detect it for over four hours. The push denial events were buried in the Entra sign-in logs with no alert, no dashboard, and no escalation path.
Risk
- MFA fatigue attacks go undetected — no alerting on push denial volume
- Impossible travel sign-ins create an undetected account compromise window
- Privileged role activations at 2am are invisible without SIEM correlation
- Legacy auth spike post-block-policy has no automated detection or alerting
- Manual log review creates 2–4 hour detection gaps with no audit trail
- Non-compliant with SOC 2 CC7.1 (threat monitoring) and CC7.2 (incident detection)
Scope
| Field | Detail |
|---|---|
| Affected systems | Microsoft Entra ID sign-in and audit logs → Splunk Enterprise |
| Ingestion method | Python OAuth2 HEC ingestor (primary), Splunk Add-on for Microsoft Security (documented alternative) |
| Detections covered | 4 — MFA fatigue, impossible travel, after-hours PIM, legacy auth spike |
| Detection framework | MITRE ATT&CK — T1621, T1078, T1078.004, T1110.003 |
| Polling interval | 5 minutes |
| Compliance target | SOC 2 Type II — CC7.1, CC7.2 |
Detections Deployed
| Detection | Attack Pattern | Threshold | Severity | MITRE |
|---|---|---|---|---|
| D-01: MFA Fatigue | Push denial storm | >5 denials / user / 60min | HIGH | T1621 |
| D-02: Impossible Travel | Two sign-ins 500+ miles apart in 2 hours | 500mi / 120min | HIGH | T1078 |
| D-03: After-Hours PIM | Privileged role activated 10pm–6am | Any activation | MEDIUM | T1078.004 |
| D-04: Legacy Auth Spike | Password spray via SMTP/IMAP/POP3 | >10 attempts / IP / 60min | HIGH | T1110.003 |
Solution Design
Two ingestion methods implemented to demonstrate both the enterprise-grade approach and a fully scripted alternative:
Splunk Add-on for Microsoft Security
Official Microsoft add-on installed and configured with app registration credentials. Documents the enterprise credential configuration path — available for future native Entra sign-in log input support.
Custom Python HEC Ingestor (Primary)
Python script authenticating to Graph API via OAuth2 client credentials, pulling sign-in and audit log events, forwarding to Splunk via HTTP Event Collector. State tracking via last_run.json prevents duplicates. Scheduled via Windows Task Scheduler at 5-minute intervals. This is the primary ingestion method.
Design decision: Reused the existing Scenario 06 app registration — added IdentityRiskEvent.Read.All and RoleManagement.Read.All permissions. Dedicated Splunk index (idsentinel_identity) isolates identity logs. All four detections map to INC-TYPE-001 from Scenario 07 — no new runbook required.

Implementation
Ingestion Pipeline
-
01
Ingestion — Method A (Splunk Add-on for Microsoft Security)
The official Splunk Add-on for Microsoft Security installed and configured with the existing app registration credentials. Documents the enterprise credential configuration path for future native Entra sign-in log input support.
// 01-addon-install
// 02-addon-credentials
-
02
Ingestion — Method B (Python HEC Ingestor — Primary)
HEC token created in Splunk. Python script configured with token and Graph API credentials — authenticates via OAuth2 client credentials, pulls sign-in and audit logs since last run, forwards to HEC in batch format with timestamps preserved. State tracking via
last_run.jsonprevents duplicates. Scheduled via Windows Task Scheduler at 5-minute intervals. Ingestion confirmed — sign-in events confirmed inidsentinel_identityindex with real user and application data.// 05-hec-token
// 06-hec-script-output
// 07-task-scheduler
// 04-ingestion-verified
Detection Deployment
-
03
D-01 — MFA Fatigue (T1621)
SPL query filters for sign-ins matching MFA failure error codes (500121, 500082) and aggregates per user over a 60-minute rolling window. Alert fires when a single user exceeds 5 push denials. Throttled to once per user per hour. Alert fired against test data — confirmed in Triggered Alerts with HIGH severity badge.
// 08a-mfa-fatigue-alert
// 08b-mfa-fatigue-alert
-
04
D-02 — Impossible Travel (T1078)
SPL uses
streamstatsto compare consecutive successful sign-ins per user, then applies the Haversine formula to calculate great-circle distance. Known corporate VPN egress IPs excluded. Alert fired — New York to Seattle, 2,402 miles apart, 25-minute gap. Result set confirmed locations, IPs, distance, MITRE technique, response SLA, and runbook reference.// 09a-impossible-travel-alert
// 09b-impossible-travel-alert
-
05
D-03 — After-Hours PIM (T1078.004)
SPL filters Entra audit logs for PIM activation events (
loggedByService = PIM,result = success), converts UTC to local time, flags activations between 22:00–06:00. UTC offset configurable. Scheduled every 60 minutes. All four alerts confirmed enabled and scheduled.// 12-identity-threat-alerts
-
06
D-04 — Legacy Auth Spike (T1110.003) + Identity Threat Dashboard
SPL filters for legacy
clientAppUsedvalues, aggregates by source IP over 60 minutes, alerts when any IP exceeds 10 attempts. Dashboard confirmed 36 legacy auth attempts from185.220.101.55(NL) across Exchange ActiveSync, IMAP, SMTP, POP3. Dashboard deployed with live data — 66 sign-ins, 21 MFA denials, 3 PIM activations, and 36 legacy auth attempts visible. SOC achieves full identity threat visibility without a single Entra portal login.// 13-identity-threat-dashboard
Outcome
Detection Coverage Summary
| Detection | Schedule | Severity | MITRE | Validated |
|---|---|---|---|---|
| D-01 MFA Fatigue | 15min | HIGH | T1621 | ✅ Alert fired |
| D-02 Impossible Travel | 30min | HIGH | T1078 | ✅ 2,402mi confirmed |
| D-03 After-Hours PIM | 60min | MEDIUM | T1078.004 | ✅ Dashboard confirmed |
| D-04 Legacy Auth Spike | 15min | HIGH | T1110.003 | ✅ 36 attempts confirmed |
Files
-
scripts/Invoke-EntraLogIngestor.pyPython HEC ingestor — OAuth2 auth + Splunk forwarding with state tracking -
scripts/Test-DetectionData.pyGenerates synthetic test events to validate all four alert searches -
splunk/searches/D-01-MFA-Fatigue.splSPL query — MFA fatigue detection -
splunk/searches/D-02-Impossible-Travel.splSPL query — impossible travel with Haversine formula -
splunk/searches/D-03-After-Hours-PIM.splSPL query — after-hours PIM activation -
splunk/searches/D-04-Legacy-Auth-Spike.splSPL query — legacy auth spike post-block-policy -
splunk/searches/Identity-Threat-Dashboard.xmlSplunk dashboard XML — SOC single-pane view -
diagrams/pipeline-architecture.pngEnd-to-end pipeline architecture diagram -
screenshots/Evidence of implementation at each stage