Skip to content

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.

HTTPSHTTPSOpenSearchREST APISyslogTCP/UDPwazuhREST API

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:

/var/ossec/etc/ossec.conf
<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:

Terminal window
systemctl restart wazuh-manager

See 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.

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 = payload
to_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.

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.hits
this = hits.hits._source

Replace 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.hits
this = hits.hits._source

Keep 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.

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.

Last updated: