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.
Prerequisites
Section titled “Prerequisites”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
Azure AD app registration
Section titled “Azure AD app registration”The connector authenticates using the OAuth 2.0 client credentials flow. Create a dedicated app registration for Arbitex:
- In the Azure portal, go to Microsoft Entra ID → App registrations → New registration.
- Name the app (e.g.
arbitex-sentinel-ingest) and click Register. - Note the Application (client) ID and Directory (tenant) ID.
- 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:
- In the Azure portal, navigate to your Data Collection Rule.
- Go to Access control (IAM) → Add role assignment.
- Select the role Monitoring Metrics Publisher.
- Assign it to your
arbitex-sentinel-ingestapp registration.
Create a DCR and custom table
Section titled “Create a DCR and custom table”Sentinel uses a DCR to define the schema and destination for incoming custom log data.
- In the Azure portal, go to Log Analytics workspace → Tables → Create → New custom log (DCR-based).
- 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. - Create or select a Data Collection Endpoint for the DCR.
- Note the DCR Immutable ID (shown on the DCR overview page, format:
dcr-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx). - Note the DCE Logs Ingestion URL (format:
https://{dce-name}.{region}.ingest.monitor.azure.com). - Note the Stream Name configured in the DCR (default used by Arbitex:
Custom-ArbitexOCSF_CL).
Configuration
Section titled “Configuration”Configure the connector using environment variables on the Arbitex platform deployment.
| Variable | Required | Default | Description |
|---|---|---|---|
SENTINEL_TENANT_ID | Yes | — | Azure AD tenant (directory) ID |
SENTINEL_CLIENT_ID | Yes | — | Azure AD application (client) ID |
SENTINEL_CLIENT_SECRET | Yes | — | Azure AD client secret value |
SENTINEL_DCE_ENDPOINT | Yes | — | Data Collection Endpoint URL |
SENTINEL_DCR_IMMUTABLE_ID | Yes | — | DCR immutable ID |
SENTINEL_STREAM_NAME | No | Custom-ArbitexOCSF_CL | DCR stream name |
SENTINEL_BATCH_SIZE | No | 100 | Maximum events per batch send |
SENTINEL_FLUSH_INTERVAL | No | 5 | Maximum seconds between batch flushes |
SENTINEL_MAX_RETRIES | No | 3 | Maximum retry attempts on transient failures |
SENTINEL_DEAD_LETTER_PATH | No | /var/log/arbitex/sentinel_dead_letter.jsonl | Path for the dead letter queue file |
Example configuration
Section titled “Example configuration”SENTINEL_TENANT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxSENTINEL_CLIENT_ID=yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyySENTINEL_CLIENT_SECRET=<secret-value>SENTINEL_DCE_ENDPOINT=https://arbitex-ingest-xxxx.eastus-1.ingest.monitor.azure.comSENTINEL_DCR_IMMUTABLE_ID=dcr-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxSENTINEL_STREAM_NAME=Custom-ArbitexOCSF_CLAuthentication
Section titled “Authentication”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/tokenThe connector health check validates credentials by attempting token acquisition — if this succeeds, the connector is marked healthy.
Event format
Section titled “Event format”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-01Authorization: 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.
Event types streamed
Section titled “Event types streamed”| OCSF class | class_uid | Description |
|---|---|---|
| API Activity | 6003 | Every request processed through the gateway |
| Security Finding | 2001 | DLP trigger events |
| Authentication | 3002 | Login, token exchange, SSO events |
| Account Change | 3001 | User and group lifecycle events |
Delivery behavior
Section titled “Delivery behavior”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.
Verification
Section titled “Verification”Check connector health
Section titled “Check connector health”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 }}Query events in Sentinel
Section titled “Query events in Sentinel”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 20To 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 timechartNote: 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).
Troubleshooting
Section titled “Troubleshooting”status: not_configured
Section titled “status: not_configured”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:
kubectl logs -n arbitex -l app=arbitex-platform --tail=200 | grep -i sentinelHTTP 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).
Ingestion latency
Section titled “Ingestion latency”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.
Events in dead letter queue
Section titled “Events in dead letter queue”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.