Skip to main content

Syslog forwarding

Forward every audit event to a SIEM as RFC 5424 syslog over UDP, TCP, or TCP+TLS. Delivery is queued in MongoDB and retried with exponential backoff, so a receiver outage doesn't drop events. This page is the deep dive behind the audit page's syslog summary.

What gets forwarded

Audit events only — the same entries that appear in Audit & SIEM. When the forwarder is enabled, each new audit entry is written with a syslog_status: pending marker at creation; a background forwarder picks pending entries up and ships them. Two consequences:

  • The local audit record is always persisted first — syslog problems never lose or block audit writes.
  • Forwarding is not retroactive: only events created while syslog is enabled are sent. Enabling it does not replay history.

Message format

The only wire format is RFC 5424 — there is no CEF, RFC 3164, or JSON option.

<134>1 2026-06-25T12:34:56.789012Z cap-backend-1 certautopilot - - [audit@certautopilot audit_id="665f..." org_id="org-1" action="CERTIFICATE_ISSUED" actor="alex@example.com" resource_type="certificate" resource_id="9b2e..." outcome="success"]
PartValue
PRIfixed <134> — facility 16 (local0), severity 6 (info)
VERSION1
TIMESTAMPRFC 3339 with nanoseconds, UTC
HOSTNAMEbackend host / pod name (resolved at process start, - if unknown)
APP-NAMEcertautopilot
PROCID / MSGID- (unused)
STRUCTURED-DATAone SD element, [audit@certautopilot ...]

Structured-data keys:

KeyContent
audit_idAudit entry ID — join back to the local log
org_idOrganization
actionAudit action, e.g. CERTIFICATE_ISSUED (truncated at 64 chars)
actorActor name — user email, or system
resource_typee.g. certificate, settings
resource_idResource identifier (truncated at 128 chars)
outcomefailure for actions ending _FAILED / _DEAD, cancelled for _CANCELLED, else success

Values are quoted with Go-style escaping (JSON-like), and truncation keeps messages within safe UDP bounds.

Settings

Settings → Syslog. Viewing requires the admin org role; saving and testing additionally require an Enterprise license (syslog feature — the page shows a locked state otherwise). Config lives in the settings collection under syslog_config.

Field (JSON)UI labelDefault / rangeNotes
enabledEnableoffMaster switch for the forwarder.
protocolProtocoludp, tcp, or tcp+tls.
hostHostReceiver hostname / IP (also the TLS SNI + verification name).
portPort514 (1–65535)
max_attemptsMax Retry Attempts10 (1–100)Per event, before it's abandoned as dead.
lock_timeoutLock Timeout (seconds)120 (30–3600)How long a replica may hold an in-flight event before another reclaims it.
ca_certCA CertificatePEM; only shown for tcp+tls.
client_certClient CertificatePEM; enables mTLS. Must be paired with the key.
client_keyClient KeyPEM; both-or-neither with the client cert.

The three TLS fields are envelope-encrypted at rest and never returned to the browser — responses carry has_ca_cert / has_client_cert / has_client_key booleans, and leaving a field blank on save keeps the stored value.

Config changes are picked up by running forwarders automatically (the config is re-read about once a minute) — no restart needed.

Transports & TLS

  • udp — fire-and-forget datagrams; no delivery signal beyond the local send.
  • tcp — persistent connection, 10-second connect timeout, 10-second write deadline per message; the connection is closed and re-established after a failed send.
  • tcp+tls — as TCP, plus TLS with minimum version 1.2 and server-name verification against Host. A pasted CA certificate is used to verify private receivers; supplying a client cert + key turns on mutual TLS.

Delivery semantics

Queued, at-least-once, bounded:

  • Each audit entry tracks its own state: pending → sending → sent, or dead after max_attempts failures. Dead entries stay in MongoDB with the last error for forensics — they are never silently discarded, but they are not retried further.
  • The forwarder polls every 2 seconds, claims up to 50 pending entries per cycle in FIFO order, and marks each sent on success.
  • Failures are retried with exponential backoff — 5 s, 30 s, 2 min, 10 min, then hourly (±20% jitter) — until max_attempts is reached. A SIEM outage therefore delays events rather than losing them (size max_attempts to cover your worst outage: the default 10 attempts spans roughly 6–7 hours).
  • Multi-replica safe: entries are claimed with a per-pod lock, so only one replica sends a given event. If a replica dies mid-send, its claim expires after lock_timeout and another replica retries — in that crash window the receiver may see a duplicate (use audit_id to de-duplicate downstream).

Test the connection

The Test Connection button (POST /settings/syslog/test) opens a dedicated one-off connection with the values currently in the form (falling back to stored TLS material where fields are blank) and sends a single test event with action="SYSLOG_TEST". Success or the transport/TLS error is reported inline; the test itself is audit-logged as SYSLOG_CONNECTION_TESTED.

UDP tests prove little

A UDP "success" only means the datagram left the host — there is no acknowledgement. Confirm arrival in the SIEM. TCP/TLS tests genuinely validate connectivity and the handshake.

Troubleshooting

Nothing arrives at the SIEM

Check, in order: the Enable switch is on; the license includes syslog; the test button succeeds; and the events you expect were created after enabling (no retroactive replay). For TCP+TLS, a wrong CA or hostname mismatch fails the handshake — the test surfaces the exact TLS error.

Events arrive in bursts, minutes late

That's backoff draining after a receiver outage — entries queued as pending and are being retried on the 5 s → hourly schedule. Expected; nothing to fix once the receiver is stable.

Some events never arrived

They likely exhausted max_attempts during a long outage and are marked dead (with the last error) on the audit entries. Raise Max Retry Attempts to widen the tolerance window; dead entries are not re-sent automatically.

Duplicate events in the SIEM

A replica crashed between sending and acknowledging; the entry was reclaimed after lock_timeout and re-sent. De-duplicate on the audit_id structured-data key.

See also