Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new alerter for a more flexible HTTP Post #530

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
- [Alertmanager] Added support for Alertmanager - [#503](https://github.com/jertel/elastalert2/pull/503) - @nsano-rururu
- Add summary_table_max_rows optional configuration to limit rows in summary tables - [#508](https://github.com/jertel/elastalert2/pull/508) - @mdavyt92
- Added support for shortening Kibana Discover URLs using Kibana Shorten URL API - [#512](https://github.com/jertel/elastalert2/pull/512) - @JeffAshton
- Added new alerter `HTTP Post 2` which allow more flexibility to build the body/headers of the request. - [#530](https://github.com/jertel/elastalert2/pull/530) - @lepouletsuisse

## Other changes
- [Docs] Add exposed metrics documentation - [#498](https://github.com/jertel/elastalert2/pull/498) - @thisisxgp
Expand Down
1 change: 1 addition & 0 deletions docs/source/elastalert.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Currently, we have support built in for these alert types:
- Gitter
- GoogleChat
- HTTP POST
- HTTP POST 2
- Jira
- Line Notify
- Mattermost
Expand Down
41 changes: 41 additions & 0 deletions docs/source/ruletypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2209,6 +2209,47 @@ Example usage::
http_post_headers:
authorization: Basic 123dr3234

HTTP POST 2
~~~~~~~~~~~

This alert type will send results to a JSON endpoint using HTTP POST. The key names are configurable so this is compatible with almost any endpoint. By default, the JSON will contain all the items from the match, unless you specify http_post_payload, in which case it will only contain those items.
This alert is a more flexible version of the HTTP Post alerter.

Required:

``http_post2_url``: The URL to POST.

Optional:

``http_post2_payload``: List of keys:values to use for the payload of the HTTP Post. You can use {{ field }} (Jinja2 template) in the key and the value to reference any field in the matched events (works for nested fields). If not defined, all the Elasticsearch keys will be sent. Ex: `"description_{{ my_field }}": "Type: {{ type }}\\nSubject: {{ title }}"`

``http_post2_raw_fields``: List of keys:values to use as the content of the POST. Example - ip:clientip will map the value from the clientip field of Elasticsearch to JSON key named ip. This field overwrite the keys with the same name in `http_post2_payload`.

``http_post2_headers``: List of keys:values to use for as headers of the HTTP Post. You can use {{ field }} (Jinja2 template) in the key and the value to reference any field in the matched events (works for nested fields). Ex: `"Authorization": "{{ user }}"`. Headers `"Content-Type": "application/json"` and `"Accept": "application/json;charset=utf-8"` are present by default, you can overwrite them if you think this is necessary.

``http_post2_proxy``: URL of proxy, if required. only supports https.

``http_post2_all_values``: Boolean of whether or not to include every key value pair from the match in addition to those in http_post2_payload and http_post2_static_payload. Defaults to True if http_post2_payload is not specified, otherwise False.

``http_post2_timeout``: The timeout value, in seconds, for making the post. The default is 10. If a timeout occurs, the alert will be retried next time elastalert cycles.

``http_post2_ca_certs``: Set this option to ``True`` if you want to validate the SSL certificate.

``http_post2_ignore_ssl_errors``: By default ElastAlert 2 will verify SSL certificate. Set this option to ``False`` if you want to ignore SSL errors.

Example usage::

alert: post2
http_post2_url: "http://example.com/api"
http_post2_payload:
description: "An event came from IP {{clientip}}"
username: "{{user.name}}"
http_post2_raw_fields:
ip: clientip
http_post2_headers:
authorization: Basic 123dr3234
X-custom-type: {{type}}

Jira
~~~~

Expand Down
75 changes: 75 additions & 0 deletions elastalert/alerters/httppost2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import json

import requests
from requests import RequestException

from elastalert.alerts import Alerter, DateTimeEncoder
from elastalert.util import lookup_es_key, EAException, elastalert_logger
from jinja2 import Template


class HTTPPost2Alerter(Alerter):
""" Requested elasticsearch indices are sent by HTTP POST. Encoded with JSON. """
required_options = frozenset(['http_post2_url'])

def __init__(self, rule):
super(HTTPPost2Alerter, self).__init__(rule)
post_url = self.rule.get('http_post2_url', None)
if isinstance(post_url, str):
post_url = [post_url]
self.post_url = post_url
self.post_proxy = self.rule.get('http_post2_proxy', None)
self.post_payload = self.rule.get('http_post2_payload', {})
self.post_raw_fields = self.rule.get('http_post2_raw_fields', {})
self.post_all_values = self.rule.get('http_post2_all_values', not self.post_payload)
self.post_http_headers = self.rule.get('http_post2_headers', {})
self.post_ca_certs = self.rule.get('http_post2_ca_certs')
self.post_ignore_ssl_errors = self.rule.get('http_post2_ignore_ssl_errors', False)
self.timeout = self.rule.get('http_post2_timeout', 10)

def alert(self, matches):
""" Each match will trigger a POST to the specified endpoint(s). """
for match in matches:
payload = match if self.post_all_values else {}
for post_key, post_value in list(self.post_payload.items()):
post_key_template = Template(post_key)
post_key_res = post_key_template.render(**match)
post_value_template = Template(post_value)
post_value_res = post_value_template.render(**match)
payload[post_key_res] = post_value_res

for post_key, es_key in list(self.post_raw_fields.items()):
payload[post_key] = lookup_es_key(match, es_key)

headers = {
"Content-Type": "application/json",
"Accept": "application/json;charset=utf-8"
}
if self.post_ca_certs:
verify = self.post_ca_certs
else:
verify = not self.post_ignore_ssl_errors
if self.post_ignore_ssl_errors:
requests.packages.urllib3.disable_warnings()

for header_key, header_value in list(self.post_http_headers.items()):
header_key_template = Template(header_key)
header_key_res = header_key_template.render(**match)
header_value_template = Template(header_value)
header_value_res = header_value_template.render(**match)
headers[header_key_res] = header_value_res

proxies = {'https': self.post_proxy} if self.post_proxy else None
for url in self.post_url:
try:
response = requests.post(url, data=json.dumps(payload, cls=DateTimeEncoder),
headers=headers, proxies=proxies, timeout=self.timeout,
verify=verify)
response.raise_for_status()
except RequestException as e:
raise EAException("Error posting HTTP Post 2 alert: %s" % e)
elastalert_logger.info("HTTP Post 2 alert sent.")

def get_info(self):
return {'type': 'http_post2',
'http_post2_webhook_url': self.post_url}
2 changes: 2 additions & 0 deletions elastalert/loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import elastalert.alerters.gitter
import elastalert.alerters.googlechat
import elastalert.alerters.httppost
import elastalert.alerters.httppost2
import elastalert.alerters.line
import elastalert.alerters.pagertree
import elastalert.alerters.rocketchat
Expand Down Expand Up @@ -111,6 +112,7 @@ class RulesLoader(object):
'servicenow': elastalert.alerters.servicenow.ServiceNowAlerter,
'alerta': elastalert.alerters.alerta.AlertaAlerter,
'post': elastalert.alerters.httppost.HTTPPostAlerter,
'post2': elastalert.alerters.httppost2.HTTPPost2Alerter,
'pagertree': elastalert.alerters.pagertree.PagerTreeAlerter,
'linenotify': elastalert.alerters.line.LineNotifyAlerter,
'hivealerter': elastalert.alerters.thehive.HiveAlerter,
Expand Down
7 changes: 7 additions & 0 deletions elastalert/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,13 @@ properties:
http_post_ignore_ssl_errors: {type: boolean}
http_post_timeout: {type: integer}

### HTTP POST 2
http_post2_url: *arrayOfString
http_post2_proxy: { type: string }
http_post2_ca_certs: { type: boolean }
http_post2_ignore_ssl_errors: { type: boolean }
http_post2_timeout: { type: integer }

### Jira
jira_server: {type: string}
jira_project: {type: string}
Expand Down
Loading