Skip to content

Commit 323feb9

Browse files
35C4n0rshahargl
andauthored
feat(api): support for graylog v4.x (#2452)
Signed-off-by: 35C4n0r <[email protected]> Co-authored-by: Shahar Glazner <[email protected]>
1 parent 2fc3bdf commit 323feb9

File tree

4 files changed

+120
-18
lines changed

4 files changed

+120
-18
lines changed

docs/providers/documentation/graylog-provider.mdx

+6-4
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,13 @@ Example:
4646
```
4747
- You can modify this to fetch either alerts, events or both.
4848

49-
---
50-
51-
**Note**: Ensure that the product of `page` and `per_page` does not exceed 10,000.
49+
<Note>
50+
Ensure that the product of `page` and `per_page` does not exceed 10,000.
51+
</Note>
5252

53-
---
53+
<Note>
54+
The notification URL for Graylog v4.x has the api_key as a query param, this is the default behaviour.
55+
</Note>
5456

5557
## Useful Links
5658

keep/providers/graylog_provider/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Instructions for a quick setup
22

3-
## Setting up Graylog
3+
## Setting up Graylog (v6)
44

55
### Installation
66

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
version: '3'
2+
services:
3+
# MongoDB: https://hub.docker.com/_/mongo/
4+
mongo:
5+
image: mongo:4.2
6+
networks:
7+
- graylog
8+
9+
# Elasticsearch: https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docker.html
10+
elasticsearch:
11+
image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2
12+
environment:
13+
- http.host=0.0.0.0
14+
- transport.host=localhost
15+
- network.host=0.0.0.0
16+
- "ES_JAVA_OPTS=-Xms512m -Xmx512m"
17+
ulimits:
18+
memlock:
19+
soft: -1
20+
hard: -1
21+
deploy:
22+
resources:
23+
limits:
24+
memory: 1g
25+
networks:
26+
- graylog
27+
ports:
28+
- "9200:9200"
29+
- "9300:9300"
30+
31+
# Graylog: https://hub.docker.com/r/graylog/graylog/
32+
graylog:
33+
image: graylog/graylog:4.0
34+
environment:
35+
- GRAYLOG_PASSWORD_SECRET=somepasswordpepper
36+
- GRAYLOG_ROOT_PASSWORD_SHA2=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
37+
- GRAYLOG_HTTP_EXTERNAL_URI=http://127.0.0.1:9000/
38+
- GRAYLOG_ELASTICSEARCH_HOSTS=http://elasticsearch:9200
39+
entrypoint: /usr/bin/tini -- wait-for-it elasticsearch:9200 -t 60 -- /docker-entrypoint.sh
40+
networks:
41+
- graylog
42+
restart: always
43+
depends_on:
44+
- mongo
45+
- elasticsearch
46+
ports:
47+
- "9000:9000"
48+
- "1514:1514"
49+
- "1514:1514/udp"
50+
- "12201:12201"
51+
- "12201:12201/udp"
52+
53+
networks:
54+
graylog:
55+
driver: bridge

keep/providers/graylog_provider/graylog_provider.py

+58-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
Graylog Provider is a class that allows to install webhooks in Graylog.
33
"""
4+
# Documentation for older versions of graylog: https://github.com/Graylog2/documentation
45

56
import dataclasses
67
import math
@@ -67,6 +68,8 @@ class GraylogProvider(BaseProvider):
6768
2. Click "Create Notification".
6869
3. In the New Notification form, configure:
6970
71+
**Note**: For Graylog v4.x please set the **URL** to `{keep_webhook_api_url}?api_key={api_key}`.
72+
7073
- **Display Name**: keep-graylog-webhook-integration
7174
- **Title**: keep-graylog-webhook-integration
7275
- **Notification Type**: Custom HTTP Notification
@@ -105,6 +108,7 @@ def __init__(
105108
):
106109
super().__init__(context_manager, provider_id, config)
107110
self._host = None
111+
self.is_v4 = self.__get_graylog_version().startswith("4")
108112

109113
def dispose(self):
110114
"""
@@ -224,6 +228,22 @@ def validate_scopes(self) -> dict[str, bool | str]:
224228
"authorized": authorized,
225229
}
226230

231+
def __get_graylog_version(self) -> str:
232+
self.logger.info("Getting graylog version info")
233+
try:
234+
version_response = requests.get(
235+
url=self.__get_url(),
236+
headers=self._headers
237+
)
238+
if version_response.status_code != 200:
239+
raise Exception(version_response.text)
240+
version = version_response.json()["version"].strip()
241+
self.logger.info(f"We are working with Graylog version: {version}")
242+
return version
243+
except Exception as e:
244+
self.logger.error("Error while getting Graylog Version", extra={"exception": str(e)})
245+
246+
227247
def __get_url_whitelist(self):
228248
try:
229249
self.logger.info("Fetching URL Whitelist")
@@ -410,6 +430,16 @@ def setup_webhook(
410430
self, tenant_id: str, keep_api_url: str, api_key: str, setup_alerts: bool = True
411431
):
412432
self.logger.info("Setting up webhook in Graylog")
433+
434+
# Extracting provider_id from the keep_api_url
435+
parsed_url = urlparse(keep_api_url)
436+
query_params = parsed_url.query
437+
provider_id = query_params.split("provider_id=")[-1]
438+
notification_name = f"Keep-{provider_id}"
439+
440+
if self.is_v4:
441+
keep_api_url = f"{keep_api_url}&api_key={api_key}"
442+
413443
try:
414444
event_definitions = []
415445
events_1 = self.__get_events(page=1, per_page=100)
@@ -422,12 +452,6 @@ def setup_webhook(
422452
self.__get_events(page=page, per_page=100)["event_definitions"]
423453
)
424454

425-
# Extracting provider_id from the keep_api_url
426-
parsed_url = urlparse(keep_api_url)
427-
query_params = parsed_url.query
428-
provider_id = query_params.split("provider_id=")[-1]
429-
notification_name = f"Keep-{provider_id}"
430-
431455
# Whitelist URL
432456
url_whitelist = self.__get_url_whitelist()
433457
url_found = False
@@ -452,17 +476,27 @@ def setup_webhook(
452476
notification = self.__get_notification(
453477
page=1, per_page=1, notification_name=notification_name
454478
)
479+
480+
existing_notification_id = None
481+
455482
if int(notification["count"]) > 0:
456483
self.logger.info("Notification already exists, deleting it")
484+
485+
# We need to clean up the previously installed notification
486+
existing_notification_id = notification["notifications"][0]["id"]
487+
457488
self.__delete_notification(
458-
notification_id=notification["notifications"][0]["id"]
489+
notification_id=existing_notification_id
459490
)
460491

461492
self.logger.info("Creating new notification")
462-
notification_body = {
463-
"title": notification_name,
464-
"description": "Hello, this Notification is created by Keep, please do not change the title.",
465-
"config": {
493+
if self.is_v4:
494+
config = {
495+
"type": "http-notification-v1",
496+
"url": keep_api_url
497+
}
498+
else:
499+
config = {
466500
"type": "http-notification-v2",
467501
"basic_auth": None,
468502
"api_key_as_header": False,
@@ -475,17 +509,28 @@ def setup_webhook(
475509
"content_type": "JSON",
476510
"headers": f"X-API-KEY:{api_key}",
477511
"body_template": "",
478-
},
512+
}
513+
notification_body = {
514+
"title": notification_name,
515+
"description": "Hello, this Notification is created by Keep, please do not change the title.",
516+
"config": config,
479517
}
480518
new_notification = self.__create_notification(
481519
notification_name=notification_name, notification_body=notification_body
482520
)
483521

484522
for event_definition in event_definitions:
485-
if event_definition["_scope"] == "SYSTEM_NOTIFICATION_EVENT":
523+
if not self.is_v4 and event_definition["_scope"] == "SYSTEM_NOTIFICATION_EVENT":
486524
self.logger.info("Skipping SYSTEM_NOTIFICATION_EVENT")
487525
continue
488526
self.logger.info(f"Updating event with ID: {event_definition['id']}")
527+
528+
# Attempting to clean up the deleted notification from the event, it is not handled well in Graylog v4.
529+
for ind, notification in enumerate(event_definition["notifications"]):
530+
if notification["notification_id"] == existing_notification_id:
531+
event_definition["notifications"].pop(ind)
532+
break
533+
489534
event_definition["notifications"].append(
490535
{"notification_id": new_notification["id"]}
491536
)

0 commit comments

Comments
 (0)