Back to Integrations

Wazuh Integration

Enrich your Wazuh SIEM alerts with real-time IP threat intelligence from ipinsights.io.

Overview

Wazuh is a free, open-source XDR and SIEM platform used for threat detection, integrity monitoring, incident response and compliance. By integrating ipinsights.io you can automatically enrich source-IP fields in Wazuh alerts with reputation scores, geolocation, ASN data and blocklist membership — giving analysts the context they need without leaving the console.

The integration uses Wazuh's active-response framework to call the ipinsights.io API whenever an alert fires, writing enrichment data back as a local log that Wazuh can decode and correlate with custom rules.

Architecture Overview

The diagram below shows how data flows through the integration:

┌──────────────┐ alert ┌──────────────────┐ HTTP GET ┌──────────────────────┐ │ Wazuh Agent │ ─────────────▶ │ Wazuh Manager │ ────────────▶ │ ipinsights.io API │ │ (endpoint) │ │ (ossec.conf) │ │ /api/v1/lookup │ └──────────────┘ └────────┬─────────┘ └──────────┬───────────┘ │ │ │ active-response │ JSON response ▼ ▼ ┌──────────────────┐ ┌──────────────────────┐ │ Enrichment │ ◀──────────── │ IP reputation, │ │ Script (bash) │ parse & │ geolocation, ASN, │ └────────┬─────────┘ enrich │ blocklists │ │ └──────────────────────┘ │ writes JSON log ▼ ┌──────────────────┐ │ Custom Decoder │ │ & Alert Rules │ └──────────────────┘
  1. A Wazuh agent detects an event (e.g. failed SSH login) and forwards the alert to the manager.
  2. The manager triggers the active-response enrichment script for qualifying alerts.
  3. The script extracts the source IP, queries the ipinsights.io API and writes the enriched result as a JSON log.
  4. Wazuh's custom decoder parses the enrichment log, and custom rules generate secondary alerts based on threat scores.

Prerequisites

  • Wazuh 4.x or later (manager + agent deployed)
  • An ipinsights.io API key — available on your profile page (or register for free)
  • curl and jq installed on the Wazuh manager
  • Outbound HTTPS (port 443) access from the manager to https://ipinsights.io

Step 1 — Create the Enrichment Script

Create the active-response script on the Wazuh manager at /var/ossec/active-response/bin/ipinsights-enrich.sh:

