How to integrate external software using Integrator
![Post icon](https://wazuh.com/wp-content/themes/wazuh-v3/assets/images/blog/blog-engineering-category-post-icon.png)
Integrator is a tool which easily connects Wazuh with external software. This is achieved by integrating the alert system with the APIs of the software products through scripts. Examples of this are the current integrations with Virustotal, Slack or PagerDuty.
In this article, we will learn how to configure Wazuh to communicate with external APIs with Integrator. In addition, we will show how a script should be prepared to process alerts as required.
To illustrate this process, we will develop a basic integration with the Jira planning tool, creating an issue in its system with each file integrity monitoring alert produced by Syscheck.
To start the custom integration, the ossec.conf file, including the block integration component, has to be modified in the manager. The following parameters can be used:
<integration> <name>custom-integration</name> <hook_url>WEBHOOK</hook_url> <level>10</level> <group>multiple_drops|authentication_failures</group> <alert_format>json</alert_format> </integration>
The first line of the integration script must indicate its interpreter or else Wazuh won’t know how to read and execute the script.
#!/usr/bin/env python
The script must check its arguments because it will receive configuration options from them. The first parameter includes the location of the file that contains the alert. The second parameter contains the api_key, and the third contains the hook_url option. If none of the above are indicated, the parameters will be received empty.
alert_file = open(sys.argv[1]) api_key = sys.argv[2].split(':')[1] hook_url = sys.argv[3]
The next step is to read the contents of the file indicated in the first parameter and extract, from the alert, the fields that are relevant for the integration. If JSON was used in the alert_format option, the information has to be loaded as a JSON object.
alert_level = alert_json['rule']['level'] ruleid = alert_json['rule']['id'] description = alert_json['rule']['description'] agentid = alert_json['agent']['id'] agentname = alert_json['agent']['name'] path = alert_json['syscheck']['path']
We recommend that you check the file /logs/alerts/alerts.json
before starting the development of the integration in order to find the format of the alerts to be interpreted.
To carry out this use case, let’s presuppose an environment in Jira with the following configuration:
WT
.10002
.https://testwazuhintegrator.atlassian.net
.The configuration block takes the following considerations into account:
hook_url
contains the API address to work with the issues.api_key
option will include the email address separated from the key by :
, in order to separate them in the script.<integration> <name>custom-jira</name> <group>syscheck</group> <hook_url>https://testwazuhintegrator.atlassian.net/rest/api/3/issue/</hook_url> <api_key>integratortest@accountemail.com:api_key</api_key> <alert_format>json</alert_format> </integration>
With this information, we can develop a basic integration script with Jira which will create an issue for each FIM event, indicating the rule ID and level of the alert, the name and ID of the agent involved, and the type of event (modification, creation, or deletion). The configuration used here is for version 3 of the Jira API.
#!/usr/bin/env python import sys import json import requests from requests.auth import HTTPBasicAuth # Read configuration parameters alert_file = open(sys.argv[1]) user = sys.argv[2].split(':')[0] api_key = sys.argv[2].split(':')[1] hook_url = sys.argv[3] # Read the alert file alert_json = json.loads(alert_file.read()) alert_file.close() # Extract issue fields alert_level = alert_json['rule']['level'] ruleid = alert_json['rule']['id'] description = alert_json['rule']['description'] agentid = alert_json['agent']['id'] agentname = alert_json['agent']['name'] path = alert_json['syscheck']['path'] # Set the project attributes ===> This section needs to be manually configured before running! project_key = 'WT' # You can get this from the beggining of an issue key. For example, WS for issue key WS-5018 issuetypeid = '10002' # Check https://confluence.atlassian.com/jirakb/finding-the-id-for-issue-types-646186508.html. There's also an API endpoint to get it. # Generate request headers = {'content-type': 'application/json'} issue_data = { "update": {}, "fields": { "summary": 'FIM alert on [' + path + ']', "issuetype": { "id": issuetypeid }, "project": { "key": project_key }, "description": { 'version': 1, 'type': 'doc', 'content': [ { "type": "paragraph", "content": [ { "text": '- State: ' + description + '\n- Rule ID: ' + str(ruleid) + '\n- Alert level: ' + str(alert_level) + '\n- Agent: ' + str(agentid) + ' ' + agentname, "type": "text" } ] } ], }, } } # Send the request response = requests.post(hook_url, data=json.dumps(issue_data), headers=headers, auth=(user, api_key)) #print(json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": "))) # <--- Uncomment this line for debugging sys.exit(0)
In the following image, we can see a FIM issue generated by this integration.
Note that this script uses the requests
module as dependency, so it will need to be previously installed.
The Issue type ID can be queried to Jira API by running the following command.
curl --request GET \ --url 'https://your-domain.atlassian.net/rest/api/3/issuetype' \ --user 'email@example.com:<api_token>' \ --header 'Accept: application/json'
The script must be located in /var/ossec/integrations
with the same name indicated in the configuration block, contain execution permissions, and belong to the root
user of the ossec
group.
chmod 750 /var/ossec/integrations/custom-script chown root:ossec /var/ossec/integrations/custom-script
If we want the script to redirect outputs to a log file, it must have written permissions and belong to the ossec user of the ossec group.
As a final note, the following script can be used instead for other Wazuh alerts not related to the FIM module.
#!/usr/bin/env python import sys import json import requests from requests.auth import HTTPBasicAuth # Read configuration parameters alert_file = open(sys.argv[1]) user = sys.argv[2].split(':')[0] api_key = sys.argv[2].split(':')[1] hook_url = sys.argv[3] # Read the alert file alert_json = json.loads(alert_file.read()) alert_file.close() # Extract issue fields alert_level = alert_json['rule']['level'] ruleid = alert_json['rule']['id'] description = alert_json['rule']['description'] agentid = alert_json['agent']['id'] agentname = alert_json['agent']['name'] # Set the project attributes ===> This section needs to be manually configured before running! project_key = 'WT' # You can get this from the beggining of an issue key. For example, WS for issue key WS-5018 issuetypeid = '10002' # Check https://confluence.atlassian.com/jirakb/finding-the-id-for-issue-types-646186508.html. There's also an API endpoint to get it. # Generate request headers = {'content-type': 'application/json'} issue_data = { "update": {}, "fields": { "summary": 'Wazuh Alert: ' + description, "issuetype": { "id": issuetypeid }, "project": { "key": project_key }, "description": { 'version': 1, 'type': 'doc', 'content': [ { "type": "paragraph", "content": [ { "text": '- Rule ID: ' + str(ruleid) + '\n- Alert level: ' + str(alert_level) + '\n- Agent: ' + str(agentid) + ' ' + agentname, "type": "text" } ] } ], }, } } # Send the request response = requests.post(hook_url, data=json.dumps(issue_data), headers=headers, auth=(user, api_key)) #print(json.dumps(json.loads(response.text), sort_keys=True, indent=4, separators=(",", ": "))) # <--- Uncomment this line for debugging sys.exit(0)
This article has set forth the basic guidelines for developing an external software integration with Wazuh, Integrator and using Jira as an example.
If you have any questions about how to integrate external software using Integrator, don’t hesitate to check out our documentation or you can contribute to the Wazuh community by making your own integrations and sharing them through our GitHub repository, where they will be appreciated.