Skip to content

Microsoft Sentinel Integration Guide

Arbitex streams audit events to Microsoft Sentinel using the Azure Monitor Log Ingestion API (DCR-based ingestion, not the legacy Log Analytics Data Collector API). Events are formatted as OCSF v1.1 JSON, batched for efficiency, and authenticated with Azure AD client credentials.


Before configuring the connector, you need:

  • An Azure subscription with Microsoft Sentinel enabled on a Log Analytics workspace
  • A Data Collection Rule (DCR) configured to accept custom log data
  • A Data Collection Endpoint (DCE) associated with the DCR
  • An Azure AD app registration with the Monitoring Metrics Publisher role assigned to the DCR

The connector authenticates using the OAuth 2.0 client credentials flow. Create a dedicated app registration for Arbitex:

  1. In the Azure portal, go to Microsoft Entra ID → App registrations → New registration.
  2. Name the app (e.g. arbitex-sentinel-ingest) and click Register.
  3. Note the Application (client) ID and Directory (tenant) ID.
  4. Go to Certificates & secrets → New client secret. Set an expiry and save the secret value — it is shown only once.

Assign the Monitoring Metrics Publisher role

Section titled “Assign the Monitoring Metrics Publisher role”

The app registration needs write permission on the DCR:

  1. In the Azure portal, navigate to your Data Collection Rule.
  2. Go to Access control (IAM) → Add role assignment.
  3. Select the role Monitoring Metrics Publisher.
  4. Assign it to your arbitex-sentinel-ingest app registration.

