diff --git a/docs/providers/documentation/graylog-provider.mdx b/docs/providers/documentation/graylog-provider.mdx
index 9f6d9a160..5323dd1ea 100644
--- a/docs/providers/documentation/graylog-provider.mdx
+++ b/docs/providers/documentation/graylog-provider.mdx
@@ -46,11 +46,13 @@ Example:
```
- You can modify this to fetch either alerts, events or both.
----
-
-**Note**: Ensure that the product of `page` and `per_page` does not exceed 10,000.
+
+Ensure that the product of `page` and `per_page` does not exceed 10,000.
+
----
+
+The notification URL for Graylog v4.x has the api_key as a query param, this is the default behaviour.
+
## Useful Links
diff --git a/keep/providers/graylog_provider/README.md b/keep/providers/graylog_provider/README.md
index f1d327f7c..29d7c6893 100644
--- a/keep/providers/graylog_provider/README.md
+++ b/keep/providers/graylog_provider/README.md
@@ -1,6 +1,6 @@
# Instructions for a quick setup
-## Setting up Graylog
+## Setting up Graylog (v6)
### Installation
diff --git a/keep/providers/graylog_provider/docker-compose-v4.yml b/keep/providers/graylog_provider/docker-compose-v4.yml
new file mode 100644
index 000000000..bf83afa75
--- /dev/null
+++ b/keep/providers/graylog_provider/docker-compose-v4.yml
@@ -0,0 +1,55 @@
+version: '3'
+services:
+ # MongoDB: https://hub.docker.com/_/mongo/
+ mongo:
+ image: mongo:4.2
+ networks:
+ - graylog
+
+ # Elasticsearch: https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docker.html
+ elasticsearch:
+ image: docker.elastic.co/elasticsearch/elasticsearch-oss:7.10.2
+ environment:
+ - http.host=0.0.0.0
+ - transport.host=localhost
+ - network.host=0.0.0.0
+ - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
+ ulimits:
+ memlock:
+ soft: -1
+ hard: -1
+ deploy:
+ resources:
+ limits:
+ memory: 1g
+ networks:
+ - graylog
+ ports:
+ - "9200:9200"
+ - "9300:9300"
+
+ # Graylog: https://hub.docker.com/r/graylog/graylog/
+ graylog:
+ image: graylog/graylog:4.0
+ environment:
+ - GRAYLOG_PASSWORD_SECRET=somepasswordpepper
+ - GRAYLOG_ROOT_PASSWORD_SHA2=8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918
+ - GRAYLOG_HTTP_EXTERNAL_URI=http://127.0.0.1:9000/
+ - GRAYLOG_ELASTICSEARCH_HOSTS=http://elasticsearch:9200
+ entrypoint: /usr/bin/tini -- wait-for-it elasticsearch:9200 -t 60 -- /docker-entrypoint.sh
+ networks:
+ - graylog
+ restart: always
+ depends_on:
+ - mongo
+ - elasticsearch
+ ports:
+ - "9000:9000"
+ - "1514:1514"
+ - "1514:1514/udp"
+ - "12201:12201"
+ - "12201:12201/udp"
+
+networks:
+ graylog:
+ driver: bridge
diff --git a/keep/providers/graylog_provider/graylog_provider.py b/keep/providers/graylog_provider/graylog_provider.py
index 8a7904d04..a59156d65 100644
--- a/keep/providers/graylog_provider/graylog_provider.py
+++ b/keep/providers/graylog_provider/graylog_provider.py
@@ -1,6 +1,7 @@
"""
Graylog Provider is a class that allows to install webhooks in Graylog.
"""
+# Documentation for older versions of graylog: https://github.com/Graylog2/documentation
import dataclasses
import math
@@ -67,6 +68,8 @@ class GraylogProvider(BaseProvider):
2. Click "Create Notification".
3. In the New Notification form, configure:
+**Note**: For Graylog v4.x please set the **URL** to `{keep_webhook_api_url}?api_key={api_key}`.
+
- **Display Name**: keep-graylog-webhook-integration
- **Title**: keep-graylog-webhook-integration
- **Notification Type**: Custom HTTP Notification
@@ -105,6 +108,7 @@ def __init__(
):
super().__init__(context_manager, provider_id, config)
self._host = None
+ self.is_v4 = self.__get_graylog_version().startswith("4")
def dispose(self):
"""
@@ -224,6 +228,22 @@ def validate_scopes(self) -> dict[str, bool | str]:
"authorized": authorized,
}
+ def __get_graylog_version(self) -> str:
+ self.logger.info("Getting graylog version info")
+ try:
+ version_response = requests.get(
+ url=self.__get_url(),
+ headers=self._headers
+ )
+ if version_response.status_code != 200:
+ raise Exception(version_response.text)
+ version = version_response.json()["version"].strip()
+ self.logger.info(f"We are working with Graylog version: {version}")
+ return version
+ except Exception as e:
+ self.logger.error("Error while getting Graylog Version", extra={"exception": str(e)})
+
+
def __get_url_whitelist(self):
try:
self.logger.info("Fetching URL Whitelist")
@@ -410,6 +430,16 @@ def setup_webhook(
self, tenant_id: str, keep_api_url: str, api_key: str, setup_alerts: bool = True
):
self.logger.info("Setting up webhook in Graylog")
+
+ # Extracting provider_id from the keep_api_url
+ parsed_url = urlparse(keep_api_url)
+ query_params = parsed_url.query
+ provider_id = query_params.split("provider_id=")[-1]
+ notification_name = f"Keep-{provider_id}"
+
+ if self.is_v4:
+ keep_api_url = f"{keep_api_url}&api_key={api_key}"
+
try:
event_definitions = []
events_1 = self.__get_events(page=1, per_page=100)
@@ -422,12 +452,6 @@ def setup_webhook(
self.__get_events(page=page, per_page=100)["event_definitions"]
)
- # Extracting provider_id from the keep_api_url
- parsed_url = urlparse(keep_api_url)
- query_params = parsed_url.query
- provider_id = query_params.split("provider_id=")[-1]
- notification_name = f"Keep-{provider_id}"
-
# Whitelist URL
url_whitelist = self.__get_url_whitelist()
url_found = False
@@ -452,17 +476,27 @@ def setup_webhook(
notification = self.__get_notification(
page=1, per_page=1, notification_name=notification_name
)
+
+ existing_notification_id = None
+
if int(notification["count"]) > 0:
self.logger.info("Notification already exists, deleting it")
+
+ # We need to clean up the previously installed notification
+ existing_notification_id = notification["notifications"][0]["id"]
+
self.__delete_notification(
- notification_id=notification["notifications"][0]["id"]
+ notification_id=existing_notification_id
)
self.logger.info("Creating new notification")
- notification_body = {
- "title": notification_name,
- "description": "Hello, this Notification is created by Keep, please do not change the title.",
- "config": {
+ if self.is_v4:
+ config = {
+ "type": "http-notification-v1",
+ "url": keep_api_url
+ }
+ else:
+ config = {
"type": "http-notification-v2",
"basic_auth": None,
"api_key_as_header": False,
@@ -475,17 +509,28 @@ def setup_webhook(
"content_type": "JSON",
"headers": f"X-API-KEY:{api_key}",
"body_template": "",
- },
+ }
+ notification_body = {
+ "title": notification_name,
+ "description": "Hello, this Notification is created by Keep, please do not change the title.",
+ "config": config,
}
new_notification = self.__create_notification(
notification_name=notification_name, notification_body=notification_body
)
for event_definition in event_definitions:
- if event_definition["_scope"] == "SYSTEM_NOTIFICATION_EVENT":
+ if not self.is_v4 and event_definition["_scope"] == "SYSTEM_NOTIFICATION_EVENT":
self.logger.info("Skipping SYSTEM_NOTIFICATION_EVENT")
continue
self.logger.info(f"Updating event with ID: {event_definition['id']}")
+
+ # Attempting to clean up the deleted notification from the event, it is not handled well in Graylog v4.
+ for ind, notification in enumerate(event_definition["notifications"]):
+ if notification["notification_id"] == existing_notification_id:
+ event_definition["notifications"].pop(ind)
+ break
+
event_definition["notifications"].append(
{"notification_id": new_notification["id"]}
)