Security event export
This page preserves the merged Next documentation snapshot at e1ddcf6940adb7b619ce509063749e740eecc795. It can describe implementation beyond the source revision selected for the rebuilt Next guides. Retain the implementation-scope notes below and confirm your deployed version before applying these details. This is not a current-release availability or deployment claim. For the task-based entry point, see the rebuilt guide.
The transaction fields and explicit security-event tagging described below refer to platform PR 554 (internal implementation reference), reviewed at commit 300e8a9956ada4ac628fd5fceda13855510a73b0. This scope note concerns explicit security tagging, not the separate direct-write audit-export fix in platform PR 551 (internal implementation reference). Confirm each implementation independently. These changes are not a statement that the current released platform or a customer deployment contains them. Confirm the deployed implementation before relying on these fields; source checks do not establish live ingestion or delivery.
Delphi marks the security-relevant events it emits so the observability stack can single them out and fan them out to an external SIEM. This page covers that marking — the contract, which component sets it for which event, and how to verify it. Routing those events onward to a destination is a separate concern; SigNoz operations inventories the collector container that does it.
The tag contract
Web audit events use recordKind: Audit in SigNoz, including security/access events and managed-resource changes. Check the Web coverage table against the deployed version: the VGWK-126 / SCRUM-801 fix adds export for previously DB-only Web paths such as password reset and platform-role changes. The export path fans those events out through the SigNoz / collector configuration on the observability host.
Two log attributes carry the marking:
| Attribute | Value |
|---|---|
security_event | true — a genuine boolean, on the log record's attributes |
security_category | one of authentication, authorization, audit, certificate |
Two details are load-bearing:
security_eventmust be the booleantrue. The export filter keeps a record only for the boolean after classification; a string"true"or the number1does not satisfy that filter by itself. Fallback classification may still mark a record from other fields or body text, so do not rely on stringly-typed values.security_categoryis a closed set of four values. It is the export vocabulary, and it is not the same thing as thecategoryattribute on an audit record — that one (AUTH,ROLE_MANAGEMENT,FLOW,NUMBER,SECURITY,SYSTEM) drives the Access logs UI and the audit row. Do not use one where the other belongs.
The four values live in one place in code — SECURITY_CATEGORIES in
packages/logger/src/security-classification.ts — and are pinned by a test against the literals in
the export collector config, so the two cannot drift apart.
Why the tag is needed
The export collector can classify a record from its text when no service tagged it, but that
fallback does not work for the platform's own audit events. An audit record's OTLP body is the bare
action name (LOGIN_FAILED, ACCESS_DENIED, ACCOUNT_LOCKED), and the fallback matches phrases
like "login failed" — which LOGIN_FAILED is not. Without the tag, essentially every security
audit event the platform produced was dropped by the export filter.
Who sets the tag
| Event source | How it is tagged |
|---|---|
| TelWeb, TelPhi, and the auth/API audit emitters | @delphi/logger stamps it in StructuredLogger.log(), so logSecurityEvent, logAuth, logLogout and logEntityChange all carry it |
| TelAPI | Call sites spread securityTagAttributes(...) onto a bare-pino log record — the error handler does this once for every thrown authentication/authorization error |
| TelPro (Kamailio) | transform/kamailio_promote in the host collector tags the four trunk-admission rejects below |
The tag rides both log routes. On the direct OTLP path it is a record attribute; on the stdout path
it travels inside the Pino envelope, which the host collector promotes for recordKind: Audit. One
event, one export.
Because the structured-logger seam sits on the whole audit surface, tagging is not limited to
failures: successful LOGIN, LOGOUT and SESSION_END sign-ins are access events and are exported
too. The audit category and the action decide what is a security event — CREATE / UPDATE /
DELETE on ordinary business objects are audited but deliberately not exported, so routine changes
do not dilute the security signal.
Which action maps to which category
packages/logger/src/security-classification.ts is the source of truth; this is its effect.
| Action | security_category |
|---|---|
LOGIN, LOGIN_FAILED, LOGOUT, SESSION_END, PASSWORD_CHANGE, PASSWORD_RESET_*, ACCOUNT_LOCKED, ACCOUNT_UNLOCKED | authentication |
REJECTED_CONNECTION, ACCESS_DENIED, PRIVILEGE_ESCALATION_ATTEMPT, PLATFORM_ROLE_CHANGE_*, PLATFORM_ROLE_SESSION_CLEANUP_FAILED, SUPER_ADMIN_RECOVERY_* | authorization |
SYSTEM_MANIPULATION_ATTEMPT, SECURITY_LOGS_ACCESSED, SECURITY_POLICY_MODIFIED | audit |
CREATE, UPDATE, DELETE | (not exported) |
An action that is not in that list is still exported, without a category, so a new action surfaces instead of disappearing. The audit log remains the authoritative record of what the platform logged.
TelPro: the trunk-admission rejects
TelPro's Kamailio emits four rejects as structured records, and the host collector tags them:
event | security_category | Reject |
|---|---|---|
trunk_identify_failed | certificate, or authorization when the message does not mention TLS or a peer name | Unknown trunk, or a TLS / peer-identity verification failure |
trunk_call_rejected | authentication | The trunk requires an X-Call-ID and it was invalid or missing (403 Forbidden) |
xcall_invalid | authentication | A Janus call's X-Call-ID had no entry, so it did not resolve |
xcall_missing | authentication | A Janus call arrived without an X-Call-ID at all |
trunk_identify_failed is one event name for two different situations — an access-control reject
and a transport-identity reject — so the category is decided from the message text.
Rejects that are not exported
Five further rejects in kamailio.cfg are written with xlog only. They are dropped before any
collector statement runs, so they cannot be tagged and do not reach the SIEM:
| Location | Reject |
|---|---|
kamailio.cfg:617 | Transfer from an unverified source (403) |
kamailio.cfg:646 | Transfer from an unverified source (403) |
kamailio.cfg:810 | Authentication misconfiguration (500) |
kamailio.cfg:816 | Source IP not authorized (403) |
kamailio.cfg:835 | Digest username mismatch (401) |
There is no BYE self-relay reject at all: the route that would classify one is defined and never called. Making these exportable means emitting them as structured records — a change to the voice application and its image, tracked separately.
Without destination credentials the export collector renders a nop pipeline and drops everything it
receives — classification never runs. A healthy collector container does not mean events are leaving
the deployment. Check the init script output for Export ENABLED before reading anything into a
lack of security events.
Verify the tag on a running deployment
- Provoke a known event. A failed sign-in or a request with a bad API key is the quickest.
- In SigNoz, find the record and confirm it carries
security_event = true— as a boolean, not a string — and thesecurity_categoryyou expect. - Note that the record body is still the bare action name (
LOGIN_FAILED). That is expected, and is exactly why the tag exists. - Confirm the event is delivered once: one record, with
log_transport = 'otlp_direct'andaudit.delivery_role = 'canonical'. - For TelPro, place a call from an unknown source and force a TLS peer-name mismatch. Expect
event = 'trunk_identify_failed'withsecurity_categoryofauthorizationandcertificaterespectively.
Verify forwarding separately
- Confirm SigNoz monitoring is healthy and receiving audit / access events.
- Enable the security-event export collector / fan-out configuration shipped with the SigNoz service.
- Provide destination credentials (API tokens, endpoints) for the external system.
- Follow the step-by-step audit verification with fresh failed-login, password-reset and role-change events. Verify each appears in SigNoz and in the external sink.
Export is best effort. A DB record alone does not prove external delivery, and enabling export does not backfill historical audit rows.
Related surfaces
| Surface | Use |
|---|---|
| Access logs | Super Admin UI for authentication and role-management events |
| Audit logging | What the platform records as an audit event |
| SigNoz monitoring | Investigate raw logs, traces, and dashboards |
| PII redaction | Controls what PII leaves the collector |
See also
- SigNoz operations — the collector container inventory, ports, and upgrade notes.
- Application and integration flow logging
- Environment variable index