Wazuh is an open source XDR and SIEM platform. Tenzir can forward events to Wazuh over Syslog and query Wazuh alerts from the Wazuh indexer API.
Configure Wazuh to receive Syslog
Section titled “Configure Wazuh to receive Syslog”Wazuh can receive Syslog messages on the Wazuh server with a <remote>
configuration in /var/ossec/etc/ossec.conf. For example, this configuration
accepts TCP Syslog from a Tenzir node at 10.0.0.5:
<ossec_config> <remote> <connection>syslog</connection> <port>514</port> <protocol>tcp</protocol> <allowed-ips>10.0.0.5</allowed-ips> <local_ip>0.0.0.0</local_ip> </remote></ossec_config>Restart the Wazuh manager after changing the configuration:
systemctl restart wazuh-managerSee Wazuh’s Syslog server documentation for the complete Wazuh configuration. For Wazuh Cloud, Wazuh documents a relay pattern where rsyslog or Logstash receives Syslog on an endpoint that runs a Wazuh agent.
Examples
Section titled “Examples”Send events to Wazuh over Syslog
Section titled “Send events to Wazuh over Syslog”Use to_tcp with write_syslog to forward events to the Wazuh
manager. This keeps Wazuh in the analysis path, so Wazuh decoders and rules can
process the event stream.
subscribe "detections"payload = this.print_json(strip_null_fields=true)hostname = "tenzir-node"app_name = "tenzir"message = payloadto_tcp "wazuh-manager.example.com:514" { write_syslog}Replace wazuh-manager.example.com with the Wazuh manager host. If Wazuh
listens on a different port, replace 514 with that port.
Wazuh alerting and dashboards depend on matching decoders and rules. When you send structured JSON in the Syslog message body, configure Wazuh’s JSON decoder or a custom decoder for the event shape that you forward from Tenzir.
Query Wazuh alerts from the indexer
Section titled “Query Wazuh alerts from the indexer”Wazuh stores alerts in wazuh-alerts-* indices and, when archives are enabled,
raw archived events in wazuh-archives-* indices. You can query these indices
through the Wazuh indexer API with from_http:
let $auth = f"{secret("WAZUH_INDEXER_USER")}:{secret("WAZUH_INDEXER_PASSWORD")}"let $headers = { "Authorization": f"Basic {$auth.encode_base64()}", "Content-Type": "application/json",}let $body = { size: 100, query: {match_all: {}}, sort: [{"@timestamp": {order: "desc"}}],}
from_http "https://wazuh-indexer.example.com:9200/wazuh-alerts-*/_search", headers=$headers, body=$body { read_json}unroll hits.hitsthis = hits.hits._sourceReplace wazuh-indexer.example.com with the Wazuh indexer host and store the
indexer credentials as Tenzir secrets. See the Wazuh documentation for
index names and indexer API authentication.
For larger exports, use the same request-record pagination pattern as
OpenSearch. The Wazuh indexer response includes the sort values for each hit
when you request a stable sort. Return a request record from paginate to add
search_after for the next page:
let $auth = f"{secret("WAZUH_INDEXER_USER")}:{secret("WAZUH_INDEXER_PASSWORD")}"let $headers = { "Authorization": f"Basic {$auth.encode_base64()}", "Content-Type": "application/json",}
from_http "https://wazuh-indexer.example.com:9200/wazuh-alerts-*/_search", headers=$headers, body={ size: 1000, query: {match_all: {}}, sort: [{"@timestamp": "asc"}, {"_id": "asc"}], }, paginate=(x => { body: { size: 1000, query: {match_all: {}}, sort: [{"@timestamp": "asc"}, {"_id": "asc"}], search_after: x.hits.hits[-1].sort, }, } if x.hits.hits != []) { read_json}unroll hits.hitsthis = hits.hits._sourceKeep unroll after from_http so the pagination lambda can inspect the
whole search response. Follow-up requests inherit the POST method and
headers from the first request and replace only the request body.
Write directly to the Wazuh indexer
Section titled “Write directly to the Wazuh indexer”The Wazuh indexer exposes an OpenSearch-compatible API. You can use
to_opensearch to write already-shaped documents to a custom index:
subscribe "detections"to_opensearch "https://wazuh-indexer.example.com:9200", action="create", index="tenzir-detections", user=secret("WAZUH_INDEXER_USER"), passwd=secret("WAZUH_INDEXER_PASSWORD")Use this path for custom index storage or other indexer-specific workflows. It bypasses the Wazuh manager, so Wazuh decoders and rules won’t analyze those events as incoming log data.