Интеграционный слой
Внутри поставки имеется гибкий инструмент для организации интеграции между Платформой Радар и любой другой системой, с которой можно взаимодействовать через Json API.
Концепция интеграционного слоя
Основной логикой является наблюдение за изменением данных в структуре хранения информации PostgreSQL и запуск некоторых действий при наступлении того или иного изменения.
Наблюдение за изменениями
Основной для реагирования на изменение в файле /opt/pangeoradar/configs/pangeoradar-pgr-wal-listener.yaml
является секция radar-tables-trigger
. По сути является перечнем наблюдателей, реагирующих на изменения в базе данных.
radar-tables-trigger: &radar-tables-trigger
- name: create_incident
table: service_asset_findings
fields: [ ]
kind: insert
sql: "SELECT ..."
sql_vars:
id: float64toInt64
outputs:
- *rvision_insert
Доступные триггеры, поле kind
:
insert
update
delete
При срабатывании тригера на выбранной таблице указанной в секции table
запускается sql
скрипт собирающий основной объект для передачи запуска сборки объекта отправляемого в интегрируемую системы. Если sql
скрипт не указан будет взята строка из наблюдаемой таблицы.
Также есть поле fields
, заполнив которое можно указать те поля, при изменении которых должен запускать триггер.
поле sql_vars
необходимо для приведения типов:
- bool
- int
- int32
- int64
- string
- float32
- float64
- float64toInt64
поле outputs
указывает необходимые каналы для дальнейшей интеграции с внешними системами.
Отправка изменений
Для организации канала отправки объекта соответствия, сформированного после срабатывания триггера, необходимо создать секцию, в которую направить вывод в поле outputs
Секция имеет следующую структуру:
rvision_update: &rvision_update
type: http
url: "https://IP/api/v2/incidents"
method: POST
content_type: "application/json"
headers:
PgrApiKey: "test"
prepend:
- type: http
url: "https://IP/api/v2/incidents"
method: GET
content_type: "application/json"
query:
token: "SECRET"
fields: "identifier"
filter: '[{"operator":"=","value":%d,"property":"id_siem"}]'
query_vars_from_trigger:
filter:
field: "id"
type: "float64toInt64"
append_to_mapping:
identifier: "data.result.0.identifier"
mappging: *rvision_mapping
type
- транспорт, на данны момент поддерживается толькоhttp
;url
- адрес ендпоинта для отправки запроса;method
- тип запроса (GET, POST, PUT);content_type
- значение заголовка content-type;headers
- дополнительные заголовки в формате ключ: значение;mapping
- объект соответствия;prepend
- дополнительная секция, которая будет выполнена перед отправкой основного запроса. Полезна, если нужно сделать запрос на получение доп. информации и обогащения объекта соответствия перед отправкой.
В секции prepend
доступны те же основные поля, что и в основной. В дополнении к ней доступны опции:
query
- строка запроса;query_vars_from_trigger
- шаблонизация для строки запроса;append_to_mapping
- обогащение объекта соответветствия по ключу и значению из ответа.
Объект соответствия
Объект соответствия - это объект, который будет собран после срабатывания триггера и передан в канал на отправку.
Структура объекта:
rvision_mapping: &rvision_mapping
token:
type: "manual"
value: "SECRET_KEY"
status_siem:
type: "map"
value: "status"
STATUS:
type: "active_map"
value: "status"
map:
new: "Создан"
risk_accepted: "Зарегистрирован"
assigned_customer: "Назначен"
working_customer: "Обработка"
feedback_required: "Раследование"
closed: "Закрыт"
type
- тип соответствия, доступны:
manual
- заданное ручное значение в ключеvalue
;map
- ключу объекта будет соответствовать поле указанного в значение ключаvalue
из триггера изменений;active_map
- ключу объекта будет соответствовать значение из объектаmap
, найденного при совпадении ключа, и значение поля из триггера изменений, указанного в ключеvalue
.
Пример интеграции с SOAR RVision
Ниже представлен конфигурационный файл /opt/pangeoradar/configs/pangeoradar-pgr-wal-listener.yaml
, настроенный на обмен информацией об инцидентах с SOAR RVision.
---
global:
force_replica_identity: true
log_level: warning
# Mappings
rvision_mapping: &rvision_mapping
token:
type: "manual"
value: "SECRET_KEY"
category:
type: "manual"
value: "Инцидент из Пагео Радар"
info_source:
type: "manual"
value: "SIEM Пангео"
type:
type: "manual"
value: "Инцидент полученный из Пангео Радар"
id_siem:
type: "map"
value: "id"
DESCRIPTION:
type: "map"
value: "DESCRIPTION"
risk_impact:
type: "map"
value: "risk_impact"
solution:
type: "map"
value: "solution"
mitigation:
type: "map"
value: "mitigation"
status_siem:
type: "map"
value: "status"
STATUS:
type: "active_map"
value: "status"
map:
new: "Создан"
risk_accepted: "Зарегистрирован"
assigned_customer: "Назначен"
working_customer: "Обработка"
feedback_required: "Раследование"
closed: "Закрыт"
risklevel:
type: "map"
value: "risklevel"
service_asset_id:
type: "map"
value: "service_asset_id"
DETECTION_DATE:
type: "map"
value: "created_at"
UPDATE:
type: "map"
value: "updated_at"
finding_id:
type: "map"
value: "finding_id"
analysis_output:
type: "map"
value: "analysis_output"
synopsis:
type: "map"
value: "synopsis"
title:
type: "map"
value: "title"
risk:
type: "map"
value: "risk"
OCCUR_DATE:
type: "map"
value: "acknowledged_at"
alert_type:
type: "map"
value: "alert_type"
client_note:
type: "map"
value: "client_note"
internal_note:
type: "map"
value: "internal_note"
external:
type: "map"
value: "external"
immediate_action_score:
type: "map"
value: "immediate_action_score"
throughput_period:
type: "map"
value: "throughput_period"
throughput_period_change:
type: "map"
value: "throughput_period_change"
customer_created:
type: "map"
value: "customer_created"
c_visible_since:
type: "map"
value: "c_visible_since"
c_visible_since_in_days:
type: "map"
value: "c_visible_since_in_days"
c_reopened_count:
type: "map"
value: "c_reopened_count"
c_last_customer_status_change:
type: "map"
value: "c_last_customer_status_change"
c_customer_retention_time:
type: "map"
value: "c_customer_retention_time"
logmule_identifier:
type: "map"
value: "logmule_identifier"
c_remote_exploitable:
type: "map"
value: "c_remote_exploitable"
c_occurrence_count:
type: "map"
value: "c_occurrence_count"
last_occurrence_id:
type: "map"
value: "last_occurrence_id"
itsm_last_synced_at:
type: "map"
value: "itsm_last_synced_at"
itsm_sync_status:
type: "map"
value: "itsm_sync_status"
external_id:
type: "map"
value: "external_id"
itsm_sync_error:
type: "map"
value: "itsm_sync_error"
user_id:
type: "map"
value: "user_id"
updated_by:
type: "map"
value: "updated_by"
group_id:
type: "map"
value: "group_id"
acknowledged_by:
type: "map"
value: "acknowledged_by"
created_by_customer:
type: "map"
value: "created_by_customer"
edited_by:
type: "map"
value: "edited_by"
active_name:
type: "map"
value: "active_name"
IP:
type: "map_from_json"
value: "ip"
from: "inet"
fqdn:
type: "map_form_json"
value: "fqdn"
from: "varchar_array"
# Outputs
rvision_insert: &rvision_insert
type: http
url: "https://IP/api/v2/incidents"
method: POST
content_type: "application/json"
headers:
PgrApiKey: "test"
mappging: *rvision_mapping
rvision_update: &rvision_update
type: http
url: "https://IP/api/v2/incidents"
method: POST
content_type: "application/json"
headers:
PgrApiKey: "test"
prepend:
- type: http
url: "https://IP/api/v2/incidents"
method: GET
content_type: "application/json"
query:
token: "SECRET"
fields: "identifier"
filter: '[{"operator":"=","value":%d,"property":"id_siem"}]'
query_vars_from_trigger:
filter:
field: "id"
type: "float64toInt64"
append_to_mapping:
identifier: "data.result.0.identifier"
mappging: *rvision_mapping
radar-tables-trigger: &radar-tables-trigger
- name: create_incident
table: service_asset_findings
fields: [ ]
kind: insert
sql: "SELECT t.id, CASE WHEN t.description ISNULL THEN f.description ELSE t.description END, CASE WHEN t.risk_impact ISNULL THEN f.risk_impact ELSE t.risk_impact END, CASE WHEN t.solution ISNULL THEN f.solution ELSE t.solution END, t.mitigation, CASE WHEN t.solution ISNULL THEN f.solution ELSE t.solution END, t.status, t.risklevel, t.service_asset_id, t.created_at, t.updated_at, t.finding_id, t.analysis_output, t.synopsis, CASE WHEN t.synopsis ISNULL THEN f.synopsis ELSE t.synopsis END, t.title, CASE WHEN t.title ISNULL THEN f.title ELSE t.title END, t.risk, t.acknowledged_at, t.alert_type, t.client_note, t.internal_note, t.external, t.immediate_action_score, t.throughput_period, t.throughput_period_change, t.customer_created, t.c_visible_since, t.c_visible_since_in_days, t.c_reopened_count, t.c_last_customer_status_change, t.c_customer_retention_time, t.logmule_identifier, t.c_remote_exploitable, t.c_occurrence_count, t.last_occurrence_id, t.itsm_last_synced_at, t.itsm_sync_status, t.external_id, t.itsm_sync_error, t.user_id, t.updated_by, t.group_id, t.acknowledged_by, t.created_by_customer, t.edited_by, s.name as active_name, ni.ip as ip, ni.fqdn as fqdn FROM public.service_asset_findings t left join findings f on t.finding_id = f.id left join service_assets s on t.service_asset_id = s.id left join network_interfaces ni on s.id = ni.service_asset_id where t.id = $1"
sql_vars:
id: float64toInt64
outputs:
- *rvision_insert
- name: update_incident
table: service_asset_findings
fields: [ ]
kind: update
sql: "SELECT t.id, CASE WHEN t.description ISNULL THEN f.description ELSE t.description END, CASE WHEN t.risk_impact ISNULL THEN f.risk_impact ELSE t.risk_impact END, CASE WHEN t.solution ISNULL THEN f.solution ELSE t.solution END, t.mitigation, CASE WHEN t.solution ISNULL THEN f.solution ELSE t.solution END, t.status, t.risklevel, t.service_asset_id, t.created_at, t.updated_at, t.finding_id, t.analysis_output, t.synopsis, CASE WHEN t.synopsis ISNULL THEN f.synopsis ELSE t.synopsis END, t.title, CASE WHEN t.title ISNULL THEN f.title ELSE t.title END, t.risk, t.acknowledged_at, t.alert_type, t.client_note, t.internal_note, t.external, t.immediate_action_score, t.throughput_period, t.throughput_period_change, t.customer_created, t.c_visible_since, t.c_visible_since_in_days, t.c_reopened_count, t.c_last_customer_status_change, t.c_customer_retention_time, t.logmule_identifier, t.c_remote_exploitable, t.c_occurrence_count, t.last_occurrence_id, t.itsm_last_synced_at, t.itsm_sync_status, t.external_id, t.itsm_sync_error, t.user_id, t.updated_by, t.group_id, t.acknowledged_by, t.created_by_customer, t.edited_by, s.name as active_name, ni.ip as ip, ni.fqdn as fqdn FROM public.service_asset_findings t left join findings f on t.finding_id = f.id left join service_assets s on t.service_asset_id = s.id left join network_interfaces ni on s.id = ni.service_asset_id where t.id = $1"
sql_vars:
id: float64toInt64
outputs:
- *rvision_update
connections:
- database: radar
username: user
password: secret
host: 127.0.0.1
port: 5432
triggers: *radar-tables-trigger