Skip to content

SIEM Integration — Microsoft Sentinel

The SIEMDirectSink feature (outpost-0008-siem-parity) allows Arbitex Hybrid Outpost to stream audit events directly to Microsoft Sentinel without routing traffic through Arbitex Cloud. Events are delivered via the Azure Monitor Logs Ingestion API (DCR-based) using client credentials authentication, batching, and automatic retry with dead letter fallback.

This guide applies to Outpost deployments only. For Cloud-managed SIEM forwarding see SIEM integration.


Before configuring the Outpost sink, ensure the following are in place:

  • Arbitex Hybrid Outpost version 1.8.0 or later deployed and registered to your organization
  • An Azure subscription with Microsoft Sentinel enabled on a Log Analytics workspace
  • An Azure AD App Registration for Outpost to authenticate with Azure Monitor (created in Step 3)
  • A Data Collection Endpoint (DCE) in the same Azure region as the Log Analytics workspace
  • A Data Collection Rule (DCR) with a custom stream targeting a ArbitexAuditLogs_CL custom table
  • The Monitoring Metrics Publisher role assigned to the App Registration on the DCR resource
  • Network connectivity from the Outpost host to the DCE ingestion endpoint (HTTPS/443)

Step 1: Create the Log Analytics workspace and enable Sentinel

Section titled “Step 1: Create the Log Analytics workspace and enable Sentinel”

If you already have a workspace with Sentinel enabled, skip to Step 2.

  1. In the Azure Portal, search for Log Analytics workspaces and click Create.
  2. Select your Subscription and Resource Group.
  3. Set a Name (e.g., arbitex-siem-workspace) and Region.
  4. Click Review + Create, then Create.
  5. After the workspace is provisioned, search for Microsoft Sentinel and click Create.
  6. Select the workspace created above and click Add.

2.1 Create a Data Collection Endpoint (DCE)

Section titled “2.1 Create a Data Collection Endpoint (DCE)”

The DCE is the HTTPS endpoint the Outpost sink posts events to.

  1. In the Azure Portal, search for Data Collection Endpoints and click Create.

  2. Set Name to arbitex-outpost-dce.

  3. Select the same Region as your Log Analytics workspace.

  4. Click Review + Create, then Create.

  5. After creation, open the DCE resource and copy the Logs Ingestion URL from the Overview tab. It looks like:

    https://arbitex-outpost-dce-xxxx.region.ingest.monitor.azure.com

    This value becomes SENTINEL_DCE_URL.

The Logs Ingestion API requires a destination table in your Log Analytics workspace.

  1. In the Azure Portal, open your Log Analytics workspace.
  2. Go to Tables and click Create → New custom log (DCR-based).
  3. Set Table name to ArbitexAuditLogs_CL.
  4. Under Schema, define the following columns (type as shown):
Column nameTypeDescription
TimeGenerateddatetimeEvent timestamp (ISO 8601) — required by Log Analytics
UserIdstringUUID of the acting user
ActionstringAudit action (e.g., chat_completion, policy_block)
ConversationIdstringUUID of the conversation
ModelIdstringModel identifier (e.g., claude-sonnet-4-6)
ProviderstringAI provider name
PromptTextstringPrompt content, may be [REDACTED]
ResponseTextstringResponse content, may be [REDACTED]
TokenCountInputintInput token count
TokenCountOutputintOutput token count
CostEstimaterealEstimated cost in USD
LatencyMsintEnd-to-end latency in milliseconds
TenantIdstringArbitex organization/tenant UUID
HmacstringHMAC of this event (chain integrity)
PreviousHmacstringHMAC of the previous event in the chain
HmacKeyIdstringKey ID used to compute the HMAC
MetadatadynamicAdditional key-value metadata from the event
  1. Complete the wizard. Azure creates the table and its backing DCR.
  1. In the Azure Portal, search for Data Collection Rules and click Create.

  2. Set Rule Name to arbitex-outpost-dcr.

  3. Select the same Subscription, Resource Group, and Region as the workspace.

  4. On Data Sources, add a Custom logs (DCR-based) source.

    • Stream name: Custom-ArbitexAuditLogs (this becomes SENTINEL_STREAM_NAME)
  5. On Destinations, select your Log Analytics workspace and target table ArbitexAuditLogs_CL.

  6. Associate the DCE created in Step 2.1 with this rule.

  7. Click Review + Create, then Create.

  8. After creation, open the DCR resource and copy the Immutable ID from the Overview tab. It looks like:

    dcr-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4

    This value becomes SENTINEL_DCR_RULE_ID.


Step 3: Configure App Registration and permissions

Section titled “Step 3: Configure App Registration and permissions”

The Outpost sink authenticates to Azure Monitor using an Azure AD App Registration via the client credentials (service principal) flow.

  1. In the Azure Portal, go to Azure Active Directory → App registrations → New registration.
  2. Set Name to arbitex-outpost-siem.
  3. Set Supported account types to Accounts in this organizational directory only.
  4. Click Register.
  5. Copy the Application (client) ID — this becomes AZURE_CLIENT_ID.
  6. Copy the Directory (tenant) ID — this becomes AZURE_TENANT_ID.
  1. In the App Registration, go to Certificates & secrets → New client secret.

  2. Set a Description (e.g., arbitex-outpost-siem-secret) and an Expiry (maximum 24 months recommended; set a reminder to rotate before expiry).

  3. Click Add and immediately copy the Value — this becomes AZURE_CLIENT_SECRET.

    The secret value is shown only once. Store it in your secrets manager immediately.

3.3 Assign Monitoring Metrics Publisher role

Section titled “3.3 Assign Monitoring Metrics Publisher role”

The App Registration requires the Monitoring Metrics Publisher role on the DCR resource to post events via the Logs Ingestion API.

  1. Open the Data Collection Rule resource created in Step 2.3.
  2. Go to Access control (IAM) → Add role assignment.
  3. Search for and select Monitoring Metrics Publisher.
  4. On the Members tab, select User, group, or service principal and search for arbitex-outpost-siem.
  5. Click Review + assign.

Set the following environment variables on your Outpost deployment (via .env file, Kubernetes Secret, or your secrets manager of choice):

VariableRequiredDefaultDescription
SIEM_SINKYesSet to sentinel to activate the Sentinel sink
SENTINEL_WORKSPACE_IDYesLog Analytics workspace ID (from workspace Overview)
SENTINEL_DCE_URLYesDCE Logs Ingestion URL copied in Step 2.1
SENTINEL_DCR_RULE_IDYesDCR immutable ID copied in Step 2.3 (begins with dcr-)
SENTINEL_STREAM_NAMENoCustom-ArbitexAuditLogsDCR stream name defined in Step 2.3
AZURE_TENANT_IDYesAzure AD tenant ID from Step 3.1
AZURE_CLIENT_IDYesApp Registration client ID from Step 3.1
AZURE_CLIENT_SECRETYesClient secret value from Step 3.2
SIEM_BATCH_SIZENo100Maximum events per ingestion request
SIEM_FLUSH_INTERVAL_SECONDSNo10Maximum seconds between batch flushes
Terminal window
SIEM_SINK=sentinel
SENTINEL_WORKSPACE_ID=a1b2c3d4-0001-0001-0001-000000000001
SENTINEL_DCE_URL=https://arbitex-outpost-dce-xxxx.eastus.ingest.monitor.azure.com
SENTINEL_DCR_RULE_ID=dcr-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4
SENTINEL_STREAM_NAME=Custom-ArbitexAuditLogs
AZURE_TENANT_ID=a1b2c3d4-0002-0002-0002-000000000002
AZURE_CLIENT_ID=a1b2c3d4-0003-0003-0003-000000000003
AZURE_CLIENT_SECRET=<your-client-secret>
apiVersion: v1
kind: Secret
metadata:
name: arbitex-outpost-siem
namespace: arbitex
type: Opaque
stringData:
SIEM_SINK: "sentinel"
SENTINEL_WORKSPACE_ID: "a1b2c3d4-0001-0001-0001-000000000001"
SENTINEL_DCE_URL: "https://arbitex-outpost-dce-xxxx.eastus.ingest.monitor.azure.com"
SENTINEL_DCR_RULE_ID: "dcr-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4"
SENTINEL_STREAM_NAME: "Custom-ArbitexAuditLogs"
AZURE_TENANT_ID: "a1b2c3d4-0002-0002-0002-000000000002"
AZURE_CLIENT_ID: "a1b2c3d4-0003-0003-0003-000000000003"
AZURE_CLIENT_SECRET: "<your-client-secret>"
SIEM_BATCH_SIZE: "100"
SIEM_FLUSH_INTERVAL_SECONDS: "10"

Reference the secret in your Outpost Deployment’s envFrom:

envFrom:
- secretRef:
name: arbitex-outpost-siem

On startup, the Outpost sink acquires an Azure AD bearer token using the client credentials flow against the https://monitor.azure.com/.default scope. The token is cached until expiry minus a 60-second safety margin, at which point it is refreshed automatically without dropping events. If token acquisition fails (invalid secret, revoked app, missing role), the sink logs an ERROR and continues buffering events. Events buffer in memory up to the next retry window; batches that cannot be delivered after 3 attempts are written to the dead letter file.


The Outpost sink serializes each Arbitex audit event to a JSON object matching the ArbitexAuditLogs_CL table schema. Events are posted as a JSON array to the DCE endpoint.

[
{
"TimeGenerated": "2026-03-07T12:00:00.000Z",
"UserId": "a1b2c3d4-0001-0001-0001-000000000001",
"Action": "chat_completion",
"ConversationId": "conv_01HZ_EXAMPLE",
"ModelId": "claude-sonnet-4-6",
"Provider": "anthropic",
"PromptText": "[REDACTED]",
"ResponseText": "[REDACTED]",
"TokenCountInput": 312,
"TokenCountOutput": 847,
"CostEstimate": 0.0024,
"LatencyMs": 1840,
"TenantId": "org_acme",
"Hmac": "sha256:3f2a1b...",
"PreviousHmac": "sha256:7c4e9d...",
"HmacKeyId": "key_2026_03",
"Metadata": {
"client_ip": "10.0.1.42",
"user_agent": "arbitex-sdk/2.1.0"
}
}
]

