Integrations
Wazuh
Wazuh has no webhook of its own: its integrator daemon runs a script for every alert at or above a level you choose. EvoHub provides that script. It posts the alert exactly as Wazuh wrote it, and uses only Python's standard library and the Python that ships with the Wazuh manager.
Set it up
Create the integration
In EvoHub, go to On-Call → Integrations → + Add Integration, choose Wazuh, pick an Escalation Policy and click Create Integration. Copy the Webhook URL.
Install the script
On the Wazuh manager, save the script below as /var/ossec/integrations/custom-evohub, then make it executable by the wazuh group:
chmod 750 /var/ossec/integrations/custom-evohub
chown root:wazuh /var/ossec/integrations/custom-evohub
Script (/var/ossec/integrations/custom-evohub):
#!/var/ossec/framework/python/bin/python3
# EvoHub On-Call — Wazuh custom integration.
# Install as /var/ossec/integrations/custom-evohub (root:wazuh, mode 750).
# integratord runs it as: custom-evohub <alert file> <api key> <hook url>
# Test by hand: custom-evohub --test <hook url>
import json
import sys
import urllib.error
import urllib.request
def post(url, payload):
req = urllib.request.Request(
url,
data=json.dumps(payload).encode("utf-8"),
method="POST",
headers={"Content-Type": "application/json", "User-Agent": "evohub-wazuh/1"},
)
try:
with urllib.request.urlopen(req, timeout=10) as resp:
resp.read()
return 0
except urllib.error.HTTPError as e:
sys.stderr.write("evohub: EvoHub answered HTTP %d\n" % e.code)
except (urllib.error.URLError, OSError) as e:
sys.stderr.write("evohub: could not reach EvoHub: %s\n" % getattr(e, "reason", e))
return 1
def main(argv):
if len(argv) == 3 and argv[1] == "--test":
return post(argv[2], {"evohub_test": True})
if len(argv) < 4:
sys.stderr.write("usage: custom-evohub <alert file> <api key> <hook url>\n")
return 2
with open(argv[1], encoding="utf-8") as f:
alert = json.load(f)
return post(argv[3], alert)
if __name__ == "__main__":
sys.exit(main(sys.argv))
ossec.conf:
<integration>
<name>custom-evohub</name>
<hook_url>https://evohub.io/ingest/wazuh?key=YOUR_INTEGRATION_KEY</hook_url>
<level>10</level>
<alert_format>json</alert_format>
</integration>
Every alert at level 10 or higher is sent. Add <group> or <rule_id> to the block to send only some rules, or lower the level to send more. If the script cannot reach EvoHub it prints the reason — never the URL — and exits with an error.
Note
The first line of the script points at the Python bundled with Wazuh. If your manager has its own Python 3, #!/usr/bin/env python3 works too.
What EvoHub reads
| EvoHub alert | Taken from |
|---|---|
| Title | rule.description and the agent name, for example sshd: brute force trying to get access to the system. Authentication failed. – web-01. |
| Description | full_log, followed by the log location. |
| Labels | rule_id, rule_level, groups, mitre_id, mitre_tactic, agent_id, agent_name, agent_ip, manager, decoder, location, alert_id, timestamp and, when the decoder found them, srcip, srcport, srcuser, dstuser, dstip. |
Severity
| Wazuh rule level | EvoHub severity |
|---|---|
| 12 and above | critical |
| 10–11 | high |
| 7–9 | medium |
| 4–6 | low |
| below 4 | info |
Resolve and deduplication
An alert is identified by the rule and the agent. While it is open, the same rule firing again on the same agent is recorded as Retriggered instead of paging again; the same rule on another agent is a separate alert.
Wazuh alerts are events and Wazuh sends no recovery, so alerts stay open until someone resolves them in EvoHub.
Related
Was this page helpful?