#!/bin/bash # ───────────────────────────────────────────────────────────── # ipinsights-enrich.sh — Wazuh active-response enrichment # Queries the ipinsights.io API and writes enrichment data # to a local log for Wazuh to decode. # ───────────────────────────────────────────────────────────── API_KEY="YOUR_API_KEY_HERE" API_URL="https://ipinsights.io/api/v1/lookup" LOG_FILE="/var/ossec/logs/ipinsights-enrichment.log" CACHE_DIR="/var/ossec/tmp/ipinsights_cache" CACHE_TTL=3600 # cache results for 1 hour mkdir -p "$CACHE_DIR" # Read the alert JSON from stdin (Wazuh active-response protocol) read -r INPUT_JSON # Extract the source IP from the alert SRCIP=$(echo "$INPUT_JSON" | jq -r '.parameters.alert.data.srcip // empty') if [ -z "$SRCIP" ]; then echo "$(date '+%Y-%m-%d %T') ipinsights: no srcip found in alert" >> "$LOG_FILE" exit 0 fi # Check cache first CACHE_FILE="$CACHE_DIR/$(echo -n "$SRCIP" | md5sum | cut -d' ' -f1).json" if [ -f "$CACHE_FILE" ]; then FILE_AGE=$(( $(date +%s) - $(stat -c %Y "$CACHE_FILE") )) if [ "$FILE_AGE" -lt "$CACHE_TTL" ]; then RESPONSE=$(cat "$CACHE_FILE") fi fi # Query the API if no cached result if [ -z "${RESPONSE:-}" ]; then RESPONSE=$(curl -s -m 10 -H "X-API-Key: $API_KEY" \ "$API_URL?ip=$SRCIP" 2>/dev/null) if [ $? -ne 0 ] || [ -z "$RESPONSE" ]; then echo "$(date '+%Y-%m-%d %T') ipinsights: API request failed for $SRCIP" >> "$LOG_FILE" exit 1 fi # Cache the response echo "$RESPONSE" > "$CACHE_FILE" fi # Extract key fields THREAT_SCORE=$(echo "$RESPONSE" | jq -r '.data.threat_score // "N/A"') COUNTRY=$(echo "$RESPONSE" | jq -r '.data.country_code // "N/A"') ASN=$(echo "$RESPONSE" | jq -r '.data.asn // "N/A"') ISP=$(echo "$RESPONSE" | jq -r '.data.isp // "N/A"') IS_TOR=$(echo "$RESPONSE" | jq -r '.data.is_tor // false') IS_VPN=$(echo "$RESPONSE" | jq -r '.data.is_vpn // false') IS_PROXY=$(echo "$RESPONSE" | jq -r '.data.is_proxy // false') BLOCKLISTS=$(echo "$RESPONSE" | jq -r '.data.blocklist_count // 0') # Write enrichment log line echo "$(date '+%Y-%m-%d %T') ipinsights: ip=$SRCIP threat_score=$THREAT_SCORE country=$COUNTRY asn=$ASN isp=\"$ISP\" is_tor=$IS_TOR is_vpn=$IS_VPN is_proxy=$IS_PROXY blocklists=$BLOCKLISTS" >> "$LOG_FILE" exit 0

Make the script executable:

sudo chmod 750 /var/ossec/active-response/bin/ipinsights-enrich.sh sudo chown root:wazuh /var/ossec/active-response/bin/ipinsights-enrich.sh

Step 2 — Register the Active-Response Command

Add the following <command> block inside your /var/ossec/etc/ossec.conf on the manager:

<ossec_config> <command> <name>ipinsights-enrich</name> <executable>ipinsights-enrich.sh</executable> <timeout_allowed>no</timeout_allowed> </command> </ossec_config>

Step 3 — Configure the Active Response

Still in ossec.conf, add an <active-response> block to trigger the enrichment script on alerts at or above a chosen rule level:

<ossec_config> <active-response> <command>ipinsights-enrich</command> <location>server</location> <level>6</level> </active-response> </ossec_config>

Adjust <level> to control which alerts trigger enrichment. Level 6 covers most authentication-related events without being too noisy.

Step 4 — Add a Custom Decoder Optional

Create /var/ossec/etc/decoders/ipinsights.xml so Wazuh can parse the enrichment log:

<decoder name="ipinsights"> <prematch>^ipinsights: </prematch> </decoder> <decoder name="ipinsights-fields"> <parent>ipinsights</parent> <regex>ip=(\S+) threat_score=(\S+) country=(\S+) asn=(\S+) isp="(\.+)" is_tor=(\S+) is_vpn=(\S+) is_proxy=(\S+) blocklists=(\S+)</regex> <order>srcip,threat_score,country,asn,isp,is_tor,is_vpn,is_proxy,blocklists</order> </decoder>

Step 5 — Add Alert Rules Optional

Create /var/ossec/etc/rules/ipinsights_rules.xml to fire alerts based on enrichment results:

<group name="ipinsights,"> <!-- Base rule for every enrichment log line --> <rule id="100100" level="3"> <decoded_as>ipinsights</decoded_as> <description>IP Insights enrichment received.</description> </rule> <!-- High threat score (≥ 75) --> <rule id="100101" level="10"> <if_sid>100100</if_sid> <regex>threat_score=(7[5-9]|[89]\d|100)</regex> <description>IP Insights: High threat score ($threat_score) for $(srcip).</description> </rule> <!-- Tor exit node --> <rule id="100102" level="8"> <if_sid>100100</if_sid> <regex>is_tor=true</regex> <description>IP Insights: Source IP $(srcip) is a known Tor exit node.</description> </rule> <!-- IP appears on multiple blocklists --> <rule id="100103" level="9"> <if_sid>100100</if_sid> <regex>blocklists=([3-9]|\d{2,})</regex> <description>IP Insights: Source IP $(srcip) found on $(blocklists) blocklists.</description> </rule> </group>

