SIEM Integration
IdentityMesh’s compliance and operational signals are designed to flow into a SIEM without code changes. This document maps every emitted surface to where your SIEM picks it up, with concrete ingest recipes for the common platforms and sample detection queries to start with.
If your SIEM isn’t listed below: it almost certainly has a file / Windows Event Log / OTLP / database connector that fits one of the patterns here. The IdentityMesh side is already producing the data — pick the surface that matches your SIEM’s strengths.
Emitted surfaces — the field map
1. Application log files
| Component | File path | Format |
|---|---|---|
| Admin API | <install dir>\logs\identitymesh-api-YYYYMMDD.log | Serilog rolling, daily, 30-day retain, JSON-friendly text template |
| Sync Engine | <install dir>\logs\identitymesh-YYYYMMDD.log | Same template |
| Relay Agent | <install dir>\logs\identitymesh-relay-YYYYMMDD.log | Same template |
Per-line shape (one example):
2026-04-25 11:32:18.421 +00:00 [INF] [12] {RequestId} {RequestPath} permission=connectors.write granted to alice@corp
The interesting fields enriched by Serilog scopes:
| Field | Meaning |
|---|---|
RequestId | ASP.NET Core trace identifier — pivots to/from IM_AdminAudit.CorrelationId |
ConnectionId | Kestrel connection |
RequestPath | Concrete URL |
RequestMethod | HTTP verb |
StatusCode | Final response status |
Elapsed | Request duration ms |
SourceContext | Logger category — identifies the producing component |
MachineName | Stamped via Enrich.WithMachineName() |
ThreadId | Stamped via Enrich.WithThreadId() |
CycleId, InstanceName | Sync engine — present on every line during a connector run |
To switch from the default text template to JSON for easier
SIEM parsing, swap the Console/File Serilog sink config:
"WriteTo": [
{
"Name": "File",
"Args": {
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact",
"path": "logs/identitymesh-api-.log",
"rollingInterval": "Day",
"retainedFileCountLimit": 30
}
}
]
The package Serilog.Formatting.Compact is already a transitive
dependency; no new install needed.
2. Windows Event Log
Warning+ Serilog events are also written to the Windows Event Log on each host:
| Component | EventLog channel | Source name |
|---|---|---|
| Admin API | Application | IdentityMesh.Admin.Api |
| Sync Engine | Application | IdentityMesh |
| Relay Agent | Application | IdentityMesh.Relay.Agent |
Configured via Serilog.Sinks.EventLog with
restrictedToMinimumLevel: Warning so the Event Log gets the
“something requires attention” subset, not every INFO line.
3. Audit tables (SQL)
Two append-only tables holding compliance-grade evidence. Either
poll directly via your SIEM’s database connector or proxy through
the REST endpoints (which are gated on audit.read).
IM_ObjectAudit — identity-data changes
| Column | Type | Meaning |
|---|---|---|
AuditId | bigint | Surrogate key, monotonic |
MeshObjectId | uniqueidentifier | Affected mesh object |
CSObjectId | uniqueidentifier | Connector-space object id (or 00000000-… for non-CS changes) |
ChangeType | nvarchar(50) | Create / RefreshAttributes / Link / connector change types |
Source | nvarchar(200) | Connector name or JoinEngine for join-time mutations |
ChangeJson | nvarchar(max) | Mutation payload (object type, attributes, etc.) |
ChangedOn | datetime2 | UTC |
ActorUpn | nvarchar(256) | UPN (or instance name on engine-initiated rows) |
ActorSid | nvarchar(128) | Windows SID or Entra oid |
ActorSource | nvarchar(32) | Api / Engine / Relay / System |
REST equivalent: GET /api/audit?meshObjectId=…&since=…&take=…
(filtered) or GET /api/audit/by-object/{meshObjectId} (all
history for one object).
IM_AdminAudit — admin-surface mutations
| Column | Type | Meaning |
|---|---|---|
AuditId | bigint | Surrogate key |
WhenUtc | datetime2 | UTC |
ActorUpn | nvarchar(256) | UPN |
ActorSid | nvarchar(128) | Windows SID or Entra oid |
Action | nvarchar(200) | HTTP method + route template (e.g. POST /api/connectors) |
TargetKind | nvarchar(64) | Stable name of target type (Connector, Role, …) — populated for high-value mutations |
TargetId | nvarchar(128) | Specific id (GUID, role name) extracted from route values |
StatusCode | int | HTTP response status — denied 403s recorded too |
CorrelationId | nvarchar(128) | Pivots to/from log RequestId |
BeforeJson | nvarchar(max) | Pre-mutation snapshot for high-value handlers (sensitive fields scrubbed) |
AfterJson | nvarchar(max) | Post-mutation snapshot |
REST equivalent: GET /api/admin-audit with filters for
actorUpn, targetKind, targetId, sinceUtc, untilUtc,
paged via skip / take.
Indexes for SIEM polling:
IX_IM_AdminAudit_WhenUtc— descending, perfect for “give me the last N events since timestamp X.”IX_IM_AdminAudit_ActorUpn_WhenUtc— actor-scoped queries.IX_IM_AdminAudit_Target— incident triage (“everything that touched connector X yesterday”).
Retention is governed by license tier (see
audit-retention.md). Don’t size your SIEM
ingest assuming infinite back-history — a Standard-tier deployment
keeps 30 days, Enterprise keeps unlimited.
4. Metrics — OpenTelemetry
When Telemetry:Otlp:Enabled is true, both the Admin API and the
Sync Engine emit OTLP metrics + traces to the configured exporter.
Counters worth alerting on:
| Metric | Meter | What it tells you |
|---|---|---|
identitymesh.runs.failed | IdentityMesh.Engine | Sync run failures (with connector_type, outcome tags) |
identitymesh.exports.objects{outcome="Failed"} | same | Per-object export failures |
identitymesh.license.fallbacks | same | License → Starter trial fallback (reason tag) |
identitymesh.audit.purged | same | Retention sweep volume (per table tag) — sudden spike → investigate |
These flow to whatever your OTel Collector forwards them to — Datadog, Honeycomb, Grafana Cloud, Azure Monitor.
Per-SIEM ingestion recipes
Splunk
Pattern: Universal Forwarder → log files + Windows Event Log → HEC / indexers.
# inputs.conf on each IdentityMesh host
[monitor://C:\Program Files\IdentityMesh\logs\*.log]
sourcetype = identitymesh:json # if you flipped to CompactJsonFormatter
disabled = false
index = identitymesh
[monitor://C:\Program Files\IdentityMeshRelayAgent\logs\*.log]
sourcetype = identitymesh:relay
index = identitymesh
[WinEventLog://Application]
disabled = false
whitelist = IdentityMesh.Admin.Api,IdentityMesh,IdentityMesh.Relay.Agent
index = identitymesh
For the audit tables: a dbx database connector polling
IM_AdminAudit filtered by WhenUtc > "@last_seen".
Microsoft Sentinel
Pattern: Azure Monitor Agent (AMA) → Data Collection Rule (DCR) → Log Analytics custom table.
- Install AMA on each IdentityMesh host (Admin API, Sync Engine, each Relay).
- Author a DCR pointing at
C:\Program Files\IdentityMesh\logs\*.log(file-based) and theApplicationevent log filtered to the three IdentityMesh sources. - The audit tables flow via SQL data connector — Sentinel
workbook polls
IM_AdminAuditdirectly.
A future direct-Logs-Ingestion-API mode is on the roadmap so AMA isn’t required.
Elastic / Logstash
Pattern: Filebeat → log files + Winlogbeat → Event Log → Logstash → Elasticsearch.
# filebeat.yml
filebeat.inputs:
- type: filestream
paths:
- C:\Program Files\IdentityMesh\logs\*.log
parsers:
- ndjson:
target: "" # if CompactJson formatter
add_error_key: true
fields:
app: identitymesh
component: admin-api
# winlogbeat.yml
winlogbeat.event_logs:
- name: Application
providers:
- IdentityMesh.Admin.Api
- IdentityMesh
- IdentityMesh.Relay.Agent
Audit tables: standard JDBC input plugin polling IM_AdminAudit.
Datadog
Pattern: Datadog Agent on each host → log file + Windows Event Log integrations → Datadog.
# C:\ProgramData\Datadog\conf.d\identitymesh.d\conf.yaml
logs:
- type: file
path: C:\Program Files\IdentityMesh\logs\*.log
service: identitymesh-admin-api
source: csharp
- type: windows_event
channel_path: Application
source: windows.event_log
service: identitymesh
log_processing_rules:
- type: include_at_match
name: identitymesh_only
pattern: '^IdentityMesh'
Metrics flow via OTLP to the Datadog Agent if you’ve enabled the OTLP receiver. The audit tables ride a SQL Server integration.
Sample detection queries
Examples that work against IM_AdminAudit directly. Translate to
your SIEM’s query language as needed; the field names are stable.
-- "Privilege escalation" — role mutations grouped by actor
SELECT ActorUpn, COUNT(*) AS RoleEdits, MIN(WhenUtc) AS First, MAX(WhenUtc) AS Last
FROM dbo.IM_AdminAudit
WHERE WhenUtc > DATEADD(DAY, -7, SYSUTCDATETIME())
AND Action LIKE '%/api/roles/%'
GROUP BY ActorUpn
ORDER BY RoleEdits DESC;
-- "Connector deletes" — high-blast-radius operations
SELECT WhenUtc, ActorUpn, TargetId, StatusCode
FROM dbo.IM_AdminAudit
WHERE Action = 'DELETE /api/connectors/{id}'
ORDER BY WhenUtc DESC;
-- "Off-hours admin activity"
SELECT WhenUtc, ActorUpn, Action, TargetKind, TargetId
FROM dbo.IM_AdminAudit
WHERE Action LIKE '%/api/%'
AND Action NOT LIKE 'GET %'
AND (DATEPART(WEEKDAY, WhenUtc) IN (1, 7)
OR DATEPART(HOUR, WhenUtc) NOT BETWEEN 7 AND 19)
ORDER BY WhenUtc DESC;
-- "Denied admin attempts" — who tried and got blocked
SELECT WhenUtc, ActorUpn, Action, TargetId, StatusCode
FROM dbo.IM_AdminAudit
WHERE StatusCode IN (401, 403)
AND WhenUtc > DATEADD(DAY, -1, SYSUTCDATETIME())
ORDER BY WhenUtc DESC;
-- "License upload events" — every license rotation
SELECT WhenUtc, ActorUpn, StatusCode, CorrelationId
FROM dbo.IM_AdminAudit
WHERE Action = 'POST /api/license/upload'
ORDER BY WhenUtc DESC;
For IM_ObjectAudit (identity-data changes):
-- "Mass mesh-object deletion" — single actor / engine instance
-- removing more than 100 objects in 5 minutes.
SELECT ActorUpn, ActorSource, COUNT(*) AS Deletes,
MIN(ChangedOn) AS First, MAX(ChangedOn) AS Last
FROM dbo.IM_ObjectAudit
WHERE ChangeType = 'Delete'
AND ChangedOn > DATEADD(MINUTE, -5, SYSUTCDATETIME())
GROUP BY ActorUpn, ActorSource
HAVING COUNT(*) > 100;
Operational notes
- Time zones: every timestamp emitted by IdentityMesh is UTC. Your SIEM is responsible for any local-time presentation.
- Correlation across surfaces:
IM_AdminAudit.CorrelationIdmatches the SerilogRequestIdfor the same request. Searching for one in your log index will surface the other. - PII:
ActorUpnis identifying.IM_ObjectAudit.ChangeJsonmay contain mesh-attribute values that include PII (display names, emails, group memberships). If your SIEM ingest is cross-region, treat the audit feeds as personal data per your privacy policy. - Volume sizing: a 100k-mesh-object connector with hourly
syncs typically writes 50–200k
IM_ObjectAuditrows/day at steady state, dominated by attribute refreshes.IM_AdminAuditis operator-traffic-bound — usually a few hundred rows/day. - Log retention: in-DB audit retention is governed by
audit-retention.md. Log files retain 30 days by default. Configure your SIEM cold storage accordingly.
Related
audit-retention.md— how long the audit tables are kept.authentication.md— actor-claim shapes for theActorUpn/ActorSidcolumns under Negotiate vs JwtBearer.