Перейти к содержанию

Интеграционный слой

Внутри поставки имеется гибкий инструмент для организации интеграции между Платформой Радар и любой другой системой с которой можно коммунициировать через Json API.

Концепция интеграционного слоя

Основной логикой является наблюдение за изменением данных в структуре хранения информации Платформы PostgreSQL и запуск некоторых действий при наступлении того или иного изменения.

Наблюдение за изменениями

Основной для реагирования на изменение является секция 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