diff --git a/ansible/deploy_grafana_dashboards.yml b/ansible/deploy_grafana_dashboards.yml index 801b174..5ad7f28 100644 --- a/ansible/deploy_grafana_dashboards.yml +++ b/ansible/deploy_grafana_dashboards.yml @@ -90,7 +90,9 @@ body: title: "{{ grafana_folder_title_eff }}" version: "{{ (grafana_folder_lookup.json.version | default(0) | int) + 1 }}" - when: grafana_folder_lookup.status == 200 + when: + - grafana_folder_lookup.status == 200 + - (grafana_folder_lookup.json.title | default('')) != grafana_folder_title_eff - name: Import Grafana dashboards from repository JSON ansible.builtin.uri: diff --git a/docs/assets/screenshots/grafana-dlp-overview.png b/docs/assets/screenshots/grafana-dlp-overview.png index 9f0154e..c3a3e3e 100644 Binary files a/docs/assets/screenshots/grafana-dlp-overview.png and b/docs/assets/screenshots/grafana-dlp-overview.png differ diff --git a/grafana/dlp-dashboard.json b/grafana/dlp-dashboard.json index 9fa92e4..f0ce769 100644 --- a/grafana/dlp-dashboard.json +++ b/grafana/dlp-dashboard.json @@ -2,15 +2,325 @@ "uid": "awatch-dlp-overview", "title": "AW-rus: DLP обзор", "schemaVersion": 39, - "version": 2, + "version": 3, + "refresh": "30s", + "time": { + "from": "now-30d", + "to": "now" + }, "panels": [ { - "type": "stat", - "title": "DLP exporter: статус", - "gridPos": { "x": 0, "y": 0, "w": 8, "h": 4 }, + "datasource": { + "type": "influxdb", + "uid": "influxdb_aw" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "orange", + "value": 1 + }, + { + "color": "red", + "value": 5 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "center", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, "targets": [ - { "expr": "aw_dlp_exporter_up" } - ] + { + "query": "from(bucket: \"aw_metrics\")\n |> range(start: -7d)\n |> filter(fn: (r) => r._measurement == \"aw_dlp_incident\" and r._field == \"count\")\n |> sum()", + "refId": "A" + } + ], + "title": "Сработок за 7 дней", + "type": "stat" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influxdb_aw" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "orange", + "value": 1 + }, + { + "color": "red", + "value": 3 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 2, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "center", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "query": "from(bucket: \"aw_metrics\")\n |> range(start: -7d)\n |> filter(fn: (r) => r._measurement == \"aw_dlp_incident\" and r._field == \"count\" and (r.severity == \"high\" or r.severity == \"critical\"))\n |> sum()", + "refId": "A" + } + ], + "title": "Высокие и критичные за 7 дней", + "type": "stat" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influxdb_aw" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "orange", + "value": 1 + }, + { + "color": "red", + "value": 3 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "center", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "query": "from(bucket: \"aw_metrics\")\n |> range(start: -180d)\n |> filter(fn: (r) => r._measurement == \"aw_dlp_case\" and r._field == \"count\")\n |> group(columns:[\"case_id\"])\n |> last()\n |> filter(fn: (r) => r.status == \"open\")\n |> group()\n |> count()", + "refId": "A" + } + ], + "title": "Открытые кейсы", + "type": "stat" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influxdb_aw" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "orange", + "value": 1 + }, + { + "color": "red", + "value": 3 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "none", + "justifyMode": "center", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "targets": [ + { + "query": "from(bucket: \"aw_metrics\")\n |> range(start: -180d)\n |> filter(fn: (r) => r._measurement == \"aw_dlp_case\" and r._field == \"count\")\n |> group(columns:[\"case_id\"])\n |> last()\n |> filter(fn: (r) => r.status == \"investigating\")\n |> group()\n |> count()", + "refId": "A" + } + ], + "title": "В расследовании", + "type": "stat" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influxdb_aw" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "bars", + "fillOpacity": 80, + "lineWidth": 1, + "showPoints": "never" + }, + "displayName": "${__field.labels.series}" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 4 + }, + "id": 5, + "options": { + "legend": { + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi" + } + }, + "targets": [ + { + "query": "all = from(bucket: \"aw_metrics\")\n |> range(start: -30d)\n |> filter(fn: (r) => r._measurement == \"aw_dlp_incident\" and r._field == \"count\")\n |> aggregateWindow(every: 1d, fn: sum, createEmpty: false)\n |> set(key: \"series\", value: \"Все сработки\")\n\nhigh = from(bucket: \"aw_metrics\")\n |> range(start: -30d)\n |> filter(fn: (r) => r._measurement == \"aw_dlp_incident\" and r._field == \"count\" and (r.severity == \"high\" or r.severity == \"critical\"))\n |> aggregateWindow(every: 1d, fn: sum, createEmpty: false)\n |> set(key: \"series\", value: \"Высокие и критичные\")\n\nunion(tables: [all, high])\n |> group(columns:[\"series\"])", + "refId": "A" + } + ], + "title": "Динамика риска по дням", + "type": "timeseries" + }, + { + "datasource": { + "type": "influxdb", + "uid": "influxdb_aw" + }, + "fieldConfig": { + "defaults": { + "displayName": "${__field.labels.signal_type_ru}" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 4 + }, + "id": 6, + "options": { + "displayMode": "gradient", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true + }, + "targets": [ + { + "query": "from(bucket: \"aw_metrics\")\n |> range(start: -30d)\n |> filter(fn: (r) => r._measurement == \"aw_dlp_incident\" and r._field == \"count\")\n |> map(fn: (r) => ({ r with signal_type_ru: if r.signal_type == \"self_test\" then \"Самопроверка\" else if r.signal_type == \"print_job\" then \"Печать\" else if r.signal_type == \"clipboard_copy\" then \"Буфер обмена\" else if r.signal_type == \"file_operation\" then \"Файловая операция\" else if r.signal_type == \"email_outbound\" then \"Исходящая почта\" else if r.signal_type == \"browser_domain\" then \"Сайт\" else if r.signal_type == \"unknown\" then \"Неизвестно\" else r.signal_type }))\n |> group(columns:[\"signal_type_ru\"])\n |> sum()\n |> sort(columns:[\"_value\"], desc:true)", + "refId": "A" + } + ], + "title": "По каким типам событий чаще всего срабатывает DLP", + "type": "bargauge" } ] }