Field notes:

  • TimeGenerated must be in ISO 8601 format. Azure Monitor uses this field as the canonical event timestamp for Log Analytics queries and Sentinel analytics rules.
  • PromptText and ResponseText are redacted at the Outpost level if the DLP Output Redaction policy is active. The literal string [REDACTED] appears in place of the original text.
  • Hmac, PreviousHmac, and HmacKeyId are chain integrity fields. Each event’s PreviousHmac must equal the Hmac of the immediately preceding event for the same tenant. See Audit log verification for the full validation procedure.
  • Metadata is a dynamic column in Log Analytics, queryable with parse_json() in KQL.

After Outpost restarts with the new configuration, use these queries in the Sentinel Logs blade to confirm events are flowing.

ArbitexAuditLogs_CL
| where TimeGenerated > ago(30m)
| project TimeGenerated, UserId, Action, ModelId, TenantId
| take 20

Event volume by action type (last 24 hours)

Section titled “Event volume by action type (last 24 hours)”
ArbitexAuditLogs_CL
| where TimeGenerated > ago(24h)
| summarize EventCount = count() by Action
| order by EventCount desc

Policy blocks and DLP triggers (last 7 days)

Section titled “Policy blocks and DLP triggers (last 7 days)”
ArbitexAuditLogs_CL
| where TimeGenerated > ago(7d)
| where Action in ("policy_block", "dlp_trigger", "dlp_redaction")
| project TimeGenerated, UserId, Action, ConversationId, TenantId
| order by TimeGenerated desc
ArbitexAuditLogs_CL
| where TimeGenerated > ago(24h)
| where Action == "chat_completion"
| top 20 by CostEstimate desc
| project TimeGenerated, UserId, ModelId, TokenCountInput, TokenCountOutput, CostEstimate, LatencyMs
ArbitexAuditLogs_CL
| where TimeGenerated > ago(1h)
| where TenantId == "org_acme"
| project TimeGenerated, Hmac, PreviousHmac, HmacKeyId
| order by TimeGenerated asc

Verify that each row’s PreviousHmac matches the Hmac from the row immediately above it. Gaps indicate dropped events; mismatches indicate tampering or replay. For automated chain validation see Audit log verification.


After restarting Outpost with the new environment variables, send a synthetic test event using the Arbitex admin API:

Terminal window
curl -X POST https://api.arbitex.ai/api/admin/siem/test/sentinel \
-H "Authorization: Bearer arb_live_your-admin-api-key"

The response confirms whether the test event was accepted:

{
"connector": "sentinel",
"status": "ok",
"message": "Test event delivered. Check ArbitexAuditLogs_CL for Action: siem_test_event."
}

Then confirm in the Sentinel Logs blade:

ArbitexAuditLogs_CL
| where TimeGenerated > ago(10m)
| where Action == "siem_test_event"
| project TimeGenerated, Action, TenantId

Log Analytics ingestion latency is typically 30–90 seconds. If the query returns no results immediately, wait 2 minutes and retry before investigating.

If the test event does not appear after 5 minutes:

  1. Check the Outpost container logs for [siem] log lines. Azure AD token errors appear as ERROR [siem] token acquisition failed with the Azure error code.
  2. Verify the App Registration client secret has not expired: check Azure AD → App registrations → arbitex-outpost-siem → Certificates & secrets.
  3. Confirm the Monitoring Metrics Publisher role assignment is present on the DCR resource (not the workspace — this is a common misconfiguration).
  4. Test DCE reachability from the Outpost host: curl -v https://<dce-endpoint>.ingest.monitor.azure.com
  5. Inspect the dead letter file: /var/log/arbitex/sentinel_dead_letter.jsonl.

When all retry attempts for a batch are exhausted, events are written to /var/log/arbitex/sentinel_dead_letter.jsonl. Each line is a self-contained JSON object:

{
"event": { "TimeGenerated": "2026-03-07T12:00:00.000Z", "Action": "chat_completion", "...": "..." },
"error": "HTTP 403: Forbidden — Missing Monitoring Metrics Publisher role",
"connector": "sentinel",
"timestamp": 1741564800.0
}

To replay dead letter events after the issue is resolved, re-acquire a bearer token and post each event array to the DCE endpoint:

Terminal window
# Acquire a token (requires azure-cli or equivalent)
TOKEN=$(az account get-access-token --resource https://monitor.azure.com \
--query accessToken -o tsv)
jq -c '[.event]' /var/log/arbitex/sentinel_dead_letter.jsonl | while read -r batch; do
curl -s -X POST "${SENTINEL_DCE_URL}/dataCollectionRules/${SENTINEL_DCR_RULE_ID}/streams/${SENTINEL_STREAM_NAME}?api-version=2023-01-01" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d "$batch"
done

Contact Arbitex support for assisted bulk recovery if the dead letter file is large.