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

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

Описание

В Платформе Радар существует две механики интеграции с внешними системами.

  1. Через API Платформы Радар получать необходимую информацию и интегрировать её на стороне подключаемой системы.
  2. С помощью API интегрируемой системы передавать данные со стороны Платформы Радар

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

Ограничения

На данный момент поддерживаются только JSON REST Api с авторизацией через HTTP заголовок или GET параметр.

Описание работы сервиса интеграции

Сервис pgr-wal-listener следит за всеми изменениями в базе данных postgresql и при наступлении интересующего нас изменения, может выполнить sql запрос для формирования объекта пересылаемых данных и инициировать отправку объекта в подключаемую систему. Также предусмотрена механика формирования требуемого объекта данных для запроса в исполняемой системе из полученных данных при sql запросе.

Концептуально конфигурацию сервиса можно поделить на три секции:

  1. Описание пересылаемого объекта
  2. Описание вызова API методов подключаемой системы
  3. Описание триггера вызова 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: ""