Step 6 — Restart Wazuh Manager

Apply the changes by restarting the Wazuh manager service:

sudo systemctl restart wazuh-manager

Check /var/ossec/logs/ossec.log for any configuration errors after the restart.

Verification

After restarting, verify the integration is working:

  1. Check the enrichment log — trigger an alert (e.g. a failed SSH login) and look for output:
    tail -f /var/ossec/logs/ipinsights-enrichment.log
  2. Test the script manually — pipe a mock alert into the script:
    echo '{"parameters":{"alert":{"data":{"srcip":"8.8.8.8"}}}}' | \ /var/ossec/active-response/bin/ipinsights-enrich.sh
  3. Verify decoder parsing — use the Wazuh log-test utility:
    sudo /var/ossec/bin/wazuh-logtest
    Paste a sample enrichment log line and confirm the fields are decoded correctly.
  4. Check Wazuh dashboard — search for rule.groups:ipinsights to see enriched alerts in the UI.

Best Practices

  • Cache API responses — the enrichment script above caches results for one hour in /var/ossec/tmp/ipinsights_cache/. This avoids redundant API calls and helps you stay within your rate limit. Adjust CACHE_TTL to suit your environment.
  • Handle errors gracefully — always check the curl exit code and the success field in the API response before extracting data. Log failures to make troubleshooting easier.
  • Be aware of rate limits — the default free-tier limit is 600 requests per hour. If you have a high-volume environment, consider requesting a higher limit using the form below or adjusting the <level> threshold in your active-response configuration to reduce the number of enrichments triggered.
  • Secure your API key — restrict read access to the enrichment script (chmod 750) and consider using Wazuh's /var/ossec/etc/local_internal_options.conf or environment variables to store the key outside of the script body.
  • Rotate cache periodically — set up a cron job to purge stale cache files:
    0 * * * * find /var/ossec/tmp/ipinsights_cache/ -type f -mmin +60 -delete

Troubleshooting

No enrichment log output

  • Confirm the script is executable: ls -l /var/ossec/active-response/bin/ipinsights-enrich.sh
  • Ensure ownership is root:wazuh.
  • Check /var/ossec/logs/ossec.log for active-response errors.
  • Verify the <level> threshold — if set too high, alerts may not trigger the script.

API request failures

  • Test connectivity from the manager: curl -I https://ipinsights.io
  • Verify your API key is valid on your profile page.
  • Check for HTTP 429 (rate limit) responses — if frequent, consider increasing your limit.
  • Inspect the enrichment log for API request failed messages.

Decoder not parsing fields

  • Validate the decoder XML: sudo /var/ossec/bin/wazuh-logtest
  • Ensure the log format written by the script exactly matches the <regex> in the decoder.
  • Add /var/ossec/logs/ipinsights-enrichment.log as a <localfile> in ossec.conf:
    <localfile> <log_format>syslog</log_format> <location>/var/ossec/logs/ipinsights-enrichment.log</location> </localfile>

Custom rules not firing

  • Make sure the rule file is loaded — check /var/ossec/logs/ossec.log for XML errors.
  • Verify rule IDs don't conflict with existing rules (use IDs above 100000).
  • Use wazuh-logtest to confirm the rule triggers against a sample log line.

API Key: You can find your API key on your profile page. Don't have an account yet? Register for free.

Request Higher API Limit

Running a high-volume Wazuh deployment? If the default rate limit isn't enough for your environment, submit a request below and we'll review it.

Maximum 2,000 characters.