Перейти к основному содержимому
Версия: 4.5.X

Виджеты

В KOMRAD обновились виджеты, мы добавили возможность создавать, изменять и удалять визжеты и дашборды, а также много новых метрик, руководствуюясь методиками jira.

Виджеты

Виджеты является JSON-строкой, записанной в базе данных, у вас есть возможность отредактировать дашборд или конкретный виджет.

Добавление дашборда с виджетами

Для добавления дашборда с виджетами используйте команду:

psql -c INSERT INTO preferences.dashboards (id, user_id, config, created_at, updated_at, deleted_at) VALUES (4::integer, null::integer, '{"name": "Мониторинг", "tags": ["встроенные"], "vendor": "Эшелон", "widgets": [{"meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "select count(*) from incman.incidents where status = ''new''"}], "interval": "60s", "position": {"width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_INT64", "y": "DATA_TYPE_INT64"}}, "name": "Новых инцидентов", "description": "необработанных инцидентов"}, {"id": 1, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "select count(*) from incman.incidents where status = ''investigating''"}], "interval": "300s", "position": {"x": 1, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_INT64", "y": "DATA_TYPE_INT64"}}, "name": "В расследовании", "description": "за всё время"}, {"id": 2, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "select count(*) from incman.incidents where status = ''closed'' and DATE(close_time) = CURRENT_DATE"}], "interval": "300s", "position": {"x": 2, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_INT64", "y": "DATA_TYPE_INT64"}}, "name": "Закрыто сегодня", "description": "с датой закрытия сегодня"}, {"id": 3, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "select count(*) from incman.incidents where status = ''closed'' and DATE(close_time) = CURRENT_DATE"}], "interval": "300s", "position": {"x": 3, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_INT64", "y": "DATA_TYPE_INT64"}}, "name": "Закрыто за 7 дней", "description": "Число инцидентов закрытых за 7 дней"}, {"id": 4, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "select count(*) from incman.incidents where gossopka_sending_status = ''success''"}], "interval": "300s", "position": {"x": 4, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_INT64", "y": "DATA_TYPE_INT64"}}, "name": "ГосСОПКА", "description": "всего доставлено в ГосСОПКА"}, {"id": 5, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "select count(*) from incman.incidents where status != ''fp''"}], "interval": "300s", "position": {"x": 5, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_INT64", "y": "DATA_TYPE_INT64"}}, "name": "Всего инцидентов", "description": "без ложноположительных"}, {"id": 6, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "SELECT\n    ROUND(AVG(EXTRACT(EPOCH FROM (incidents.registration_time - incidents.initial_time)))) as MTTD_in_seconds\nFROM\n    incman.incidents\nWHERE status != ''fp''\n    AND registration_time >= NOW() - INTERVAL ''30 day'';"}], "interval": "300s", "position": {"y": 1, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_FLOAT", "y": "DATA_TYPE_FLOAT"}}, "name": "СВОИ (MTTD), секунд", "description": "среднее время обнаружения инцидента, за последние 30 дней"}, {"id": 7, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "SELECT COALESCE(CEIL(AVG(EXTRACT(EPOCH FROM (close_time - incidents.registration_time)))/60), 0) as MTTR_in_minutes\nFROM incman.incidents\nWHERE close_time IS NOT NULL\n  AND status != ''fp''\n  AND registration_time >= NOW() - INTERVAL ''30 day'';"}], "interval": "300s", "position": {"x": 1, "y": 1, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_FLOAT", "y": "DATA_TYPE_FLOAT"}}, "name": "СВРИ (MTTR), минут", "description": "среднее время реагирования на инцидент, за последние 30 дней"}, {"id": 8, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "WITH a AS (SELECT registration_time,\n                  close_time,\n                  LAG(close_time) OVER (ORDER BY registration_time) AS previous_close_time\n           FROM incman.incidents\n           WHERE close_time IS NOT NULL\n             AND status != ''fp''\n             AND registration_time >= NOW() - INTERVAL ''30 day'')\nSELECT COALESCE(ABS(AVG(EXTRACT(EPOCH FROM (registration_time - previous_close_time))) / 60), 0) AS MTBF_in_minutes\nFROM a\nWHERE previous_close_time IS NOT NULL;"}], "interval": "300s", "position": {"x": 2, "y": 1, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_FLOAT", "y": "DATA_TYPE_FLOAT"}}, "name": "СВБИ (MTBF), минут", "description": "среднее время без иницидентов, за последние 30 дней"}, {"id": 9, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "SELECT\n    AVG(EXTRACT(EPOCH FROM (incidents.registration_time - incidents.initial_time))) as MTTD_in_seconds\nFROM\n    incman.incidents\nWHERE status != ''fp''\n    AND registration_time >= NOW() - INTERVAL ''30 day'';"}], "interval": "300s", "position": {"x": 3, "y": 1, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_FLOAT", "y": "DATA_TYPE_FLOAT"}}, "name": "СВД (MTTA), минут", "description": "среднее время обнаружения инцидента, за последние 30 дней"}, {"id": 10, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "SELECT\n    AVG(EXTRACT(EPOCH FROM (incidents.registration_time - incidents.initial_time))) as MTTD_in_seconds\nFROM\n    incman.incidents\nWHERE status != ''fp''\n    AND registration_time >= NOW() - INTERVAL ''30 day'';"}], "interval": "300s", "position": {"x": 4, "y": 1, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_FLOAT", "y": "DATA_TYPE_FLOAT"}}, "name": "Без инцидентов", "description": "часов без инцидентов"}, {"id": 11, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "SELECT\n    AVG(EXTRACT(EPOCH FROM (incidents.registration_time - incidents.initial_time))) as MTTD_in_seconds\nFROM\n    incman.incidents\nWHERE status != ''fp''\n    AND registration_time >= NOW() - INTERVAL ''30 day'';"}], "interval": "300s", "position": {"x": 5, "y": 1, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_FLOAT", "y": "DATA_TYPE_FLOAT"}}, "name": "MTTD", "description": "среднее время обнаружения инцидента, за последние 30 дней"}, {"id": 12, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_TIME_SERIES", "source": "WIDGET_SOURCE_CLICKHOUSE", "queries": [{"query": "SELECT\n    toUnixTimestamp(src.m) * 1000 AS ts,\n    sumIf(src.total, src.category = ''syslog'') AS syslog,\n    sumIf(src.total, src.category = ''sql'') AS sql,\n    sumIf(src.total, src.category = ''http'') AS http,\n    sumIf(src.total, src.category = ''snmp'') AS snmp,\n    sumIf(src.total, src.category = ''xflow'') AS xflow,\n    sumIf(src.total, src.category = ''wmi'') AS wmi,\n    sumIf(src.total, src.category = ''file'') AS file,\n    sumIf(src.total, src.category = ''internal'') AS internal,\n    sum(total) AS total\nFROM\n(\n    SELECT\n        toStartOfMinute(FROM_UNIXTIME(key_time)) AS m,\n        collector_type AS category,\n        count(*) AS total\n    FROM komrad_events.events\n    WHERE (m >= ((now() - toIntervalSecond({shift_seconds:UInt32})) - toIntervalSecond({interval_seconds:UInt32}))) AND (m <= (now() - toIntervalSecond({shift_seconds:UInt32})))\n    GROUP BY\n        collector_type,\n        m\n    ORDER BY\n        m ASC,\n        collector_type ASC\n) AS src\nGROUP BY ts\nORDER BY ts ASC\n", "interval": "3600s", "granularity": "60s"}], "interval": "120s", "position": {"y": 2, "width": 3, "height": 1}, "axesTypes": {"x": "DATA_TYPE_INT64", "y": "DATA_TYPE_INT64"}}, "name": "Число событий в минуту (EPM)", "description": "Число событий в минуту за последний час"}, {"id": 13, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_CLICKHOUSE", "queries": [{"query": "SELECT toUInt64(round(exponentialMovingAverage(1)(total, key_time) OVER (ORDER BY key_time ASC))) AS eps\nFROM\n(\n    SELECT\n        key_time,\n        count(*) AS total\n    FROM komrad_events.events\n    WHERE (key_time <= now()) AND (key_time >= (toUnixTimestamp(now()) - 120))\n    GROUP BY key_time\n    ORDER BY key_time ASC WITH FILL FROM toUnixTimestamp(now()) - 120 TO toUnixTimestamp(now())\n) AS src\nORDER BY key_time DESC\nLIMIT 1, 1\n"}], "interval": "1s", "position": {"x": 3, "y": 2, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_UINT64", "y": "DATA_TYPE_UINT64"}}, "name": "EPS", "description": "cобытий в секунду, сглаженное EWMA"}, {"id": 14, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_COUNTER", "source": "WIDGET_SOURCE_CLICKHOUSE", "queries": [{"query": "SELECT count(*)\nFROM komrad_events.events\n"}], "interval": "1s", "position": {"x": 4, "y": 2, "width": 2, "height": 1}, "axesTypes": {"x": "DATA_TYPE_UINT64", "y": "DATA_TYPE_UINT64"}}, "name": "Всего событий ИБ", "description": "Общее количество событий"}, {"id": 15, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_TABLE", "source": "WIDGET_SOURCE_CLICKHOUSE", "queries": [{"label": "Top %d IP адресов за 24 часа", "query": "SELECT\n    asset_ips AS addr,\n    count(*) AS total\nFROM komrad_events.events\nARRAY JOIN asset_ips\nWHERE (now() - toIntervalHour(24)) <= FROM_UNIXTIME(key_time)\nGROUP BY addr\nORDER BY total DESC\nLIMIT 25\n"}], "interval": "300s", "position": {"y": 3, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_STRING", "y": "DATA_TYPE_UINT64"}}, "name": "IP адреса", "description": "за 24 часа"}, {"id": 16, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_TABLE", "source": "WIDGET_SOURCE_CLICKHOUSE", "queries": [{"label": "Top %d имён хостов 24 часа", "query": "SELECT\n    related_host AS addr,\n    count(*) AS total\nFROM komrad_events.events\nARRAY JOIN related_host\nWHERE (now() - toIntervalHour(24)) <= FROM_UNIXTIME(key_time)\nGROUP BY related_host\nORDER BY total DESC\nLIMIT 25\n"}], "interval": "300s", "position": {"x": 1, "y": 3, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_STRING", "y": "DATA_TYPE_UINT64"}}, "name": "Имена хостов", "description": "за 24 часа"}, {"id": 17, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_TABLE", "source": "WIDGET_SOURCE_CLICKHOUSE", "queries": [{"label": "Top %d пользователей за 24 часа", "query": "SELECT\n    related_user AS addr,\n    count(*) AS total\nFROM komrad_events.events\nARRAY JOIN related_user\nWHERE (now() - toIntervalHour(24)) <= FROM_UNIXTIME(key_time)\nGROUP BY related_user\nORDER BY total DESC\nLIMIT 25\n"}], "interval": "300s", "position": {"x": 2, "y": 3, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_STRING", "y": "DATA_TYPE_UINT64"}}, "name": "Пользователи", "description": "за 24 часа"}, {"id": 18, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_TABLE", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "WITH unnested AS (\n    SELECT unnest(threats_array) ->> ''ThreatTechnique'' AS ThreatTechnique,\n           lower(unnest(threats_array) ->> ''ThreatFrameworkName'') AS ThreatFrameworkName\n    FROM incman.incidents\n    WHERE registration_time > CURRENT_TIMESTAMP - INTERVAL ''24 hours''\n)\nSELECT ThreatTechnique, COUNT(*)\nFROM unnested\nWHERE ThreatTechnique IS NOT NULL\nAND (\n    ThreatFrameworkName ILIKE ''%'' || ''фстэк'' || ''%''\n    OR ThreatFrameworkName ILIKE ''%'' || ''бду'' || ''%''\n    )\nGROUP BY ThreatTechnique\nORDER BY COUNT(*) DESC, ThreatTechnique\nLIMIT 25;"}], "interval": "300s", "position": {"x": 3, "y": 3, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_STRING", "y": "DATA_TYPE_UINT64"}}, "name": "БДУ ФСТЭК", "description": "за 24 часа"}, {"id": 19, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_TABLE", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"query": "WITH unnested AS (\n    SELECT unnest(threats_array) ->> ''ThreatTechnique'' AS ThreatTechnique,\n           lower(unnest(threats_array) ->> ''ThreatFrameworkName'') AS ThreatFrameworkName\n    FROM incman.incidents\n    WHERE registration_time > CURRENT_TIMESTAMP - INTERVAL ''24 hours''\n)\nSELECT ThreatTechnique, COUNT(*)\nFROM unnested\nWHERE ThreatTechnique IS NOT NULL\nAND ThreatFrameworkName ILIKE ''%'' || ''mitre'' || ''%''\nGROUP BY ThreatTechnique\nORDER BY COUNT(*) DESC, ThreatTechnique\nLIMIT 25;"}], "interval": "300s", "position": {"x": 4, "y": 3, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_STRING", "y": "DATA_TYPE_UINT64"}}, "name": "MITRE", "description": "за 24 часа"}, {"id": 20, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_TABLE", "source": "WIDGET_SOURCE_CLICKHOUSE", "queries": [{"query": "SELECT\n    JSONExtractString(custom, ''ECS.Vulnerability.ID'') AS id,\n    count(*) AS total\nFROM komrad_events.events\nWHERE (length(id) > 0) AND ((now() - toIntervalHour(24)) <= FROM_UNIXTIME(key_time))\nGROUP BY id\nORDER BY\n    total DESC,\n    id ASC\nLIMIT 25\n"}], "interval": "3600s", "position": {"x": 5, "y": 3, "width": 1, "height": 1}, "axesTypes": {"x": "DATA_TYPE_STRING", "y": "DATA_TYPE_UINT64"}}, "name": "Уязвимости", "description": "за 24 часа"}, {"id": 21, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_BAR", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"label": "последние 24 часа", "query": "SELECT severity, count(*) AS total\nFROM incman.incidents\nWHERE registration_time > NOW() - INTERVAL ''24 hour''\nGROUP BY severity"}], "interval": "300s", "position": {"y": 4, "width": 2, "height": 1}}, "name": "Инциденты по важности", "description": "за последние 24 часа"}, {"id": 22, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_BAR", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"label": "последние 7 дней", "query": "SELECT status, count(*) AS total\nFROM incman.incidents\nWHERE registration_time > NOW() - INTERVAL ''7 day''\nGROUP BY status"}], "interval": "300s", "position": {"x": 2, "y": 4, "width": 2, "height": 1}}, "name": "Инциденты по статусам", "description": "за последние 7 дней"}, {"id": 23, "meta": {"tags": ["встроенные"], "type": "WIDGET_TYPE_BAR", "source": "WIDGET_SOURCE_POSTGRES", "queries": [{"label": "Незакрытые инциденты", "query": "SELECT severity, count(*) AS total\nFROM incman.incidents\nWHERE status IN (''new''::incman.incident_status, ''investigating''::incman.incident_status)\nGROUP BY severity"}], "interval": "60s", "position": {"x": 4, "y": 4, "width": 2, "height": 1}}, "name": "Незакрытые инциденты", "description": "по уровню важности за всё время"}], "readonly": true, "description": "Сводные графики системы мониторинга безопасности КОМРАД"}'::jsonb, '2023-02-25 18:42:34.346000 +00:00'::timestamp with time zone, '2024-01-24 18:42:46.376000 +00:00'::timestamp with time zone, null::timestamp with time zone)

