Интеграционный слой
Описание
В Платформе Радар существует две механики интеграции с внешними системами.
- Через API Платформы Радар получать необходимую информацию и интегрировать её на стороне подключаемой системы.
- С помощью API интегрируемой системы передавать данные со стороны Платформы Радар
В первом случае необходимо воспользоваться документацией по API Платформы Радар, которую предоставляется по запросу. Во втором же случае необходимо настроить специальный сервис и соблюсти ряд ограничений.
Ограничения
На данный момент поддерживаются только JSON REST Api с авторизацией через HTTP заголовок или GET параметр.
Описание работы сервиса интеграции
Сервис pgr-wal-listener следит за всеми изменениями в базе данных postgresql и при наступлении интересующего нас изменения, может выполнить sql запрос для формирования объекта пересылаемых данных и инициировать отправку объекта в подключаемую систему. Также предусмотрена механика формирования требуемого объекта данных для запроса в исполняемой системе из полученных данных при sql запросе.
Концептуально конфигурацию сервиса можно поделить на три секции:
- Описание пересылаемого объекта
- Описание вызова API методов подключаемой системы
- Описание триггера вызова sql запроса
Конфигурационный файл
Конфигурационный файл находится по адресу - /opt/pangeoradar/configs/pangeoradar-pgr-wal-listener.yaml
После изменения конфигурационного файла необходимо перезапустить сервис - service pangeoradar-pgr-wal-listener restart
Описание секций конфигурационного файла
Пересылаемый объект
При формировании пересылаемого объекта мы описываем структуру json объекта следующим образом:
Наименование мэппинга:
Наименование json поля объекта:
type: тип значения поля объекта (manual, map, active_map, map_form_json)
value: строковое значение присвоиваемое значению поля объекта в случае выбора типа manual, либо указание поле в sql объекте для осуществления мэпинга в случае выбора типа map, active_map, map_form_json
from: откуда брать список для приведения соответсвия в случае выбранного типа map_form_json
map: # указывается при выборе типа active_map
ключ: значение
Для типа map_for_json поддерживаемые специальные обработчики from
- varchar_array
- inet
API методы
При написании API метода для вызова мы описываем структуру следующим образом:
Наименование метода:
type: http
url: url api метода
method: http метод POST|GET|PUT|DELETE
content_type: "application/json"
headers: # заполняется, если требуется передать дополнительные заголовки (например авторизацию)
ExampleHeader: "test"
prepend: # дополнительный запрос, который нужно выполнить перед основным
- type: http
url: url другого api метода
method: GET
content_type: "application/json"
query: # описание заполнения get параметров
ключ: значение
filter: '[{"operator":"=","value":%d,"property":"id_siem"}]' # можно указать с учетом наличия внутри синтаксиса sprintf
query_vars_from_trigger: # при указании sprintf синтаксиса выше, нужно сформировать данные для подстановки
filter: # для какого ключа в query запросе будет применено формирование данных для подстановки
field: "id" # поле которое возьмется из sql запроса
type: "float64toInt64" # конвертация типов sql данных к sprintf типу
append_to_mapping: # в какое поле добавить результат ответа предварительного запроса
identifier: "data.result.0.identifier" #секция ключ: значение, для значения поддерживается доступ к json объекту ответа через обращения с помощью точки
mappging: *rvision_mapping # выбор мэппинга для формирования запроса
Поддерживаемая конвертация типов:
- bool
- int
- int32
- int64
- string
- float64
- float64toInt64
- float32
Триггеры
При формировании триггеров вызова мы оперируем следующими параметрами объектов:
Наименование группы тригеров: &radar-tables-trigger
- name: название триггера
table: наименовае наблюдаемой таблицы
fields: [ ] # список наблюдаемых полей в таблице
kind: insert # тип наблюдаемого запроса (insert, update, delete)
sql: # sql запрос для формирования объекта измененных данных, обязательно должно быть условие выборки по идентификатору, где $1 подставляемое значение идентификатора из измененной строки в таблице - "t.id = $1"
sql_vars:
id: float64toInt64 # приведение типов wal журнала к требуемым типам данным sql объекта
outputs: # в какие API методы требуется отправить результат формирования sql объектрап
- *rvision_insert
Соединение с СУБД
Финальным шагом является описание подключения к СУБД и инициализация группы триггеров:
connections:
- database: rmca
username: radar
password: ****
host: 127.0.0.1
port: 5432
triggers: *Наименование группы тригеров
UseTLS: false
SkipTLSVerify: false
PgCert: ""
PgKey: ""
RootCrt: ""
Пример конфигурации
Рассмотрим пример конфигурации с системой R-Vision
---
global:
force_replica_identity: true
log_level: warning
# Mappings (Описание пересылаемого объекта)
rvision_mapping: &rvision_mapping
token:
type: "manual"
value: "******"
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 (Описание вызова API методов подключаемой системы)
rvision_insert: &rvision_insert
type: http
url: "https://192.168.10.0/api/v2/incidents"
method: POST
content_type: "application/json"
headers:
PgrApiKey: "test"
mappging: *rvision_mapping
rvision_update: &rvision_update
type: http
url: "https://192.168.10.0/api/v2/incidents"
method: POST
content_type: "application/json"
headers:
PgrApiKey: "test"
prepend:
- type: http
url: "https://192.168.10.0/api/v2/incidents"
method: GET
content_type: "application/json"
query:
token: "61e1cce4c8b77de22574131da651d822a159225dd4d5f9781360c471046e1530"
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
# Inputs (Описание триггера вызова sql запроса)
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: rmca
username: radar
password: *****
host: 127.0.0.1
port: 5432
triggers: *radar-tables-trigger
UseTLS: false
SkipTLSVerify: false
PgCert: ""
PgKey: ""
RootCrt: ""