Integration Overview (Wazuh ➜ Icinga 2 API)

Integration Overview (Wazuh ➜ Icinga 2 API)

Assumptions:

  • Wazuh Manager is on 10.0.0.1

  • Icinga 2 Server is on 10.0.0.2

  • Icinga 2 has API enabled, with a user that can submit check results

  • Wazuh will trigger a script (active-response) that calls the Icinga 2 REST API


Step-by-Step Setup


1. Enable Icinga 2 API on Icinga Server

Edit /etc/icinga2/features-enabled/api.conf:

object ApiUser "wazuh-user" { password = "StrongPassword123" permissions = [ "actions/process-check-result", "objects/modify/*", "status/query" ] }

Restart Icinga:

 
systemctl restart icinga2

Test API from browser or curl:

 
curl -k -u wazuh-user:StrongPassword123 https://10.0.0.2:5665/v1

2. Create Wazuh Active Response Script on Wazuh Manager

File: /var/ossec/active-response/bin/wazuh_to_icinga_api.sh

 
#!/bin/bash # Parse alert file (Wazuh passes it as $1) ALERT_FILE="$1" ALERT_DATA=$(cat $ALERT_FILE) IP=$(echo "$ALERT_DATA" | grep '"srcip"' | cut -d'"' -f4) RULE_ID=$(echo "$ALERT_DATA" | grep '"rule":' | grep -o '"id":[0-9]*' | cut -d: -f2) # Icinga 2 API config ICINGA_API_USER="wazuh-user" ICINGA_API_PASS="StrongPassword123" ICINGA_HOST="10.0.0.2" ICINGA_PORT="5665" ICINGA_CHECK_HOST="monitored-host" ICINGA_CHECK_SERVICE="Security Alert" # Create payload for passive check result JSON_PAYLOAD=$(cat <<EOF { "type": "Service", "filter": "host.name==\"$ICINGA_CHECK_HOST\" && service.name==\"$ICINGA_CHECK_SERVICE\"", "exit_status": 2, "plugin_output": "Wazuh Alert: Rule ID $RULE_ID triggered from IP $IP" } EOF ) # Send passive check result to Icinga 2 API curl -k -s -u "$ICINGA_API_USER:$ICINGA_API_PASS" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -X POST "https://$ICINGA_HOST:$ICINGA_PORT/v1/actions/process-check-result" \ -d "$JSON_PAYLOAD"

Make it executable:

chmod +x /var/ossec/active-response/bin/wazuh_to_icinga_api.sh

3. Configure Wazuh to Use the Script

In /var/ossec/etc/ossec.conf:

 
<command> <name>wazuh_to_icinga</name> <executable>wazuh_to_icinga_api.sh</executable> <timeout_allowed>no</timeout_allowed> </command>
 
<active-response>
<command>wazuh_to_icinga</command>
<location>local</location>
<rules_id>100010</rules_id> <!-- match a custom rule -->
</active-response>

4. Create Matching Custom Wazuh Rule

Edit /var/ossec/etc/rules/local_rules.xml:

<group name="wazuh,">
<rule id="100010" level="10">
<if_sid>5710</if_sid> <!-- For example: SSH brute-force --> <description>Wazuh: SSH brute-force attack</description> <group>authentication_failures,</group>
</rule>
</group>

Restart Wazuh:

systemctl restart wazuh-manager

5. Ensure the Icinga Host/Service Exist

Ensure that on the Icinga server, you already have a host and service definition like:

apply Service "Security Alert" { import "generic-service" check_command = "dummy" assign where host.name == "monitored-host" }

This way, the passive check will match an existing object.


Done!

Now, when Wazuh detects a matching event, it will:

  • Trigger an active response

  • Run the shell script

  • Send a passive check result to Icinga using its REST API

  • Show the alert in Icinga Web as a CRITICAL service status