feat(1c): add file-based analytics stack scaffold

This commit is contained in:
igor04091968
2026-05-21 23:34:55 +03:00
parent b420104f1f
commit 04b45ecf03
30 changed files with 1537 additions and 13 deletions
+28
View File
@@ -8,9 +8,11 @@
- `docs/codebase-onboarding.md` — обзор структуры репозитория и маршрут изучения для новичка.
- `docs/deployment.md` — пошаговый деплой LXC и ActivityWatch Server.
- `docs/runbook.md` — быстрый runbook для оператора.
- `docs/security-analytics-stack-v1.md` — текущий security analytics контур: Hayabusa, auto-case, scoring и Telegram alerts.
- `docs/operations.md` — регламент сопровождения, бэкапов, обновлений и rollback.
- `docs/GRAFANA_DASHBOARDS_RU.md` — импорт и сопровождение Grafana dashboard'ов через Ansible API playbook.
- `docs/PRESENTATION_RU.md` — презентационные экраны Grafana и AW-rus со скриншотами.
- `docs/1C_FILE_ANALYTICS_STACK_RU.md` — новый ClickHouse/Grafana/AI Investigator контур для файловой 1С.
- `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`.
@@ -23,6 +25,7 @@
- `aw-server/` — установочные скрипты, env-шаблон, systemd unit и RU patch для Web UI.
- `ansible/` — Ansible-ensemble для автоматизированного сервера (Debian/CT).
- `grafana/` — version-controlled Grafana dashboard JSON для RDP/worktime, DLP/ИБ и overview-экранов.
- `clickhouse-1c/` — отдельный analytics stack для **файловой 1С**: ETL, ClickHouse schema, detections, Grafana catalog и AI Investigator contract.
- `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-пайплайн проверок.
@@ -44,6 +47,30 @@
8. Развернуть Windows-клиентов через `windows/deploy-ensemble.ps1`.
9. Проверить итог через `windows/validate-deployment.ps1`.
## Текущий security analytics контур
Сейчас в `AW-rus` уже есть замкнутый forensic-контур:
- Windows-хост раз в `6` часов делает `EVTX export + upload`;
- `aw-hayabusa-drop.path` автоматически подхватывает новый пакет;
- `aw-hayabusa` строит forensic-отчёт;
- `aw-hayabusa-case-alert` считает severity и score;
- при уровне от `medium` создаётся или обновляется case;
- при уровне от `high` уходит Telegram alert;
- в case пишется только bounded metadata, без сырых EVTX и полного timeline body.
Практический операторский вход:
```powershell
powershell.exe -ExecutionPolicy Bypass -File C:\ProgramData\AWatch-rus\export-upload-hayabusa-to-aw-server.ps1 -HoursBack 6 -CaseId 30
```
Подробности:
- `docs/security-analytics-stack-v1.md`
- `docs/runbook.md`
- `docs/hayabusa-operator-ib-guide-2026-05-14.md`
Для полного Ansible-сценария “с нуля” в Proxmox используйте:
- `ansible/provision_proxmox_ct_and_deploy_aw.yml`
@@ -61,6 +88,7 @@
- `ansible/deploy_grafana_dashboards.yml`
- `docs/GRAFANA_DASHBOARDS_RU.md`
- `docs/1C_FILE_ANALYTICS_STACK_RU.md`
Для Linux desktop/admin host, который должен слать watcher'ы на удалённый AW server:
+33
View File
@@ -122,6 +122,7 @@ Playbook:
- выполняет API smoke-check bucket `aw-watcher-window_<COMPUTERNAME>` и ожидает свежие события (по умолчанию включено);
- запускает `validate-deployment.ps1`;
- забирает JSON-отчёт в локальную директорию (`/tmp/aw-rus-validation-<USER>` по умолчанию).
- настраивает scheduled task `ActivityWatch Hayabusa Upload` с периодом и lookback по vars.
Дополнительные флаги:
@@ -144,6 +145,38 @@ Playbook:
- `aw_windows_api_smoke_check_min_events: 1` — минимум событий, ожидаемых в smoke-check;
- `aw_windows_fail_on_validation_error: true` — завершать playbook ошибкой, если `validate-deployment.ps1` возвращает `overallOk=false`;
- `aw_windows_skip_hardening: true` — пропустить `hardening-recovery.ps1` внутри ensemble-скрипта.
- `aw_windows_hayabusa_auto_upload_enabled: true` — включить авто-upload EVTX на AW-server;
- `aw_windows_hayabusa_auto_upload_interval_hours: 6` — период scheduled task;
- `aw_windows_hayabusa_auto_upload_hours_back: 6` — lookback для каждого запуска;
- `aw_windows_hayabusa_auto_upload_mode: "incident"` — mode для server-side processing;
- `aw_windows_hayabusa_auto_upload_task_name: "ActivityWatch Hayabusa Upload"` — имя scheduled task.
## Server-side Hayabusa auto-case и Telegram alerting
На стороне `deploy_aw_server.yml` теперь есть server-side контур:
- `aw-hayabusa-drop.path`
- `aw-hayabusa-drop.service`
- `aw-hayabusa-autoprocess`
- `aw-hayabusa-case-alert`
Что делает контур:
- автоматически подхватывает `zip` из `/opt/activitywatch/aw-rus-ops/drop`;
- запускает `aw-hayabusa`;
- считает severity/score по `timeline.jsonl`;
- создаёт или обновляет case;
- пишет bounded metadata в `forensics.hayabusa`;
- отправляет Telegram alert.
Основные vars:
- `aw_hayabusa_auto_case_enabled: true`
- `aw_hayabusa_auto_case_min_severity: "medium"`
- `aw_hayabusa_telegram_enabled: true`
- `aw_hayabusa_telegram_min_severity: "high"`
- `aw_hayabusa_telegram_bot_token`
- `aw_hayabusa_telegram_chat_ids`
## Развёртывание pfSense poller
+9
View File
@@ -0,0 +1,9 @@
CLICKHOUSE_DB=analytics_1c
CLICKHOUSE_USER=default
CLICKHOUSE_PASSWORD=change-me
CLICKHOUSE_PORT=8123
CLICKHOUSE_NATIVE_PORT=9000
GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=change-me
GRAFANA_PORT=3300
CLICKHOUSE_HOST=clickhouse
+125
View File
@@ -0,0 +1,125 @@
# file-1C analytics stack for AW-rus
Этот каталог — отдельный production scaffold для **файловой 1С**.
Он не заменяет старый `grafana-1c/` контур и не ломает его. Старый контур
остаётся для случаев, когда 1С даёт SQL/read-only views и удобна схема
`sql-exporter -> Prometheus -> Grafana`.
Этот новый контур нужен именно тогда, когда:
- 1С работает как **файловая база** на Windows/RDP host;
- на сам RDP host нежелательно ставить тяжёлые сервисы;
- нужны нормальные расследования, timeline, detections и cases;
- Grafana должна строиться не только по KPI, а по аудиту и аномалиям.
## Целевая схема
```text
File 1C + reglog + host telemetry
raw landing
ETL / normalize / enrich
ClickHouse
├─ raw_*
├─ documents
├─ postings
├─ reglog_events
├─ audit_events
├─ host_events
├─ entity_timeline
├─ detections
└─ cases
Grafana + Alerting + AI Investigator
```
## Что внутри
- `docker-compose.yml` — локальный scaffold ClickHouse + Grafana.
- `.env.example` — переменные окружения.
- `clickhouse/init/*.sql` — схема БД.
- `etl/load_1c_exports.py` — loader CSV/JSON выгрузок в raw/core таблицы.
- `etl/config.example.yml` — пример ETL-конфига.
- `detections/rules.yml` — каталог правил detections.
- `detections/insert_detections.sql` — SQL-шаблоны rule-based detections.
- `grafana/dashboard-catalog.md` — целевая структура дашбордов.
- `grafana/query-pack.sql` — базовые SQL-запросы для панелей.
- `grafana/provisioning/datasources/clickhouse.yml` — provisioned datasource для Grafana.
- `detections/build_entity_timeline.sql` — сборка единого timeline слоя.
- `detections/open_cases_from_detections.sql` — шаблон открытия cases из detections.
- `ops/etl-cron.example` — пример расписания каждые 6 часов.
- `ops/retention-policy.md` — минимальная retention policy.
- `ai/INVESTIGATOR_API.md` — контракт AI Investigator поверх ClickHouse/cases.
## Когда использовать именно этот контур
Используй `clickhouse-1c/`, если:
- 1С файловая;
- нужен контур `аудит -> detections -> cases -> timeline`;
- нужен drill-down в расследование, а не только KPI панели;
- данные можно выгружать из 1С в `CSV/JSON`, а не читать напрямую SQL exporter'ом.
Используй `grafana-1c/`, если:
- 1С даёт стабильный SQL/read-only доступ;
- достаточно KPI/Prometheus/Grafana;
- не нужен полноценный case-oriented audit stack.
## Быстрый старт
1. Скопировать env:
```bash
cd clickhouse-1c
cp .env.example .env
```
2. Поднять ClickHouse + Grafana:
```bash
docker compose up -d
```
3. Инициализировать landing-каталоги и ETL config:
```bash
mkdir -p landing/{documents,postings,reglog,audit,host}
cp etl/config.example.yml etl/config.yml
```
4. Запустить ETL:
```bash
python3 -m venv .venv
. .venv/bin/activate
pip install -r etl/requirements.txt
python etl/load_1c_exports.py --config etl/config.yml
```
5. Применить detections:
```bash
clickhouse-client --queries-file detections/insert_detections.sql
```
6. В Grafana строить dashboards из `grafana/dashboard-catalog.md` и
`grafana/query-pack.sql`.
## Ожидаемые источники данных
- выгрузки 1С по документам;
- выгрузки движений/проводок;
- журнал регистрации 1С;
- audit/export критичных изменений;
- host telemetry с Windows/RDP host.
## Границы
- AI Investigator не пишет в 1С;
- LLM не ходит прямо в production 1С;
- в ClickHouse кладутся нормализованные выгрузки и enrichment;
- case/timeline слой считается вне 1С.
+80
View File
@@ -0,0 +1,80 @@
# AI Investigator API contract
AI Investigator не должен ходить напрямую в файловую 1С.
Его правильный слой:
- ClickHouse (`analytics_1c.*`)
- DLP/forensics case API
- bounded search/timeline endpoints
## Базовые use-cases
- почему выросли ошибки по базе;
- какие пользователи дали риск за сутки;
- что произошло по case `X`;
- собрать summary по entity timeline;
- предложить next steps без write-действий.
## Рекомендуемые API endpoints
### `GET /api/1/analytics-1c/summary`
Параметры:
- `infobase`
- `from`
- `to`
Возвращает:
- sales
- returns
- overdue_receivables
- detections_by_severity
- open_cases
### `GET /api/1/analytics-1c/detections`
Фильтры:
- `infobase`
- `severity`
- `rule_id`
- `entity_type`
- `entity_id`
### `GET /api/1/analytics-1c/timeline`
Фильтры:
- `entity_type`
- `entity_id`
- `from`
- `to`
### `GET /api/1/analytics-1c/cases/{case_id}`
Возвращает:
- case card
- related detections
- related timeline rows
## Guardrails
- read-only SQL;
- whitelist queries;
- no direct write-back into 1С;
- no direct execution of arbitrary SQL from prompt;
- all investigator requests are logged.
## Output style
AI Investigator должен выдавать:
1. краткую суть;
2. что именно найдено;
3. почему это важно;
4. что проверить дальше;
5. ссылки на case/timeline.
@@ -0,0 +1 @@
CREATE DATABASE IF NOT EXISTS analytics_1c;
@@ -0,0 +1,44 @@
CREATE TABLE IF NOT EXISTS analytics_1c.raw_1c_documents
(
ingested_at DateTime DEFAULT now(),
source_file String,
payload String
)
ENGINE = MergeTree
ORDER BY (ingested_at, source_file);
CREATE TABLE IF NOT EXISTS analytics_1c.raw_1c_postings
(
ingested_at DateTime DEFAULT now(),
source_file String,
payload String
)
ENGINE = MergeTree
ORDER BY (ingested_at, source_file);
CREATE TABLE IF NOT EXISTS analytics_1c.raw_reglog
(
ingested_at DateTime DEFAULT now(),
source_file String,
payload String
)
ENGINE = MergeTree
ORDER BY (ingested_at, source_file);
CREATE TABLE IF NOT EXISTS analytics_1c.raw_audit
(
ingested_at DateTime DEFAULT now(),
source_file String,
payload String
)
ENGINE = MergeTree
ORDER BY (ingested_at, source_file);
CREATE TABLE IF NOT EXISTS analytics_1c.raw_host_metrics
(
ingested_at DateTime DEFAULT now(),
source_file String,
payload String
)
ENGINE = MergeTree
ORDER BY (ingested_at, source_file);
@@ -0,0 +1,132 @@
CREATE TABLE IF NOT EXISTS analytics_1c.documents
(
ts DateTime,
infobase LowCardinality(String),
organization String,
department String,
doc_type LowCardinality(String),
doc_id String,
doc_number String,
author String,
counterparty String,
operation_type String,
amount Decimal(18, 2),
status LowCardinality(String),
posted UInt8,
source_file String
)
ENGINE = MergeTree
ORDER BY (infobase, ts, doc_type, doc_id);
CREATE TABLE IF NOT EXISTS analytics_1c.postings
(
ts DateTime,
infobase LowCardinality(String),
registrar String,
operation_type String,
account_dt String,
account_ct String,
amount Decimal(18, 2),
source_file String
)
ENGINE = MergeTree
ORDER BY (infobase, ts, registrar);
CREATE TABLE IF NOT EXISTS analytics_1c.reglog_events
(
ts DateTime,
infobase LowCardinality(String),
user String,
host String,
app String,
event_name String,
level LowCardinality(String),
duration_ms UInt32,
message String,
source_file String
)
ENGINE = MergeTree
ORDER BY (infobase, ts, user, event_name);
CREATE TABLE IF NOT EXISTS analytics_1c.audit_events
(
ts DateTime,
infobase LowCardinality(String),
user String,
object_type String,
object_id String,
action String,
before_hash String,
after_hash String,
risk_tag String,
source_file String
)
ENGINE = MergeTree
ORDER BY (infobase, ts, object_type, object_id);
CREATE TABLE IF NOT EXISTS analytics_1c.host_events
(
ts DateTime,
host String,
cpu_pct Float32,
ram_pct Float32,
disk_free_gb Float32,
disk_latency_ms Float32,
smb_errors UInt32,
rdp_sessions UInt32,
backup_ok UInt8,
source_file String
)
ENGINE = MergeTree
ORDER BY (host, ts);
CREATE TABLE IF NOT EXISTS analytics_1c.entity_timeline
(
ts DateTime,
entity_type LowCardinality(String),
entity_id String,
infobase LowCardinality(String),
actor String,
source LowCardinality(String),
event_type String,
severity LowCardinality(String),
score UInt32,
ref_id String,
summary String
)
ENGINE = MergeTree
ORDER BY (entity_type, entity_id, ts);
CREATE TABLE IF NOT EXISTS analytics_1c.detections
(
ts DateTime,
detection_id String,
infobase LowCardinality(String),
rule_id String,
rule_title String,
entity_type LowCardinality(String),
entity_id String,
severity LowCardinality(String),
score UInt32,
summary String,
status LowCardinality(String) DEFAULT 'open'
)
ENGINE = MergeTree
ORDER BY (severity, ts, rule_id, entity_type, entity_id);
CREATE TABLE IF NOT EXISTS analytics_1c.cases
(
opened_at DateTime,
case_id String,
infobase LowCardinality(String),
title String,
severity LowCardinality(String),
status LowCardinality(String),
assignee String,
detection_id String,
entity_type String,
entity_id String,
summary String
)
ENGINE = MergeTree
ORDER BY (opened_at, case_id);
@@ -0,0 +1,26 @@
CREATE VIEW IF NOT EXISTS analytics_1c.v_documents_daily AS
SELECT
toDate(ts) AS d,
infobase,
organization,
doc_type,
count() AS docs_total,
sum(amount) AS amount_total,
sumIf(amount, posted = 0) AS unposted_amount
FROM analytics_1c.documents
GROUP BY d, infobase, organization, doc_type;
CREATE VIEW IF NOT EXISTS analytics_1c.v_detections_daily AS
SELECT
toDate(ts) AS d,
infobase,
severity,
count() AS detections_total,
sum(score) AS score_total
FROM analytics_1c.detections
GROUP BY d, infobase, severity;
CREATE VIEW IF NOT EXISTS analytics_1c.v_open_cases AS
SELECT *
FROM analytics_1c.cases
WHERE status != 'closed';
@@ -0,0 +1,44 @@
INSERT INTO analytics_1c.entity_timeline
SELECT
ts,
'document' AS entity_type,
doc_id AS entity_id,
infobase,
author AS actor,
'documents' AS source,
concat('document:', doc_type) AS event_type,
if(posted = 1, 'low', 'medium') AS severity,
if(posted = 1, 5, 20) AS score,
doc_id AS ref_id,
concat('Документ ', doc_type, '', doc_number, ' статус=', status) AS summary
FROM analytics_1c.documents;
INSERT INTO analytics_1c.entity_timeline
SELECT
ts,
'user' AS entity_type,
user AS entity_id,
infobase,
user AS actor,
'reglog' AS source,
event_name AS event_type,
if(level IN ('error', 'warn'), 'medium', 'low') AS severity,
if(level IN ('error', 'warn'), 25, 5) AS score,
concat(user, ':', toString(toUnixTimestamp(ts))) AS ref_id,
message AS summary
FROM analytics_1c.reglog_events;
INSERT INTO analytics_1c.entity_timeline
SELECT
ts,
object_type AS entity_type,
object_id AS entity_id,
infobase,
user AS actor,
'audit' AS source,
action AS event_type,
if(risk_tag != '', 'high', 'medium') AS severity,
if(risk_tag != '', 60, 30) AS score,
concat(object_type, ':', object_id, ':', toString(toUnixTimestamp(ts))) AS ref_id,
concat('Audit action ', action, ' risk=', risk_tag) AS summary
FROM analytics_1c.audit_events;
@@ -0,0 +1,52 @@
INSERT INTO analytics_1c.detections
SELECT
ts,
concat('after_hours_login:', infobase, ':', user, ':', toString(toUnixTimestamp(ts))) AS detection_id,
infobase,
'after_hours_login' AS rule_id,
'Вход вне рабочего времени' AS rule_title,
'user' AS entity_type,
user AS entity_id,
'medium' AS severity,
35 AS score,
concat('Пользователь ', user, ' выполнил вход вне рабочего времени') AS summary,
'open' AS status
FROM analytics_1c.reglog_events
WHERE event_name ILIKE '%login%'
AND toHour(ts) NOT BETWEEN 8 AND 20;
INSERT INTO analytics_1c.detections
SELECT
max(ts) AS ts,
concat('failed_login_burst:', infobase, ':', user, ':', toString(toUnixTimestamp(max(ts)))) AS detection_id,
infobase,
'failed_login_burst' AS rule_id,
'Всплеск ошибок входа' AS rule_title,
'user' AS entity_type,
user AS entity_id,
'high' AS severity,
65 AS score,
concat('У пользователя ', user, ' более 5 ошибок входа за 15 минут') AS summary,
'open' AS status
FROM analytics_1c.reglog_events
WHERE level IN ('error', 'warn')
AND (event_name ILIKE '%login%' OR message ILIKE '%парол%' OR message ILIKE '%auth%')
GROUP BY infobase, user, toStartOfFifteenMinutes(ts)
HAVING count() >= 5;
INSERT INTO analytics_1c.detections
SELECT
max(ts) AS ts,
concat('disk_latency_high:', host, ':', toString(toUnixTimestamp(max(ts)))) AS detection_id,
'' AS infobase,
'disk_latency_high' AS rule_id,
'Высокая задержка диска' AS rule_title,
'host' AS entity_type,
host AS entity_id,
'high' AS severity,
65 AS score,
concat('На хосте ', host, ' задержка диска превышает 50 мс') AS summary,
'open' AS status
FROM analytics_1c.host_events
GROUP BY host, toStartOfHour(ts)
HAVING avg(disk_latency_ms) > 50;
@@ -0,0 +1,16 @@
INSERT INTO analytics_1c.cases
SELECT
ts AS opened_at,
detection_id AS case_id,
infobase,
concat('1C ', upper(severity), ' · ', rule_title, ' · ', entity_id) AS title,
severity,
'open' AS status,
'' AS assignee,
detection_id,
entity_type,
entity_id,
summary
FROM analytics_1c.detections
WHERE severity IN ('high', 'critical')
AND detection_id NOT IN (SELECT case_id FROM analytics_1c.cases);
+61
View File
@@ -0,0 +1,61 @@
rules:
- id: after_hours_login
severity: medium
score: 35
source: reglog_events
summary: "Вход пользователя вне рабочего времени"
- id: failed_login_burst
severity: high
score: 65
source: reglog_events
summary: "Всплеск ошибок входа за короткое окно"
- id: mass_reposting
severity: high
score: 70
source: audit_events
summary: "Массовое перепроведение документов"
- id: critical_object_change
severity: high
score: 75
source: audit_events
summary: "Изменение критичного объекта 1С"
- id: manual_adjustment_spike
severity: medium
score: 45
source: documents
summary: "Аномальный рост ручных корректировок"
- id: returns_spike
severity: medium
score: 40
source: documents
summary: "Аномальный рост возвратов"
- id: overdue_receivables_growth
severity: high
score: 55
source: documents
summary: "Резкий рост просроченной дебиторки"
- id: long_running_operation
severity: medium
score: 30
source: reglog_events
summary: "Длительная операция в журнале регистрации"
- id: exchange_failure_burst
severity: high
score: 60
source: reglog_events
summary: "Всплеск ошибок обмена"
- id: disk_latency_high
severity: high
score: 65
source: host_events
summary: "Высокая задержка диска на файловом сервере 1С"
- id: backup_stale
severity: critical
score: 90
source: host_events
summary: "Бэкап файловой 1С устарел или не подтвержден"
- id: unusual_account_postings
severity: medium
score: 35
source: postings
summary: "Нетипичные проводки по счетам"
+35
View File
@@ -0,0 +1,35 @@
services:
clickhouse:
image: clickhouse/clickhouse-server:24.8
container_name: aw-rus-1c-clickhouse
restart: unless-stopped
environment:
CLICKHOUSE_DB: ${CLICKHOUSE_DB}
CLICKHOUSE_USER: ${CLICKHOUSE_USER}
CLICKHOUSE_PASSWORD: ${CLICKHOUSE_PASSWORD}
ports:
- "${CLICKHOUSE_PORT}:8123"
- "${CLICKHOUSE_NATIVE_PORT}:9000"
volumes:
- ./clickhouse/init:/docker-entrypoint-initdb.d:ro
- clickhouse_1c_data:/var/lib/clickhouse
grafana:
image: grafana/grafana:11.2.2
container_name: aw-rus-1c-grafana
restart: unless-stopped
environment:
GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER}
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD}
GF_INSTALL_PLUGINS: grafana-clickhouse-datasource
ports:
- "${GRAFANA_PORT}:3000"
volumes:
- grafana_1c_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning:ro
depends_on:
- clickhouse
volumes:
clickhouse_1c_data:
grafana_1c_data:
+24
View File
@@ -0,0 +1,24 @@
clickhouse:
host: localhost
port: 8123
username: default
password: change-me
database: analytics_1c
landing:
documents: ./landing/documents
postings: ./landing/postings
reglog: ./landing/reglog
audit: ./landing/audit
host: ./landing/host
formats:
default: jsonl
documents: jsonl
postings: jsonl
reglog: jsonl
audit: jsonl
host: jsonl
archive_dir: ./archive
delete_after_load: false
+220
View File
@@ -0,0 +1,220 @@
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import csv
import json
import shutil
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path
from typing import Any
import clickhouse_connect
import yaml
from dateutil import parser as date_parser
RAW_TABLES = {
"documents": "raw_1c_documents",
"postings": "raw_1c_postings",
"reglog": "raw_reglog",
"audit": "raw_audit",
"host": "raw_host_metrics",
}
CORE_TABLES = {
"documents": "documents",
"postings": "postings",
"reglog": "reglog_events",
"audit": "audit_events",
"host": "host_events",
}
@dataclass
class Config:
clickhouse: dict[str, Any]
landing: dict[str, str]
formats: dict[str, str]
archive_dir: str | None
delete_after_load: bool
def parse_args() -> argparse.Namespace:
p = argparse.ArgumentParser(description="Load file-based 1C exports into ClickHouse")
p.add_argument("--config", required=True, help="Path to YAML config")
p.add_argument("--dataset", choices=["documents", "postings", "reglog", "audit", "host"], help="Load only one dataset")
return p.parse_args()
def load_config(path: str) -> Config:
raw = yaml.safe_load(Path(path).read_text(encoding="utf-8"))
return Config(
clickhouse=raw["clickhouse"],
landing=raw["landing"],
formats=raw.get("formats", {"default": "jsonl"}),
archive_dir=raw.get("archive_dir"),
delete_after_load=bool(raw.get("delete_after_load", False)),
)
def ch_client(conf: Config):
return clickhouse_connect.get_client(
host=conf.clickhouse["host"],
port=conf.clickhouse.get("port", 8123),
username=conf.clickhouse.get("username", "default"),
password=conf.clickhouse.get("password", ""),
database=conf.clickhouse.get("database", "analytics_1c"),
)
def normalize_ts(value: Any) -> datetime:
if isinstance(value, datetime):
return value
if value is None or value == "":
return datetime.utcnow()
return date_parser.parse(str(value))
def iter_rows(path: Path, fmt: str) -> list[dict[str, Any]]:
if fmt == "jsonl":
return [json.loads(line) for line in path.read_text(encoding="utf-8").splitlines() if line.strip()]
if fmt == "json":
payload = json.loads(path.read_text(encoding="utf-8"))
return payload if isinstance(payload, list) else [payload]
if fmt == "csv":
with path.open("r", encoding="utf-8-sig", newline="") as fh:
return list(csv.DictReader(fh))
raise ValueError(f"unsupported format: {fmt}")
def insert_raw(client, dataset: str, source_file: str, rows: list[dict[str, Any]]) -> None:
client.insert(
RAW_TABLES[dataset],
[[source_file, json.dumps(row, ensure_ascii=False)] for row in rows],
column_names=["source_file", "payload"],
)
def map_core_row(dataset: str, source_file: str, row: dict[str, Any]) -> list[Any]:
if dataset == "documents":
return [
normalize_ts(row.get("ts") or row.get("posted_at") or row.get("created_at")),
row.get("infobase", ""),
row.get("organization", ""),
row.get("department", ""),
row.get("doc_type", ""),
row.get("doc_id", ""),
row.get("doc_number", ""),
row.get("author", ""),
row.get("counterparty", ""),
row.get("operation_type", ""),
float(row.get("amount", 0) or 0),
row.get("status", ""),
int(row.get("posted", 0) or 0),
source_file,
]
if dataset == "postings":
return [
normalize_ts(row.get("ts")),
row.get("infobase", ""),
row.get("registrar", ""),
row.get("operation_type", ""),
row.get("account_dt", ""),
row.get("account_ct", ""),
float(row.get("amount", 0) or 0),
source_file,
]
if dataset == "reglog":
return [
normalize_ts(row.get("ts")),
row.get("infobase", ""),
row.get("user", ""),
row.get("host", ""),
row.get("app", ""),
row.get("event_name", ""),
row.get("level", "info"),
int(row.get("duration_ms", 0) or 0),
row.get("message", ""),
source_file,
]
if dataset == "audit":
return [
normalize_ts(row.get("ts")),
row.get("infobase", ""),
row.get("user", ""),
row.get("object_type", ""),
row.get("object_id", ""),
row.get("action", ""),
row.get("before_hash", ""),
row.get("after_hash", ""),
row.get("risk_tag", ""),
source_file,
]
if dataset == "host":
return [
normalize_ts(row.get("ts")),
row.get("host", ""),
float(row.get("cpu_pct", 0) or 0),
float(row.get("ram_pct", 0) or 0),
float(row.get("disk_free_gb", 0) or 0),
float(row.get("disk_latency_ms", 0) or 0),
int(row.get("smb_errors", 0) or 0),
int(row.get("rdp_sessions", 0) or 0),
int(row.get("backup_ok", 0) or 0),
source_file,
]
raise ValueError(dataset)
def core_columns(dataset: str) -> list[str]:
if dataset == "documents":
return ["ts", "infobase", "organization", "department", "doc_type", "doc_id", "doc_number", "author", "counterparty", "operation_type", "amount", "status", "posted", "source_file"]
if dataset == "postings":
return ["ts", "infobase", "registrar", "operation_type", "account_dt", "account_ct", "amount", "source_file"]
if dataset == "reglog":
return ["ts", "infobase", "user", "host", "app", "event_name", "level", "duration_ms", "message", "source_file"]
if dataset == "audit":
return ["ts", "infobase", "user", "object_type", "object_id", "action", "before_hash", "after_hash", "risk_tag", "source_file"]
return ["ts", "host", "cpu_pct", "ram_pct", "disk_free_gb", "disk_latency_ms", "smb_errors", "rdp_sessions", "backup_ok", "source_file"]
def archive_or_delete(conf: Config, dataset: str, path: Path) -> None:
if conf.archive_dir:
archive_root = Path(conf.archive_dir) / dataset
archive_root.mkdir(parents=True, exist_ok=True)
shutil.move(str(path), archive_root / path.name)
return
if conf.delete_after_load:
path.unlink(missing_ok=True)
def main() -> int:
args = parse_args()
conf = load_config(args.config)
client = ch_client(conf)
datasets = [args.dataset] if args.dataset else list(RAW_TABLES)
for dataset in datasets:
landing = Path(conf.landing[dataset])
fmt = conf.formats.get(dataset, conf.formats.get("default", "jsonl"))
if not landing.exists():
continue
for path in sorted(p for p in landing.iterdir() if p.is_file()):
rows = iter_rows(path, fmt)
if not rows:
archive_or_delete(conf, dataset, path)
continue
insert_raw(client, dataset, path.name, rows)
client.insert(
CORE_TABLES[dataset],
[map_core_row(dataset, path.name, row) for row in rows],
column_names=core_columns(dataset),
)
archive_or_delete(conf, dataset, path)
print(f"loaded {dataset}: {path.name} rows={len(rows)}")
return 0
if __name__ == "__main__":
raise SystemExit(main())
+3
View File
@@ -0,0 +1,3 @@
clickhouse-connect>=0.7.16
PyYAML>=6.0.2
python-dateutil>=2.9.0
+135
View File
@@ -0,0 +1,135 @@
# Grafana dashboard catalog for file-based 1C
Ниже — целевой набор дашбордов. Это не “один giant dashboard”, а иерархия под
разные роли.
## 1. 1C Executive Summary
Для руководства и владельца процесса.
Панели:
- Выручка сегодня / 7 дней / 30 дней
- Просроченная дебиторка
- Возвраты и корректировки
- Открытые cases
- High/Critical detections
- Топ проблемных баз
- Топ риск-пользователей
- Тренд аномалий
Основные таблицы:
- `documents`
- `detections`
- `cases`
## 2. 1C Operations Health
Для сопровождения и инфраструктуры.
Панели:
- CPU / RAM / Disk
- Disk latency
- Свободное место
- RDP sessions
- Ошибки SMB / файлового доступа
- Ошибки журнала регистрации
- Длительные операции
- Backup freshness
Основные таблицы:
- `host_events`
- `reglog_events`
## 3. 1C Audit Overview
Для контроля, ИБ и внутреннего аудита.
Панели:
- Входы по пользователям
- Входы вне рабочего времени
- Изменения критичных объектов
- Массовые перепроведения
- Нетипичные корректировки
- Severity split
- Топ пользователей по risk score
Основные таблицы:
- `reglog_events`
- `audit_events`
- `detections`
## 4. 1C Detections
Для triage и контроля rules.
Панели:
- Detections by severity
- Top rules
- Cases opened by day
- Open detections
- Critical timeline
- Top entities
Основные таблицы:
- `detections`
- `cases`
## 5. 1C Investigation Timeline
Для ручного расследования.
Панели:
- Entity timeline
- Case drilldown
- User trace
- Document trace
- Related detections
- Raw event details
Основные таблицы:
- `entity_timeline`
- `detections`
- `cases`
- `reglog_events`
- `audit_events`
- `documents`
## 6. 1C Data Quality
Для контроля самого пайплайна.
Панели:
- Последняя выгрузка по каждой базе
- ETL lag
- Битые/пустые файлы
- Rows loaded per batch
- Ошибки ETL
Источники:
- ETL run log
- архив landing/ETL статусов
## Единые variables
Во все dashboards:
- `infobase`
- `organization`
- `user`
- `host`
- `document_type`
- `severity`
- `case_status`
- `time range`
@@ -0,0 +1,16 @@
apiVersion: 1
datasources:
- name: clickhouse-1c
uid: clickhouse-1c
type: grafana-clickhouse-datasource
access: proxy
editable: true
jsonData:
defaultDatabase: analytics_1c
port: 8123
server: clickhouse
protocol: http
username: ${CLICKHOUSE_USER}
secureJsonData:
password: ${CLICKHOUSE_PASSWORD}
+66
View File
@@ -0,0 +1,66 @@
-- Executive: sales today
SELECT
toDate(ts) AS d,
sum(amount) AS sales_amount
FROM analytics_1c.documents
WHERE doc_type = 'Реализация'
GROUP BY d
ORDER BY d;
-- Executive: overdue receivables
SELECT
organization,
sum(amount) AS overdue_receivables
FROM analytics_1c.documents
WHERE status = 'overdue'
GROUP BY organization
ORDER BY overdue_receivables DESC;
-- Operations: host health
SELECT
ts,
host,
cpu_pct,
ram_pct,
disk_latency_ms,
disk_free_gb
FROM analytics_1c.host_events
ORDER BY ts DESC;
-- Audit: after-hours activity
SELECT
ts,
infobase,
user,
event_name,
message
FROM analytics_1c.reglog_events
WHERE event_name ILIKE '%login%'
AND toHour(ts) NOT BETWEEN 8 AND 20
ORDER BY ts DESC;
-- Detections: top rules
SELECT
rule_title,
severity,
count() AS detections_total,
sum(score) AS score_total
FROM analytics_1c.detections
GROUP BY rule_title, severity
ORDER BY detections_total DESC;
-- Investigation: entity timeline
SELECT
ts,
entity_type,
entity_id,
actor,
source,
event_type,
severity,
score,
summary
FROM analytics_1c.entity_timeline
WHERE entity_type = {entity_type:String}
AND entity_id = {entity_id:String}
ORDER BY ts;
+5
View File
@@ -0,0 +1,5 @@
# every 6 hours: load exports, rebuild timeline, refresh cases
0 */6 * * * cd /opt/aw-rus/clickhouse-1c && . .venv/bin/activate && python etl/load_1c_exports.py --config etl/config.yml >> /var/log/aw-rus-1c-etl.log 2>&1
10 */6 * * * clickhouse-client --queries-file /opt/aw-rus/clickhouse-1c/detections/build_entity_timeline.sql >> /var/log/aw-rus-1c-timeline.log 2>&1
15 */6 * * * clickhouse-client --queries-file /opt/aw-rus/clickhouse-1c/detections/insert_detections.sql >> /var/log/aw-rus-1c-detections.log 2>&1
20 */6 * * * clickhouse-client --queries-file /opt/aw-rus/clickhouse-1c/detections/open_cases_from_detections.sql >> /var/log/aw-rus-1c-cases.log 2>&1
+11
View File
@@ -0,0 +1,11 @@
# Retention policy
Минимально разумный retention для файловой 1С analytics stack:
- landing/raw exports: `30` дней
- archived raw files: `90` дней
- raw_* в ClickHouse: `30` дней
- core tables: `365` дней
- detections/cases/timeline: `365` дней или по регламенту ИБ
Если регуляторика требует больше, меняется отдельно от Grafana UI.
+127
View File
@@ -0,0 +1,127 @@
# Файловая 1С: ClickHouse + Grafana + AI Investigator
Этот документ описывает целевой и уже подготовленный scaffold для **файловой 1С**.
Он нужен для случаев, когда:
- 1С работает как файловая база на Windows/RDP host;
- на сам RDP host не хочется ставить лишние тяжёлые сервисы;
- нужен не только KPI-обзор, но и audit/detection/investigation контур.
## Почему не `prometheus_1C_exporter`
`prometheus_1C_exporter` полезен для **серверной 1С** с `rac`.
Для файловой 1С он не даёт нужного контекста:
- нет кластера `rac`;
- нет нормального session/license/runtime слоя как у серверной 1С;
- остаются только host-level и export-level данные.
Поэтому для файловой 1С правильный путь другой:
```text
1С exports + reglog + host telemetry
ETL / normalize
ClickHouse
Grafana + detections
AI Investigator
```
## Что входит в scaffold
- `clickhouse-1c/` — новый каталог стека;
- ClickHouse schema для raw/core/timeline/cases;
- ETL loader CSV/JSON выгрузок;
- detection catalog;
- Grafana dashboard catalog;
- AI Investigator API contract.
## Основные таблицы
- `raw_1c_documents`
- `raw_1c_postings`
- `raw_reglog`
- `raw_audit`
- `raw_host_metrics`
- `documents`
- `postings`
- `reglog_events`
- `audit_events`
- `host_events`
- `entity_timeline`
- `detections`
- `cases`
## Что визуализировать в Grafana
Роли:
1. `1C Executive Summary`
2. `1C Operations Health`
3. `1C Audit Overview`
4. `1C Detections`
5. `1C Investigation Timeline`
6. `1C Data Quality`
Полный каталог панелей:
- `clickhouse-1c/grafana/dashboard-catalog.md`
- `clickhouse-1c/grafana/query-pack.sql`
## Detections
Первый production-набор правил:
- вход вне рабочего времени;
- всплеск failed logins;
- массовое перепроведение;
- изменение критичных объектов;
- аномальный рост ручных корректировок;
- аномальный рост возвратов;
- рост просроченной дебиторки;
- длительные операции;
- всплеск ошибок обмена;
- высокая задержка диска;
- stale backup;
- нетипичные проводки по счетам.
См.:
- `clickhouse-1c/detections/rules.yml`
- `clickhouse-1c/detections/insert_detections.sql`
- `clickhouse-1c/detections/build_entity_timeline.sql`
- `clickhouse-1c/detections/open_cases_from_detections.sql`
- `clickhouse-1c/ops/etl-cron.example`
## Операционный порядок
1. На файловом/RDP host:
- выгрузить данные 1С в `CSV/JSON`;
- выгрузить журнал регистрации;
- снять host telemetry.
2. На utility VM:
- положить файлы в `clickhouse-1c/landing/*`;
- прогнать `etl/load_1c_exports.py`;
- прогнать `insert_detections.sql`;
- открыть Grafana dashboards;
- при необходимости построить AI summary поверх cases/timeline.
## Где граница AI
AI не должен:
- писать обратно в 1С;
- выполнять произвольный SQL;
- менять case state без явного правила.
AI должен:
- объяснять detections;
- строить summary по case;
- связывать audit/reglog/documents в timeline;
- предлагать next steps.
+6
View File
@@ -2,6 +2,12 @@
Документ описывает внедрение контура мониторинга 1С в Grafana через Prometheus и SQL Exporter.
> Важно: этот документ относится к сценарию, где 1С удобно читается через SQL/read-only views.
> Для **файловой 1С** теперь есть отдельный контур:
>
> - `docs/1C_FILE_ANALYTICS_STACK_RU.md`
> - `clickhouse-1c/README.md`
## 1. Целевая схема
1. База 1С (PostgreSQL или MS SQL) содержит KPI views.
+12 -3
View File
@@ -26,7 +26,7 @@
- `runbook.md` — быстрые операционные действия и проверки.
- `operations.md` — сопровождение, бэкапы, rollback.
- `windows/*` — отдельная ветка документации по Windows-оркестрации.
- `1C_GRAFANA_DEPLOYMENT_RU.md`, `pfsense.md`, `linux-client.md` — специализированные подсистемы.
- `1C_GRAFANA_DEPLOYMENT_RU.md`, `1C_FILE_ANALYTICS_STACK_RU.md`, `pfsense.md`, `linux-client.md` — специализированные подсистемы.
### `proxmox/`
Скрипты ранней инфраструктурной фазы:
@@ -65,6 +65,15 @@ PowerShell toolkit для клиентской стороны:
### `grafana-1c/`
Набор для SQL exporter + Prometheus + Grafana дашбордов по 1C метрикам.
### `clickhouse-1c/`
Новый stack именно для **файловой 1С**:
- ETL выгрузок `CSV/JSON`,
- ClickHouse schema,
- rule-based detections,
- Grafana dashboard catalog,
- AI Investigator contract.
### `scripts/`
Утилиты и quality gates:
@@ -84,7 +93,7 @@ PowerShell toolkit для клиентской стороны:
4. Включение автозапуска и проверка (`systemd` + `docs/runbook.md`).
5. Rollout клиентов (обычно `windows/`, иногда `scripts/install_aw_linux_client.sh`).
6. Эксплуатация и изменения через `docs/operations.md`.
7. При необходимости — расширение мониторинга (`grafana-1c/`, `pfsense/`).
7. При необходимости — расширение мониторинга (`grafana-1c/`, `clickhouse-1c/`, `pfsense/`).
## 4) Что важно понять в первую очередь
@@ -120,7 +129,7 @@ PowerShell toolkit для клиентской стороны:
- Если интересует эксплуатация и инциденты: `docs/runbook.md`, `docs/operations.md`, `docs/windows/troubleshooting.md`.
- Если интересует автодеплой: `ansible/provision_proxmox_ct_and_deploy_aw.yml` и `ansible/tasks/`.
- Если интересует наблюдаемость: `grafana-1c/` + `pfsense/` + `prometheus`/`alerts` конфиги.
- Если интересует наблюдаемость: `grafana-1c/`, `clickhouse-1c/` + `pfsense/` + `prometheus`/`alerts` конфиги.
- Если интересует hardening и DLP: `windows/hardening-recovery.ps1`, `docs/dlp-gap-analysis.md`.
---
+42 -1
View File
@@ -82,7 +82,42 @@ Playbook вычисляет `durationDefault` автоматически (вкл
## Типовые инциденты
### Hayabusa: production validation end-to-end
### Hayabusa: операторский сценарий по умолчанию
Текущий production-сценарий уже не требует ручного `accept/process-inbox`.
Нормальный путь для оператора:
1. На Windows-хосте запустить:
```powershell
powershell.exe -ExecutionPolicy Bypass -File C:\ProgramData\AWatch-rus\export-upload-hayabusa-to-aw-server.ps1 -HoursBack 6 -CaseId 30
```
2. Сервер `10.10.10.13` сам:
- примет `zip` и `.meta.json` в `/opt/activitywatch/aw-rus-ops/drop`;
- запустит `aw-hayabusa`;
- посчитает severity/score;
- создаст case при уровне от `medium`;
- отправит Telegram alert при уровне от `high`.
3. Проверить результат:
```bash
cat /opt/hayabusa/state/latest-intake.json
journalctl -u aw-hayabusa-drop.service -n 80 --no-pager
curl -fsS http://127.0.0.1:5602/api/0/dlp/cases/30
```
Ожидаемо:
- `latest-intake.json` имеет `status=ok`;
- `drop` после обработки пустой;
- в case есть `forensics.hayabusa`;
- Telegram alert уже уходит в операторский чат.
### Hayabusa: manual fallback / production validation end-to-end
Цель: подтвердить один реальный путь
@@ -94,6 +129,12 @@ Playbook вычисляет `durationDefault` автоматически (вкл
Минимальный production-proven сценарий:
Этот путь нужен только если:
- надо руками прогнать старый пакет;
- надо повторно разобрать archived zip;
- надо отладить сам `aw-hayabusa` без drop-автоматики.
1. На Windows-хосте сделать экспорт:
```powershell
+50
View File
@@ -0,0 +1,50 @@
# File 1C Analytics
Эта страница описывает новый контур для **файловой 1С**.
## Когда он нужен
Используй этот контур, если:
- 1С файловая;
- на RDP host нельзя или нежелательно ставить тяжёлые агенты;
- нужен audit/detection/investigation стек;
- Grafana должна быть не только для KPI, но и для расследования.
## Схема
```text
1С exports + reglog + host telemetry
ETL / normalize
ClickHouse
Grafana + detections
AI Investigator
```
## Основные компоненты
- `clickhouse-1c/README.md`
- `clickhouse-1c/clickhouse/init/*.sql`
- `clickhouse-1c/etl/load_1c_exports.py`
- `clickhouse-1c/detections/rules.yml`
- `clickhouse-1c/grafana/dashboard-catalog.md`
- `clickhouse-1c/ai/INVESTIGATOR_API.md`
## Основные dashboard-ы
- `1C Executive Summary`
- `1C Operations Health`
- `1C Audit Overview`
- `1C Detections`
- `1C Investigation Timeline`
- `1C Data Quality`
## Связанные документы
- [File 1C analytics stack](../1C_FILE_ANALYTICS_STACK_RU.md)
- [1C Grafana deployment](../1C_GRAFANA_DEPLOYMENT_RU.md)
- [Runbook](../runbook.md)
+103
View File
@@ -0,0 +1,103 @@
# Hayabusa Security Analytics
Эта страница описывает текущий production-контур Hayabusa внутри `AW-rus`.
## Что уже работает
- Windows-хост раз в `6` часов делает `EVTX export + upload`
- `AW-server` автоматически подхватывает пакет из `drop`
- `aw-hayabusa` строит forensic-отчёт
- `aw-hayabusa-case-alert` считает severity и score
- при уровне от `medium` создаётся или обновляется case
- при уровне от `high` уходит Telegram alert
## Операторский сценарий
На Windows-хосте:
```powershell
powershell.exe -ExecutionPolicy Bypass -File C:\ProgramData\AWatch-rus\export-upload-hayabusa-to-aw-server.ps1 -HoursBack 6 -CaseId 30
```
На сервере для проверки:
```bash
cat /opt/hayabusa/state/latest-intake.json
journalctl -u aw-hayabusa-drop.service -n 80 --no-pager
curl -fsS http://127.0.0.1:5602/api/0/dlp/cases/30
```
## Что получает оператор
- `summary.html`
- `manifest.json`
- `run.log`
- `timeline.jsonl`
- `logon-summary-successful.csv`
- `logon-summary-failed.csv`
- case в DLP case API
- Telegram alert в операторский чат
## Как оценивается severity
Используются:
- Hayabusa `Level`
- top `RuleTitle`
- failed logons
- suspicious PowerShell
- credential-related detections
- timestomp detections
Выход:
- `low`
- `medium`
- `high`
- `critical`
## Границы
В case возвращается только bounded metadata:
- `tool`
- `host`
- `mode`
- `status`
- `intake_id`
- `package_path`
- `sha256`
- `report_dir`
- `summary_html`
- `timeline_path`
- `manifest_path`
Не возвращаются:
- сырые EVTX
- полный timeline body
- полный Sigma output
## Где настраивается
Windows:
- `aw_windows_hayabusa_auto_upload_enabled`
- `aw_windows_hayabusa_auto_upload_interval_hours`
- `aw_windows_hayabusa_auto_upload_hours_back`
- `aw_windows_hayabusa_auto_upload_mode`
Server:
- `aw_hayabusa_auto_case_enabled`
- `aw_hayabusa_auto_case_min_severity`
- `aw_hayabusa_telegram_enabled`
- `aw_hayabusa_telegram_min_severity`
- `aw_hayabusa_telegram_bot_token`
- `aw_hayabusa_telegram_chat_ids`
## Связанные документы
- [Runbook](../runbook.md)
- [Windows EVTX Export](../windows-hayabusa-evtx-export.md)
- [Security analytics stack v1](../security-analytics-stack-v1.md)
+16 -7
View File
@@ -13,6 +13,9 @@
- [Runtime status: Content analysis](../dlp-content-analysis-runtime-status-2026-05-13.md) - фактический live-статус dictionary/regex/OCR/IOC
- [Hayabusa AW-rus integration](../hayabusa-aw-rus-integration-2026-05-14.md) - bounded DFIR enrichment path для incidents/cases/operator flow
- [Hayabusa operator and IB guide](../hayabusa-operator-ib-guide-2026-05-14.md) - когда запускать forensic path, где лежат артефакты и какие у него границы
- [Hayabusa Security Analytics](Hayabusa-Security-Analytics) - текущий production-контур: auto-upload, auto-case, severity scoring и Telegram alerts
- [Security analytics stack v1](../security-analytics-stack-v1.md) - целевая v1-модель без претензии на Splunk-class SIEM
- [File 1C analytics](File-1C-Analytics) - ClickHouse/Grafana/AI Investigator контур для файловой 1С
### Компоненты
- [DLP Endpoint Monitoring](DLP-Endpoint-Monitoring) - мониторинг clipboard, печати, USB
@@ -37,14 +40,15 @@
### Минимальная конфигурация
```bash
# 1. Установка на Windows workstation
.\windows\deploy-domain-users.ps1
# 1. Развернуть сервер
cd ansible
ansible-playbook -i inventory.ini deploy_aw_server.yml
# 2. Запуск ActivityWatch Server
./aw-server/aw-server
# 2. Развернуть Windows collectors
AW_WINRM_PASSWORD='...' bash ./run_deploy_aw_windows.sh
# 3. Применение RU патчей
node aw-server/aw-ru-patch.js
# 3. Проверить операторский forensic path
powershell.exe -ExecutionPolicy Bypass -File C:\ProgramData\AWatch-rus\export-upload-hayabusa-to-aw-server.ps1 -HoursBack 6 -CaseId 30
```
### Полная конфигурация
@@ -60,7 +64,11 @@ ansible-playbook server-setup.yml
cd ../grafana-1c
docker-compose up -d
# 4. Агрегация DLP событий
# 4. Для файловой 1С поднять ClickHouse/Grafana scaffold
cd ../clickhouse-1c
docker compose up -d
# 5. Агрегация DLP событий
python3 scripts/aggregate_dlp_events.py
```
@@ -73,6 +81,7 @@ ActivityWatch-Russian - это корпоративная система мон
- **Аналитика** - агрегация данных и отчеты
- **Мониторинг** - Prometheus + Grafana дашборды
- **Автоматизация** - Ansible деплой на Windows и Linux
- **Security analytics** - Hayabusa, auto-case, severity scoring, Telegram alerts
## 🔗 Ссылки
+15 -2
View File
@@ -70,9 +70,22 @@ Example with custom window:
powershell.exe -ExecutionPolicy Bypass -File C:\ProgramData\AWatch-rus\export-evtx-for-hayabusa.ps1 -DaysBack 1
```
Current production path:
```powershell
powershell.exe -ExecutionPolicy Bypass -File C:\ProgramData\AWatch-rus\export-upload-hayabusa-to-aw-server.ps1 -HoursBack 6 -CaseId 30
```
This wrapper:
- builds the EVTX package;
- uploads `.caseid` if provided;
- uploads `.meta.json`;
- uploads the `zip` to the AW-server drop directory.
## Boundaries
- output stays outside standard AW buckets
- output stays outside normal DLP screenshot artifacts
- this phase only defines and validates Windows export
- transfer to `10.10.10.13` and Hayabusa execution belong to later phases
- server-side Hayabusa execution happens later on `10.10.10.13`
- only bounded Hayabusa metadata returns into the case layer