Удаление дашборда

Для удаления дашборда и всех виджетов на нём введите команду

psql DELETE FROM preferences.dashboards WHERE id = 2::integer

Создание виджета

Виджеты имеют определённый формат

 {
"id": 1,
"meta": {
"tags": [
"встроенные"
],
"type": "WIDGET_TYPE_COUNTER",
"source": "WIDGET_SOURCE_POSTGRES",
"queries": [
{
"query": "select count(*) from incman.incidents where status = 'investigating'"
}
],
"interval": "300s",
"position": {
"x": 1,
"width": 1,
"height": 1
},
"axesTypes": {
"x": "DATA_TYPE_INT64",
"y": "DATA_TYPE_INT64"
}
},
"name": "В расследовании",
"description": "за всё время"
},
  • type - тип виджета, возможные типы:

    • WIDGET_TYPE_UNSPECIFIED - не уточнен
    • WIDGET_TYPE_COUNTER - числовое значение
    • WIDGET_TYPE_TIME_SERIES - диаграмма временных рядов
    • WIDGET_TYPE_PIE - круговая диаграмма
    • WIDGET_TYPE_TABLE - таблица
    • WIDGET_TYPE_BAR - столбчатая диаграмма
  • source - источник данных (WIDGET_SOURCE_POSTGRES/WIDGET_SOURCE_CLICKHOUSE)

  • queries - sql-запросы, на основании результатов которых будет создан виджет

  • query - текст запроса

  • interval - периодичность обновления виджета

  • position - расположение и размер виджета

  • x - порядок по горизонтали, начиная с 0

  • y - порядок по вертикали, начиная с 0

  • width - ширина ячейки

  • height - высота ячейки

  • axesTypes - тип данных для указания расположения виджета

  • name - название

  • description - описание