Sentinel uses a DCR to define the schema and destination for incoming custom log data.

  1. In the Azure portal, go to Log Analytics workspace → Tables → Create → New custom log (DCR-based).
  2. Define the columns that match the OCSF fields you want to query. At minimum, include: TimeGenerated, class_uid, class_name, severity, actor_user_email, actor_org_uid, src_ip.
  3. Create or select a Data Collection Endpoint for the DCR.
  4. Note the DCR Immutable ID (shown on the DCR overview page, format: dcr-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx).
  5. Note the DCE Logs Ingestion URL (format: https://{dce-name}.{region}.ingest.monitor.azure.com).
  6. Note the Stream Name configured in the DCR (default used by Arbitex: Custom-ArbitexOCSF_CL).

Configure the connector using environment variables on the Arbitex platform deployment.

VariableRequiredDefaultDescription
SENTINEL_TENANT_IDYesAzure AD tenant (directory) ID
SENTINEL_CLIENT_IDYesAzure AD application (client) ID
SENTINEL_CLIENT_SECRETYesAzure AD client secret value
SENTINEL_DCE_ENDPOINTYesData Collection Endpoint URL
SENTINEL_DCR_IMMUTABLE_IDYesDCR immutable ID
SENTINEL_STREAM_NAMENoCustom-ArbitexOCSF_CLDCR stream name
SENTINEL_BATCH_SIZENo100Maximum events per batch send
SENTINEL_FLUSH_INTERVALNo5Maximum seconds between batch flushes
SENTINEL_MAX_RETRIESNo3Maximum retry attempts on transient failures
SENTINEL_DEAD_LETTER_PATHNo/var/log/arbitex/sentinel_dead_letter.jsonlPath for the dead letter queue file
Terminal window
SENTINEL_TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
SENTINEL_CLIENT_ID=yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
SENTINEL_CLIENT_SECRET=<secret-value>
SENTINEL_DCE_ENDPOINT=https://arbitex-ingest-xxxx.eastus-1.ingest.monitor.azure.com
SENTINEL_DCR_IMMUTABLE_ID=dcr-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
SENTINEL_STREAM_NAME=Custom-ArbitexOCSF_CL

The connector authenticates with Azure AD using the client credentials flow on every token acquisition. Tokens are cached until 60 seconds before their expiry (default: 1 hour tokens from Azure AD). No user interaction is required.

The token scope used is https://monitor.azure.com/.default.

Token acquisition URL:

https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token

The connector health check validates credentials by attempting token acquisition — if this succeeds, the connector is marked healthy.


Events are sent to the DCR ingestion endpoint as a JSON array. Each element is an OCSF v1.1 JSON object:

POST {dce_endpoint}/dataCollectionRules/{dcr_immutable_id}/streams/{stream_name}?api-version=2023-01-01
Authorization: Bearer {access_token}
Content-Type: application/json
[
{
"class_uid": 6003,
"class_name": "API Activity",
"category_uid": 6,
"category_name": "Application Activity",
"activity_id": 1,
"activity_name": "Create",
"severity_id": 1,
"severity": "Informational",
"status_id": 1,
"status": "Success",
"time": 1741737600000,
"message": "API request processed",
"actor": {
"user": {
"uid": "user_01jq...",
"email_addr": "alice@example.com",
"name": "Alice Smith"
},
"org": {
"uid": "org_01jq...",
"name": "Acme Corp"
}
},
"src_endpoint": {
"ip": "203.0.113.45",
"location": {
"country": "US",
"city": "New York"
}
},
"metadata": {
"version": "1.1.0",
"product": {
"name": "Arbitex",
"vendor_name": "Arbitex"
}
}
}
]

Sentinel maps the JSON fields to columns in your custom table according to the DCR transformation rules. The time field (epoch milliseconds) should be mapped to TimeGenerated in your DCR transformation.

OCSF classclass_uidDescription
API Activity6003Every request processed through the gateway
Security Finding2001DLP trigger events
Authentication3002Login, token exchange, SSO events
Account Change3001User and group lifecycle events

Events are buffered and flushed when the buffer reaches SENTINEL_BATCH_SIZE events (default: 100) or SENTINEL_FLUSH_INTERVAL seconds have elapsed (default: 5 seconds).

On transient failures (HTTP 429 or 503), the connector retries with exponential backoff (1s, 2s, 4s) up to SENTINEL_MAX_RETRIES attempts. Events that cannot be delivered are written to the dead letter queue at SENTINEL_DEAD_LETTER_PATH.


Terminal window
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \
https://api.arbitex.ai/api/admin/siem/connectors | jq '.[] | select(.connector_id == "sentinel")'

A healthy connector returns:

{
"connector_id": "sentinel",
"display_name": "Microsoft Sentinel",
"status": "healthy",
"config_summary": {
"tenant_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"client_id": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy",
"dce_endpoint": "https://arbitex-ingest-xxxx.eastus-1.ingest.monitor.azure.com",
"dcr_immutable_id": "dcr-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"stream_name": "Custom-ArbitexOCSF_CL",
"client_secret_configured": true
}
}

Use KQL in the Sentinel Log Analytics workspace to verify events are arriving:

ArbitexOCSF_CL
| where TimeGenerated > ago(15m)
| project TimeGenerated, class_name_s, severity_s, actor_user_email_s, actor_org_uid_s, src_ip_s
| order by TimeGenerated desc
| take 20

To query DLP events specifically:

ArbitexOCSF_CL
| where TimeGenerated > ago(1h)
| where class_name_s == "Security Finding"
| summarize count() by bin(TimeGenerated, 5m), actor_org_uid_s
| render timechart

Note: The custom table name in KQL depends on the name you chose when creating it. If you named your table ArbitexOCSF, the KQL table name will be ArbitexOCSF_CL (Sentinel appends _CL for custom log tables).


One or more of the required variables (SENTINEL_TENANT_ID, SENTINEL_CLIENT_ID, SENTINEL_CLIENT_SECRET, SENTINEL_DCE_ENDPOINT, SENTINEL_DCR_IMMUTABLE_ID) is not set.

status: error — token acquisition failed

Section titled “status: error — token acquisition failed”

Azure AD rejected the client credentials. Common causes:

  • Wrong tenant ID — verify the Directory (tenant) ID in Entra ID.
  • Wrong client ID — verify the Application (client) ID on the app registration.
  • Expired or incorrect client secret — create a new client secret in App registrations → Certificates & secrets and update SENTINEL_CLIENT_SECRET.
  • App not in tenant — ensure the app registration is in the same tenant as the Log Analytics workspace.

Check platform logs:

Terminal window
kubectl logs -n arbitex -l app=arbitex-platform --tail=200 | grep -i sentinel

HTTP 403 on ingestion — Monitoring Metrics Publisher role missing

Section titled “HTTP 403 on ingestion — Monitoring Metrics Publisher role missing”

The app registration is missing the Monitoring Metrics Publisher role on the DCR. See the Assign the Monitoring Metrics Publisher role section above.

HTTP 404 on ingestion — DCR or stream not found

Section titled “HTTP 404 on ingestion — DCR or stream not found”

Verify that SENTINEL_DCR_IMMUTABLE_ID and SENTINEL_STREAM_NAME match what is shown in the Azure portal on the DCR. The immutable ID is displayed on the DCR Overview page (not the resource ID).

Sentinel custom log ingestion can take 5–15 minutes to appear in queries after successful API acknowledgement. This is an Azure Monitor platform characteristic, not an Arbitex issue. The connector logs a debug message for each successful batch send — use these to confirm delivery before querying Sentinel.

Each entry in SENTINEL_DEAD_LETTER_PATH includes the OCSF event, error description, connector ID, and timestamp:

{
"event": { ... },
"error": "Azure AD token acquisition failed: HTTP 401",
"connector": "sentinel",
"timestamp": 1741737600.0
}

Dead letter events are not automatically replayed. Resolve the root cause and reingest manually if needed.