Microsoft Sentinel
The Sentinel sink ships events to a Log Analytics workspace, where Microsoft Sentinel's analytics rules, hunting queries and workbooks pick them up. Two modes are supported.
Mode 1: Logs Ingestion API (recommended)#
The modern, Microsoft-recommended path: a Data Collection Endpoint (DCE) plus a Data Collection Rule (DCR) writing into a custom table, authenticated with an Entra ID app registration.
Azure setup#
- Create a custom table (e.g.
Gatekeeper_CL) in your Log Analytics workspace — the portal's Tables → New custom log (DCR-based) wizard creates the DCR for you. Give the table aTimeGeneratedcolumn; Gatekeeper includes aTimeGeneratedfield on every event ready for the DCR transform. - Create a Data Collection Endpoint in the same region.
- Create an app registration in Entra ID, note its client ID and secret.
- Assign the role — on the DCR (not the workspace), grant the app registration Monitoring Metrics Publisher.
Laravel configuration#
SIEM_SINKS=sentinel
SIEM_SENTINEL_MODE=dcr
SIEM_SENTINEL_TENANT_ID=00000000-0000-0000-0000-000000000000
SIEM_SENTINEL_CLIENT_ID=00000000-0000-0000-0000-000000000000
SIEM_SENTINEL_CLIENT_SECRET=your-client-secret
SIEM_SENTINEL_DCE=https://gatekeeper-dce.westeurope-1.ingest.monitor.azure.com
SIEM_SENTINEL_DCR_ID=dcr-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
SIEM_SENTINEL_STREAM=Custom-Gatekeeper_CL
Verify:
php artisan siem:test --sink=sentinel
Entra ID tokens are acquired via client credentials against the https://monitor.azure.com/.default scope and cached until 5 minutes before expiry, so token traffic is negligible.
Mode 2: HTTP Data Collector API (legacy)#
Deprecated by Microsoft but still widely deployed. Uses the workspace ID and shared key with HMAC-SHA256 request signing:
SIEM_SENTINEL_MODE=legacy
SIEM_SENTINEL_WORKSPACE_ID=00000000-0000-0000-0000-000000000000
SIEM_SENTINEL_SHARED_KEY=base64-encoded-workspace-key
SIEM_SENTINEL_LOG_TYPE=Gatekeeper
Events land in a Gatekeeper_CL table that Log Analytics creates automatically on first ingestion.
All settings#
| Key | Env | Default |
|---|---|---|
sinks.sentinel.mode |
SIEM_SENTINEL_MODE |
dcr |
sinks.sentinel.tenant_id |
SIEM_SENTINEL_TENANT_ID |
— |
sinks.sentinel.client_id |
SIEM_SENTINEL_CLIENT_ID |
— |
sinks.sentinel.client_secret |
SIEM_SENTINEL_CLIENT_SECRET |
— |
sinks.sentinel.dce_endpoint |
SIEM_SENTINEL_DCE |
— |
sinks.sentinel.dcr_immutable_id |
SIEM_SENTINEL_DCR_ID |
— |
sinks.sentinel.stream_name |
SIEM_SENTINEL_STREAM |
Custom-Gatekeeper_CL |
sinks.sentinel.workspace_id |
SIEM_SENTINEL_WORKSPACE_ID |
— |
sinks.sentinel.shared_key |
SIEM_SENTINEL_SHARED_KEY |
— |
sinks.sentinel.log_type |
SIEM_SENTINEL_LOG_TYPE |
Gatekeeper |
sinks.sentinel.timeout |
SIEM_SENTINEL_TIMEOUT |
10 |
Example KQL#
Top attacking IPs in the last 24 hours:
Gatekeeper_CL
| where TimeGenerated > ago(24h)
| where event_severity >= 7
| summarize hits = count(), actions = make_set(event_action) by tostring(source_ip)
| order by hits desc
Honeypot hits with geo context:
Gatekeeper_CL
| where event_action == "honeypot_route_hit"
| project TimeGenerated, source_ip, source_geo_country_iso_code, url_path, user_agent_original
Brute force detections worth an incident:
Gatekeeper_CL
| where event_action in ("brute_force_detected", "resource_enumeration_detected")
| extend technique = tostring(threat_technique_id[0])
| project TimeGenerated, event_action, source_ip, technique, laravel_context
An analytics rule on event_severity >= 9 gives you Sentinel incidents from brute_force_detected out of the box.