diff --git a/README.md b/README.md index 556cf03..04bbe3a 100755 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ - `docs/deployment.md` — пошаговый деплой LXC и ActivityWatch Server. - `docs/runbook.md` — быстрый runbook для оператора. - `docs/operations.md` — регламент сопровождения, бэкапов, обновлений и rollback. +- `docs/GRAFANA_DASHBOARDS_RU.md` — импорт и сопровождение Grafana dashboard'ов через Ansible API playbook. +- `docs/PRESENTATION_RU.md` — презентационные экраны Grafana и AW-rus со скриншотами. - `docs/windows/ensemble.md` — orchestration-пакет для Windows-деплоя и проверки. - `docs/linux-client.md` — user-space rollout Linux-клиента ActivityWatch на удалённый `AW server`. - `docs/linux-remote-worker.md` — полный Linux remote-worker stack: GUI, SSH/console и browser admin UI вроде Proxmox `:8006`. @@ -20,6 +22,7 @@ - `proxmox/` — шаблонные скрипты подготовки и наполнения CT на стороне Proxmox. - `aw-server/` — установочные скрипты, env-шаблон, systemd unit и RU patch для Web UI. - `ansible/` — Ansible-ensemble для автоматизированного сервера (Debian/CT). +- `grafana/` — version-controlled Grafana dashboard JSON для RDP/worktime, DLP/ИБ и overview-экранов. - `pfsense/` — внешний poller для pfSense API и systemd unit под Debian/Ubuntu utility VM. - `windows/` — PowerShell toolkit: single-user, domain-users, ensemble orchestration, hardening/recovery, validation, Windows/RDP DLP telemetry (`aw-dlp-incidents_*`, `aw-dlp-endpoint-signals_*`) и session-level presence для удалённых Windows/RDP пользователей (`aw-worktime-sessions_*`). - `scripts/quality-gate.sh` — локальный preflight-пайплайн проверок. @@ -54,6 +57,11 @@ - `ansible/deploy_aw_pfsense_poller.yml` +Для импорта Grafana dashboard'ов через HTTP API: + +- `ansible/deploy_grafana_dashboards.yml` +- `docs/GRAFANA_DASHBOARDS_RU.md` + Для Linux desktop/admin host, который должен слать watcher'ы на удалённый AW server: - `docs/linux-client.md` @@ -90,7 +98,9 @@ ## Ограничения -- Интеграции с InfluxDB/Grafana/LDAP оставлены как следующий слой, не как обязательная база. +- Базовый серверный контур AW-rus работает и без Grafana/InfluxDB. +- Для управленческих и ИБ-dashboard'ов нужен отдельный мониторинговый стек: Grafana + InfluxDB. +- Часть интеграционных сценариев всё ещё требует внешних систем: pfSense, 1С, почтовый контур, SQL/monitoring stack. ## Быстрые ссылки @@ -100,6 +110,8 @@ - `docs/deployment.md` - `docs/runbook.md` - `docs/operations.md` +- `docs/GRAFANA_DASHBOARDS_RU.md` +- `docs/PRESENTATION_RU.md` - `proxmox/create-ct.sh` - `aw-server/install_aw_server.sh` - `windows/deploy-ensemble.ps1` diff --git a/SALES_OVERVIEW_RU.md b/SALES_OVERVIEW_RU.md index 61aa8c1..edbb5be 100644 --- a/SALES_OVERVIEW_RU.md +++ b/SALES_OVERVIEW_RU.md @@ -463,6 +463,20 @@ AW-rus особенно силен там, где нужен не “короб - оценка эффекта на реальных данных компании; - решение о масштабировании на всю организацию. +## Визуальная презентация + +Для демонстрации живых интерфейсов и dashboard'ов используйте: + +- [docs/PRESENTATION_RU.md](docs/PRESENTATION_RU.md) + +В документ уже включены скриншоты: + +- управленческого dashboard по активности пользователей в RDP; +- технического DLP/ИБ dashboard; +- управленческого ИБ dashboard; +- обзорного DLP dashboard; +- экранов AW-rus с activity summary и raw DLP bucket. + ## Что получает заказчик на первом этапе - работающий мониторинговый контур; diff --git a/ansible/README.md b/ansible/README.md index 75d978d..b8fbe87 100644 --- a/ansible/README.md +++ b/ansible/README.md @@ -14,6 +14,7 @@ - `ansible/provision_proxmox_ct_matrix_and_deploy_aw.yml` — массовый полный playbook (несколько CT). - `ansible/deploy_aw_windows.yml` — WinRM playbook для развёртывания Windows/RDP collector'ов. - `ansible/deploy_aw_pfsense_poller.yml` — развёртывание pfSense poller'а. +- `ansible/deploy_grafana_dashboards.yml` — импорт version-controlled Grafana dashboard'ов через HTTP API. - `ansible/deploy_tsj_guardian_bot_proxmox.yml` — развёртывание TSJ Guardian Telegram Bot на Proxmox host. - `ansible/install_full_stack.yml` — полный установочный playbook (оркестратор всех этапов). - `ansible/inventory.example.ini` — шаблон inventory. @@ -55,7 +56,8 @@ ansible-playbook -i inventory.ini install_full_stack.yml - `provision_proxmox_ct_and_deploy_aw.yml` (если есть хосты в группе `[proxmox]`); - `deploy_aw_server.yml` (группа `[aw_server]`); - `deploy_aw_windows.yml` (группа `[aw_windows]`); -- `deploy_aw_pfsense_poller.yml` (группа `[aw_pfsense_pollers]`). +- `deploy_aw_pfsense_poller.yml` (группа `[aw_pfsense_pollers]`); +- `deploy_grafana_dashboards.yml` (группа `[grafana]`). Пустые группы в `inventory.ini` безопасны: соответствующий play будет пропущен. @@ -162,6 +164,41 @@ Playbook: - пишет `/etc/aw-pfsense/poller.json`; - поднимает `aw-pfsense-poller.service`. +## Импорт Grafana dashboard'ов + +1. Подготовьте inventory и vars: + - `cp ansible/inventory.example.ini ansible/inventory.ini` + - `cp ansible/group_vars/grafana.example.yml ansible/group_vars/grafana.yml` +2. Укажите в inventory группу `[grafana]` и переменную `grafana_url`. +3. Экспортируйте пароль Grafana API: + +```bash +export GRAFANA_ADMIN_PASSWORD='...' +``` + +4. Запустите: + +```bash +cd ansible +ansible-playbook -i inventory.ini deploy_grafana_dashboards.yml +``` + +Playbook: + +- проверяет `GET /api/health`; +- создает или актуализирует folder `AWatch-rus` в Grafana; +- импортирует dashboard JSON из каталога `grafana/`; +- верифицирует доступность dashboard'ов по `uid` через Grafana API. + +По умолчанию импортируются: + +- `DetMir: Работа пользователей в RDP` +- `DetMir: DLP и ИБ обзор` +- `DetMir: ИБ сводка для руководства` +- `AW-rus: DLP обзор` + +Подробная документация: `docs/GRAFANA_DASHBOARDS_RU.md` + ## Развёртывание TSJ Guardian Bot на Proxmox 1. Подготовьте vars: diff --git a/ansible/deploy_grafana_dashboards.yml b/ansible/deploy_grafana_dashboards.yml new file mode 100644 index 0000000..801b174 --- /dev/null +++ b/ansible/deploy_grafana_dashboards.yml @@ -0,0 +1,125 @@ +--- +- name: Import AW-rus Grafana dashboards through HTTP API + hosts: grafana + gather_facts: false + connection: local + run_once: true + vars: + aw_repo_root: "{{ playbook_dir | dirname }}" + grafana_api_url: "{{ grafana_url | regex_replace('/+$', '') }}" + grafana_validate_tls_eff: "{{ grafana_validate_tls | default(true) }}" + grafana_folder_uid_eff: "{{ grafana_folder_uid | default('awatch-rus') }}" + grafana_folder_title_eff: "{{ grafana_folder_title | default('AWatch-rus') }}" + grafana_dashboards_import_overwrite_eff: "{{ grafana_dashboards_import_overwrite | default(true) }}" + grafana_dashboards: + - file: "grafana/detmir-rdp-user-activity-dashboard.json" + uid: "detmir-rdp-user-activity" + title: "DetMir: Работа пользователей в RDP" + - file: "grafana/detmir-dlp-security-dashboard.json" + uid: "detmir-dlp-security" + title: "DetMir: DLP и ИБ обзор" + - file: "grafana/detmir-dlp-management-dashboard.json" + uid: "detmir-dlp-management" + title: "DetMir: ИБ сводка для руководства" + - file: "grafana/dlp-dashboard.json" + uid: "awatch-dlp-overview" + title: "AW-rus: DLP обзор" + + tasks: + - name: Validate required Grafana settings + ansible.builtin.assert: + that: + - grafana_url is defined + - grafana_url | length > 0 + - grafana_admin_user is defined + - grafana_admin_user | length > 0 + - grafana_admin_password is defined + - grafana_admin_password | length > 0 + fail_msg: "Заполните grafana_url, grafana_admin_user и grafana_admin_password." + + - name: Check Grafana health endpoint + ansible.builtin.uri: + url: "{{ grafana_api_url }}/api/health" + method: GET + user: "{{ grafana_admin_user }}" + password: "{{ grafana_admin_password }}" + force_basic_auth: true + validate_certs: "{{ grafana_validate_tls_eff | bool }}" + return_content: true + status_code: 200 + + - name: Lookup Grafana folder by uid + ansible.builtin.uri: + url: "{{ grafana_api_url }}/api/folders/{{ grafana_folder_uid_eff }}" + method: GET + user: "{{ grafana_admin_user }}" + password: "{{ grafana_admin_password }}" + force_basic_auth: true + validate_certs: "{{ grafana_validate_tls_eff | bool }}" + return_content: true + status_code: + - 200 + - 404 + register: grafana_folder_lookup + + - name: Create Grafana folder when absent + ansible.builtin.uri: + url: "{{ grafana_api_url }}/api/folders" + method: POST + user: "{{ grafana_admin_user }}" + password: "{{ grafana_admin_password }}" + force_basic_auth: true + validate_certs: "{{ grafana_validate_tls_eff | bool }}" + body_format: json + status_code: 200 + body: + uid: "{{ grafana_folder_uid_eff }}" + title: "{{ grafana_folder_title_eff }}" + when: grafana_folder_lookup.status == 404 + + - name: Update Grafana folder title when it already exists + ansible.builtin.uri: + url: "{{ grafana_api_url }}/api/folders/{{ grafana_folder_uid_eff }}" + method: PUT + user: "{{ grafana_admin_user }}" + password: "{{ grafana_admin_password }}" + force_basic_auth: true + validate_certs: "{{ grafana_validate_tls_eff | bool }}" + body_format: json + status_code: 200 + body: + title: "{{ grafana_folder_title_eff }}" + version: "{{ (grafana_folder_lookup.json.version | default(0) | int) + 1 }}" + when: grafana_folder_lookup.status == 200 + + - name: Import Grafana dashboards from repository JSON + ansible.builtin.uri: + url: "{{ grafana_api_url }}/api/dashboards/db" + method: POST + user: "{{ grafana_admin_user }}" + password: "{{ grafana_admin_password }}" + force_basic_auth: true + validate_certs: "{{ grafana_validate_tls_eff | bool }}" + body_format: json + status_code: 200 + body: + dashboard: "{{ (lookup('file', aw_repo_root ~ '/' ~ item.file) | from_json) | combine({'id': None}, recursive=True) }}" + folderUid: "{{ grafana_folder_uid_eff }}" + overwrite: "{{ grafana_dashboards_import_overwrite_eff | bool }}" + message: "Imported by Ansible from {{ item.file }}" + loop: "{{ grafana_dashboards }}" + loop_control: + label: "{{ item.title }}" + + - name: Verify imported dashboards by uid + ansible.builtin.uri: + url: "{{ grafana_api_url }}/api/dashboards/uid/{{ item.uid }}" + method: GET + user: "{{ grafana_admin_user }}" + password: "{{ grafana_admin_password }}" + force_basic_auth: true + validate_certs: "{{ grafana_validate_tls_eff | bool }}" + status_code: 200 + loop: "{{ grafana_dashboards }}" + loop_control: + label: "{{ item.uid }}" diff --git a/ansible/group_vars/grafana.example.yml b/ansible/group_vars/grafana.example.yml new file mode 100644 index 0000000..336e24e --- /dev/null +++ b/ansible/group_vars/grafana.example.yml @@ -0,0 +1,7 @@ +grafana_url: "http://10.20.30.11:3000" +grafana_admin_user: "admin" +grafana_admin_password: "{{ lookup('env', 'GRAFANA_ADMIN_PASSWORD') }}" +grafana_validate_tls: false +grafana_folder_uid: "awatch-rus" +grafana_folder_title: "AWatch-rus" +grafana_dashboards_import_overwrite: true diff --git a/ansible/install_full_stack.yml b/ansible/install_full_stack.yml index cd3a7f6..f2694c9 100644 --- a/ansible/install_full_stack.yml +++ b/ansible/install_full_stack.yml @@ -5,6 +5,7 @@ # 2) развёртывание AW server на хостах [aw_server] # 3) развёртывание Windows/RDP collector'ов на [aw_windows] # 4) развёртывание pfSense poller'а на [aw_pfsense_pollers] +# 5) импорт Grafana dashboard'ов на [grafana] # # Примечания: # - Заполняйте только нужные группы inventory для своего окружения. @@ -14,3 +15,4 @@ - import_playbook: deploy_aw_server.yml - import_playbook: deploy_aw_windows.yml - import_playbook: deploy_aw_pfsense_poller.yml +- import_playbook: deploy_grafana_dashboards.yml diff --git a/ansible/inventory.example.ini b/ansible/inventory.example.ini index e1c77ff..62669da 100644 --- a/ansible/inventory.example.ini +++ b/ansible/inventory.example.ini @@ -10,3 +10,8 @@ win-node1 ansible_host=192.168.100.21 ansible_user=Администратор an [aw_pfsense_pollers] # pfsense-poller1 ansible_host=192.168.100.30 ansible_user=root ansible_port=22 + +[grafana] +# Для API-import playbook достаточно указать grafana_url. +# SSH-подключение не требуется: playbook работает через HTTP API с control host. +grafana-main grafana_url=http://10.20.30.11:3000 diff --git a/docs/GRAFANA_DASHBOARDS_RU.md b/docs/GRAFANA_DASHBOARDS_RU.md new file mode 100644 index 0000000..2e72cff --- /dev/null +++ b/docs/GRAFANA_DASHBOARDS_RU.md @@ -0,0 +1,74 @@ +# Grafana dashboard'ы AW-rus + +Документ описывает воспроизводимый импорт Grafana dashboard'ов из репозитория через Ansible и HTTP API Grafana. + +## Что лежит в git + +Version-controlled dashboard JSON находятся в каталоге `grafana/`: + +- `grafana/detmir-rdp-user-activity-dashboard.json` +- `grafana/detmir-dlp-security-dashboard.json` +- `grafana/detmir-dlp-management-dashboard.json` +- `grafana/dlp-dashboard.json` + +Их импортирует playbook: + +- `ansible/deploy_grafana_dashboards.yml` + +## Что импортируется + +1. `DetMir: Работа пользователей в RDP` +2. `DetMir: DLP и ИБ обзор` +3. `DetMir: ИБ сводка для руководства` +4. `AW-rus: DLP обзор` + +По умолчанию playbook складывает их в folder `AWatch-rus` с `uid=awatch-rus`. + +## Быстрый запуск + +1. Подготовьте inventory и vars: + +```bash +cd /mnt/usb_hdd2/Projects/ActivityWatch-Russian +cp ansible/inventory.example.ini ansible/inventory.ini +cp ansible/group_vars/grafana.example.yml ansible/group_vars/grafana.yml +``` + +2. Укажите `grafana_url` и заполните группу `[grafana]` в `ansible/inventory.ini`. + +3. Перед запуском задайте пароль Grafana через переменную окружения: + +```bash +export GRAFANA_ADMIN_PASSWORD='...' +``` + +4. Запустите импорт: + +```bash +cd ansible +ansible-playbook -i inventory.ini deploy_grafana_dashboards.yml +``` + +## Что делает playbook + +- проверяет `GET /api/health`; +- создает или обновляет folder `AWatch-rus`; +- импортирует dashboard JSON из репозитория; +- перезаписывает существующие dashboard'ы при `overwrite=true`; +- верифицирует каждый dashboard по `uid` через `GET /api/dashboards/uid/`. + +## Переменные + +- `grafana_url` — base URL Grafana, например `http://10.20.30.11:3000` +- `grafana_admin_user` — Grafana admin/API user +- `grafana_admin_password` — пароль, рекомендуется через `GRAFANA_ADMIN_PASSWORD` +- `grafana_validate_tls` — включать ли проверку TLS-сертификата +- `grafana_folder_uid` — UID целевого folder +- `grafana_folder_title` — отображаемое имя folder +- `grafana_dashboards_import_overwrite` — перезаписывать ли dashboard'ы при повторном импорте + +## Рекомендуемый эксплуатационный режим + +- редактировать dashboard JSON в `grafana/`, а не править production только руками в UI; +- после изменений прогонять `deploy_grafana_dashboards.yml`, чтобы Grafana вернулась к version-controlled состоянию; +- для презентации использовать [docs/PRESENTATION_RU.md](PRESENTATION_RU.md), где уже лежат скриншоты ключевых экранов. diff --git a/docs/PRESENTATION_RU.md b/docs/PRESENTATION_RU.md new file mode 100644 index 0000000..d41bcd5 --- /dev/null +++ b/docs/PRESENTATION_RU.md @@ -0,0 +1,62 @@ +# AW-rus: презентационные экраны + +Документ собирает живые экраны AW-rus и Grafana для demo, коммерческой презентации и внутренних согласований. + +## 1. Работа пользователей в RDP + +Управленческий экран по активности пользователей: кто работал, сколько времени, как выглядит команда по дням и кто активен сегодня. + +![DetMir: Работа пользователей в RDP](assets/screenshots/grafana-rdp-worktime.png) + +Источник в репозитории: + +- `grafana/detmir-rdp-user-activity-dashboard.json` + +## 2. DLP и ИБ обзор + +Технический dashboard для ИБ: сработки, severity, типы сигналов, verdict'ы, очередь кейсов и состояние доставки данных. + +![DetMir: DLP и ИБ обзор](assets/screenshots/grafana-dlp-security.png) + +Источник в репозитории: + +- `grafana/detmir-dlp-security-dashboard.json` + +## 3. ИБ сводка для руководства + +Экран для руководителя ИБ: открытые кейсы, инциденты повышенного риска, ожидающие решения события и верхнеуровневая динамика. + +![DetMir: ИБ сводка для руководства](assets/screenshots/grafana-dlp-management.png) + +Источник в репозитории: + +- `grafana/detmir-dlp-management-dashboard.json` + +## 4. DLP overview + +Обзорный dashboard для быстрых стендовых demo и smoke-проверки самого DLP-контура. + +![AW-rus: DLP обзор](assets/screenshots/grafana-dlp-overview.png) + +Источник в репозитории: + +- `grafana/dlp-dashboard.json` + +## 5. AW-rus summary по активности + +Экран ActivityWatch-Russian для просмотра реальной активности хоста и summary по выбранному дню. + +![AW-rus summary](assets/screenshots/aw-rus-summary.png) + +## 6. AW-rus raw DLP bucket + +Raw-представление bucket'а с endpoint-сигналами DLP. Показывает, что данные реально приходят в AW-rus до того, как уйти в InfluxDB/Grafana. + +![AW-rus DLP bucket](assets/screenshots/aw-rus-dlp-bucket.png) + +## Что показывать на встрече + +1. `RDP` dashboard — ценность для руководства и HR. +2. `DLP и ИБ обзор` — глубина технического контроля для ИБ. +3. `ИБ сводка для руководства` — понятный риск-ориентированный слой. +4. `AW-rus summary` и `raw DLP bucket` — доказательство, что система не только рисует графики, а реально получает события на сервере. diff --git a/docs/assets/screenshots/aw-rus-dlp-bucket.png b/docs/assets/screenshots/aw-rus-dlp-bucket.png new file mode 100644 index 0000000..4e6fe33 Binary files /dev/null and b/docs/assets/screenshots/aw-rus-dlp-bucket.png differ diff --git a/docs/assets/screenshots/aw-rus-summary.png b/docs/assets/screenshots/aw-rus-summary.png new file mode 100644 index 0000000..f02eb5e Binary files /dev/null and b/docs/assets/screenshots/aw-rus-summary.png differ diff --git a/docs/assets/screenshots/grafana-dlp-management.png b/docs/assets/screenshots/grafana-dlp-management.png new file mode 100644 index 0000000..6f51915 Binary files /dev/null and b/docs/assets/screenshots/grafana-dlp-management.png differ diff --git a/docs/assets/screenshots/grafana-dlp-overview.png b/docs/assets/screenshots/grafana-dlp-overview.png new file mode 100644 index 0000000..60f4be7 Binary files /dev/null and b/docs/assets/screenshots/grafana-dlp-overview.png differ diff --git a/docs/assets/screenshots/grafana-dlp-security.png b/docs/assets/screenshots/grafana-dlp-security.png new file mode 100644 index 0000000..8a8db46 Binary files /dev/null and b/docs/assets/screenshots/grafana-dlp-security.png differ diff --git a/docs/assets/screenshots/grafana-rdp-worktime.png b/docs/assets/screenshots/grafana-rdp-worktime.png new file mode 100644 index 0000000..62a7ff4 Binary files /dev/null and b/docs/assets/screenshots/grafana-rdp-worktime.png differ diff --git a/grafana/dlp-dashboard.json b/grafana/dlp-dashboard.json index 084cd45..9fa92e4 100644 --- a/grafana/dlp-dashboard.json +++ b/grafana/dlp-dashboard.json @@ -1,11 +1,12 @@ { - "title": "AWatch DLP Overview", + "uid": "awatch-dlp-overview", + "title": "AW-rus: DLP обзор", "schemaVersion": 39, - "version": 1, + "version": 2, "panels": [ { "type": "stat", - "title": "DLP Exporter Up", + "title": "DLP exporter: статус", "gridPos": { "x": 0, "y": 0, "w": 8, "h": 4 }, "targets": [ { "expr": "aw_dlp_exporter_up" }