chore(home): mirror from kalinamall (9883e6a) with papatramp URLs
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
# Индекс документации SAC
|
||||
|
||||
| Документ | Назначение |
|
||||
|----------|------------|
|
||||
| [TZ.md](TZ.md) | **Техническое задание** (главный документ) |
|
||||
| [diagrams/data-flow.md](diagrams/data-flow.md) | Диаграмма «Как это работает» (Mermaid) |
|
||||
| [architecture.md](architecture.md) | Компоненты, API, модель данных |
|
||||
| [agent-integration.md](agent-integration.md) | UseSAC, протокол ingest, маппинг типов |
|
||||
| [event-schema-v1.json](event-schema-v1.json) | JSON Schema событий |
|
||||
| [work-plan.md](work-plan.md) | План работ по фазам |
|
||||
| [roadmap.md](roadmap.md) | Дорожная карта версий |
|
||||
| [install-ubuntu-24.04-native.md](install-ubuntu-24.04-native.md) | **Подготовка сервера (native)** |
|
||||
| [install-ubuntu-24.04-docker.md](install-ubuntu-24.04-docker.md) | Подготовка сервера (Docker, альтернатива) |
|
||||
| [install-ubuntu-24.04.md](install-ubuntu-24.04.md) | Указатель |
|
||||
| [ssl-certificate.md](ssl-certificate.md) | Wildcard TLS: формат, scp, пути `/etc/ssl/sac/` |
|
||||
| [deployment.md](deployment.md) | Эксплуатация, backup, TLS, `sac-deploy.sh` |
|
||||
| [operations-prod-status.md](operations-prod-status.md) | **Статус prod** и следующие шаги |
|
||||
| [seaca-mobile.md](seaca-mobile.md) | **Seaca**: коды, устройства, сессия, API |
|
||||
| [seaca-fcm.md](seaca-fcm.md) | **Seaca push**: Firebase и `SAC_FCM_*` |
|
||||
| [workspace-three-repos.md](workspace-three-repos.md) | Multi-root workspace (три репо) |
|
||||
| [agent-control-plane.md](agent-control-plane.md) | **v0.7:** RDG flap, qwinsta/logoff, обновления агентов, config push |
|
||||
| [agent-update-backlog.md](agent-update-backlog.md) | Ранний backlog (см. agent-control-plane.md) |
|
||||
|
||||
## Порядок чтения
|
||||
|
||||
1. TZ.md
|
||||
2. diagrams/data-flow.md
|
||||
3. agent-integration.md + event-schema-v1.json
|
||||
4. work-plan.md
|
||||
+310
@@ -0,0 +1,310 @@
|
||||
# Техническое задание
|
||||
# Security Alert Center (SAC)
|
||||
|
||||
| Поле | Значение |
|
||||
|------|----------|
|
||||
| Версия документа | 1.0 |
|
||||
| Дата | 2026-05-26 |
|
||||
| Статус | Черновик на согласование |
|
||||
| Целевая ОС сервера | **Ubuntu 24.04 LTS** |
|
||||
|
||||
---
|
||||
|
||||
## 1. Назначение и цели
|
||||
|
||||
### 1.1. Назначение
|
||||
|
||||
**Security Alert Center (SAC)** — центральное веб-приложение, которое:
|
||||
|
||||
1. Принимает структурированные события безопасности от агентов **ssh-monitor** (Linux) и **RDP-login-monitor** (Windows).
|
||||
2. Хранит их в базе данных для поиска, аудита и аналитики.
|
||||
3. Отображает ленту событий, инциденты (Problems) и дашборды в стиле **Zabbix** (Monitoring → Problems, графики, хосты).
|
||||
4. По правилам доставляет оповещения операторам (Telegram, email, webhook) — **когда на агентах включён режим `UseSAC`**.
|
||||
|
||||
### 1.2. Цели
|
||||
|
||||
- Единая точка наблюдения за входами, неудачными попытками, sudo, банами IP, RD Gateway и т.д.
|
||||
- Снижение «шума» в мессенджерах за счёт дедупликации, группировки и правил в SAC.
|
||||
- Сохранение привычного поведения агентов при **`UseSAC=off`** (уведомления напрямую в Telegram/email, как сейчас).
|
||||
- Эксплуатация на одном сервере **Ubuntu 24.04** без обязательного Kubernetes.
|
||||
|
||||
### 1.3. Не входит в scope MVP (см. [roadmap.md](roadmap.md))
|
||||
|
||||
- Кластеризация SAC (active-active).
|
||||
- Полноценный SIEM / ML-аномалии.
|
||||
- Замена существующих агентов — они остаются, меняется только канал доставки при `UseSAC`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Контекст: три репозитория
|
||||
|
||||
| № | Репозиторий | Роль |
|
||||
|---|-------------|------|
|
||||
| 1 | `ssh-monitor` | Агент на Linux-серверах |
|
||||
| 2 | `RDP-login-monitor` | Агент на Windows Server |
|
||||
| 3 | `security-alert-center` | Центральный сервер (этот проект) |
|
||||
|
||||
Совместная разработка в multi-root workspace — см. [workspace-three-repos.md](workspace-three-repos.md).
|
||||
|
||||
---
|
||||
|
||||
## 3. Как это работает (архитектура потоков)
|
||||
|
||||
Ниже — целевая схема взаимодействия компонентов (рис. 1).
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph agents [Агенты на хостах]
|
||||
SSH[ssh-monitor Linux]
|
||||
RDP[RDP-login-monitor Windows]
|
||||
end
|
||||
|
||||
subgraph sac [Security Alert Center Ubuntu 24.04]
|
||||
API[Ingest API HTTPS]
|
||||
Q[Очередь / воркер]
|
||||
DB[(PostgreSQL)]
|
||||
RT[Realtime SSE/WebSocket]
|
||||
UI[Web UI]
|
||||
NOTIFY[Правила оповещений]
|
||||
end
|
||||
|
||||
subgraph channels [Каналы наружу]
|
||||
TG[Telegram]
|
||||
MAIL[Email]
|
||||
WEBHOOK[Webhook / Slack]
|
||||
end
|
||||
|
||||
SSH -->|JSON события + API key| API
|
||||
RDP -->|JSON события + API key| API
|
||||
API --> Q --> DB
|
||||
DB --> UI
|
||||
DB --> RT --> UI
|
||||
DB --> NOTIFY --> TG
|
||||
NOTIFY --> MAIL
|
||||
NOTIFY --> WEBHOOK
|
||||
```
|
||||
|
||||
**Рис. 1.** Поток данных: агенты → SAC → БД/UI; оповещения пользователю при `UseSAC=exclusive` идут только из SAC.
|
||||
|
||||
### 3.1. Жизненный цикл события
|
||||
|
||||
1. На хосте возникает событие (успешный SSH, неудачный RDP, sudo, бан IP и т.д.).
|
||||
2. Агент формирует **каноническое JSON-событие** (схема v1 — [event-schema-v1.json](event-schema-v1.json)).
|
||||
3. `POST /api/v1/events` по HTTPS с API-ключом; при сбое — запись в локальный **spool** и повтор.
|
||||
4. SAC: валидация → дедупликация → запись в PostgreSQL → оценка правил → при необходимости создание **Problem**.
|
||||
5. Оператор просматривает UI; при `UseSAC=exclusive` Telegram/email отправляет **SAC**, не агент.
|
||||
|
||||
### 3.2. Режим `UseSAC` на агентах
|
||||
|
||||
| Режим | Значение | Поведение агента | Кто шлёт в Telegram/email |
|
||||
|-------|----------|------------------|---------------------------|
|
||||
| `off` | `0` | Как сейчас | Агент |
|
||||
| `exclusive` | `1` | Только SAC (расширенный JSON) | **Только SAC** |
|
||||
| `dual` | `2` | SAC + локальные каналы | Оба (миграция/отладка) |
|
||||
| `fallback` | `3` | SAC; при N сбоях подряд — снова локально | SAC, при аварии SAC — агент |
|
||||
|
||||
**Требования:**
|
||||
|
||||
- При `UseSAC=exclusive` функции `notify_send` / `Send-TelegramMessage` для **оповещений о событиях** не вызываются.
|
||||
- Локальные **лог-файлы** на агенте (`LOG_FILE`, `login_monitor.log` и т.д.) **сохраняются** всегда.
|
||||
- При `UseSAC=exclusive` обязательны `SAC_URL`, `SAC_API_KEY`; при старте — проверка доступности SAC (`--check-sac` / аналог).
|
||||
- Подробности — [agent-integration.md](agent-integration.md).
|
||||
|
||||
---
|
||||
|
||||
## 4. Функциональные требования
|
||||
|
||||
### 4.1. Приём событий (Ingest API)
|
||||
|
||||
| ID | Требование |
|
||||
|----|------------|
|
||||
| F-ING-01 | `POST /api/v1/events` принимает одно событие JSON, соответствующее `event-schema-v1.json`. |
|
||||
| F-ING-02 | Аутентификация: заголовок `Authorization: Bearer <api_key>` или `X-SAC-API-Key`. |
|
||||
| F-ING-03 | Ответ `202 Accepted` с `event_id`, `sac_event_url`; при создании Problem — `problem_id` (опционально). |
|
||||
| F-ING-04 | Идемпотентность: повтор с тем же `event_id` не создаёт дубликат. |
|
||||
| F-ING-05 | `POST /api/v1/events/batch` — до 100 событий (фаза 1.5). |
|
||||
| F-ING-06 | Rate limiting: настраиваемый лимит на ключ/хост. |
|
||||
| F-ING-07 | `GET /health` — проверка БД и версии (для агентов и мониторинга). |
|
||||
|
||||
### 4.2. Учёт хостов (Hosts)
|
||||
|
||||
| ID | Требование |
|
||||
|----|------------|
|
||||
| F-HST-01 | Первый валидный ingest с API key регистрирует/обновляет карточку хоста. |
|
||||
| F-HST-02 | Поля: hostname, display_name, os_family, os_version, ipv4/ipv6, версия агента, `use_sac_mode`, last_seen, tags. |
|
||||
| F-HST-03 | Статус «жив/мёртв» по последнему `agent.heartbeat` (порог N минут — настраивается). |
|
||||
| F-HST-04 | UI: список хостов, фильтр, переход к событиям хоста. |
|
||||
|
||||
### 4.3. Хранение событий (Events)
|
||||
|
||||
| ID | Требование |
|
||||
|----|------------|
|
||||
| F-EVT-01 | Хранение всех полей события + `received_at`, `host_id`. |
|
||||
| F-EVT-02 | Поиск/фильтр: период, хост, `type`, `severity`, IP, user, текст в `summary`. |
|
||||
| F-EVT-03 | Просмотр карточки события с `details`, `raw` (с лимитом отображения). |
|
||||
| F-EVT-04 | Экспорт CSV за выбранный фильтр (фаза 1.5). |
|
||||
| F-EVT-05 | Retention: настраиваемое хранение сырых событий (по умолчанию 90 дней). |
|
||||
|
||||
### 4.4. Инциденты (Problems)
|
||||
|
||||
| ID | Требование |
|
||||
|----|------------|
|
||||
| F-PRB-01 | Правила создают Problem из одного или нескольких событий (пример: ≥30 `ssh.login.failed` за 15 мин с одного IP). |
|
||||
| F-PRB-02 | Статусы: `open`, `acknowledged`, `resolved`. |
|
||||
| F-PRB-03 | UI: список Problems с severity, хостом, временем, действиями ack/resolve. |
|
||||
| F-PRB-04 | Связь Problem ↔ Events (просмотр связанных событий). |
|
||||
|
||||
### 4.5. Веб-интерфейс
|
||||
|
||||
| ID | Требование |
|
||||
|----|------------|
|
||||
| F-UI-01 | Страница **Problems** — активные инциденты, счётчики по severity. |
|
||||
| F-UI-02 | Страница **Events** — лента с пагинацией и фильтрами. |
|
||||
| F-UI-03 | Страница **Hosts** — инвентарь агентов. |
|
||||
| F-UI-04 | Страница **Dashboards** — графики: успешные/неудачные входы по времени, топ IP, sudo, баны (MVP: базовый набор виджетов). |
|
||||
| F-UI-05 | Live-лента последних событий (SSE или WebSocket). |
|
||||
| F-UI-06 | Аутентификация в UI: логин/пароль (MVP); LDAP — фаза 3. |
|
||||
| F-UI-07 | Роли MVP: `admin`, `operator`, `viewer`. |
|
||||
|
||||
### 4.6. Оповещения из SAC
|
||||
|
||||
| ID | Требование |
|
||||
|----|------------|
|
||||
| F-NOT-01 | Каналы: Telegram, SMTP email, generic webhook (JSON). |
|
||||
| F-NOT-02 | Правила: условие (тип, severity, хост, тег) → каналы + шаблон. |
|
||||
| F-NOT-03 | Дедупликация и cooldown на уровне SAC (аналог `BRUTE_NOTIFY_COOLDOWN_SEC`, `SSH_ACCEPT_NOTIFY_DEDUP_SEC`). |
|
||||
| F-NOT-04 | Расписание тишины (maintenance window) — фаза 2. |
|
||||
| F-NOT-05 | Суточные отчёты (`report.daily.*`) формируются и отправляются **из SAC**, не с агента при `UseSAC=exclusive`. |
|
||||
|
||||
### 4.7. Типы событий (минимальный перечень MVP)
|
||||
|
||||
**ssh-monitor:**
|
||||
|
||||
- `ssh.login.success`, `ssh.login.failed`, `ssh.session.disconnected`
|
||||
- `privilege.sudo.command`
|
||||
- `ssh.ip.banned`, `ssh.ip.bruteforce.threshold`, `ssh.bruteforce.mass`
|
||||
- `session.logind.new`, `session.logind.removed`, `session.logind.failed`
|
||||
- `report.daily.ssh`, `agent.heartbeat`, `agent.recovered`, `agent.test`
|
||||
|
||||
**RDP-login-monitor:**
|
||||
|
||||
- `rdp.login.success`, `rdp.login.failed`, `auth.explicit.credentials` (4648)
|
||||
- `rdg.connection.success`, `rdg.connection.failed`
|
||||
- `report.daily.rdp`, `agent.heartbeat`, `agent.lifecycle`, `agent.test`
|
||||
|
||||
Полный контракт — [event-schema-v1.json](event-schema-v1.json) и [agent-integration.md](agent-integration.md).
|
||||
|
||||
### 4.8. Расширенные поля событий (при `UseSAC=exclusive`)
|
||||
|
||||
Агент передаёт структуру **сверх** текущего текста Telegram:
|
||||
|
||||
- Идентификаторы: `event_id`, `correlation_id`, `dedup_key`, `fingerprint`
|
||||
- Контекст хоста: FQDN, timezone, версия продукта, `agent.instance_id`
|
||||
- Пороги: `enrichment.attempt_number`, `enrichment.threshold`
|
||||
- SSH/RDP-специфика: port, logon_type, gateway target, sudo command, ban_until
|
||||
- `raw`: обрезанный фрагмент journal / Event XML
|
||||
- `filtered_out` + `filter_reason` (опционально, отдельный тип)
|
||||
|
||||
Обогащение **в SAC** (не обязательно в MVP): GeoIP, «новый IP для user», корреляция SSH+RDP с одного IP.
|
||||
|
||||
---
|
||||
|
||||
## 5. Нефункциональные требования
|
||||
|
||||
| ID | Требование |
|
||||
|----|------------|
|
||||
| NF-01 | Сервер приложения: **Ubuntu 24.04 LTS** (единственная поддерживаемая платформа для SAC). |
|
||||
| NF-02 | БД: **PostgreSQL 16+** (production); SQLite допустим только для dev. |
|
||||
| NF-03 | Ingest: p95 < 2 с при нормальной нагрузке (до 50 событий/с мин суммарно). |
|
||||
| NF-04 | Доступность UI по HTTPS (TLS). |
|
||||
| NF-05 | API keys хранятся в БД как hash; секреты конфигурации — в `/etc/security-alert-center/` или env, не в git. |
|
||||
| NF-06 | Резервное копирование БД: документированная процедура `pg_dump` (см. [deployment.md](deployment.md)). |
|
||||
| NF-07 | Логи приложения: structured JSON, ротация logrotate. |
|
||||
| NF-08 | Язык UI: русский (основной); i18n — фаза 3. |
|
||||
| NF-09 | Время в БД: UTC; отображение — timezone пользователя или `Europe/Moscow` по умолчанию. |
|
||||
|
||||
---
|
||||
|
||||
## 6. Технологический стек (целевой)
|
||||
|
||||
| Слой | Технология |
|
||||
|------|------------|
|
||||
| Backend | Python 3.12, FastAPI, SQLAlchemy 2, Alembic |
|
||||
| БД | PostgreSQL 16 |
|
||||
| Очередь (фаза 1.5+) | Redis 7, воркер (ARQ или Celery) |
|
||||
| Frontend | Vue 3 + Vite, UI-kit (Naive UI / PrimeVue), ECharts |
|
||||
| Realtime | Server-Sent Events (приоритет MVP) |
|
||||
| Reverse proxy | nginx |
|
||||
| Развёртывание | **Native:** PostgreSQL + systemd + nginx (production). Docker Compose — альтернатива для стенда |
|
||||
|
||||
Детали — [architecture.md](architecture.md).
|
||||
|
||||
---
|
||||
|
||||
## 7. Безопасность
|
||||
|
||||
- Только HTTPS для ingest и UI.
|
||||
- Отдельные API keys на хост (ротация из UI).
|
||||
- RBAC в UI (MVP: 3 роли).
|
||||
- Аудит действий: ack/resolve, смена правил.
|
||||
- PII в `raw` — ограничение размера; опция маскирования в логах SAC.
|
||||
- Разделение сетей: агенты → исходящий 443 на SAC; SAC не требует входящих на агенты.
|
||||
|
||||
---
|
||||
|
||||
## 8. Интеграция с существующими агентами
|
||||
|
||||
Изменения в репозиториях `ssh-monitor` и `RDP-login-monitor` — **отдельные задачи**, не в этом репозитории.
|
||||
|
||||
Обязательно:
|
||||
|
||||
1. Параметры `UseSAC`, `SAC_URL`, `SAC_API_KEY`, `SAC_MODE` (`off|exclusive|dual|fallback`).
|
||||
2. Функция отправки структурированного события + локальный spool.
|
||||
3. Команда проверки `--test-sac` / `Test-SacConnection`.
|
||||
4. Сохранение локальных логов при любом режиме.
|
||||
|
||||
Спецификация — [agent-integration.md](agent-integration.md).
|
||||
|
||||
---
|
||||
|
||||
## 9. Критерии приёмки MVP
|
||||
|
||||
1. Развёрнут SAC на Ubuntu 24.04, доступны UI и `POST /api/v1/events`.
|
||||
2. Тестовый агент (curl / `agent.test`) создаёт событие, видимое в UI < 10 с.
|
||||
3. Реализованы режимы ingest для типов из п. 4.7 (тестовыми payload).
|
||||
4. Страницы Problems (базовые правила), Events, Hosts, Dashboard (минимум 3 виджета).
|
||||
5. Настроен канал Telegram из SAC; при `UseSAC=exclusive` на тестовом ssh-monitor Telegram **с агента** не приходит, с SAC — приходит.
|
||||
6. Heartbeat: Problem «хост недоступен» при отсутствии heartbeat > N мин.
|
||||
7. Документация развёртывания воспроизводима с нуля по [deployment.md](deployment.md).
|
||||
8. Spool: при остановке SAC события буферизуются на агенте и доставляются после восстановления.
|
||||
|
||||
---
|
||||
|
||||
## 10. Риски и митигация
|
||||
|
||||
| Риск | Митигация |
|
||||
|------|-----------|
|
||||
| SAC недоступен, алерты потеряны | spool на агенте, режим `fallback` |
|
||||
| Дубли SSH + logind | `dedup_key` на агенте и в SAC |
|
||||
| Перегруз БД | партиции по месяцу, retention, агрегаты (фаза 2) |
|
||||
| Двойные Telegram при миграции | явный `dual`, затем `exclusive` |
|
||||
|
||||
---
|
||||
|
||||
## 11. Связанные документы
|
||||
|
||||
- [architecture.md](architecture.md)
|
||||
- [event-schema-v1.json](event-schema-v1.json)
|
||||
- [agent-integration.md](agent-integration.md)
|
||||
- [work-plan.md](work-plan.md)
|
||||
- [roadmap.md](roadmap.md)
|
||||
- [deployment.md](deployment.md)
|
||||
- [workspace-three-repos.md](workspace-three-repos.md)
|
||||
|
||||
---
|
||||
|
||||
## 12. История изменений
|
||||
|
||||
| Версия | Дата | Изменения |
|
||||
|--------|------|-----------|
|
||||
| 1.0 | 2026-05-26 | Первоначальная версия ТЗ |
|
||||
@@ -0,0 +1,329 @@
|
||||
# Agent Control Plane — концепция SAC v0.7+
|
||||
|
||||
**Статус:** утверждено для реализации (2026-06).
|
||||
**Связано:** [roadmap.md](roadmap.md) §v0.7, [agent-integration.md](agent-integration.md), [agent-update-backlog.md](agent-update-backlog.md).
|
||||
|
||||
---
|
||||
|
||||
## 1. Зачем
|
||||
|
||||
Сейчас SAC — **односторонний** канал: агент → ingest. Для задач из [roadmap.md](roadmap.md) (§ «Добавить») нужен **обратный канал** SAC ↔ агент и управление хостами:
|
||||
|
||||
| # | Задача | Кратко |
|
||||
|---|--------|--------|
|
||||
| П.1 | RDG flap 302→303 | Детект, Problem, кнопка **qwinsta** / **logoff** в UI |
|
||||
| П.2 | Обновления агентов | Режим GPO или SAC (pull + fallback SSH/WinRM) |
|
||||
| П.3 | Настройки агента | Desired config в карточке хоста → poll агента |
|
||||
|
||||
**Эталонный git для prod и агентов:** [git.kalinamall.ru/PapaTramp](https://git.kalinamall.ru/PapaTramp). GitHub — публичная sanitized-копия; mirror-скрипты (`push-mirror.sh`, `Rewrite-GitHostUrls.ps1`) живут на kalinamall и нужны только для синхронизации URL в docs между remotes, к runtime агентов не относятся.
|
||||
|
||||
---
|
||||
|
||||
## 2. Общая архитектура
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph sac [SAC Ubuntu]
|
||||
API[FastAPI]
|
||||
UI[Vue SPA]
|
||||
PG[(PostgreSQL)]
|
||||
VAULT[Encrypted secrets]
|
||||
end
|
||||
|
||||
subgraph win [Windows host]
|
||||
RDP[RDP-login-monitor]
|
||||
end
|
||||
|
||||
subgraph linux [Linux host]
|
||||
SSH[ssh-monitor]
|
||||
end
|
||||
|
||||
RDP -->|POST events / heartbeat| API
|
||||
SSH -->|POST events / heartbeat| API
|
||||
RDP -->|GET agent/commands poll| API
|
||||
SSH -->|GET agent/commands poll| API
|
||||
UI --> API
|
||||
API --> PG
|
||||
API --> VAULT
|
||||
```
|
||||
|
||||
**Принципы:**
|
||||
|
||||
- Агент за NAT — только **исходящий HTTPS**; inbound на хост не требуется.
|
||||
- Команды и конфиг — **poll** на heartbeat (или отдельный timer 30–60 с).
|
||||
- Секреты (admin password, SSH private keys, WinRM password) — **encrypted at rest** в PostgreSQL; master key в `SAC_HOST_KEY_ENCRYPTION_KEY` (env).
|
||||
- Audit: все команды и результаты — события ingest `agent.command.*`, `agent.update.*`.
|
||||
|
||||
---
|
||||
|
||||
## 3. П.1 — RDG flap 302→303 и qwinsta / logoff
|
||||
|
||||
### 3.1. Смысл проблемы
|
||||
|
||||
При неудачном RDP через RD Gateway типична пара событий Windows **302 → 303** за несколько секунд. Клиент не удерживает сессию; **«зависшая» сессия обычно остаётся на компьютере пользователя** (session host / рабочая станция из `details.internal_ip`), а не на gateway.
|
||||
|
||||
SAC уже принимает:
|
||||
|
||||
| Windows | SAC `type` | Пример severity |
|
||||
|---------|------------|-----------------|
|
||||
| 302 | `rdg.connection.success` | info / warning |
|
||||
| 303 | `rdg.connection.disconnected` | info |
|
||||
| 303 (alt) | `rdg.connection.failed` | warning |
|
||||
|
||||
Правило должно учитывать **оба** варианта 303.
|
||||
|
||||
### 3.2. Правило детекта `rule:rdg_session_flap`
|
||||
|
||||
```
|
||||
WHEN event_B.type IN (rdg.connection.disconnected, rdg.connection.failed)
|
||||
AND exists event_A within 1..10 seconds BEFORE event_B
|
||||
AND event_A.type = rdg.connection.success
|
||||
AND same host_id
|
||||
AND same details.user
|
||||
AND (recommended) same details.internal_ip
|
||||
OPTIONAL reduce false positives:
|
||||
AND event_B.details.session_duration_sec <= 15 # если агент передаёт из 303
|
||||
AND/OR low bytes transferred in 303 payload
|
||||
THEN:
|
||||
mark event_B.details.rdg_flap = true
|
||||
create Problem rule:rdg_session_flap (dedup 30 s, см. ниже)
|
||||
send notification (Telegram / email / webhook по policy)
|
||||
```
|
||||
|
||||
**Порядок:** только **302 → 303**, не наоборот.
|
||||
|
||||
**Окно:** **1–10 секунд** между 302 и 303.
|
||||
|
||||
**Dedup Problem:** **30 секунд** по ключу `{host_id}|{user}|{internal_ip}`. Пользователи часто пробуют 1–2 раза подряд и звонят админам — 60 с слишком долго.
|
||||
|
||||
**Хост:** правило **универсальное** для любого хоста с RDG-событиями в домене (любой DC / gateway / session host, где стоит агент).
|
||||
|
||||
**Маршрутизация команды qwinsta:** команда уходит на хост, где **установлен агент** и куда привязано событие (`host_id`). Если session host ≠ gateway, в перспективе — таблица «gateway → session hosts» или агент на session host; MVP — агент на том же сервере, что шлёт события RDG.
|
||||
|
||||
### 3.3. UI — веб и Seaca
|
||||
|
||||
Бейдж **RDG flap** и кнопка **qwinsta** на событиях **302 и 303** (пара вычисляется при чтении):
|
||||
|
||||
- Веб: **Обзор**, **События**, карточка события
|
||||
- **Seaca:** список событий + карточка → `POST .../actions/qwinsta` / `logoff`
|
||||
|
||||
**Поток:**
|
||||
|
||||
1. Оператор нажимает **qwinsta**.
|
||||
2. `POST /api/v1/events/{id}/actions/qwinsta` → SAC выполняет **WinRM qwinsta** на **клиентский ПК** (`internal_ip` из события).
|
||||
3. Результат — модалка: SESSION, USER, ID, STATE.
|
||||
4. **logoff:** `POST .../actions/logoff { session_id }` → WinRM `logoff` → повторный qwinsta.
|
||||
5. Нужен **Windows domain admin** в настройках SAC (`SAC_WIN_ADMIN_*` или UI).
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant Op as Оператор
|
||||
participant UI as SAC UI
|
||||
participant API as SAC API
|
||||
participant Ag as RDP-agent
|
||||
|
||||
Op->>UI: qwinsta
|
||||
UI->>API: POST events/{id}/actions/qwinsta
|
||||
API->>Ag: poll command qwinsta
|
||||
Ag->>Ag: runas domain admin
|
||||
Ag->>API: agent.command.result
|
||||
API->>UI: modal + parsed sessions
|
||||
Op->>UI: logoff session_id
|
||||
UI->>API: POST actions/logoff
|
||||
Ag->>API: agent.command.result
|
||||
```
|
||||
|
||||
**Автоматический logoff без участия оператора — не делаем** в первых итерациях.
|
||||
|
||||
---
|
||||
|
||||
## 4. П.2 — Обновления агентов (Windows + Linux)
|
||||
|
||||
### 4.1. Настройки SAC → «Обновления агентов»
|
||||
|
||||
| Режим | Описание |
|
||||
|-------|----------|
|
||||
| **A — GPO / ручной** | Как сейчас: NETLOGON, `Deploy-LoginMonitor.ps1`, `update_ssh_monitor.sh`. SAC только показывает устаревшие версии. |
|
||||
| **B — SAC** | SAC инициирует обновление; агент тянет пакет сам (pull). |
|
||||
|
||||
**Рекомендуемые версии** по продукту (`RDP-login-monitor`, `ssh-monitor`) — min / recommended; сверка с `host.product_version` (уже есть в UI «Хосты»).
|
||||
|
||||
**Источник пакетов** (выбор в настройках):
|
||||
|
||||
| Источник | Windows | Linux |
|
||||
|----------|---------|-------|
|
||||
| SMB / NETLOGON | `\\dc\NETLOGON\...` | — |
|
||||
| Git | private repo kalinamall | `git pull` в `/opt/ssh-monitor` |
|
||||
| HTTP(S) SAC | zip + checksum с SAC | zip + checksum |
|
||||
|
||||
### 4.2. B1 — Self-update после «пинка» (основной путь)
|
||||
|
||||
1. Admin: «Запросить обновление» на хосте / группе.
|
||||
2. SAC: `host.pending_update = true` в ответе poll.
|
||||
3. **Windows:** агент запускает `Deploy-LoginMonitor.ps1` (существующий скрипт).
|
||||
4. **Linux:** агент запускает `update_ssh_monitor.sh`.
|
||||
5. Ingest: `agent.update.started` → `agent.update.success` | `agent.update.failed`.
|
||||
|
||||
### 4.3. B2 — Fallback (SSH / WinRM)
|
||||
|
||||
Кнопка на карточке хоста: **«Обновить через WinRM»** / **«Fallback SSH»** (`POST .../actions/agent-update-fallback`). Лог операции — модалка сразу при старте (не ждёт конца).
|
||||
|
||||
Если за **N минут** нет `agent.update.*` или статус `failed` — тот же fallback может сработать автоматически (если включён в настройках).
|
||||
|
||||
| OS | Метод | Credentials | Как работает (SAC 0.20.18+) |
|
||||
|----|--------|-------------|------------------------------|
|
||||
| Linux | SSH | ключ после bootstrap (§5) | SAC передаёт `REPO_URL` / `GIT_BRANCH` из **Настройки → Обновления агентов** в `update_ssh_monitor.sh` (не дефолт GitHub на хосте) |
|
||||
| Windows | WinRM | encrypted login/password в БД | 1) SAC `git fetch` RDP-login-monitor на сервере → zip с UTF-8 BOM для `.ps1`<br>2) Клиент по WinRM: `Invoke-WebRequest` → `https://<SAC_PUBLIC_URL>/api/v1/agent/rdp-bundle/<token>`<br>3) Распаковка в `C:\ProgramData\RDP-login-monitor\_sac_staging`<br>4) `Deploy-LoginMonitor.ps1 -SourceShareRoot` (файлы в `ProgramData\RDP-login-monitor\`) |
|
||||
|
||||
**Windows — требования:** domain admin в **Настройки → Управление хостами → Windows**; `rdp_git_repo_url` в **Обновления агентов**; ПК должен открывать `SAC_PUBLIC_URL` (HTTPS). **Git на клиенте не нужен.** GPO/NETLOGON по-прежнему основной путь в режиме GPO.
|
||||
|
||||
**nginx:** для `agent-update-fallback` и SSH/WinRM-тестов — `proxy_read_timeout 960s` (см. `deploy/nginx/sac.conf.tls.example`).
|
||||
|
||||
---
|
||||
|
||||
## 5. П.2C — Доступ SAC к хостам
|
||||
|
||||
### 5.1. Windows — WinRM / учётки
|
||||
|
||||
- **Глобальный доменный admin** в **Настройки → Windows**: `DOMAIN\user` + password (encrypted). Аналогично **Linux admin** для SSH.
|
||||
- **Override на карточке хоста** (**Хосты → WinRM/SSH / доступ к хосту**): `COMPUTER\user` / `.\Administrator` + password (encrypted в `hosts.mgmt_*`). Если пусто — берутся глобальные.
|
||||
- Effective creds: `get_effective_win_admin_for_host` / `get_effective_linux_admin_for_host` (source: `host` | `db` | `env`).
|
||||
- API: `GET` / `PUT /api/v1/hosts/{id}/access` (`user`, `password`, `clear`).
|
||||
- Используются для WinRM/SSH-test, fallback-update, qwinsta/logoff, remote ops; для run_as через агента — те же creds в command poll (TLS + API key, не пишутся на диск агента).
|
||||
|
||||
### 5.2. Linux — bootstrap password → SSH key → удалить password
|
||||
|
||||
На карточке хоста → «Доступ для управления»:
|
||||
|
||||
```
|
||||
1. Admin вводит login + password (временно)
|
||||
2. SAC по SSH: генерирует ed25519, добавляет pubkey в authorized_keys
|
||||
3. SAC проверяет вход по ключу
|
||||
4. Успех → password DELETE из БД, status = key_ready
|
||||
5. Ошибка → password остаётся, status = bootstrap_failed, алерт
|
||||
6. Кнопка «Переустановить ключи» — повтор bootstrap
|
||||
```
|
||||
|
||||
Private key — encrypted в PostgreSQL.
|
||||
|
||||
### 5.3. Статусы доступа
|
||||
|
||||
| Статус | Linux | Windows |
|
||||
|--------|-------|---------|
|
||||
| `no_access` | нет данных | нет WinRM |
|
||||
| `bootstrap_pending` | идёт настройка ключа | — |
|
||||
| `key_ready` | SSH по ключу | — |
|
||||
| `winrm_ready` | — | WinRM настроен |
|
||||
|
||||
---
|
||||
|
||||
## 6. П.3 — Настройки агента в карточке хоста
|
||||
|
||||
**Desired state** в SAC; агент забирает на poll:
|
||||
|
||||
```json
|
||||
{
|
||||
"config_revision": 42,
|
||||
"settings": {
|
||||
"ServerDisplayName": "UNMS Kalina",
|
||||
"EnableRcmShadowControlMonitoring": true,
|
||||
"GetInventory": true,
|
||||
"HEARTBEAT_INTERVAL": "300"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Whitelist ключей — без секретов (`SAC_API_KEY` только локально).
|
||||
- **Windows:** поля из `login_monitor.settings.ps1`.
|
||||
- **Linux:** поля из `/etc/ssh-monitor.conf`.
|
||||
- Merge: remote перекрывает локальное, revision монотонно растёт.
|
||||
|
||||
---
|
||||
|
||||
## 7. API (черновик)
|
||||
|
||||
### 7.1. Poll (агент)
|
||||
|
||||
```http
|
||||
GET /api/v1/agent/commands?since=<last_ack>
|
||||
Authorization: Bearer sac_xxx
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"config_revision": 42,
|
||||
"config": { "settings": { } },
|
||||
"update": { "requested": false, "target_version": "2.0.38-SAC", "source": "smb://..." },
|
||||
"commands": [
|
||||
{ "id": "uuid", "type": "qwinsta", "params": { "user": "B26\\user" } }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2. UI actions (JWT: admin / monitor / mobile)
|
||||
|
||||
| Метод | Путь | Назначение |
|
||||
|-------|------|------------|
|
||||
| POST | `/api/v1/events/{id}/actions/qwinsta` | qwinsta (WinRM на клиентский ПК) |
|
||||
| POST | `/api/v1/events/{id}/actions/logoff` | logoff `{ "session_id": 5 }` |
|
||||
| GET | `/api/v1/events/{id}/actions/{cmd_id}` | Статус / результат |
|
||||
| PATCH | `/api/v1/hosts/{id}/config` | Desired config |
|
||||
| GET/PUT | `/api/v1/hosts/{id}/access` | Per-host WinRM/SSH override (mgmt_user/password) |
|
||||
| GET/PATCH | `/api/v1/settings/agent-updates` | Режим A/B, версии, источники |
|
||||
| GET/PATCH | `/api/v1/settings/host-management` | Доменный admin Windows |
|
||||
|
||||
### 7.3. Ingest (новые типы)
|
||||
|
||||
| `type` | Назначение |
|
||||
|--------|------------|
|
||||
| `agent.command.result` | stdout/stderr qwinsta, logoff |
|
||||
| `agent.update.started` | начало self-update |
|
||||
| `agent.update.success` | успех |
|
||||
| `agent.update.failed` | ошибка |
|
||||
|
||||
---
|
||||
|
||||
## 8. Фазы реализации
|
||||
|
||||
| Фаза | Содержание | Статус |
|
||||
|------|------------|--------|
|
||||
| **1** | `rule:rdg_session_flap`, Problem, notify, флаг `rdg_flap` | ✅ SAC |
|
||||
| **2** | **qwinsta** / **logoff** — веб + Seaca | ✅ |
|
||||
| **3** | Poll API, `agent_commands` (агент) | ✅ RDP ≥ 2.1.0-SAC |
|
||||
| **4** | WinRM qwinsta с сервера SAC | ✅ |
|
||||
| **5** | Settings «Обновления агентов», SSH bootstrap | частично ✅ |
|
||||
| **6** | Self-update B1 | ⏳ |
|
||||
| **7** | SSH bootstrap + WinRM fallback | частично ✅ (SSH/WinRM update из UI, git URL из настроек) |
|
||||
| **8** | Desired config per host | ⏳ |
|
||||
|
||||
**Миграция:** `016_agent_commands`. Env: `SAC_RDG_FLAP_*`, `SAC_WIN_ADMIN_USER`, `SAC_WIN_ADMIN_PASSWORD`.
|
||||
|
||||
---
|
||||
|
||||
## 9. Безопасность
|
||||
|
||||
- Команды qwinsta/logoff — JWT (веб и Seaca); `requested_by` в `agent_commands`.
|
||||
- Rate limit на actions per host.
|
||||
- logoff — confirm dialog; по умолчанию только matching user.
|
||||
- Password bootstrap Linux — удаляется после успеха; re-bootstrap явной кнопкой.
|
||||
- WinRM password — только encrypted storage, не в логах и не в Telegram.
|
||||
|
||||
---
|
||||
|
||||
## 10. Git / remotes (справка)
|
||||
|
||||
| Репозиторий | Prod (kalinamall) | Public (github) |
|
||||
|-------------|-------------------|-----------------|
|
||||
| security-alert-center | основной | sanitized |
|
||||
| RDP-login-monitor | prod paths/secrets | sanitized settings |
|
||||
| ssh-monitor | mirror-скрипты + URLs | без mirror-скриптов |
|
||||
|
||||
Mirror-скрипты: временно переписывают URL в docs под целевой host, пушат на remote, **откатывают** локальный main — чтобы в одной ветке не смешивать kalinamall/github URLs.
|
||||
|
||||
---
|
||||
|
||||
## См. также
|
||||
|
||||
- [agent-integration.md](agent-integration.md) — ingest, типы RDG
|
||||
- [agent-update-backlog.md](agent-update-backlog.md) — ранний backlog (superseded деталями этого документа)
|
||||
- [roadmap.md](roadmap.md) — v0.7
|
||||
@@ -0,0 +1,306 @@
|
||||
# Интеграция агентов с SAC
|
||||
|
||||
Контракт между **ssh-monitor**, **RDP-login-monitor** и **Security Alert Center**.
|
||||
Изменения вносятся в репозитории агентов отдельными задачами.
|
||||
|
||||
---
|
||||
|
||||
## 1. Режим `UseSAC`
|
||||
|
||||
### 1.1. Параметры конфигурации
|
||||
|
||||
**ssh-monitor** (`/etc/ssh-monitor.conf`):
|
||||
|
||||
```ini
|
||||
# off | exclusive | dual | fallback
|
||||
UseSAC="exclusive"
|
||||
SAC_URL="https://sac.kalinamall.ru/api/v1/events"
|
||||
SAC_API_KEY="sac_xxxxxxxx"
|
||||
SAC_SPOOL_DIR="/var/lib/ssh-monitor/sac-spool"
|
||||
SAC_SEND_HEARTBEAT="1"
|
||||
SAC_FALLBACK_FAILURES="5"
|
||||
SAC_TIMEOUT_SEC="12"
|
||||
```
|
||||
|
||||
**RDP-login-monitor** (`Login_Monitor.ps1` или отдельный `.conf`):
|
||||
|
||||
```powershell
|
||||
$UseSAC = "exclusive" # off | exclusive | dual | fallback
|
||||
$SacUrl = "https://sac.kalinamall.ru/api/v1/events"
|
||||
$SacApiKey = "sac_xxxxxxxx"
|
||||
$SacSpoolDir = "D:\Soft\Logs\sac-spool"
|
||||
```
|
||||
|
||||
### 1.2. Матрица поведения
|
||||
|
||||
| Событие | `off` | `exclusive` | `dual` | `fallback` |
|
||||
|---------|-------|-------------|--------|------------|
|
||||
| Auth / sudo / ban / RDP login | Telegram/email с агента | Только SAC JSON | SAC + Telegram | SAC; при сбоях → Telegram |
|
||||
| Daily report | С агента | SAC формирует и шлёт | Оба | SAC, fallback как выше |
|
||||
| Heartbeat | С агента (если включён) | Только SAC (`agent.heartbeat`) | Оба | SAC |
|
||||
| Локальный LOG_FILE | Да | Да | Да | Да |
|
||||
|
||||
### 1.3. Проверка при старте
|
||||
|
||||
- `UseSAC=off` — без изменений: хотя бы один канал `NOTIFY_CHAIN` (как сейчас).
|
||||
- `UseSAC≠off` — обязательны `SAC_URL`, `SAC_API_KEY`; HTTP `GET {base}/health` OK.
|
||||
- `--check-sac` / `Test-SacConnection` — отправка `agent.test`, ожидание **HTTP 201** (повтор с тем же `event_id` — **409**, тоже успех для spool).
|
||||
|
||||
### 1.3.1. Telegram и email при `UseSAC=exclusive`
|
||||
|
||||
При **`exclusive`** агент **не** шлёт Telegram/email — оператору нужны оповещения **из SAC** (`backend/app/services/telegram_notify.py`).
|
||||
|
||||
На сервере SAC — **`sac-api.env`** или UI **Настройки** → **Правило оповещений**: один порог severity и выбор каналов (Telegram / webhook / email).
|
||||
|
||||
```env
|
||||
NOTIFY_MIN_SEVERITY=warning
|
||||
NOTIFY_CHANNELS=telegram,webhook,email
|
||||
TELEGRAM_ENABLED=true
|
||||
TELEGRAM_BOT_TOKEN=<bot>
|
||||
TELEGRAM_CHAT_ID=<chat>
|
||||
```
|
||||
|
||||
| Severity события | `NOTIFY_MIN_SEVERITY=warning` | `high` |
|
||||
|------------------|-------------------------------|--------|
|
||||
| `info` (успешный RDP/SSH login) | нет | нет |
|
||||
| `warning` (`*.login.failed`, sudo) | **да** | нет |
|
||||
| `high` / `critical` (ban, problem) | **да** | **да** |
|
||||
|
||||
Events и problems используют **одно** глобальное правило (`notification_policy` в БД, миграция `007`).
|
||||
|
||||
Telegram из SAC отправляется с **`parse_mode=HTML`** (как у RDP-login-monitor): для `rdp.login.*` — пользователь, IP, `logon_type`, рабочая станция, Event ID Windows; для `ssh.login.*` и `privilege.sudo.command` — поля из `details`.
|
||||
|
||||
UI **Настройки** (`/settings`) — правило + параметры каналов (JWT admin). После деплоя: `alembic upgrade head`.
|
||||
|
||||
### 1.4. Версии и доставка обновлений
|
||||
|
||||
При **любом** изменении агента, влияющем на SAC или поведение на хосте, поднимайте версию и пушьте в **GitHub** (`github.com/PTah`); для зеркала kalinamall — `.\scripts\Push-Mirror.ps1 kalinamall`:
|
||||
|
||||
| Агент | Маркер версии | Как хост узнаёт о новой версии |
|
||||
|-------|---------------|--------------------------------|
|
||||
| **ssh-monitor** | `SSH_MONITOR_VERSION` в `ssh-monitor`; `# SAC client release:` в `sac-client.sh` | `update_ssh_monitor.sh`: `git pull` в клоне → сравнение sha256 `ssh-monitor` и `sac-client.sh` |
|
||||
| **RDP-login-monitor** | `$ScriptVersion` в `Login_Monitor.ps1` и **та же** строка в `version.txt` на шаре NETLOGON | `Deploy-LoginMonitor.ps1`: сверка `version.txt` и SHA256 пакета (`Login_Monitor.ps1`, `Sac-Client.ps1`); при отсутствии SAC в settings — **`UseSAC=dual`** из example; подсказка `# $ServerDisplayName` |
|
||||
|
||||
**Кириллица в SAC (RDP):** до **1.2.8-SAC** `Invoke-WebRequest` мог слать JSON не в UTF-8 — в UI «Отчёты» summary вида `RDP 24?: ??????` вместо `RDP 24ч: сессий …`. Обновите `Sac-Client.ps1` на всех хостах; старые события в БД не пересчитываются, исправятся только новые ingest после деплоя.
|
||||
|
||||
**HTTP 422 и spool (RDP):** до **1.2.9-SAC** при отклонении схемой (часто `title` длиннее 256 символов) JSON попадал в `sac-spool` и повторялся бесконечно. С **1.2.9-SAC**: обрезка `title`/`summary`, UTF-8 POST, при 422 файл уходит в `sac-spool/rejected/` (не ретраится). Старые `.json` в spool на хосте удалите или перенесите вручную после обновления.
|
||||
|
||||
**HTTP 409 и spool (RDP):** в PowerShell `Invoke-WebRequest` часто **бросает исключение** на 409 (и иногда на 201), хотя событие уже в SAC. До **1.2.10-SAC** клиент считал это ошибкой и снова слал тот же `event_id` из spool каждые ~5 с (лог `WARN: SAC POST HTTP 409`). С **1.2.10-SAC** коды **201/409/202** обрабатываются как успех и файл spool удаляется.
|
||||
|
||||
**HTTP 422 на `agent.lifecycle` (RDP):** часто из‑за битого JSON с кириллицей в `summary` (`ConvertTo-Json` + неверная кодировка POST). С **1.2.11-SAC** — сериализация через `JavaScriptSerializer` (Unicode `\uXXXX`), в лог пишется тело ответа SAC (`schema_errors`). Файлы в `sac-spool/rejected/` после 422 можно удалить.
|
||||
|
||||
**422 `json_invalid` / `Extra data` (позиция 4):** тело POST было `null` + JSON (утечка в pipeline от `Write-Log`). С **1.2.12-SAC**: `[void](Write-Log)`, одна строка JSON, без `ConvertFrom-Json` перед POST.
|
||||
|
||||
Только правки `Sac-Client.ps1` / `sac-client.sh`: для RDP достаточно поднять patch в `version.txt` (и при необходимости `$ScriptVersion`); для Linux `sac-client.sh` обновится по checksum даже без смены `SSH_MONITOR_VERSION`, но **рекомендуется** поднимать обе метки для логов.
|
||||
|
||||
### 1.5. Правила Problems v1 (SAC backend)
|
||||
|
||||
| `rule_id` | Условие | Пороги (env) |
|
||||
|-----------|---------|--------------|
|
||||
| `rule:brute_force_burst` | `ssh.login.failed` / `rdp.login.failed`, один `source_ip` | `SAC_BRUTE_FORCE_WINDOW_MINUTES=15`, `SAC_BRUTE_FORCE_THRESHOLD=30` |
|
||||
| `rule:privilege_spike` | `privilege.sudo.command` на хосте | `SAC_PRIVILEGE_SPIKE_WINDOW_MINUTES=10`, `SAC_PRIVILEGE_SPIKE_THRESHOLD=10` |
|
||||
| `rule:host_silence` | был heartbeat, но устарел (`agent.heartbeat`) | `SAC_HEARTBEAT_STALE_MINUTES` (как для UI «Хосты») |
|
||||
|
||||
**Proactive host_silence:** фоновый scan в `sac-api` (`SAC_HOST_SILENCE_SCAN_ENABLED`, интервал `SAC_HOST_SILENCE_SCAN_INTERVAL_MINUTES`, по умолчанию каждые 5 мин) создаёт Problem и шлёт Telegram **без ожидания** нового ingest с хоста. Альтернатива: `systemd sac-host-silence-scan.timer` + `python -m app.jobs.host_silence_scan` (отключите in-process scan при нескольких воркерах uvicorn).
|
||||
|
||||
Свежий `agent.heartbeat` **автоматически resolve** open/ack проблему `rule:host_silence`. Одиночные `high`/`critical` (ban, mass bruteforce) — как раньше.
|
||||
|
||||
---
|
||||
|
||||
## 2. Протокол ingest
|
||||
|
||||
### 2.1. Запрос
|
||||
|
||||
```http
|
||||
POST /api/v1/events HTTP/1.1
|
||||
Host: sac.kalinamall.ru
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer sac_xxxxxxxx
|
||||
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
|
||||
|
||||
```
|
||||
|
||||
### 2.2. Ответ
|
||||
|
||||
| HTTP | Значение | `status` в теле | `created` |
|
||||
|------|----------|-----------------|-----------|
|
||||
| **201** | Событие записано впервые | `created` | `true` |
|
||||
| **409** | Тот же `event_id` уже есть (идемпотентность) | `duplicate` | `false` |
|
||||
| **422** | Ошибка JSON Schema | — | — |
|
||||
|
||||
Пример **201**:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "created",
|
||||
"event_id": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"created": true,
|
||||
"sac_event_url": "https://sac.kalinamall.ru/api/v1/events/12345",
|
||||
"problem_id": null
|
||||
}
|
||||
```
|
||||
|
||||
`event_id` — обязательный **UUID** (RFC 4122), уникален глобально; в БД индекс `UNIQUE (event_id)`.
|
||||
|
||||
### 2.3. Spool при ошибке
|
||||
|
||||
1. Записать JSON в `SAC_SPOOL_DIR/{event_id}.json`.
|
||||
2. **ssh-monitor:** каждую итерацию цикла вызывается `sac_flush_spool` (до 20 файлов).
|
||||
3. После успеха (**HTTP 201** или **409**) — удалить файл из spool.
|
||||
4. Лимит размера spool (например 500 MB) — логировать WARN, не удалять без алерта.
|
||||
|
||||
---
|
||||
|
||||
## 3. Маппинг уведомлений → типы событий
|
||||
|
||||
### 3.1. ssh-monitor
|
||||
|
||||
| Текущий текст (сокращённо) | `type` | `severity` |
|
||||
|----------------------------|--------|------------|
|
||||
| Успешное SSH | `ssh.login.success` | info |
|
||||
| Неудачная SSH | `ssh.login.failed` | warning |
|
||||
| IP заблокирован | `ssh.ip.banned` | high |
|
||||
| Лимит без бана | `ssh.ip.bruteforce.threshold` | warning |
|
||||
| Массовый брутфорс | `ssh.bruteforce.mass` | high |
|
||||
| Sudo | `privilege.sudo.command` | warning–critical* |
|
||||
| logind new/removed/failed | `session.logind.*` | info–warning |
|
||||
| Ежедневный отчёт | `report.daily.ssh` | info |
|
||||
| Heartbeat | `agent.heartbeat` | info |
|
||||
|
||||
\* critical — по эвристике команды (`useradd`, `passwd`, `rm -rf`, …) в `details.risk_level`.
|
||||
|
||||
**Дополнительные поля в `details` (exclusive):**
|
||||
|
||||
- `user`, `source_ip`, `port`, `attempt_number`, `max_attempts`
|
||||
- `sudo`: `run_as`, `command`, `pwd`, `risk_level`
|
||||
- `ban`: `ban_until`, `enable_ip_ban` (SSH / ipset)
|
||||
- RDP-login-monitor: автобан IP в схеме **пока не стандартизирован** (`rdp.ip.banned` зарезервирован в SAC для будущего); в отчёте Windows строка «Активных банов» = 0 или число событий `rdp.ip.banned`, если агент начнёт слать
|
||||
- `brute`: `window_sec`, `fails_in_window`
|
||||
- `whitelist_matched`: boolean
|
||||
|
||||
### 3.2. RDP-login-monitor
|
||||
|
||||
| Событие | `type` | `severity` |
|
||||
|---------|--------|------------|
|
||||
| 4624 успех | `rdp.login.success` | info |
|
||||
| 4625 неудача | `rdp.login.failed` | warning |
|
||||
| 4634 / 4647 выход (прямой RDP, **только рабочая станция**) | `rdp.session.logoff` | info |
|
||||
| RCM **20506** Shadow Control started | `rdp.shadow.control.started` | **warning** |
|
||||
| RCM **20507** Shadow Control stopped | `rdp.shadow.control.stopped` | **warning** |
|
||||
| RCM **20510** Shadow Control permission | `rdp.shadow.control.permission` | **warning** |
|
||||
| WinRM **91** inbound shell (Enter-PSSession) | `winrm.session.started` | **warning** |
|
||||
| Security **5140** admin share (`C$`, `ADMIN$`) | `smb.admin_share.access` | **warning** |
|
||||
| 4648 | `auth.explicit.credentials` | warning |
|
||||
| RD Gateway 302 | `rdg.connection.success` | info |
|
||||
| RD Gateway 303 | `rdg.connection.failed` | warning |
|
||||
| Старт/стоп | `agent.lifecycle` | info |
|
||||
| Отчёт | `report.daily.rdp` | info |
|
||||
| Инвентаризация железа/ПО | `agent.inventory` | info (SAC: **warning**, если изменилось железо) |
|
||||
|
||||
**Инвентаризация (`agent.inventory`, RDP ≥ 2.0.21-SAC):** агент шлёт снимок в `details.inventory` (CPU, RAM, диски, GPU, Windows, IPv4). Интервал по умолчанию **12 ч**; отключение: `$GetInventory = $false` в `login_monitor.settings.ps1`. SAC хранит последний снимок в `hosts.inventory`; при изменении железа ingest повышает severity до **warning** и шлёт оповещение.
|
||||
|
||||
**Дополнительные поля:**
|
||||
|
||||
- `event_id_windows`, `logon_type`, `ip_address`, `workstation_name`
|
||||
- Shadow: `shadower_user`, `target_user`, `session_id`, `shadow_mode`, `shadow_action`
|
||||
- WinRM: `source_ip`, `resource_uri`, `transport`
|
||||
- Admin share 5140: `share_name`, `share_path`, `relative_target`, `access_mask`
|
||||
- `gateway_target`, `gateway_error_code`
|
||||
- `filtered_out`, `filter_reason`
|
||||
|
||||
**Переключатели в `login_monitor.settings.ps1` (≥ 1.2.23-SAC):** `$EnableRcmShadowControlMonitoring`, `$EnableWinRmInboundMonitoring`, `$EnableAdminShareMonitoring` (по умолчанию `1`; Security **5140**, audit File Share). **`$GetInventory`** (по умолчанию `$true`) — опрос железа/ПО для SAC. Подавление: `ignore.lst` с префиксами `shadow:`, `winrm:`, `smb:` / `5140:`.
|
||||
|
||||
**Exchange (RDP ≥ 2.0.23-SAC):** на почтовом сервере `$WinRmExchangeStrictMode = 1` — WinRM **91** без user в EventData не уходит в SAC; корреляция **4624** только при `LogonProcess WinRM` (отсекает ложные связки с Outlook/LT3).
|
||||
|
||||
---
|
||||
|
||||
## 3.3. Человекочитаемое имя хоста (`host.display_name`)
|
||||
|
||||
В UI SAC (**Хосты**, фильтры Problems/Events) показывается `display_name`, если оно задано; иначе `hostname` из ОС.
|
||||
|
||||
| Агент | Параметр | В ingest |
|
||||
|-------|----------|--------|
|
||||
| **ssh-monitor** | `SERVER_DISPLAY_NAME` в `/etc/ssh-monitor.conf` | `host.display_name` (пусто — поле не передаётся) |
|
||||
| **RDP-login-monitor** | `$ServerDisplayName` в `login_monitor.settings.ps1` | `host.display_name`; `hostname` = `$env:COMPUTERNAME` |
|
||||
|
||||
Пример фрагмента JSON:
|
||||
|
||||
```json
|
||||
"host": {
|
||||
"hostname": "NEW-ADMIN-PC",
|
||||
"display_name": "UNMS Kalina",
|
||||
"os_family": "windows"
|
||||
}
|
||||
```
|
||||
|
||||
Telegram у ssh/RDP использует ту же подпись, что и `display_name`, когда параметр задан.
|
||||
|
||||
### Версии агентов (единый номер)
|
||||
|
||||
| Репозиторий | Источник версии | SAC `product_version` |
|
||||
|-------------|-----------------|------------------------|
|
||||
| **ssh-monitor** | `SSH_MONITOR_VERSION` в `ssh-monitor` + `version.txt` | из `SSH_MONITOR_VERSION` |
|
||||
| **RDP-login-monitor** | `$ScriptVersion` в `Login_Monitor.ps1` + `version.txt` | из `$ScriptVersion` |
|
||||
|
||||
Не задавайте разные номера для «скрипта» и «SAC-модуля» — в UI **Хосты** отображается одна версия с ingest.
|
||||
|
||||
---
|
||||
|
||||
## 4. Поля `dedup_key` (рекомендации)
|
||||
|
||||
| Тип | Формат dedup_key |
|
||||
|-----|------------------|
|
||||
| ssh.login.success | `{product}\|{host}\|ssh.login.success\|{user}\|{ip}` |
|
||||
| ssh.login.failed | `{product}\|{host}\|ssh.login.failed\|{ip}` (окно в SAC) |
|
||||
| privilege.sudo | `{product}\|{host}\|sudo\|{user}\|{hash(command)}` |
|
||||
| rdp.login.failed | `{product}\|{host}\|rdp.failed\|{ip}\|{user}` |
|
||||
|
||||
SAC применяет cooldown по `dedup_key` (события, по умолчанию **90 с**) и по `fingerprint` problem (**300 с**). Таблица `notification_cooldown`, env: `SAC_NOTIFY_EVENT_COOLDOWN_SEC`, `SAC_NOTIFY_PROBLEM_COOLDOWN_SEC`. В логах API: `notify cooldown skip`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Точки встраивания в код агентов
|
||||
|
||||
### ssh-monitor
|
||||
|
||||
- Новая функция `send_sac_event()` вызывается из мест, где сейчас `notify_send "$message"`.
|
||||
- Обёртка `notify_or_sac()`:
|
||||
- `UseSAC=off` → `notify_send`
|
||||
- `exclusive` → только `send_sac_event` (в `summary` — тот же текст)
|
||||
- `dual` → оба
|
||||
- `fallback` → `send_sac_event`; при fail increment counter → при пороге `notify_send`
|
||||
|
||||
### RDP-login-monitor
|
||||
|
||||
- `Send-SacEvent` + замена вызовов `Send-TelegramMessage` для событий мониторинга.
|
||||
- Heartbeat и daily report — отдельные типы в SAC.
|
||||
- **Команды SAC (≥ 2.1.0-SAC):** poll `GET /api/v1/agent/commands?agent_instance_id=…` каждые `$SacCommandPollIntervalSec` (по умолчанию 60 с); типы `qwinsta`, `logoff`. Ответ: `POST /api/v1/agent/commands/{uuid}/result`. Учётные данные доменного admin приходят в `run_as` (на SAC — `SAC_WIN_ADMIN_*`). Подробнее: [agent-control-plane.md](agent-control-plane.md).
|
||||
- При `UseSAC=exclusive` суточный отчёт может формироваться **на SAC** (`generated_by: sac` в `details`), если агент за день не прислал `report.daily.*` — см. `SAC_DAILY_REPORT_*`, job `python -m app.jobs.daily_report`, timer `sac-daily-report.timer`.
|
||||
- **Единый шаблон отчёта** (SSH / Windows): агенты `ssh-monitor` ≥ 1.2.8-SAC, `RDP-login-monitor` ≥ 1.2.21-SAC и SAC используют одинаковые секции в `report_body` / `details.stats`.
|
||||
- **Только SAC, без отчёта с агента:** на агенте `DAILY_REPORT_ENABLED=0` (ssh) или `$DailyReportEnabled = $false` (RDP); на SAC `SAC_DAILY_REPORT_ENABLED=true`, `SAC_DAILY_REPORT_SKIP_IF_AGENT_SENT=true`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Обратная совместимость
|
||||
|
||||
- По умолчанию `UseSAC=off` — поведение 100% как сейчас.
|
||||
- `BACKUP_WEBHOOK_URL` в ssh-monitor при `exclusive` не используется для обычных алертов (только emergency в `fallback` — опционально).
|
||||
|
||||
---
|
||||
|
||||
## 7. Чеклист готовности агента
|
||||
|
||||
- [x] Параметры конфига задокументированы в README агента (ssh-monitor, RDP-login-monitor)
|
||||
- [x] `--check-sac` / `Test-SacConnection` / `-CheckSac`
|
||||
- [x] Spool и повторная отправка
|
||||
- [ ] Все типы из п. 3 покрыты (RDP: основные; 4648 — при появлении обработки)
|
||||
- [ ] `event_id` UUID на каждое событие
|
||||
- [ ] Секреты не в git
|
||||
|
||||
---
|
||||
|
||||
## 8. См. также
|
||||
|
||||
- [event-schema-v1.json](event-schema-v1.json)
|
||||
- [TZ.md](TZ.md) §3.2, §4.8
|
||||
- [TZ.md](TZ.md) §3.2, §4.8
|
||||
@@ -0,0 +1,58 @@
|
||||
# ToDo — управление версиями агентов и удалённое обновление
|
||||
|
||||
**Статус:** superseded — основной документ [agent-control-plane.md](agent-control-plane.md).
|
||||
**Связано:** [roadmap.md](roadmap.md) (v0.7), [agent-integration.md](agent-integration.md), UI «Хосты».
|
||||
|
||||
---
|
||||
|
||||
## Цель
|
||||
|
||||
SAC должен:
|
||||
|
||||
1. **Отслеживать соответствие версий** агентов (`ssh-monitor`, `RDP-login-monitor`) ожидаемым/минимальным для текущей версии SAC.
|
||||
2. **Инициировать обновление удалённо** с компьютеров/серверов из UI SAC (или по политике), без ручного захода на каждый хост.
|
||||
|
||||
Сейчас версии видны по `host.product_version` и heartbeat; обновление — вручную (`update_ssh_monitor.sh`, `Deploy-LoginMonitor.ps1` / NETLOGON, GPO).
|
||||
|
||||
---
|
||||
|
||||
## Вопросы для проработки
|
||||
|
||||
| # | Тема | Варианты / заметки |
|
||||
|---|------|-------------------|
|
||||
| 1 | **Источник истины версии** | Матрица в SAC (min/recommended per `product`); теги в репо; отдельный manifest API |
|
||||
| 2 | **Сигнал «устарел»** | Problem `agent.version.stale`; severity на карточке хоста; дашборд «не на версии» |
|
||||
| 3 | **Канал команд** | Pull-only (агент сам тянет по расписанию) vs push-команда от SAC (нужен обратный канал) |
|
||||
| 4 | **Linux** | Вызов `update_ssh_monitor.sh` по systemd timer + флаг «pending update» из SAC ingest response? Отдельный `agent.command` event? SSH/Ansible с SAC — вне scope агента |
|
||||
| 5 | **Windows** | GPO/NETLOGON уже есть; remote = триггер `Deploy-LoginMonitor.ps1` через scheduled task / WinRM / SCCM — что допустимо по безопасности |
|
||||
| 6 | **Авторизация** | Только admin SAC; audit log; подтверждение массового обновления; rate limit |
|
||||
| 7 | **Отчёт о результате** | `agent.update.started` / `agent.update.success` / `agent.update.failed` в ingest; привязка к `host_id` |
|
||||
| 8 | **Сеть** | Агент за NAT только исходящий HTTPS — предпочтителен **pull**, не inbound на хост |
|
||||
| 9 | **Совместимость** | Связка с `schema_version`, откат, окно maintenance |
|
||||
|
||||
---
|
||||
|
||||
## Черновые критерии приёмки (когда дойдём до реализации)
|
||||
|
||||
- [ ] В UI «Хосты»: колонка/бейдж «версия OK / устарела / неизвестна».
|
||||
- [ ] Настройка минимальной/рекомендуемой версии по продукту в SAC (или env).
|
||||
- [ ] Problem или оповещение при расхождении (с cooldown).
|
||||
- [ ] Действие admin: «Запросить обновление» на одном хосте / группе (MVP).
|
||||
- [ ] Агент подтверждает попытку обновления событием в SAC.
|
||||
- [ ] Документация: Linux + Windows runbook, ограничения безопасности.
|
||||
|
||||
---
|
||||
|
||||
## Не в первой итерации (вероятно)
|
||||
|
||||
- Полная замена Ansible/GPO/SCCM.
|
||||
- Обновление SAC с агентов.
|
||||
- macOS-агент.
|
||||
|
||||
---
|
||||
|
||||
## См. также
|
||||
|
||||
- [analytics-backlog.md](analytics-backlog.md) — отложенная аналитика
|
||||
- [todo-2026-05-29.md](todo-2026-05-29.md) — оповещения и настройки
|
||||
- Репозитории агентов: `update_ssh_monitor.sh`, `Deploy-LoginMonitor.ps1`, `update-rdp-monitor.ps1`
|
||||
@@ -0,0 +1,41 @@
|
||||
# Analytics backlog (SAC)
|
||||
|
||||
Разработка отложена; задачи для `work-plan.md` / спринта.
|
||||
|
||||
## Фаза A — API
|
||||
|
||||
| ID | Задача | Готово когда |
|
||||
|----|--------|--------------|
|
||||
| analytics-a1 | `GET /api/v1/analytics/series` (`bucket=hour\|day\|week\|month`, `from`/`to`) | JSON series + тесты |
|
||||
| analytics-a2 | `group_by=severity\|type\|product`, `exclude_types=agent.heartbeat` | heartbeat не в общем счётчике |
|
||||
| analytics-a3 | Presets 24h / 7d / 30d / 90d | документация API |
|
||||
| analytics-a4 | Dashboard: `daily_reports_24h` учитывает `report.daily.rdp` | ✅ test_dashboard |
|
||||
| analytics-a5 | Индексы под агрегации | EXPLAIN без full scan |
|
||||
|
||||
## Фаза B — UI
|
||||
|
||||
| ID | Задача |
|
||||
|----|--------|
|
||||
| analytics-b1 | Страница «Аналитика» + сайдбар |
|
||||
| analytics-b2 | Графики: события по дням; failed vs success login |
|
||||
| analytics-b3 | Sparklines на «Обзоре» (опционально) |
|
||||
| analytics-b4 | Chart.js / аналог в Vite bundle |
|
||||
|
||||
## Фаза C — отчёты и SOC
|
||||
|
||||
| ID | Задача |
|
||||
|----|--------|
|
||||
| analytics-c1 | Тренды из `report.daily.*` → `details.stats` |
|
||||
| analytics-c2 | KPI: % хостов с отчётом за 25h |
|
||||
| analytics-c3 | Problems opened/resolved, MTTR |
|
||||
| analytics-c4 | Top `source_ip` для `*.login.failed` |
|
||||
|
||||
## Фаза D — масштаб
|
||||
|
||||
| ID | Задача |
|
||||
|----|--------|
|
||||
| analytics-d1 | `analytics_daily_rollups` + nightly job |
|
||||
| analytics-d2 | Экспорт CSV |
|
||||
| analytics-d3 | `docs/analytics.md` (метрики и лимиты retention) |
|
||||
|
||||
**Приоритет:** A1 → B1 → C1 → остальное.
|
||||
@@ -0,0 +1,163 @@
|
||||
# Архитектура Security Alert Center
|
||||
|
||||
Дополнение к [TZ.md](TZ.md). Описывает компоненты, границы и модель данных.
|
||||
|
||||
---
|
||||
|
||||
## 1. Диаграмма компонентов
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph external [Внешние системы]
|
||||
AG_SSH[ssh-monitor]
|
||||
AG_RDP[RDP-login-monitor]
|
||||
TG[Telegram API]
|
||||
SMTP[SMTP]
|
||||
end
|
||||
|
||||
subgraph sac_host [Ubuntu 24.04 — хост SAC]
|
||||
NGX[nginx TLS]
|
||||
API[FastAPI — api]
|
||||
WRK[Worker]
|
||||
FE[Static SPA]
|
||||
PG[(PostgreSQL)]
|
||||
RD[(Redis — фаза 1.5+)]
|
||||
end
|
||||
|
||||
AG_SSH -->|HTTPS ingest| NGX
|
||||
AG_RDP -->|HTTPS ingest| NGX
|
||||
NGX --> API
|
||||
NGX --> FE
|
||||
API --> PG
|
||||
API --> RD
|
||||
WRK --> PG
|
||||
WRK --> RD
|
||||
WRK --> TG
|
||||
WRK --> SMTP
|
||||
FE -->|REST + SSE| NGX
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Компоненты
|
||||
|
||||
| Компонент | Ответственность |
|
||||
|-----------|-----------------|
|
||||
| **nginx** | TLS, rate limit, раздача static UI, прокси `/api` → FastAPI |
|
||||
| **api** | Ingest, REST для UI, auth JWT, health |
|
||||
| **worker** | Правила Problems, отправка уведомлений, суточные отчёты, retention |
|
||||
| **frontend** | SPA: Problems, Events, Hosts, Dashboards, Settings |
|
||||
| **PostgreSQL** | События, хосты, problems, пользователи, правила, audit |
|
||||
| **Redis** | Очередь задач, pub/sub для SSE (опционально) |
|
||||
|
||||
---
|
||||
|
||||
## 3. Границы контекстов
|
||||
|
||||
### 3.1. Агент (вне SAC)
|
||||
|
||||
- Чтение локальных журналов (journalctl, Security.evtx).
|
||||
- Формирование JSON-события.
|
||||
- Режим `UseSAC`: маршрутизация «локальные каналы» vs «только SAC».
|
||||
- Локальный spool при недоступности SAC.
|
||||
|
||||
### 3.2. SAC
|
||||
|
||||
- Единственный источник доставки оповещений при `UseSAC=exclusive`.
|
||||
- Дедупликация, корреляция, Problems.
|
||||
- Долговременное хранение и UI.
|
||||
|
||||
---
|
||||
|
||||
## 4. Логическая модель данных
|
||||
|
||||
### 4.1. Сущности
|
||||
|
||||
```
|
||||
tenants (опционально, фаза 3)
|
||||
└── hosts
|
||||
└── events (партиции по occurred_at)
|
||||
└── problems
|
||||
└── problem_events (M:N)
|
||||
└── notification_rules
|
||||
└── notification_log
|
||||
└── users
|
||||
└── audit_log
|
||||
└── api_keys (hash)
|
||||
```
|
||||
|
||||
### 4.2. Ключевые поля
|
||||
|
||||
**hosts**
|
||||
|
||||
- `id`, `agent_instance_id` (unique), `hostname`, `display_name`
|
||||
- `os_family`, `os_version`, `product` (`ssh-monitor` | `rdp-login-monitor`)
|
||||
- `use_sac_mode`, `last_seen_at`, `tags[]`
|
||||
|
||||
**events**
|
||||
|
||||
- `id`, `event_id` (UUID от агента, unique), `host_id`
|
||||
- `occurred_at`, `received_at`
|
||||
- `category`, `type`, `severity`
|
||||
- `title`, `summary`, `details` (JSONB), `raw` (JSONB/text)
|
||||
- `dedup_key`, `correlation_id`
|
||||
|
||||
**problems**
|
||||
|
||||
- `id`, `title`, `severity`, `status`
|
||||
- `opened_at`, `acknowledged_at`, `resolved_at`
|
||||
- `rule_id`, `dedup_key`
|
||||
|
||||
---
|
||||
|
||||
## 5. API (черновой перечень)
|
||||
|
||||
| Метод | Путь | Назначение |
|
||||
|-------|------|------------|
|
||||
| POST | `/api/v1/events` | Ingest одного события |
|
||||
| POST | `/api/v1/events/batch` | Batch (фаза 1.5) |
|
||||
| GET | `/health` | Healthcheck |
|
||||
| GET | `/api/v1/events` | Список (UI, auth) |
|
||||
| GET | `/api/v1/events/{id}` | Карточка |
|
||||
| GET | `/api/v1/problems` | Список Problems |
|
||||
| PATCH | `/api/v1/problems/{id}` | ack / resolve |
|
||||
| GET | `/api/v1/hosts` | Хосты |
|
||||
| GET | `/api/v1/dashboards/summary` | Агрегаты для виджетов |
|
||||
| GET | `/api/v1/stream/events` | SSE live |
|
||||
| POST | `/api/v1/auth/login` | JWT |
|
||||
| CRUD | `/api/v1/notification-rules` | Правила (admin) |
|
||||
|
||||
OpenAPI — генерируется FastAPI при реализации.
|
||||
|
||||
---
|
||||
|
||||
## 6. Каталоги репозитория (целевая структура)
|
||||
|
||||
```
|
||||
security-alert-center/
|
||||
backend/ # FastAPI, models, services
|
||||
frontend/ # Vue SPA
|
||||
deploy/
|
||||
docker-compose.yml
|
||||
nginx/
|
||||
systemd/
|
||||
docs/ # ТЗ, планы (текущая фаза)
|
||||
schemas/ # Копия/ссылка JSON Schema
|
||||
```
|
||||
|
||||
На фазе документации каталоги `backend/` и `frontend/` — заглушки (см. README внутри).
|
||||
|
||||
---
|
||||
|
||||
## 7. Наблюдаемость SAC
|
||||
|
||||
- `GET /health` — для агентов и внешнего мониторинга.
|
||||
- Метрики (фаза 2): Prometheus endpoint или textfile.
|
||||
- Логирование: каждый ingest (без полного `raw` в info-логах).
|
||||
|
||||
---
|
||||
|
||||
## 8. См. также
|
||||
|
||||
- [TZ.md](TZ.md) — требования
|
||||
- [deployment.md](deployment.md) — инфраструктура Ubuntu 24.04
|
||||
@@ -0,0 +1,138 @@
|
||||
# Развёртывание на Ubuntu 24.04
|
||||
|
||||
Эксплуатация SAC: **native** (PostgreSQL + systemd + nginx). Docker — только альтернатива.
|
||||
|
||||
## Руководства по установке
|
||||
|
||||
| Документ | Назначение |
|
||||
|----------|------------|
|
||||
| **[install-ubuntu-24.04-native.md](install-ubuntu-24.04-native.md)** | **Production** — пошаговая подготовка сервера |
|
||||
| [install-ubuntu-24.04-docker.md](install-ubuntu-24.04-docker.md) | Стенд / отладка (Compose) |
|
||||
| [install-ubuntu-24.04.md](install-ubuntu-24.04.md) | Указатель |
|
||||
|
||||
## Артефакты native в репозитории
|
||||
|
||||
```
|
||||
deploy/
|
||||
env.native.example → /opt/security-alert-center/config/sac-api.env
|
||||
systemd/sac-api.service → /etc/systemd/system/
|
||||
nginx/sac.conf.example → /etc/nginx/sites-available/sac (HTTP)
|
||||
nginx/sac.conf.tls.example → HTTPS + wildcard
|
||||
sac-deploy.sh → /opt/sac-deploy.sh (полное обновление)
|
||||
```
|
||||
|
||||
**Production URL:** `https://sac.kalinamall.ru`
|
||||
**Конфиг:** `/opt/security-alert-center/config/sac-api.env` (владелец `sac:sac`, chmod 600).
|
||||
**UI:** статика `frontend/dist`, раздаётся через FastAPI (после `npm run build`).
|
||||
|
||||
---
|
||||
|
||||
## 1. Требования к серверу
|
||||
|
||||
| Параметр | Минимум | Рекомендуется |
|
||||
|----------|---------|---------------|
|
||||
| ОС | Ubuntu 24.04 LTS | Ubuntu 24.04 LTS |
|
||||
| CPU | 2 vCPU | 4 vCPU |
|
||||
| RAM | 4 GB | 8 GB |
|
||||
| Диск | 50 GB SSD | 100+ GB SSD |
|
||||
|
||||
**Порты снаружи:** 443 (nginx), 80 (редирект). API `8000` — только `127.0.0.1`. PostgreSQL — только localhost.
|
||||
|
||||
---
|
||||
|
||||
## 2. Сетевые правила
|
||||
|
||||
**Агенты →** `https://sac.kalinamall.ru/api/v1/events`
|
||||
**SAC →** Telegram, SMTP (исходящие)
|
||||
**Админы →** 443 (UI/API через nginx)
|
||||
|
||||
---
|
||||
|
||||
## 3. Вариант A: Native (production)
|
||||
|
||||
Компоненты на хосте:
|
||||
|
||||
| Компонент | Как |
|
||||
|-----------|-----|
|
||||
| PostgreSQL 16 | `apt`, БД `sac` |
|
||||
| SAC API | Python 3.12 venv, **systemd** `sac-api` |
|
||||
| TLS / proxy | **nginx** |
|
||||
| UI | `frontend/dist`, сборка `npm run build`, раздача из API |
|
||||
|
||||
Полная инструкция: **[install-ubuntu-24.04-native.md](install-ubuntu-24.04-native.md)**.
|
||||
|
||||
Кратко:
|
||||
|
||||
```bash
|
||||
systemctl status sac-api
|
||||
curl -sS http://127.0.0.1:8000/health
|
||||
curl -sS https://sac.kalinamall.ru/health
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Вариант B: Docker Compose (альтернатива)
|
||||
|
||||
См. [install-ubuntu-24.04-docker.md](install-ubuntu-24.04-docker.md) и `deploy/docker-compose.yml`.
|
||||
**Не используется** для production KalinaMall.
|
||||
|
||||
---
|
||||
|
||||
## 5. TLS
|
||||
|
||||
- **Production (KalinaMall):** корпоративный **wildcard** (VeriSign) — [ssl-certificate.md](ssl-certificate.md) (копирование, форматы, `/etc/ssl/sac/`), [install-ubuntu-24.04-native.md](install-ubuntu-24.04-native.md) §9, `deploy/nginx/sac.conf.tls.example`
|
||||
- Альтернатива: **certbot** + Let's Encrypt (`deploy/nginx/sac.conf.example`)
|
||||
|
||||
---
|
||||
|
||||
## 6. Резервное копирование (native)
|
||||
|
||||
```bash
|
||||
# /etc/cron.d/sac-backup
|
||||
0 3 * * * postgres pg_dump -Fc -U sac sac > /var/backups/sac/sac_$(date +\%Y\%m\%d).dump
|
||||
```
|
||||
|
||||
Восстановление: `pg_restore -d sac_restored /var/backups/sac/sac_YYYYMMDD.dump`
|
||||
|
||||
---
|
||||
|
||||
## 7. Обслуживание
|
||||
|
||||
| Задача | Периодичность |
|
||||
|--------|---------------|
|
||||
| `unattended-upgrades` | автоматически |
|
||||
| `journalctl -u sac-api` | по инцидентам |
|
||||
| `/health` | каждые 5 мин |
|
||||
| Тест restore БД | ежемесячно |
|
||||
|
||||
---
|
||||
|
||||
## 8. Обновление (native)
|
||||
|
||||
```bash
|
||||
sudo /opt/sac-deploy.sh
|
||||
```
|
||||
|
||||
Краткий **502 Bad Gateway** в UI (~10 с) возможен при перезапуске `sac-api` — список хостов автоматически повторяет запрос; после деплоя обновите страницу.
|
||||
|
||||
**Важно в `sac-api.env`:** `SAC_PUBLIC_URL=https://sac.kalinamall.ru` — нужен для WinRM-обновления RDP (клиент скачивает zip с SAC). API: **4 worker** uvicorn по умолчанию (`SAC_UVICORN_WORKERS`, `deploy/systemd/sac-api-start.sh`).
|
||||
|
||||
Установка скрипта (один раз): `sudo cp /opt/security-alert-center/deploy/sac-deploy.sh /opt/sac-deploy.sh && sudo chmod 755 /opt/sac-deploy.sh`
|
||||
|
||||
После **force-push** на upstream remote обычный `git pull` на сервере падает с «diverging branches». Скрипт `sac-deploy.sh` (актуальная версия) делает `fetch` и при необходимости `reset --hard` к upstream. **Один раз вручную**, если на сервере ещё старый скрипт:
|
||||
|
||||
```bash
|
||||
sudo -u sac git -C /opt/security-alert-center fetch --prune
|
||||
sudo -u sac git -C /opt/security-alert-center reset --hard origin/main
|
||||
sudo cp /opt/security-alert-center/deploy/sac-deploy.sh /opt/sac-deploy.sh
|
||||
sudo /opt/sac-deploy.sh
|
||||
```
|
||||
|
||||
Подробности: [install-ubuntu-24.04-native.md §13](install-ubuntu-24.04-native.md#13-обновление-sac-деплой).
|
||||
|
||||
---
|
||||
|
||||
## См. также
|
||||
|
||||
- [TZ.md](TZ.md)
|
||||
- [agent-integration.md](agent-integration.md)
|
||||
@@ -0,0 +1,45 @@
|
||||
# Диаграмма потоков данных (рис. 1 к ТЗ)
|
||||
|
||||
Используется в [TZ.md](../TZ.md), раздел 3.
|
||||
В GitLab/GitHub и в VS Code с поддержкой Mermaid диаграмма рендерится автоматически.
|
||||
|
||||
## Экспорт в PNG/SVG
|
||||
|
||||
1. Открыть этот файл в preview редактора или на https://mermaid.live
|
||||
2. Экспортировать как изображение для презентаций
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph agents [Агенты на хостах]
|
||||
SSH[ssh-monitor Linux]
|
||||
RDP[RDP-login-monitor Windows]
|
||||
end
|
||||
|
||||
subgraph sac [Security Alert Center Ubuntu 24.04]
|
||||
API[Ingest API HTTPS]
|
||||
Q[Очередь / воркер]
|
||||
DB[(PostgreSQL)]
|
||||
RT[Realtime SSE/WebSocket]
|
||||
UI[Web UI]
|
||||
NOTIFY[Правила оповещений]
|
||||
end
|
||||
|
||||
subgraph channels [Каналы наружу]
|
||||
TG[Telegram]
|
||||
MAIL[Email]
|
||||
WEBHOOK[Webhook / Slack]
|
||||
end
|
||||
|
||||
SSH -->|JSON события + API key| API
|
||||
RDP -->|JSON события + API key| API
|
||||
API --> Q --> DB
|
||||
DB --> UI
|
||||
DB --> RT --> UI
|
||||
DB --> NOTIFY --> TG
|
||||
NOTIFY --> MAIL
|
||||
NOTIFY --> WEBHOOK
|
||||
```
|
||||
|
||||
## Режим UseSAC=exclusive
|
||||
|
||||
При включённом `UseSAC` стрелки от агентов к Telegram/email **отсутствуют**; доставка пользователю только через блок `NOTIFY` в SAC.
|
||||
@@ -0,0 +1,174 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://git.papatramp.ru/PapaTramp/security-alert-center/schemas/event-v1.json",
|
||||
"title": "Security Alert Center Event v1",
|
||||
"description": "Каноническое событие от ssh-monitor или RDP-login-monitor",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"schema_version",
|
||||
"event_id",
|
||||
"occurred_at",
|
||||
"source",
|
||||
"host",
|
||||
"category",
|
||||
"type",
|
||||
"severity",
|
||||
"title",
|
||||
"summary"
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"schema_version": {
|
||||
"type": "string",
|
||||
"const": "1.0"
|
||||
},
|
||||
"event_id": {
|
||||
"type": "string",
|
||||
"format": "uuid",
|
||||
"description": "UUID v4, уникален глобально, для идемпотентности"
|
||||
},
|
||||
"occurred_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"description": "ISO 8601 с offset, время события на хосте"
|
||||
},
|
||||
"source": {
|
||||
"type": "object",
|
||||
"required": ["product", "product_version"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"product": {
|
||||
"type": "string",
|
||||
"enum": ["ssh-monitor", "rdp-login-monitor"]
|
||||
},
|
||||
"product_version": {
|
||||
"type": "string"
|
||||
},
|
||||
"agent_instance_id": {
|
||||
"type": "string",
|
||||
"description": "Стабильный ID установки агента"
|
||||
}
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"type": "object",
|
||||
"required": ["hostname", "os_family"],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"hostname": { "type": "string" },
|
||||
"display_name": { "type": "string" },
|
||||
"fqdn": { "type": "string" },
|
||||
"os_family": {
|
||||
"type": "string",
|
||||
"enum": ["linux", "windows"]
|
||||
},
|
||||
"os_version": { "type": "string" },
|
||||
"ipv4": { "type": "string" },
|
||||
"ipv6": { "type": "string" },
|
||||
"timezone": {
|
||||
"type": "string",
|
||||
"description": "IANA, например Europe/Moscow"
|
||||
}
|
||||
}
|
||||
},
|
||||
"category": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auth",
|
||||
"privilege",
|
||||
"network",
|
||||
"session",
|
||||
"report",
|
||||
"agent"
|
||||
]
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "Машиночитаемый тип, см. docs/agent-integration.md",
|
||||
"examples": [
|
||||
"ssh.login.success",
|
||||
"ssh.login.failed",
|
||||
"privilege.sudo.command",
|
||||
"ssh.ip.banned",
|
||||
"ssh.bruteforce.mass",
|
||||
"session.logind.new",
|
||||
"rdp.login.success",
|
||||
"rdp.login.failed",
|
||||
"rdp.session.logoff",
|
||||
"rdp.shadow.control.started",
|
||||
"rdp.shadow.control.stopped",
|
||||
"rdp.shadow.control.permission",
|
||||
"winrm.session.started",
|
||||
"smb.admin_share.access",
|
||||
"rdg.connection.success",
|
||||
"report.daily.ssh",
|
||||
"agent.heartbeat",
|
||||
"agent.inventory",
|
||||
"agent.test"
|
||||
]
|
||||
},
|
||||
"severity": {
|
||||
"type": "string",
|
||||
"enum": ["info", "warning", "high", "critical"]
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"maxLength": 256
|
||||
},
|
||||
"summary": {
|
||||
"type": "string",
|
||||
"description": "Человекочитаемый текст (как в Telegram сейчас)",
|
||||
"maxLength": 8192
|
||||
},
|
||||
"details": {
|
||||
"type": "object",
|
||||
"description": "Структурированные поля по типу события",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"raw": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"format": {
|
||||
"type": "string",
|
||||
"enum": ["journal", "windows_event_xml", "text"]
|
||||
},
|
||||
"payload": {
|
||||
"type": "string",
|
||||
"maxLength": 16384
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"tags": {
|
||||
"type": "array",
|
||||
"items": { "type": "string", "maxLength": 64 },
|
||||
"maxItems": 32
|
||||
},
|
||||
"dedup_key": {
|
||||
"type": "string",
|
||||
"maxLength": 512
|
||||
},
|
||||
"correlation_id": {
|
||||
"type": "string",
|
||||
"format": "uuid"
|
||||
},
|
||||
"fingerprint": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
},
|
||||
"enrichment": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"attempt_number": { "type": "integer", "minimum": 0 },
|
||||
"threshold": { "type": "integer", "minimum": 0 },
|
||||
"risk_level": {
|
||||
"type": "string",
|
||||
"enum": ["low", "medium", "high", "critical"]
|
||||
},
|
||||
"filtered_out": { "type": "boolean" },
|
||||
"filter_reason": { "type": "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
# Backlog: ingest и массовое обновление агентов
|
||||
|
||||
**Статус:** ToDo (не в текущем релизе).
|
||||
**Контекст:** массовый SSH-update через SAC (10+ хостов) + `sac-deploy` в одно окно → часть POST в ingest «теряется» с точки зрения агента (`SAC POST HTTP :`), flood в Telegram (fallback + watchdog).
|
||||
**Связано:** [runbook-ops.md](runbook-ops.md), [agent-integration.md](agent-integration.md), ssh-monitor [security-roadmap.ru.md](https://git.papatramp.ru/PapaTramp/ssh-monitor/src/branch/main/docs/security-roadmap.ru.md).
|
||||
|
||||
Увеличение `SAC_DB_POOL_SIZE` / defer daily в **0.5.0** лечит штурм суточных отчётов и пул БД; **не** снимает узкие места ниже при одновременном restart многих агентов.
|
||||
|
||||
---
|
||||
|
||||
## Операционно (сразу, без кода)
|
||||
|
||||
- [ ] **Не совмещать** `sudo /opt/sac-deploy.sh` и массовое «Обновить ssh-monitor (SSH)» по многим хостам — сначала deploy SAC, потом агенты (или наоборот).
|
||||
- [ ] Обновлять Linux-хосты **пачками по 2–3**, не все подряд.
|
||||
- [ ] На зрелых хостах перевести **`UseSAC=exclusive`** (нет дубля в Telegram с агента при fallback); watchdog по-прежнему шлёт в Telegram сам.
|
||||
- [ ] Перед первым SSH-update с SAC: **`ssh-keyscan`** в `config/ssh_known_hosts` (см. runbook).
|
||||
- [ ] В `sac-api.env`: только `KEY=value` на строку, комментарии отдельной строкой с `#`.
|
||||
|
||||
---
|
||||
|
||||
## SAC (backend / deploy)
|
||||
|
||||
- [x] **Defer** `notify_lifecycle` и `notify_auth_login` в background (как `report.daily.*` → `schedule_notify_daily_report`), чтобы ingest не ждал Telegram API — **0.5.5**
|
||||
- [x] **Uvicorn workers:** 4 по умолчанию или `SAC_UVICORN_WORKERS` в `sac-api.env` / `sac-api-start.sh` — **0.5.5**
|
||||
- [x] **nginx:** отдельный `location` для `POST /api/v1/events` с увеличенным `proxy_read_timeout` — **0.5.5**
|
||||
- [ ] Опционально: метрики/лог длительности ingest и очереди при burst.
|
||||
- [x] UI: предупреждение при массовом update («N хостов — рекомендуется пачками») — **0.5.5**
|
||||
|
||||
---
|
||||
|
||||
## ssh-monitor (агент)
|
||||
|
||||
- [x] При **shutdown** / `SIGTERM` не увеличивать `sac-fail.count` — **2.3.2-SAC**
|
||||
- [x] После успешного heartbeat сбрасывать fail counter (успешный POST ingest) — уже было
|
||||
- [x] Watchdog: не слать Telegram при штатном restart во время SAC-update (state file `/var/lib/ssh-monitor/agent-update-in-progress` от updater) — **2.2.1-SAC**
|
||||
- [x] Sudo bootstrap/update через SAC: не слать Telegram (`ssh_monitor_sudo_is_sac_maintenance`, state-file раньше) — **2.2.3-SAC**
|
||||
- [x] SAC: suppress `privilege.sudo.command` при `agent_update_state=running` / maintenance command — **0.5.3**
|
||||
- [x] Документировать рекомендуемый `SAC_TIMEOUT_SEC` при тяжёлом ingest — **2.3.2-SAC** (`docs/sac-ingest.ru.md`)
|
||||
|
||||
---
|
||||
|
||||
## Принято / сделано
|
||||
|
||||
- [x] Pool БД 15+25, defer daily push — SAC **0.5.0**
|
||||
- [x] `sac-deploy.sh` без `source` конфига, preflight pydantic — SAC `fa1bd41`
|
||||
- [x] Watchdog: строка `🖥️ Сервер:` в Telegram — ssh-monitor **2.1.9-SAC**
|
||||
|
||||
---
|
||||
|
||||
*После реализации пунктов SAC — bump `APP_VERSION` и runbook.*
|
||||
@@ -0,0 +1,105 @@
|
||||
# Ubuntu 24.04 — установка SAC (Docker Compose)
|
||||
|
||||
**Альтернативный** способ. В KalinaMall для production используется **[native](install-ubuntu-24.04-native.md)**.
|
||||
|
||||
Docker удобен для локальной отладки или изолированного стенда.
|
||||
|
||||
---
|
||||
|
||||
## 0. Исходные данные
|
||||
|
||||
| Параметр | Пример |
|
||||
|----------|--------|
|
||||
| Каталог | `/opt/security-alert-center` |
|
||||
|
||||
---
|
||||
|
||||
## 1. Базовая ОС и ufw
|
||||
|
||||
Как в [native-руководстве](install-ubuntu-24.04-native.md) §1 (без PostgreSQL/nginx на хосте, если всё в контейнерах — nginx можно на хосте для TLS).
|
||||
|
||||
---
|
||||
|
||||
## 2. Git и клон
|
||||
|
||||
```bash
|
||||
sudo apt install -y git
|
||||
sudo git clone https://git.papatramp.ru/PapaTramp/security-alert-center.git /opt/security-alert-center
|
||||
sudo chown -R "$USER:$USER" /opt/security-alert-center
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Docker Engine + Compose
|
||||
|
||||
```bash
|
||||
sudo apt install -y ca-certificates curl gnupg
|
||||
sudo install -m 0755 -d /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
sudo chmod a+r /etc/apt/keyrings/docker.gpg
|
||||
|
||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu noble stable" | \
|
||||
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
|
||||
sudo apt update
|
||||
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
|
||||
sudo usermod -aG docker "$USER"
|
||||
# перелогиниться
|
||||
docker compose version
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Конфигурация
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /etc/security-alert-center
|
||||
cp /opt/security-alert-center/deploy/.env.example /etc/security-alert-center/.env
|
||||
chmod 600 /etc/security-alert-center/.env
|
||||
nano /etc/security-alert-center/.env
|
||||
ln -sf /etc/security-alert-center/.env /opt/security-alert-center/deploy/.env
|
||||
```
|
||||
|
||||
Заполнить: `POSTGRES_PASSWORD`, `JWT_SECRET`, `SAC_PUBLIC_URL`, `SAC_BOOTSTRAP_API_KEY`.
|
||||
|
||||
---
|
||||
|
||||
## 5. Запуск
|
||||
|
||||
```bash
|
||||
cd /opt/security-alert-center/deploy
|
||||
docker compose up -d --build
|
||||
docker compose run --rm migrate
|
||||
docker compose ps
|
||||
curl -sS http://127.0.0.1:8000/health
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Бэкап (Docker)
|
||||
|
||||
```bash
|
||||
sudo tee /etc/cron.d/sac-backup <<'EOF'
|
||||
0 3 * * * root docker compose -f /opt/security-alert-center/deploy/docker-compose.yml exec -T postgres pg_dump -U sac -Fc sac > /var/backups/sac/sac_$(date +\%Y\%m\%d).dump
|
||||
EOF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Обновление
|
||||
|
||||
```bash
|
||||
cd /opt/security-alert-center
|
||||
git pull
|
||||
cd deploy
|
||||
docker compose build
|
||||
docker compose up -d
|
||||
docker compose run --rm migrate
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## См. также
|
||||
|
||||
- [install-ubuntu-24.04-native.md](install-ubuntu-24.04-native.md) — основной путь
|
||||
- [../deploy/docker-compose.yml](../deploy/docker-compose.yml)
|
||||
@@ -0,0 +1,465 @@
|
||||
# Ubuntu 24.04 — установка SAC (native, без Docker)
|
||||
|
||||
Пошаговое руководство: **PostgreSQL + Python venv + systemd + nginx**.
|
||||
Рекомендуемый путь для production.
|
||||
|
||||
---
|
||||
|
||||
## 0. Исходные данные
|
||||
|
||||
| Параметр | Пример |
|
||||
|----------|--------|
|
||||
| FQDN | `sac.kalinamall.ru` |
|
||||
| IP | `10.0.0.50` |
|
||||
| Каталог | `/opt/security-alert-center` |
|
||||
| Пользователь сервиса | `sac` |
|
||||
| API только на localhost | `127.0.0.1:8000` |
|
||||
| Снаружи | nginx → 443 → API |
|
||||
|
||||
---
|
||||
|
||||
## 1. Базовая настройка ОС
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt upgrade -y
|
||||
sudo timedatectl set-timezone Europe/Moscow
|
||||
```
|
||||
|
||||
### Firewall (ufw)
|
||||
|
||||
```bash
|
||||
sudo apt install -y ufw
|
||||
sudo ufw default deny incoming
|
||||
sudo ufw default allow outgoing
|
||||
sudo ufw allow OpenSSH
|
||||
sudo ufw allow 80/tcp
|
||||
sudo ufw allow 443/tcp
|
||||
sudo ufw enable
|
||||
sudo ufw status verbose
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Пакеты
|
||||
|
||||
```bash
|
||||
sudo apt install -y \
|
||||
git \
|
||||
postgresql \
|
||||
postgresql-contrib \
|
||||
nginx \
|
||||
python3.12 \
|
||||
python3.12-venv \
|
||||
python3-pip \
|
||||
jq \
|
||||
certbot \
|
||||
python3-certbot-nginx
|
||||
```
|
||||
|
||||
Проверка:
|
||||
|
||||
```bash
|
||||
python3.12 --version
|
||||
psql --version
|
||||
nginx -v
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Клонирование репозитория
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /opt
|
||||
sudo git clone https://git.papatramp.ru/PapaTramp/security-alert-center.git /opt/security-alert-center
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. PostgreSQL
|
||||
|
||||
Создать пользователя и БД (пароль сохраните для `.env`):
|
||||
|
||||
```bash
|
||||
sudo -u postgres psql <<'SQL'
|
||||
CREATE USER sac WITH PASSWORD 'ЗАМЕНИТЕ_НА_ДЛИННЫЙ_ПАРОЛЬ';
|
||||
CREATE DATABASE sac OWNER sac;
|
||||
GRANT ALL PRIVILEGES ON DATABASE sac TO sac;
|
||||
SQL
|
||||
```
|
||||
|
||||
PostgreSQL по умолчанию слушает `127.0.0.1` — для SAC этого достаточно.
|
||||
Проверка:
|
||||
|
||||
```bash
|
||||
psql "postgresql://sac@127.0.0.1/sac" -c 'SELECT 1'
|
||||
```
|
||||
|
||||
Каталог бэкапов:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /var/backups/sac
|
||||
sudo chown postgres:postgres /var/backups/sac
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Пользователь `sac` и Python venv
|
||||
|
||||
```bash
|
||||
sudo useradd --system --home /opt/security-alert-center --shell /usr/sbin/nologin sac || true
|
||||
sudo chown -R sac:sac /opt/security-alert-center
|
||||
|
||||
cd /opt/security-alert-center/backend
|
||||
sudo -u sac python3.12 -m venv .venv
|
||||
sudo -u sac .venv/bin/pip install --upgrade pip
|
||||
sudo -u sac .venv/bin/pip install -r requirements.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Конфигурация
|
||||
|
||||
Файл лежит **в каталоге приложения** (владелец `sac`) — так проще, чем права на `/etc/...`.
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /opt/security-alert-center/config
|
||||
sudo cp /opt/security-alert-center/deploy/env.native.example \
|
||||
/opt/security-alert-center/config/sac-api.env
|
||||
sudo nano /opt/security-alert-center/config/sac-api.env
|
||||
sudo chown sac:sac /opt/security-alert-center/config/sac-api.env
|
||||
sudo chmod 600 /opt/security-alert-center/config/sac-api.env
|
||||
```
|
||||
|
||||
Если уже создавали `/etc/security-alert-center/sac-api.env` — перенесите:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /opt/security-alert-center/config
|
||||
sudo cp /etc/security-alert-center/sac-api.env /opt/security-alert-center/config/sac-api.env
|
||||
sudo chown sac:sac /opt/security-alert-center/config/sac-api.env
|
||||
sudo chmod 600 /opt/security-alert-center/config/sac-api.env
|
||||
```
|
||||
|
||||
Обязательно задать:
|
||||
|
||||
- `DATABASE_URL` — с паролем PostgreSQL из шага 4 (если в пароле есть `#`, `@`, `%` — возьмите значение в **кавычки**: `DATABASE_URL="postgresql+psycopg2://..."`)
|
||||
- `JWT_SECRET` — `openssl rand -hex 32`
|
||||
- `SAC_PUBLIC_URL` — `https://sac.kalinamall.ru`
|
||||
- `SAC_BOOTSTRAP_API_KEY` — `python3.12 -c "import secrets; print('sac_'+secrets.token_urlsafe(32))"`
|
||||
- `SAC_ADMIN_PASSWORD` — пароль входа в веб-UI (отдельно от API key агентов)
|
||||
- `EVENT_SCHEMA_PATH=/opt/security-alert-center/schemas/event-schema-v1.json`
|
||||
- (опц.) Telegram из SAC: `TELEGRAM_ENABLED=true`, `TELEGRAM_BOT_TOKEN`, `TELEGRAM_CHAT_ID`, `TELEGRAM_MIN_SEVERITY=high`
|
||||
|
||||
---
|
||||
|
||||
## 7. Миграции БД
|
||||
|
||||
Проверка, что `sac` читает конфиг (должно быть без `Permission denied`):
|
||||
|
||||
```bash
|
||||
ls -la /opt/security-alert-center/config/sac-api.env
|
||||
# должно быть: -rw------- sac sac
|
||||
sudo -u sac test -r /opt/security-alert-center/config/sac-api.env && echo OK
|
||||
```
|
||||
|
||||
Миграции:
|
||||
|
||||
```bash
|
||||
cd /opt/security-alert-center/backend
|
||||
sudo -u sac bash -c 'set -a; source /opt/security-alert-center/config/sac-api.env; set +a; .venv/bin/alembic upgrade head'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. systemd
|
||||
|
||||
Приложение загружает `config/sac-api.env` **само** (не через `EnvironmentFile` systemd) — так же, как при `alembic` с `source`.
|
||||
|
||||
```bash
|
||||
cd /opt/security-alert-center && sudo git pull
|
||||
sudo cp /opt/security-alert-center/deploy/systemd/sac-api.service /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable sac-api
|
||||
sudo systemctl start sac-api
|
||||
sudo systemctl status sac-api --no-pager
|
||||
```
|
||||
|
||||
Логи:
|
||||
|
||||
```bash
|
||||
journalctl -u sac-api -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. nginx и TLS
|
||||
|
||||
Для KalinaMall: **корпоративный wildcard VeriSign** (или DigiCert), не Let's Encrypt.
|
||||
Хост `sac.kalinamall.ru` должен попадать под `*.kalinamall.ru`.
|
||||
|
||||
**Подробно:** форматы, scp с Windows/Linux, `.pfx` → PEM, права — **[ssl-certificate.md](ssl-certificate.md)**.
|
||||
|
||||
### 9.1. Кратко: куда положить файлы
|
||||
|
||||
nginx ожидает **два PEM-файла**:
|
||||
|
||||
| Файл на сервере | Содержимое |
|
||||
|-----------------|------------|
|
||||
| `/etc/ssl/sac/fullchain.pem` | Wildcard-сертификат + промежуточные CA |
|
||||
| `/etc/ssl/sac/privkey.pem` | Закрытый ключ |
|
||||
|
||||
```bash
|
||||
# каталог: группа ssl-cert, чтобы www-data мог зайти в каталог (chmod 750)
|
||||
sudo mkdir -p /etc/ssl/sac
|
||||
sudo chown root:ssl-cert /etc/ssl/sac
|
||||
sudo chmod 750 /etc/ssl/sac
|
||||
|
||||
# nginx читает ключ через группу ssl-cert (на чистой Ubuntu в группе часто только postgres)
|
||||
sudo groupadd -f ssl-cert
|
||||
sudo usermod -aG ssl-cert www-data
|
||||
```
|
||||
|
||||
Скопировать с рабочего ПК (пример):
|
||||
|
||||
```bash
|
||||
# с вашего компьютера:
|
||||
scp fullchain.pem privkey.pem papatramp@<IP_SAC>:/tmp/
|
||||
|
||||
# на сервере:
|
||||
sudo mv /tmp/fullchain.pem /tmp/privkey.pem /etc/ssl/sac/
|
||||
sudo chmod 644 /etc/ssl/sac/fullchain.pem
|
||||
sudo chmod 640 /etc/ssl/sac/privkey.pem
|
||||
sudo chown root:root /etc/ssl/sac/fullchain.pem
|
||||
sudo chown root:ssl-cert /etc/ssl/sac/privkey.pem
|
||||
# каталог снова root:ssl-cert (если меняли владельца при mv)
|
||||
sudo chown root:ssl-cert /etc/ssl/sac
|
||||
sudo chmod 750 /etc/ssl/sac
|
||||
|
||||
# worker nginx должен подхватить группу www-data
|
||||
sudo systemctl restart nginx
|
||||
|
||||
sudo -u www-data test -x /etc/ssl/sac && echo dir OK || echo dir FAIL
|
||||
sudo -u www-data test -r /etc/ssl/sac/fullchain.pem && echo fullchain OK || echo fullchain FAIL
|
||||
sudo -u www-data test -r /etc/ssl/sac/privkey.pem && echo key OK || echo key FAIL
|
||||
```
|
||||
|
||||
Если `test -r privkey.pem` молчит: каталог был `root:root` при `750` — у `www-data` нет права `x` на `/etc/ssl/sac/`; либо `www-data` не в `ssl-cert`. См. [ssl-certificate.md §3](ssl-certificate.md#3-каталог-и-права-на-сервере).
|
||||
|
||||
Если PFX с другого Linux — `scp` на SAC: [ssl-certificate.md §4.3](ssl-certificate.md#43-забрать-файл-с-другого-linux-сервера-scp).
|
||||
Распаковка PFX на Ubuntu 24.04: **`openssl pkcs12 -legacy`** — [§4.4](ssl-certificate.md#44-распаковка-pfx--p12-на-сервере-ubuntu-2404).
|
||||
|
||||
### 9.2. Конфиг nginx (HTTPS)
|
||||
|
||||
```bash
|
||||
cd /opt/security-alert-center
|
||||
sudo git pull
|
||||
sudo cp deploy/nginx/sac.conf.tls.example /etc/nginx/sites-available/sac
|
||||
sudo nano /etc/nginx/sites-available/sac
|
||||
# Проверьте пути ssl_certificate и ssl_certificate_key → /etc/ssl/sac/...
|
||||
|
||||
sudo ln -sf /etc/nginx/sites-available/sac /etc/nginx/sites-enabled/sac
|
||||
sudo rm -f /etc/nginx/sites-enabled/default
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
Шаблон `sac.conf.tls.example` содержит **default_server** с `return 444` (:80) и `ssl_reject_handshake` (:443) для любого Host, кроме `sac.kalinamall.ru`. Это защищает от ситуации, когда на IP SAC (например `192.168.160.145`) по ошибке DNS попадает `ext.kalinamall.ru` и открывается форма входа SAC.
|
||||
|
||||
Проверка после reload:
|
||||
|
||||
```bash
|
||||
curl -sS -o /dev/null -w '%{http_code}\n' --resolve sac.kalinamall.ru:443:127.0.0.1 https://sac.kalinamall.ru/health
|
||||
# ожидается 200
|
||||
|
||||
curl -sS -o /dev/null -w '%{http_code}\n' --resolve ext.kalinamall.ru:443:127.0.0.1 https://ext.kalinamall.ru/ 2>/dev/null || echo "connection closed (444/reject OK)"
|
||||
```
|
||||
|
||||
Проверка:
|
||||
|
||||
```bash
|
||||
curl -sS https://sac.kalinamall.ru/health | jq .
|
||||
```
|
||||
|
||||
В `config/sac-api.env` должно быть: `SAC_PUBLIC_URL=https://sac.kalinamall.ru`
|
||||
|
||||
### 9.3. Агенты (ssh-monitor, RDP) и доверие к CA
|
||||
|
||||
- Агенты ходят на `https://sac.kalinamall.ru/api/v1/events`.
|
||||
- Если используется **внутренний корневой CA**, а не публичный VeriSign/DigiCert в системном store — на Linux/Windows может понадобиться установка корневого сертификата в доверенные (или корпоративный прокси с подменой TLS).
|
||||
- Для публичного коммерческого wildcard от известного УЦ обычно **дополнительных действий на агентах не нужно**.
|
||||
|
||||
### 9.4. Альтернатива: только HTTP (отладка)
|
||||
|
||||
Шаблон `deploy/nginx/sac.conf.example` — порт 80 без TLS. Не для production.
|
||||
|
||||
### 9.5. Альтернатива: Let's Encrypt
|
||||
|
||||
Если понадобится публичный бесплатный сертификат только на этот хост:
|
||||
|
||||
```bash
|
||||
sudo cp deploy/nginx/sac.conf.example /etc/nginx/sites-available/sac
|
||||
# ... nginx -t, reload, затем:
|
||||
sudo certbot --nginx -d sac.kalinamall.ru
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Сборка веб-UI (фаза 1C)
|
||||
|
||||
```bash
|
||||
sudo apt install -y nodejs npm
|
||||
cd /opt/security-alert-center
|
||||
sudo -u sac git pull
|
||||
cd frontend
|
||||
sudo -u sac npm ci
|
||||
sudo -u sac npm run build
|
||||
ls -la dist/index.html
|
||||
sudo systemctl restart sac-api
|
||||
```
|
||||
|
||||
В `config/sac-api.env` задайте `SAC_ADMIN_PASSWORD`, затем откройте `https://sac.kalinamall.ru/` (логин `SAC_ADMIN_USERNAME`, по умолчанию `admin`).
|
||||
|
||||
После обновления с multi-user (миграция `009_sac_users`): выполните `alembic upgrade head` в каталоге `backend/`. При первом старте API создаст пользователя **admin** из `SAC_ADMIN_*`, если таблица `sac_users` пуста.
|
||||
|
||||
Добавить сотрудника с ролью **monitor** (просмотр без «Настройки»):
|
||||
|
||||
```bash
|
||||
cd /opt/security-alert-center/backend
|
||||
sudo -u sac python scripts/sac_manage_user.py create ivanov 'StrongPass123' --role monitor
|
||||
```
|
||||
|
||||
Роли: **admin** — полный доступ; **monitor** — события, хосты, проблемы, отчёты (без `/settings` и `/users`).
|
||||
|
||||
---
|
||||
|
||||
## 11. Проверка
|
||||
|
||||
Локально на сервере:
|
||||
|
||||
```bash
|
||||
curl -sS http://127.0.0.1:8000/health | jq .
|
||||
```
|
||||
|
||||
Через nginx (после TLS):
|
||||
|
||||
```bash
|
||||
curl -sS https://sac.kalinamall.ru/health | jq .
|
||||
```
|
||||
|
||||
Тест ingest (подставьте `SAC_BOOTSTRAP_API_KEY`):
|
||||
|
||||
```bash
|
||||
API_KEY="ваш_ключ_из_sac-api.env"
|
||||
curl -sS -X POST http://127.0.0.1:8000/api/v1/events \
|
||||
-H "Authorization: Bearer ${API_KEY}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"schema_version": "1.0",
|
||||
"event_id": "00000000-0000-4000-8000-000000000002",
|
||||
"occurred_at": "2026-05-26T12:00:00+03:00",
|
||||
"source": {"product": "ssh-monitor", "product_version": "test"},
|
||||
"host": {"hostname": "test-host", "os_family": "linux"},
|
||||
"category": "agent",
|
||||
"type": "agent.test",
|
||||
"severity": "info",
|
||||
"title": "Test",
|
||||
"summary": "Native install check"
|
||||
}'
|
||||
```
|
||||
|
||||
Ожидается HTTP **202** и `"status": "accepted"`.
|
||||
|
||||
---
|
||||
|
||||
## 12. Резервное копирование
|
||||
|
||||
```bash
|
||||
sudo tee /etc/cron.d/sac-backup <<'EOF'
|
||||
0 3 * * * postgres pg_dump -Fc -U sac sac > /var/backups/sac/sac_$(date +\%Y\%m\%d).dump
|
||||
EOF
|
||||
```
|
||||
|
||||
Для `pg_dump` без пароля в cron настройте `~postgres/.pgpass` (см. документацию PostgreSQL).
|
||||
|
||||
---
|
||||
|
||||
## 13. Обновление SAC (деплой)
|
||||
|
||||
### Рекомендуется: скрипт `/opt/sac-deploy.sh`
|
||||
|
||||
После первой установки один раз:
|
||||
|
||||
```bash
|
||||
sudo cp /opt/security-alert-center/deploy/sac-deploy.sh /opt/sac-deploy.sh
|
||||
sudo chmod 755 /opt/sac-deploy.sh
|
||||
```
|
||||
|
||||
Каждое обновление с git:
|
||||
|
||||
```bash
|
||||
sudo /opt/sac-deploy.sh
|
||||
```
|
||||
|
||||
Скрипт: `chown sac:sac` → `git pull` (от **sac**) → `pip` → `alembic` → `npm run build` → `systemctl restart sac-api` → проверка `/health`.
|
||||
|
||||
### Вручную (если без скрипта)
|
||||
|
||||
```bash
|
||||
sudo chown -R sac:sac /opt/security-alert-center
|
||||
sudo -u sac git -C /opt/security-alert-center pull
|
||||
cd /opt/security-alert-center/frontend && sudo -u sac npm ci && sudo -u sac npm run build
|
||||
sudo -u sac /opt/security-alert-center/backend/.venv/bin/pip install -r /opt/security-alert-center/backend/requirements.txt
|
||||
sudo -u sac bash -c 'set -a; source /opt/security-alert-center/config/sac-api.env; set +a; cd /opt/security-alert-center/backend && .venv/bin/alembic upgrade head'
|
||||
sudo systemctl restart sac-api
|
||||
```
|
||||
|
||||
### Git: только от пользователя `sac`
|
||||
|
||||
Не выполняйте `sudo git pull` в `/opt/security-alert-center` — `.git` станет root и появится:
|
||||
|
||||
`error: cannot open '.git/FETCH_HEAD': Permission denied`
|
||||
|
||||
Исправление: `sudo chown -R sac:sac /opt/security-alert-center`.
|
||||
|
||||
---
|
||||
|
||||
## 14. Чеклист
|
||||
|
||||
- [ ] Ubuntu 24.04, timezone
|
||||
- [ ] ufw: 22, 80, 443
|
||||
- [ ] PostgreSQL: БД `sac`, пользователь `sac`
|
||||
- [ ] venv, зависимости установлены
|
||||
- [ ] `/opt/security-alert-center/config/sac-api.env`, владелец `sac:sac`, chmod 600
|
||||
- [ ] `alembic upgrade head` без ошибок
|
||||
- [ ] `sac-api` active (systemd)
|
||||
- [ ] nginx + TLS
|
||||
- [ ] `/health` ok, ingest 202
|
||||
- [ ] `frontend/dist` собран, UI открывается, вход admin OK
|
||||
- [ ] cron backup
|
||||
|
||||
---
|
||||
|
||||
## 15. Устранение неполадок
|
||||
|
||||
| Симптом | Действие |
|
||||
|---------|----------|
|
||||
| `sac-api.env: Permission denied` | Конфиг в `/opt/security-alert-center/config/`, `chown sac:sac`, `chmod 600`. Не используйте `/etc/...` с каталогом `root:root` |
|
||||
| `password authentication failed` в **sac-api**, но alembic OK | Старый unit с `EnvironmentFile=` — `git pull`, обновить `sac-api.service`, `daemon-reload`, `restart`. Либо пароль в `DATABASE_URL` ≠ PostgreSQL |
|
||||
| `password authentication failed` везде | Пароль в `DATABASE_URL` в кавычках; `ALTER USER sac WITH PASSWORD`; тот же пароль в URL |
|
||||
| `database: error` / SQLAlchemy connect | `systemctl status postgresql`; проверить `DATABASE_URL` после успешного `source` |
|
||||
| 401 ingest | ключ в `Authorization: Bearer`; проверить `SAC_BOOTSTRAP_API_KEY` |
|
||||
| 502 от nginx | API не слушает: `ss -lntp \| grep 8000`, `systemctl restart sac-api` |
|
||||
| Schema errors 422 | путь `EVENT_SCHEMA_PATH`, наличие файла schema |
|
||||
| `FETCH_HEAD: Permission denied` | `sudo chown -R sac:sac /opt/security-alert-center`; далее `sudo -u sac git pull` |
|
||||
| UI 404 / пустая главная | `cd frontend && sudo -u sac npm run build`; `restart sac-api` |
|
||||
| 503 на `/auth/login` | задать `SAC_ADMIN_PASSWORD` в `config/sac-api.env` |
|
||||
| `test -r privkey.pem` без вывода | каталог `/etc/ssl/sac` → `root:ssl-cert`, `www-data` в группе `ssl-cert` — [ssl-certificate.md](ssl-certificate.md) §3 |
|
||||
| PFX `RC2-40-CBC unsupported` | `openssl pkcs12 -legacy` — [ssl-certificate.md](ssl-certificate.md) §4.4 |
|
||||
|
||||
---
|
||||
|
||||
## См. также
|
||||
|
||||
- [install-ubuntu-24.04.md](install-ubuntu-24.04.md) — указатель
|
||||
- [install-ubuntu-24.04-docker.md](install-ubuntu-24.04-docker.md) — альтернатива (не prod)
|
||||
- [deployment.md](deployment.md)
|
||||
@@ -0,0 +1,24 @@
|
||||
# Подготовка сервера Ubuntu 24.04 для SAC
|
||||
|
||||
В эксплуатации KalinaMall используется **только native** (без Docker): PostgreSQL, Python venv, systemd, nginx.
|
||||
|
||||
## Руководства
|
||||
|
||||
| Путь | Когда использовать |
|
||||
|------|-------------------|
|
||||
| **[install-ubuntu-24.04-native.md](install-ubuntu-24.04-native.md)** | **Основной** — подготовка и запуск SAC |
|
||||
| [install-ubuntu-24.04-docker.md](install-ubuntu-24.04-docker.md) | Альтернатива (Docker Compose), не для prod |
|
||||
|
||||
## Быстрый старт (native)
|
||||
|
||||
```bash
|
||||
# см. полный чеклист в native-руководстве
|
||||
sudo apt update && sudo apt install -y git postgresql nginx python3.12 python3.12-venv
|
||||
sudo git clone https://git.papatramp.ru/PapaTramp/security-alert-center.git /opt/security-alert-center
|
||||
# … PostgreSQL, venv, config/sac-api.env, systemd, nginx
|
||||
```
|
||||
|
||||
## См. также
|
||||
|
||||
- [deployment.md](deployment.md)
|
||||
- [../deploy/README.md](../deploy/README.md)
|
||||
@@ -0,0 +1,66 @@
|
||||
# SAC production — текущий статус (KalinaMall)
|
||||
|
||||
Ориентир для продолжения работ. Обновляйте при смене этапа.
|
||||
|
||||
**Сервер:** Ubuntu 24.04, FQDN `sac.kalinamall.ru`
|
||||
**Каталог:** `/opt/security-alert-center`
|
||||
**Пользователь сервиса:** `sac` (git, venv, npm — только от него)
|
||||
**Конфиг:** `/opt/security-alert-center/config/sac-api.env`
|
||||
|
||||
---
|
||||
|
||||
## Что уже работает (2026-05-26)
|
||||
|
||||
| Компонент | Статус |
|
||||
|-----------|--------|
|
||||
| PostgreSQL + Alembic | ✅ |
|
||||
| `POST /api/v1/events` (ingest 202) | ✅ |
|
||||
| `GET /health` | ✅ |
|
||||
| nginx + wildcard TLS (`/etc/ssl/sac/`) | ✅ |
|
||||
| JWT UI: Events, Hosts, **Problems** | ✅ (Problems после деплоя) |
|
||||
| `SAC_ADMIN_PASSWORD` + вход в браузере | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## Деплой обновлений
|
||||
|
||||
```bash
|
||||
sudo /opt/sac-deploy.sh
|
||||
```
|
||||
|
||||
См. `deploy/sac-deploy.sh`, [install-ubuntu-24.04-native.md §13](install-ubuntu-24.04-native.md#13-обновление-sac-деплой).
|
||||
|
||||
**Не делать:** `sudo git pull` в каталоге приложения (ломает права `.git` для `sac`).
|
||||
|
||||
---
|
||||
|
||||
## Тестовый агент (ubabuba, 10.10.36.9)
|
||||
|
||||
| Параметр | Значение |
|
||||
|----------|----------|
|
||||
| Хост | `ubabuba` / `10.10.36.9` |
|
||||
| Репозиторий | `git.papatramp.ru/PapaTramp/ssh-monitor` (`main`, есть `sac-client.sh`) |
|
||||
| `UseSAC` | пилот **exclusive** — см. [pilot-2.1-exclusive.md](pilot-2.1-exclusive.md) |
|
||||
| Сервис | `ssh-monitor.service` — **active** |
|
||||
| `--check-sac` | OK (health + ingest `agent.test` 202) |
|
||||
|
||||
Переключить на `dual` после настройки Telegram в `/etc/ssh-monitor.conf`.
|
||||
|
||||
---
|
||||
|
||||
## Следующие шаги (2026-05-29)
|
||||
|
||||
1. **Деплой SAC v0.5.0** — `sudo /opt/sac-deploy.sh` (миграции **`004`–`008`**: каналы, правило, cooldown)
|
||||
2. **notif-02** — прогон [testing-e2e-checklist.md](testing-e2e-checklist.md) § «SAC Telegram» на prod
|
||||
3. **Timer** — `sac-daily-report.timer` + `SAC_DAILY_REPORT_*` (миграций нет; см. runbook § F-NOT-05)
|
||||
4. **Настройки UI** — `/settings`: Telegram `warning+`, кнопка «Проверить Telegram»
|
||||
5. **RDP 1.2.20-SAC** — NETLOGON + `Deploy-LoginMonitor.ps1` на пилотных хостах
|
||||
6. Пилот **UseSAC=exclusive** на Windows — ~16.06 (см. [todo-2026-05-29.md](todo-2026-05-29.md))
|
||||
|
||||
---
|
||||
|
||||
## Ссылки
|
||||
|
||||
- [agent-integration.md](agent-integration.md)
|
||||
- [ssl-certificate.md](ssl-certificate.md)
|
||||
- [work-plan.md](work-plan.md)
|
||||
@@ -0,0 +1,92 @@
|
||||
# Пилот 2.1 — UseSAC=exclusive
|
||||
|
||||
Цель: один Linux-хост и (позже) один Windows-хост шлют **только в SAC**, без дублирования в Telegram с агента.
|
||||
|
||||
---
|
||||
|
||||
## Linux (ssh-monitor) — ubabuba / новые хосты
|
||||
|
||||
### 1. Обновить агент
|
||||
|
||||
```bash
|
||||
sudo /opt/scripts/update_ssh_monitor.sh
|
||||
# или первично: sudo ./first_deploy.sh
|
||||
```
|
||||
|
||||
### 2. Конфиг `/etc/ssh-monitor.conf`
|
||||
|
||||
```ini
|
||||
UseSAC=exclusive
|
||||
SAC_URL=https://sac.kalinamall.ru
|
||||
SAC_API_KEY=sac_xxxxxxxx
|
||||
SAC_TLS_SKIP_VERIFY=0
|
||||
SAC_SPOOL_DIR=/var/lib/ssh-monitor/sac-spool
|
||||
SAC_TIMEOUT_SEC=12
|
||||
```
|
||||
|
||||
Telegram/email **можно оставить** в конфиге — в `exclusive` они **не вызываются** для событий (`notify_or_sac` → только SAC).
|
||||
|
||||
### 3. Проверки на агенте
|
||||
|
||||
```bash
|
||||
sudo /usr/local/bin/ssh-monitor --check-sac
|
||||
sudo bash /opt/scripts/update/ssh-monitor/scripts/pilot-verify-exclusive.sh
|
||||
# или из клона:
|
||||
sudo bash /opt/scripts/update/ssh-monitor/scripts/pilot-verify-exclusive.sh
|
||||
|
||||
sudo systemctl restart ssh-monitor.service
|
||||
sudo systemctl status ssh-monitor.service --no-pager
|
||||
```
|
||||
|
||||
### 4. Проверки в SAC
|
||||
|
||||
1. UI → **Хосты** — появился/обновился хост пилота.
|
||||
2. Сгенерировать: успешный SSH, `sudo` (успешный), при необходимости неудачный SSH.
|
||||
3. UI → **События** — типы `ssh.login.success`, `privilege.sudo.command`, …
|
||||
4. **Telegram бота агента** — новых сообщений от этого хоста **нет** (только SAC, если включён Telegram **сервера SAC** — это отдельно).
|
||||
5. При `high`/`critical` — **Проблемы** и опционально Telegram из `TELEGRAM_*` в `sac-api.env`.
|
||||
|
||||
### 5. Spool (сбой SAC)
|
||||
|
||||
При недоступности SAC события пишутся в `SAC_SPOOL_DIR`. После восстановления SAC цикл монитора вызывает `sac_flush_spool` (до 20 файлов за итерацию).
|
||||
|
||||
```bash
|
||||
ls -la /var/lib/ssh-monitor/sac-spool/
|
||||
```
|
||||
|
||||
### 6. Откат на dual
|
||||
|
||||
```ini
|
||||
UseSAC=dual
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo systemctl restart ssh-monitor.service
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Windows (RDP-login-monitor)
|
||||
|
||||
**Статус:** интеграция UseSAC в RDP-monitor **ещё не реализована** — пилот 2.1 сейчас только **Linux**.
|
||||
|
||||
После появления `UseSAC` в RDP — повторить сценарий с `Test-SacConnection` и событиями `rdp.login.*`.
|
||||
|
||||
---
|
||||
|
||||
## Критерии приёмки 2.1 (Linux)
|
||||
|
||||
| # | Критерий |
|
||||
|---|----------|
|
||||
| 1 | `UseSAC=exclusive`, сервис `active` |
|
||||
| 2 | `--check-sac` → ingest OK |
|
||||
| 3 | События видны в SAC UI |
|
||||
| 4 | Telegram **агента** молчит |
|
||||
| 5 | Spool очищается после восстановления SAC |
|
||||
|
||||
---
|
||||
|
||||
## См. также
|
||||
|
||||
- [agent-integration.md](agent-integration.md)
|
||||
- [operations-prod-status.md](operations-prod-status.md)
|
||||
@@ -0,0 +1,93 @@
|
||||
# Фаза 2.2 — Heartbeat и daily report через SAC
|
||||
|
||||
Агент **уже** шлёт в SAC (в т.ч. в `exclusive`):
|
||||
|
||||
| Тип | Интервал (ssh-monitor) |
|
||||
|-----|-------------------------|
|
||||
| `agent.heartbeat` | каждые **12 ч** |
|
||||
| `report.daily.ssh` | раз в сутки после `DAILY_REPORT_HOUR` |
|
||||
|
||||
SAC отображает их в **События** и на **Dashboard / Хосты**.
|
||||
|
||||
---
|
||||
|
||||
## UI SAC
|
||||
|
||||
- **Dashboard:** счётчики heartbeat/отчётов за 24 ч, хосты с устаревшим heartbeat.
|
||||
- **Хосты:** колонки *Агент* (`online` / `stale` / `unknown`), время последнего heartbeat и отчёта (ссылка на **Отчёты** по hostname).
|
||||
- **Отчёты** (`/reports`): список `report.daily.*` по узлам; клик по строке — карточка с метриками и полным текстом (HTML/`report_body` в `details`).
|
||||
- Старые события без `details.report_body` показывают подсказку обновить агент.
|
||||
|
||||
---
|
||||
|
||||
## Настройка порога «живости» (сервер SAC)
|
||||
|
||||
В `config/sac-api.env`:
|
||||
|
||||
```bash
|
||||
# По умолчанию 780 мин (13 ч) — чуть больше интервала heartbeat агента (12 ч)
|
||||
SAC_HEARTBEAT_STALE_MINUTES=780
|
||||
```
|
||||
|
||||
После изменения: `sudo systemctl restart sac-api`.
|
||||
|
||||
---
|
||||
|
||||
## Проверка на пилотном хосте (exclusive)
|
||||
|
||||
1. Дождаться heartbeat или ускорить тест: на агенте временно уменьшить интервал нельзя без правки кода — проще подождать или вручную:
|
||||
```bash
|
||||
sudo /usr/local/bin/ssh-monitor --dry-run
|
||||
```
|
||||
(не шлёт реально; для реального теста — дождаться цикла 12 ч или смотреть уже пришедшие события).
|
||||
|
||||
2. В SAC UI → **События**, фильтр `type=agent.heartbeat`.
|
||||
|
||||
3. **Хосты** → статус `online` после свежего heartbeat.
|
||||
|
||||
4. Ежедневный отчёт: после `DAILY_REPORT_HOUR` — событие `report.daily.ssh` (от агента) **или** от SAC при `SAC_DAILY_REPORT_ENABLED=true` и отсутствии отчёта агента за сутки.
|
||||
|
||||
---
|
||||
|
||||
## SAC: отчёт без агента (exclusive / пропуск агента)
|
||||
|
||||
В `config/sac-api.env`:
|
||||
|
||||
```bash
|
||||
SAC_DAILY_REPORT_ENABLED=true
|
||||
SAC_DAILY_REPORT_HOUR=9
|
||||
SAC_DAILY_REPORT_TIMEZONE=Europe/Moscow
|
||||
SAC_DAILY_REPORT_SKIP_IF_AGENT_SENT=true
|
||||
SAC_DAILY_REPORT_REQUIRE_ACTIVITY=true
|
||||
```
|
||||
|
||||
- Job: `cd backend && .venv/bin/python -m app.jobs.daily_report` (ручной прогон: `--force`).
|
||||
- Timer: `deploy/systemd/sac-daily-report.service` + `.timer` — **09:00** в `SAC_DAILY_REPORT_TIMEZONE` (генерируется из `SAC_DAILY_REPORT_HOUR`, без `RandomizedDelaySec`).
|
||||
- Оповещение: `notify_daily_report` — **не** режется `NOTIFY_MIN_SEVERITY=warning` (severity отчёта `info`).
|
||||
- UI **Отчёты** и Telegram используют `details.report_html` / `report_body` как у агента.
|
||||
|
||||
Установка timer (один раз на сервере):
|
||||
|
||||
```bash
|
||||
sudo cp /opt/security-alert-center/deploy/systemd/sac-daily-report.service /etc/systemd/system/
|
||||
sudo bash /opt/security-alert-center/deploy/systemd/render-sac-daily-report-timer.sh \
|
||||
/opt/security-alert-center/config/sac-api.env \
|
||||
/etc/systemd/system/sac-daily-report.timer
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now sac-daily-report.timer
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Деплой
|
||||
|
||||
```bash
|
||||
sudo /opt/sac-deploy.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## См. также
|
||||
|
||||
- [pilot-2.1-exclusive.md](pilot-2.1-exclusive.md)
|
||||
- [agent-integration.md](agent-integration.md)
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
# Дорожная карта Security Alert Center
|
||||
|
||||
Продуктовые фазы после MVP. Сроки ориентировочные, уточняются после фазы 1.
|
||||
|
||||
---
|
||||
|
||||
## v0.1 — MVP (ядро SAC)
|
||||
|
||||
**Цель:** ingest на сервере; агенты в `dual` по мере готовности фазы 1A.
|
||||
|
||||
- Ingest API + PostgreSQL (**prod**)
|
||||
- Events, Hosts, базовый UI (**prod**)
|
||||
- Problems (2 правила)
|
||||
- Telegram из SAC
|
||||
- 3 виджета dashboard
|
||||
- Ubuntu 24.04 deploy
|
||||
|
||||
---
|
||||
|
||||
## v0.2 — Агенты + UseSAC
|
||||
|
||||
**Цель:** production-пилот с `UseSAC=exclusive` на части хостов.
|
||||
|
||||
- ssh-monitor: UseSAC, spool, все типы событий
|
||||
- RDP-login-monitor: аналог
|
||||
- Режимы `dual`, `fallback`
|
||||
- Daily reports из SAC
|
||||
- Документация миграции с Telegram-only
|
||||
|
||||
---
|
||||
|
||||
## v0.3 — Операционная зрелость
|
||||
|
||||
- `POST /events/batch`
|
||||
- Email SMTP из SAC
|
||||
- UI: редактор правил уведомлений
|
||||
- Maintenance windows (тишина)
|
||||
- Retention job + агрегаты по часам
|
||||
- Экспорт CSV
|
||||
- Redis + выделенный worker
|
||||
|
||||
---
|
||||
|
||||
## v0.4 — Аналитика и корреляция
|
||||
|
||||
- GeoIP / ASN по source IP
|
||||
- «Новый IP для пользователя»
|
||||
- Корреляция: один IP → SSH + RDP на разных хостах → один Problem
|
||||
- Расширенные дашборды (RD Gateway vs RDP, sudo heatmap)
|
||||
- Тёмная тема UI
|
||||
|
||||
---
|
||||
|
||||
## v0.5 — Enterprise
|
||||
|
||||
- LDAP / OIDC
|
||||
- Multi-tenant (несколько организаций)
|
||||
- RBAC расширенный, audit export
|
||||
- Prometheus metrics endpoint
|
||||
- Webhook CEF/JSON для SIEM
|
||||
- HA: документированный cold standby (второй сервер, restore БД)
|
||||
|
||||
---
|
||||
|
||||
## v0.6 — Mobile (Seaca)
|
||||
|
||||
**Цель:** нативный Android-клиент и push по тем же правилам оповещений, что Telegram/email/webhook.
|
||||
|
||||
Репозиторий клиента: [seaca](https://git.papatramp.ru/PapaTramp/seaca) (Kotlin, Jetpack Compose, FCM).
|
||||
|
||||
**Сервер SAC:**
|
||||
|
||||
- Настройки → **Мобильные устройства**: вкл/выкл подключений, коды регистрации, список устройств, отзыв, способ логина
|
||||
- API: enrollment codes, `mobile_devices`, refresh JWT, регистрация FCM-токена
|
||||
- Worker: канал `push_mobile` в notification policy (severity, cooldown, dedup — как у остальных каналов)
|
||||
- FCM HTTP v1 (service account на сервере; FCM — бесплатный транспорт доставки)
|
||||
|
||||
**Не в мобильном клиенте:** пользователи SAC, каналы Telegram/SMTP/webhook, админ-настройки.
|
||||
|
||||
Подробный план клиента — [seaca/docs/ROADMAP.md](https://git.papatramp.ru/PapaTramp/seaca/src/branch/main/docs/ROADMAP.md).
|
||||
|
||||
---
|
||||
|
||||
## v0.7 — Версии агентов и удалённое обновление (ToDo)
|
||||
|
||||
**Цель:** SAC контролирует актуальность `ssh-monitor` и `RDP-login-monitor` на хостах и может **инициировать обновление** без обхода всех машин вручную.
|
||||
|
||||
- Сверка `product_version` с политикой SAC (min / recommended)
|
||||
- UI: статус версии на карточке хоста, список отстающих
|
||||
- Problems / оповещения при устаревании агента
|
||||
- Команда обновления (предпочтительно **pull** с хоста: агент видит «нужно обновиться» и запускает свой updater)
|
||||
- События `agent.update.*` в ingest для аудита
|
||||
|
||||
**Проработка:** [agent-control-plane.md](agent-control-plane.md) (основной документ), [agent-update-backlog.md](agent-update-backlog.md).
|
||||
|
||||
---
|
||||
|
||||
## Добавить
|
||||
|
||||
См. [agent-control-plane.md](agent-control-plane.md):
|
||||
|
||||
- RDG flap 302→303 (1–10 с): Problem, оповещение, кнопки **qwinsta** / **logoff** на «Обзоре»
|
||||
- Обновления агентов: режим GPO или SAC (pull + fallback SSH/WinRM), Windows + Linux
|
||||
- Настройки агента в карточке хоста (desired config → poll)
|
||||
|
||||
---
|
||||
|
||||
## Зависимости от внешних репо
|
||||
|
||||
| Версия SAC | Минимальная версия ssh-monitor | Минимальная версия RDP-monitor |
|
||||
|------------|-------------------------------|--------------------------------|
|
||||
| v0.1 | — (не требуется) | — |
|
||||
| v0.2 | TBD (тег с UseSAC) | TBD |
|
||||
| v0.3+ | совместимость schema 1.0 | совместимость schema 1.0 |
|
||||
| v0.6 | — | — (мобильный клиент [seaca](https://git.papatramp.ru/PapaTramp/seaca), не агент) |
|
||||
|
||||
При breaking change схемы — `schema_version: 1.1` с поддержкой 1.0 на ingest.
|
||||
|
||||
---
|
||||
|
||||
## Метрики успеха (KPI)
|
||||
|
||||
- Среднее время от события до Telegram < 30 с (p95)
|
||||
- 0 потерянных событий при 1 ч недоступности SAC (spool)
|
||||
- Снижение сообщений в Telegram на 40%+ за счёт dedup (через 1 мес. exclusive)
|
||||
|
||||
---
|
||||
|
||||
## См. также
|
||||
|
||||
- [work-plan.md](work-plan.md)
|
||||
- [TZ.md](TZ.md)
|
||||
@@ -0,0 +1,130 @@
|
||||
# Runbook: эксплуатация SAC
|
||||
|
||||
Краткие процедуры для prod (`sac.kalinamall.ru`, native install в `/opt/security-alert-center`).
|
||||
|
||||
## Деплой приложения
|
||||
|
||||
```bash
|
||||
sudo /opt/sac-deploy.sh
|
||||
```
|
||||
|
||||
Скрипт: `git pull` / `reset --hard`, `pip install`, `alembic upgrade head`, `npm run build`, `systemctl restart sac-api`.
|
||||
|
||||
Проверка:
|
||||
|
||||
```bash
|
||||
curl -sS https://sac.kalinamall.ru/health | jq .
|
||||
```
|
||||
|
||||
Ожидается `status: ok`, `database: ok`. При устаревших heartbeat агентов — `status: degraded`, поле `hosts_stale` > 0.
|
||||
|
||||
### `sac-api.env`: формат строк
|
||||
|
||||
Файл читается **pydantic** (`SAC_CONFIG_FILE`), не как произвольный bash-скрипт.
|
||||
|
||||
- Одна переменная — одна строка: `SAC_SSH_AUTO_ADD_HOST_KEY=false`
|
||||
- Комментарии — **отдельной** строкой с `#` в начале
|
||||
- **Нельзя** inline после значения: `false ← так и оставляем` — deploy упадёт на `alembic` с `bool_parsing`
|
||||
|
||||
Проверка без деплоя:
|
||||
|
||||
```bash
|
||||
sudo -u sac bash -c 'export SAC_CONFIG_FILE=/opt/security-alert-center/config/sac-api.env; cd /opt/security-alert-center/backend && .venv/bin/python -c "from app.config import get_settings; get_settings(); print(\"OK\")"'
|
||||
```
|
||||
|
||||
### Linux SSH update: `known_hosts`
|
||||
|
||||
Перед «Обновить ssh-monitor (SSH)» ключ хоста должен быть в файле (по умолчанию `config/ssh_known_hosts`):
|
||||
|
||||
```bash
|
||||
ssh-keyscan -H 10.10.7.2 | sudo tee -a /opt/security-alert-center/config/ssh_known_hosts
|
||||
sudo chown sac:sac /opt/security-alert-center/config/ssh_known_hosts
|
||||
sudo chmod 600 /opt/security-alert-center/config/ssh_known_hosts
|
||||
```
|
||||
|
||||
Иначе SAC: `Server '…' not found in known_hosts`. `SAC_SSH_AUTO_ADD_HOST_KEY=true` для prod не рекомендуется.
|
||||
|
||||
## Мобильные устройства (Seaca)
|
||||
|
||||
См. [seaca-mobile.md](seaca-mobile.md) и [seaca-fcm.md](seaca-fcm.md).
|
||||
|
||||
После деплоя 0.9.0+: в веб-SAC включить мобильные устройства, выдать код оператору. Push — после настройки FCM и сборки APK с `google-services.json`.
|
||||
|
||||
## Резервное копирование PostgreSQL
|
||||
|
||||
```bash
|
||||
sudo -u postgres pg_dump -Fc sac > /var/backups/sac-$(date +%Y%m%d).dump
|
||||
```
|
||||
|
||||
Восстановление (на тестовый инстанс):
|
||||
|
||||
```bash
|
||||
sudo -u postgres pg_restore -d sac_test --clean /var/backups/sac-YYYYMMDD.dump
|
||||
```
|
||||
|
||||
Перед restore на prod — остановить API: `sudo systemctl stop sac-api`.
|
||||
|
||||
## Retention (очистка БД)
|
||||
|
||||
Политика по умолчанию (`config/sac-api.env`):
|
||||
|
||||
| Данные | Срок |
|
||||
|--------|------|
|
||||
| `events` | 90 дней (`SAC_EVENTS_RETENTION_DAYS`) |
|
||||
| `problems` со статусом `resolved` | 180 дней (`SAC_PROBLEMS_RETENTION_DAYS`) |
|
||||
|
||||
Ручной прогон:
|
||||
|
||||
```bash
|
||||
sudo -u sac bash -c '
|
||||
set -a; source /opt/security-alert-center/config/sac-api.env; set +a
|
||||
cd /opt/security-alert-center/backend
|
||||
.venv/bin/python -m app.jobs.retention
|
||||
'
|
||||
```
|
||||
|
||||
Установка ежедневного timer (один раз):
|
||||
|
||||
```bash
|
||||
sudo cp /opt/security-alert-center/deploy/systemd/sac-retention.service /etc/systemd/system/
|
||||
sudo cp /opt/security-alert-center/deploy/systemd/sac-retention.timer /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now sac-retention.timer
|
||||
systemctl list-timers sac-retention.timer
|
||||
```
|
||||
|
||||
## Суточные отчёты (F-NOT-05)
|
||||
|
||||
```bash
|
||||
sudo cp /opt/security-alert-center/deploy/systemd/sac-daily-report.service /etc/systemd/system/
|
||||
sudo bash /opt/security-alert-center/deploy/systemd/render-sac-daily-report-timer.sh \
|
||||
/opt/security-alert-center/config/sac-api.env \
|
||||
/etc/systemd/system/sac-daily-report.timer
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now sac-daily-report.timer
|
||||
systemctl list-timers sac-daily-report.timer
|
||||
|
||||
# Ручной прогон (игнор часа)
|
||||
sudo -u sac bash -lc 'cd /opt/security-alert-center/backend && .venv/bin/python -m app.jobs.daily_report --force'
|
||||
```
|
||||
|
||||
Переменные: `SAC_DAILY_REPORT_*` в `config/sac-api.env` (см. `deploy/env.native.example`).
|
||||
|
||||
## Health и мониторинг
|
||||
|
||||
| Endpoint | Назначение |
|
||||
|----------|------------|
|
||||
| `GET /health` | БД, версия, `hosts_stale`, `last_event_received_at` |
|
||||
| `GET /api/v1/stream/events` | SSE для UI (счётчики + `last_event_id` каждые 5 с) |
|
||||
|
||||
Агенты: `GET /health` без JWT. UI Dashboard: блок «Последние события» подгружается при смене `last_event_id` в SSE.
|
||||
|
||||
## Типовые проблемы
|
||||
|
||||
**События в Telegram есть, в UI нет** — проверить ingest (лог агента `SAC: accepted`), режим `UseSAC`, обновить Dashboard (live ~5 с).
|
||||
|
||||
**422 на ingest** — см. `Logs/sac-last-post.json` на Windows-агенте; обновить `Sac-Client.ps1` (RDP) или `sac-client.sh` (Linux).
|
||||
|
||||
**Устаревший heartbeat** — увеличить `SAC_HEARTBEAT_STALE_MINUTES` или проверить `agent.heartbeat` на хосте.
|
||||
|
||||
**Чужой Host на IP SAC (форма SAC на ext.kalinamall.ru)** — в nginx только `server_name sac.kalinamall.ru`; default_server → 444 / `ssl_reject_handshake`. Обновить конфиг из `deploy/nginx/sac.conf.tls.example`, `sudo nginx -t && sudo systemctl reload nginx`. HAProxy на этом не решается — правка на **192.168.160.145** (nginx SAC).
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 63 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,49 @@
|
||||
# FCM (push) для Seaca
|
||||
|
||||
Настраивается **только на сервере SAC** и в **Firebase**; в веб-UI — индикатор и тест push на устройство.
|
||||
|
||||
## 1. Firebase
|
||||
|
||||
1. [Firebase Console](https://console.firebase.google.com/) → создать проект (или использовать существующий).
|
||||
2. Добавить Android-приложение с package name **`ru.kalinamall.seaca`** (как в APK Seaca).
|
||||
3. Скачать `google-services.json` — файл для **сборки Seaca**, в git не коммитить.
|
||||
4. **Project settings → Service accounts → Generate new private key** — JSON для **сервера SAC**.
|
||||
|
||||
## 2. Сервер SAC
|
||||
|
||||
```bash
|
||||
sudo install -o sac -g sac -m 600 /path/to/firebase-key.json \
|
||||
/etc/security-alert-center/fcm-service-account.json
|
||||
```
|
||||
|
||||
В `/opt/security-alert-center/config/sac-api.env`:
|
||||
|
||||
```ini
|
||||
SAC_FCM_ENABLED=true
|
||||
SAC_FCM_PROJECT_ID=your-firebase-project-id
|
||||
SAC_FCM_SERVICE_ACCOUNT_JSON=/etc/security-alert-center/fcm-service-account.json
|
||||
```
|
||||
|
||||
Перезапуск API:
|
||||
|
||||
```bash
|
||||
sudo systemctl restart sac-api
|
||||
```
|
||||
|
||||
## 3. Политика оповещений
|
||||
|
||||
**Настройки → Правило оповещений** → канал **Seaca (push)**.
|
||||
|
||||
Действуют те же `min_severity`, cooldown и dedup, что для Telegram/email.
|
||||
|
||||
## 4. Проверка
|
||||
|
||||
1. Телефон привязан (enroll), в списке устройств **FCM: да**.
|
||||
2. **Настройки → Мобильные устройства → Тест push** на строке устройства.
|
||||
3. Либо сгенерировать событие с severity выше порога policy.
|
||||
|
||||
## 5. Ограничения
|
||||
|
||||
- FCM доставляет через инфраструктуру Google; payload формирует SAC (заголовок, id, deep link).
|
||||
- Без `SAC_FCM_ENABLED=true` push не отправляется; приложение и REST API работают.
|
||||
- `google-services.json` нужен приложению; service account JSON — только серверу.
|
||||
@@ -0,0 +1,113 @@
|
||||
# Seaca — мобильный клиент SAC
|
||||
|
||||
Репозиторий приложения: [seaca](https://git.papatramp.ru/PapaTramp/seaca).
|
||||
Требуется SAC **≥ 0.9.0** с применённой миграцией `014`.
|
||||
|
||||
---
|
||||
|
||||
## Роли
|
||||
|
||||
| Где | Кто |
|
||||
|-----|-----|
|
||||
| Веб-SAC | Админ: мобильные устройства, коды, отзыв, FCM на сервере |
|
||||
| Seaca (Android) | Оператор: обзор, события, проблемы, хосты, отчёты; ack/resolve |
|
||||
| Веб-SAC | Пользователи SAC, Telegram/SMTP — **не** в приложении |
|
||||
|
||||
---
|
||||
|
||||
## Включение мобильных устройств (админ)
|
||||
|
||||
1. **Настройки → Мобильные устройства (Seaca)**
|
||||
2. Включить **«Разрешать мобильным устройствам подключаться»** → **Сохранить мобильные**
|
||||
3. В **Правило оповещений** при необходимости включить канал **Seaca (push)** (для push после настройки FCM)
|
||||
|
||||
### «Сохранить мобильные»
|
||||
|
||||
Сохраняет в БД:
|
||||
|
||||
- разрешение подключения новых устройств;
|
||||
- максимум активных устройств на одного пользователя SAC;
|
||||
- минимальную версию приложения (опционально).
|
||||
|
||||
Не настраивает FCM и не выдаёт коды.
|
||||
|
||||
### Коды регистрации
|
||||
|
||||
| Поле | Смысл |
|
||||
|------|--------|
|
||||
| Метка | Произвольная подпись для админа |
|
||||
| Пользователь | Если выбран — enroll только для этого пользователя |
|
||||
| Способ входа | **Логин и пароль + код** — в приложении нужны учётные данные SAC; **Только код** — пароль не нужен, пользователь должен быть выбран в форме |
|
||||
| Срок (часов) | Код перестаёт принимать **новые** привязки; уже подключённые телефоны не отключаются |
|
||||
|
||||
Код показывается **один раз** после «Выдать код». Передайте оператору: URL сервера (**`https://sac-api.kalinamall.ru`** для Seaca; веб-админка — `https://sac.kalinamall.ru`), код `sacmob_…`, при режиме password — логин/пароль SAC.
|
||||
|
||||
### Подключённые устройства
|
||||
|
||||
- **Отключить** — отзыв устройства и refresh-токенов; приложение получит 401 при следующем запросе
|
||||
- **Тест push** — только если FCM настроен на сервере и у устройства есть FCM-токен
|
||||
|
||||
---
|
||||
|
||||
## Сессия после привязки
|
||||
|
||||
1. Оператор один раз выполняет enroll (`POST /api/v1/mobile/enroll`).
|
||||
2. Приложение хранит **access_token** (JWT, ~24 ч) и **refresh_token** (по умолчанию **90 дней**, `SAC_MOBILE_REFRESH_EXPIRE_DAYS` в `sac-api.env`).
|
||||
3. Код регистрации после успешного enroll больше не нужен.
|
||||
|
||||
Для долгой работы без повторной привязки увеличьте `SAC_MOBILE_REFRESH_EXPIRE_DAYS` (например `3650`). Отзыв устройства в вебе обнуляет доступ немедленно.
|
||||
|
||||
---
|
||||
|
||||
## Push (FCM) на сервере
|
||||
|
||||
Подробно: [seaca-fcm.md](seaca-fcm.md).
|
||||
|
||||
Кратко в `config/sac-api.env`:
|
||||
|
||||
```ini
|
||||
SAC_FCM_ENABLED=true
|
||||
SAC_FCM_PROJECT_ID=ваш-firebase-project-id
|
||||
SAC_FCM_SERVICE_ACCOUNT_JSON=/etc/security-alert-center/fcm-service-account.json
|
||||
```
|
||||
|
||||
После изменений: `sudo systemctl restart sac-api` или `sudo /opt/sac-deploy.sh`.
|
||||
|
||||
В UI индикатор **FCM: настроен / не настроен** читает эти переменные; править их через веб нельзя.
|
||||
|
||||
---
|
||||
|
||||
## Perimeter (HAProxy)
|
||||
|
||||
| Hostname | Clients | IP allowlist |
|
||||
|----------|---------|--------------|
|
||||
| `sac.kalinamall.ru` | Web UI | yes (`git-sac-allowed`) |
|
||||
| `sac-api.kalinamall.ru` | Seaca, `/api/v1/mobile/*` | no (enroll + JWT) |
|
||||
|
||||
Both resolve to the same SAC server (**192.168.160.145**). nginx must accept both names in `server_name`. See [reverse-proxy/docs/sac-access.md](https://git.papatramp.ru/PapaTramp/reverse-proxy/src/branch/main/docs/sac-access.md).
|
||||
|
||||
---
|
||||
|
||||
## API (для разработчиков Seaca)
|
||||
|
||||
| Метод | Путь |
|
||||
|-------|------|
|
||||
| GET | `/health` |
|
||||
| POST | `/api/v1/mobile/enroll` |
|
||||
| POST | `/api/v1/mobile/auth/refresh` |
|
||||
| PUT | `/api/v1/mobile/devices/me/fcm` |
|
||||
| GET | `/api/v1/dashboards/summary` |
|
||||
| GET | `/api/v1/events`, `/api/v1/events/{id}` |
|
||||
| GET | `/api/v1/problems`, `/api/v1/problems/{id}` |
|
||||
| POST | `/api/v1/problems/{id}/ack`, `/resolve` |
|
||||
| GET | `/api/v1/hosts`, `/api/v1/hosts/{id}` |
|
||||
|
||||
JWT с мобильного устройства содержит claim `device_id`.
|
||||
|
||||
---
|
||||
|
||||
## См. также
|
||||
|
||||
- [seaca-fcm.md](seaca-fcm.md) — Firebase и push
|
||||
- [deployment.md](deployment.md) — деплой SAC
|
||||
- [runbook-ops.md](runbook-ops.md) — эксплуатация
|
||||
@@ -0,0 +1,313 @@
|
||||
# TLS-сертификат для SAC (wildcard VeriSign / DigiCert)
|
||||
|
||||
Куда положить файлы, в каком формате, как скопировать на сервер `sac.kalinamall.ru`.
|
||||
|
||||
Связано: [install-ubuntu-24.04-native.md](install-ubuntu-24.04-native.md) §9, шаблон `deploy/nginx/sac.conf.tls.example`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Что должно получиться на сервере
|
||||
|
||||
nginx читает **два PEM-файла** (текст, начинается с `-----BEGIN ...-----`):
|
||||
|
||||
| Путь на сервере | Содержимое | Кто читает |
|
||||
|-----------------|------------|------------|
|
||||
| `/etc/ssl/sac/fullchain.pem` | Сертификат сайта/wildcard **+** промежуточные CA (без корневого — обычно не нужен) | nginx |
|
||||
| `/etc/ssl/sac/privkey.pem` | Закрытый ключ (RSA или EC) | nginx |
|
||||
|
||||
Имена файлов можно другие, если пути совпадают с `ssl_certificate` / `ssl_certificate_key` в `/etc/nginx/sites-available/sac`.
|
||||
|
||||
**Покрытие имени:** в сертификате должен быть CN или SAN вида `*.kalinamall.ru` (wildcard) или `sac.kalinamall.ru`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Что вам могут выдать (входные форматы)
|
||||
|
||||
| От УЦ / админа | Расширения | Что делать |
|
||||
|----------------|------------|------------|
|
||||
| Готовый PEM | `.pem`, `.crt` + `.key` | Собрать fullchain, скопировать на сервер |
|
||||
| PKCS#12 | `.pfx`, `.p12` | Распаковать в PEM (см. §4.3, на Ubuntu 24.04 нужен `-legacy`) |
|
||||
| Отдельные файлы | `certificate.crt`, `ca-bundle.crt`, `private.key` | Склеить fullchain (см. §5) |
|
||||
| Windows (MMC) | экспорт `.pfx` | Распаковать на ПК или сервере (§4) |
|
||||
|
||||
nginx **не** понимает напрямую: `.pfx`, `.p12`, `.der` без конвертации.
|
||||
|
||||
---
|
||||
|
||||
## 3. Каталог и права на сервере
|
||||
|
||||
Выполнить **один раз** на SAC-сервере:
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /etc/ssl/sac
|
||||
sudo chown root:ssl-cert /etc/ssl/sac
|
||||
sudo chmod 750 /etc/ssl/sac
|
||||
|
||||
sudo groupadd -f ssl-cert
|
||||
sudo usermod -aG ssl-cert www-data
|
||||
```
|
||||
|
||||
Каталог **`root:ssl-cert` `750`**, не `root:root`: иначе у `www-data` нет права `x` (зайти в каталог), даже если ключ `640` и `root:ssl-cert`.
|
||||
|
||||
После копирования файлов:
|
||||
|
||||
```bash
|
||||
sudo chmod 644 /etc/ssl/sac/fullchain.pem
|
||||
sudo chmod 640 /etc/ssl/sac/privkey.pem
|
||||
sudo chown root:root /etc/ssl/sac/fullchain.pem
|
||||
sudo chown root:ssl-cert /etc/ssl/sac/privkey.pem
|
||||
sudo chown root:ssl-cert /etc/ssl/sac
|
||||
sudo chmod 750 /etc/ssl/sac
|
||||
|
||||
sudo systemctl restart nginx
|
||||
```
|
||||
|
||||
Группа `ssl-cert` нужна, чтобы **nginx** (`www-data`) читал ключ и обходил каталог. На Ubuntu в `ssl-cert` по умолчанию может быть только `postgres` — добавьте `www-data` (`usermod` выше).
|
||||
|
||||
Проверка:
|
||||
|
||||
```bash
|
||||
id www-data # в groups должна быть ssl-cert
|
||||
sudo -u www-data test -x /etc/ssl/sac && echo "dir OK" || echo "dir FAIL"
|
||||
sudo -u www-data test -r /etc/ssl/sac/fullchain.pem && echo "fullchain OK" || echo "fullchain FAIL"
|
||||
sudo -u www-data test -r /etc/ssl/sac/privkey.pem && echo "key OK" || echo "key FAIL"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Копирование на сервер
|
||||
|
||||
Подставьте IP или hostname SAC-сервера вместо `SAC_SERVER`.
|
||||
Команды `scp` выполняются **на той машине, куда копируете** (обычно на SAC-сервере — «забрать» файл с другого хоста).
|
||||
|
||||
### 4.1. С Linux / macOS (scp)
|
||||
|
||||
Если уже есть `fullchain.pem` и `privkey.pem` на ПК:
|
||||
|
||||
```bash
|
||||
scp fullchain.pem privkey.pem papatramp@SAC_SERVER:/tmp/
|
||||
```
|
||||
|
||||
На сервере:
|
||||
|
||||
```bash
|
||||
sudo mv /tmp/fullchain.pem /tmp/privkey.pem /etc/ssl/sac/
|
||||
sudo chmod 644 /etc/ssl/sac/fullchain.pem
|
||||
sudo chmod 640 /etc/ssl/sac/privkey.pem
|
||||
sudo chown root:root /etc/ssl/sac/fullchain.pem
|
||||
sudo chown root:ssl-cert /etc/ssl/sac/privkey.pem
|
||||
sudo chown root:ssl-cert /etc/ssl/sac
|
||||
sudo chmod 750 /etc/ssl/sac
|
||||
sudo rm -f /tmp/fullchain.pem /tmp/privkey.pem
|
||||
```
|
||||
|
||||
### 4.2. С Windows (PowerShell / pscp)
|
||||
|
||||
Файлы, например, в `D:\Certs\kalinamall\`:
|
||||
|
||||
```powershell
|
||||
scp D:\Certs\kalinamall\fullchain.pem papatramp@SAC_SERVER:/tmp/
|
||||
scp D:\Certs\kalinamall\privkey.pem papatramp@SAC_SERVER:/tmp/
|
||||
```
|
||||
|
||||
Дальше на сервере — те же `sudo mv` и `chown`, что в §4.1.
|
||||
|
||||
Если есть только **`wildcard.pfx`**:
|
||||
|
||||
```powershell
|
||||
scp D:\Certs\kalinamall\wildcard.pfx papatramp@SAC_SERVER:/tmp/
|
||||
```
|
||||
|
||||
Распаковка на **сервере** (§4.3).
|
||||
|
||||
### 4.3. Забрать файл с другого Linux-сервера (scp)
|
||||
|
||||
Выполнять **на SAC-сервере** (pull с хоста, где лежит PFX/PEM):
|
||||
|
||||
```bash
|
||||
mkdir -p /tmp/certs
|
||||
|
||||
# один файл
|
||||
scp user@certs-host.example.com:/path/to/wildcard_kalinamall_ru.pfx /tmp/certs/
|
||||
|
||||
# несколько файлов
|
||||
scp user@certs-host:/path/to/fullchain.pem user@certs-host:/path/to/privkey.pem /tmp/certs/
|
||||
|
||||
# нестандартный SSH-порт (у scp заглавная P)
|
||||
scp -P 2222 user@certs-host:/path/to/wildcard_kalinamall_ru.pfx /tmp/certs/
|
||||
```
|
||||
|
||||
С другого сервера **отдать** на SAC (push — команда на сервере-источнике):
|
||||
|
||||
```bash
|
||||
scp /path/to/wildcard_kalinamall_ru.pfx papatramp@<IP_SAC>:/tmp/certs/
|
||||
```
|
||||
|
||||
Нужен SSH-доступ и право **читать** файл на источнике.
|
||||
|
||||
### 4.4. Распаковка `.pfx` / `.p12` на сервере (Ubuntu 24.04)
|
||||
|
||||
На Ubuntu 24.04 стоит **OpenSSL 3.x**. Старые PFX от VeriSign/DigiCert часто используют **RC2-40-CBC** — без флага `-legacy` будет ошибка:
|
||||
|
||||
```text
|
||||
Algorithm (RC2-40-CBC : 0), Properties (), unsupported
|
||||
```
|
||||
|
||||
**Всегда добавляйте `-legacy`** к `openssl pkcs12`:
|
||||
|
||||
```bash
|
||||
sudo apt install -y openssl
|
||||
|
||||
sudo mkdir -p /tmp/certs
|
||||
cd /tmp/certs
|
||||
# замените имя PFX; Enter Import Password: — пароль от PFX (не sudo)
|
||||
|
||||
sudo openssl pkcs12 -legacy -in wildcard_kalinamall_ru.pfx -nocerts -nodes \
|
||||
-out privkey.pem
|
||||
|
||||
sudo openssl pkcs12 -legacy -in wildcard_kalinamall_ru.pfx -clcerts -nokeys \
|
||||
-out server.crt
|
||||
|
||||
sudo openssl pkcs12 -legacy -in wildcard_kalinamall_ru.pfx -cacerts -nokeys \
|
||||
-out ca-chain.crt
|
||||
|
||||
# fullchain = сервер + промежуточные (порядок важен)
|
||||
cat server.crt ca-chain.crt | sudo tee /etc/ssl/sac/fullchain.pem > /dev/null
|
||||
sudo cp privkey.pem /etc/ssl/sac/privkey.pem
|
||||
sudo chmod 644 /etc/ssl/sac/fullchain.pem
|
||||
sudo chmod 640 /etc/ssl/sac/privkey.pem
|
||||
sudo chown root:root /etc/ssl/sac/fullchain.pem
|
||||
sudo chown root:ssl-cert /etc/ssl/sac/privkey.pem
|
||||
sudo chown root:ssl-cert /etc/ssl/sac
|
||||
sudo chmod 750 /etc/ssl/sac
|
||||
|
||||
# очистка временных файлов
|
||||
sudo shred -u server.crt ca-chain.crt privkey.pem 2>/dev/null
|
||||
sudo rm -f /tmp/certs/wildcard_kalinamall_ru.pfx
|
||||
```
|
||||
|
||||
Если `-legacy` недостаточно:
|
||||
|
||||
```bash
|
||||
sudo openssl pkcs12 -provider legacy -provider default \
|
||||
-in wildcard_kalinamall_ru.pfx -nocerts -nodes -out privkey.pem
|
||||
```
|
||||
|
||||
Проверить содержимое PFX:
|
||||
|
||||
```bash
|
||||
sudo openssl pkcs12 -legacy -in wildcard_kalinamall_ru.pfx -info -noout
|
||||
```
|
||||
|
||||
Пароль PFX вводится интерактивно (`Enter Import Password`). **Не** коммитьте PFX и ключ в git.
|
||||
|
||||
---
|
||||
|
||||
## 5. Сборка fullchain из отдельных `.crt`
|
||||
|
||||
Типичный набор от VeriSign / DigiCert:
|
||||
|
||||
- `star_kalinamall_ru.crt` — ваш wildcard
|
||||
- `DigiCertCA.crt` / `intermediate.crt` — промежуточный
|
||||
- (иногда) `TrustedRoot.crt` — корневой **не** добавляйте в fullchain для nginx
|
||||
|
||||
```bash
|
||||
# на ПК или на сервере, в каталоге с исходниками:
|
||||
cat star_kalinamall_ru.crt intermediate.crt > fullchain.pem
|
||||
# ключ переименовать:
|
||||
cp private.key privkey.pem
|
||||
```
|
||||
|
||||
Проверка порядка (первая строка сертификата — ваш сайт):
|
||||
|
||||
```bash
|
||||
openssl crl2pkcs7 -nocrl -certfile fullchain.pem | openssl pkcs7 -print_certs -noout | grep subject=
|
||||
```
|
||||
|
||||
Скопировать `fullchain.pem` и `privkey.pem` на сервер (§4).
|
||||
|
||||
---
|
||||
|
||||
## 6. Проверка сертификата
|
||||
|
||||
На сервере:
|
||||
|
||||
```bash
|
||||
# кому выдан, срок действия
|
||||
sudo openssl x509 -in /etc/ssl/sac/fullchain.pem -noout -subject -issuer -dates
|
||||
|
||||
# wildcard / SAN
|
||||
sudo openssl x509 -in /etc/ssl/sac/fullchain.pem -noout -ext subjectAltName
|
||||
|
||||
# ключ соответствует сертификату
|
||||
CERT_MD5=$(sudo openssl x509 -in /etc/ssl/sac/fullchain.pem -noout -modulus | openssl md5)
|
||||
KEY_MD5=$(sudo openssl rsa -in /etc/ssl/sac/privkey.pem -noout -modulus 2>/dev/null | openssl md5)
|
||||
# для EC-ключа:
|
||||
# KEY_MD5=$(sudo openssl pkey -in /etc/ssl/sac/privkey.pem -noout -modulus | openssl md5)
|
||||
echo "cert $CERT_MD5"
|
||||
echo "key $KEY_MD5"
|
||||
# хеши должны совпадать
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Подключение в nginx
|
||||
|
||||
```bash
|
||||
sudo cp /opt/security-alert-center/deploy/nginx/sac.conf.tls.example \
|
||||
/etc/nginx/sites-available/sac
|
||||
```
|
||||
|
||||
В файле должны быть (по умолчанию в шаблоне):
|
||||
|
||||
```nginx
|
||||
ssl_certificate /etc/ssl/sac/fullchain.pem;
|
||||
ssl_certificate_key /etc/ssl/sac/privkey.pem;
|
||||
```
|
||||
|
||||
```bash
|
||||
sudo ln -sf /etc/nginx/sites-available/sac /etc/nginx/sites-enabled/sac
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
curl -sS https://sac.kalinamall.ru/health | jq .
|
||||
```
|
||||
|
||||
В приложении SAC (`/opt/security-alert-center/config/sac-api.env`):
|
||||
|
||||
```ini
|
||||
SAC_PUBLIC_URL=https://sac.kalinamall.ru
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Обновление сертификата (продление)
|
||||
|
||||
1. Получить новые файлы от УЦ.
|
||||
2. Заменить `/etc/ssl/sac/fullchain.pem` и при необходимости `privkey.pem`.
|
||||
3. `sudo nginx -t && sudo systemctl reload nginx`.
|
||||
4. Проверить срок: `openssl x509 -in /etc/ssl/sac/fullchain.pem -noout -dates`.
|
||||
|
||||
Перезапуск `sac-api` **не** обязателен — TLS терминируется на nginx.
|
||||
|
||||
---
|
||||
|
||||
## 9. Безопасность
|
||||
|
||||
- Закрытый ключ только на сервере SAC, права `640`, группа `ssl-cert`.
|
||||
- Не хранить PFX/ключ в репозитории, почте, мессенджерах.
|
||||
- После распаковки PFX удалить `/tmp/*.pfx` и промежуточные копии.
|
||||
|
||||
---
|
||||
|
||||
## 10. Устранение неполадок
|
||||
|
||||
| Симптом | Решение |
|
||||
|---------|---------|
|
||||
| `RC2-40-CBC` / `unsupported` при `pkcs12` | OpenSSL 3 на Ubuntu 24.04: добавить **`-legacy`** (см. §4.4) |
|
||||
| `mac verify failure` | Неверный пароль PFX |
|
||||
| `nginx: PEM_read_bio_X509_AUX() failed` | Неверный PEM, проверьте `fullchain.pem` текстом, нет ли `.der` без конвертации |
|
||||
| `key values mismatch` | Ключ не от этой пары сертификатов |
|
||||
| `test -r privkey.pem` без вывода / key FAIL | Каталог `chown root:ssl-cert`, `750`; `usermod -aG ssl-cert www-data`; `systemctl restart nginx` |
|
||||
| `permission denied` на key | То же + `chmod 640` на ключ; `test -x /etc/ssl/sac` |
|
||||
| Браузер/агент не доверяет | Неполная цепочка — добавьте intermediate в fullchain |
|
||||
| `certificate has expired` | Продлить у УЦ, заменить файлы |
|
||||
@@ -0,0 +1,109 @@
|
||||
# E2E и нагрузочное тестирование SAC + агенты
|
||||
|
||||
Чеклист после freeze MVP (`work-plan.md`). Отмечайте дату и хост.
|
||||
|
||||
## Дни 1–2: функциональный E2E
|
||||
|
||||
### Linux (ssh-monitor, `UseSAC=dual` или `exclusive`)
|
||||
|
||||
- [ ] `ssh-monitor --check-sac` → HTTP 201/202, событие `agent.test` в UI
|
||||
- [ ] Успешный SSH login → `ssh.login.success` в SAC + Telegram (dual)
|
||||
- [ ] Неудачный SSH → `ssh.login.failed`
|
||||
- [ ] `SERVER_DISPLAY_NAME` задан → в SAC **Хосты** отображается display name
|
||||
- [ ] Heartbeat → `agent.heartbeat`, хост не `stale` в пределах `SAC_HEARTBEAT_STALE_MINUTES`
|
||||
- [ ] Daily report → `report.daily.ssh` (агент или SAC: `python -m app.jobs.daily_report --force`, `details.generated_by`)
|
||||
|
||||
### Windows (RDP-login-monitor, `UseSAC=dual`)
|
||||
|
||||
- [ ] `-CheckSac` → ingest OK
|
||||
- [ ] Старт монитора → `agent.lifecycle` в SAC (HTTP 201), Telegram «ЗАПУЩЕН»
|
||||
- [ ] Версия в UI **Хосты** = `$ScriptVersion` после деплоя
|
||||
- [ ] `$ServerDisplayName` → display name в SAC
|
||||
- [ ] 4624/4625 (тестовый вход) → `rdp.login.*` при наличии событий
|
||||
- [ ] Dashboard: новое событие появляется в «Последние события» без F5 (~5 с)
|
||||
|
||||
### SAC UI
|
||||
|
||||
- [ ] Problems: open → ack → resolve
|
||||
- [ ] Дубликат `event_id` → HTTP 409, одна строка в БД
|
||||
- [ ] Правило brute-force (порог событий) → Problem
|
||||
|
||||
### SAC Telegram — severity и exclusive (`notif-02`)
|
||||
|
||||
**Предусловие:** на prod после `79a78dc+` выполнен деплой (`sudo /opt/sac-deploy.sh` → миграция **`004_notification_channels`**).
|
||||
|
||||
| # | Шаг | Ожидание |
|
||||
|---|-----|----------|
|
||||
| 1 | UI → **Настройки** → «Проверить Telegram» | Сообщение «✅ SAC: тестовое сообщение…» в чате |
|
||||
| 2 | Включить Telegram, `min severity` = **warning**, сохранить (token/chat из env или форма) | GET: `source=db`, `configured=true` |
|
||||
| 3 | Ingest **`rdp.login.failed`** (severity `warning`) — см. curl ниже | Telegram: «🚨 SAC событие», severity warning |
|
||||
| 4 | Ingest **`rdp.login.success`** (severity `info`) — новый `event_id` | Событие в UI, **нет** сообщения в Telegram |
|
||||
| 5 | Сменить `min severity` на **high**, сохранить | Повтор `failed` (warning) → **нет** TG; `high` problem → TG |
|
||||
| 6 | Агент **`UseSAC=exclusive`**: неудачный вход | TG только из SAC, **не** из бота агента |
|
||||
|
||||
**Синтетический ingest (без RDP-хоста):** подставьте `SAC_API_KEY` и уникальный `event_id`.
|
||||
|
||||
```bash
|
||||
API_KEY="sac_…"
|
||||
BASE="https://sac.kalinamall.ru"
|
||||
|
||||
# warning → должен уйти в TG при min=warning
|
||||
curl -sS -X POST "$BASE/api/v1/events" \
|
||||
-H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"schema_version": "1.0",
|
||||
"event_id": "00000000-0000-4000-8000-000000000101",
|
||||
"occurred_at": "2026-05-29T12:00:00+03:00",
|
||||
"source": {"product": "rdp-login-monitor", "product_version": "1.2.20-SAC"},
|
||||
"host": {"hostname": "E2E-RDP", "os_family": "windows", "display_name": "E2E RDP test"},
|
||||
"category": "auth",
|
||||
"type": "rdp.login.failed",
|
||||
"severity": "warning",
|
||||
"title": "RDP login failed (E2E)",
|
||||
"summary": "notif-02 synthetic failed login"
|
||||
}'
|
||||
|
||||
# info → не должен уйти в TG при min=warning
|
||||
curl -sS -X POST "$BASE/api/v1/events" \
|
||||
-H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"schema_version": "1.0",
|
||||
"event_id": "00000000-0000-4000-8000-000000000102",
|
||||
"occurred_at": "2026-05-29T12:01:00+03:00",
|
||||
"source": {"product": "rdp-login-monitor", "product_version": "1.2.20-SAC"},
|
||||
"host": {"hostname": "E2E-RDP", "os_family": "windows"},
|
||||
"category": "auth",
|
||||
"type": "rdp.login.success",
|
||||
"severity": "info",
|
||||
"title": "RDP login success (E2E)",
|
||||
"summary": "notif-02 synthetic success — no TG expected"
|
||||
}'
|
||||
```
|
||||
|
||||
Отметка: дата ______, оператор ______, результат TG шагов 3–4: ☐ OK / ☐ fail
|
||||
|
||||
## Дни 3–4: нагрузка и устойчивость
|
||||
|
||||
- [ ] Пакет 50+ `ssh.login.failed` с одного IP → агрегация/Problem, без зависания UI
|
||||
- [ ] Повтор ingest с тем же `event_id` → 409
|
||||
- [ ] Остановка SAC API → spool на агенте, восстановление после `/health`
|
||||
- [ ] Flapping heartbeat: stale → warning в health / хостах
|
||||
|
||||
## День 5: регресс
|
||||
|
||||
- [ ] Обновление RDP через Deploy: одна версия в `deployed_version.txt`, ingest после 1.2.14+ JSON
|
||||
- [ ] `sac-retention.timer` active; ручной `systemctl start sac-retention.service` — exit 0
|
||||
- [ ] Известные issues занесены в issue tracker / `known-issues.md`
|
||||
|
||||
## Дни 6–7: soak
|
||||
|
||||
- [ ] 48–72 ч dual mode: нет роста spool без причины, диск БД в норме
|
||||
- [ ] Только bugfix по результатам выше
|
||||
|
||||
## Версии на момент чеклиста
|
||||
|
||||
| Компонент | Версия |
|
||||
|-----------|--------|
|
||||
| ssh-monitor | 1.2.6-SAC |
|
||||
| RDP-login-monitor | 1.2.20-SAC |
|
||||
| security-alert-center | 0.7.0 (`backend/app/version.py`) |
|
||||
@@ -0,0 +1,89 @@
|
||||
# ToDo — 29.05.2026 (оповещения SAC + «Настройки»)
|
||||
|
||||
Контекст: при **`UseSAC=exclusive`** на агентах Telegram/email с хоста **не идут** — оператору нужны оповещения **из SAC**. Аналитика и прочее — отдельно ([analytics-backlog.md](analytics-backlog.md)).
|
||||
|
||||
---
|
||||
|
||||
## Уже есть в коде (не путать с «ещё не сделано»)
|
||||
|
||||
| Что | Где | Ограничение |
|
||||
|-----|-----|-------------|
|
||||
| Telegram из SAC | `backend/app/services/telegram_notify.py` | Только если в `sac-api.env`: `TELEGRAM_ENABLED=true`, токен, chat_id |
|
||||
| Порог severity | `telegram_min_severity` (по умолчанию **`high`**) | События **`info`** (успешный RDP `rdp.login.success`) **не** уходят в TG, пока порог не снизить до `warning` |
|
||||
| Вызов при ingest | `events.py` → `notify_event` / `notify_problem` | Шаблон короткий («🚨 SAC событие»), не как у агента |
|
||||
| UI «Настройки» | `/settings`, GET/PUT Telegram | БД `notification_channels` (миграция `004`) + fallback на `sac-api.env` |
|
||||
| Email / webhook | TZ F-NOT-01 | Email ✅, Webhook ✅ |
|
||||
|
||||
**Вывод на завтра:** для exclusive нужно (1) включить и настроить TG на сервере SAC **или** (2) сделать раздел **«Настройки»** в UI + хранение каналов; порог **`warning` и выше** для событий и problems.
|
||||
|
||||
**Замечание по коду:** `notify_problem()` сейчас **не проверяет** `telegram_min_severity` (в отличие от `notify_event`) — исправить в рамках `notif-03`.
|
||||
|
||||
---
|
||||
|
||||
## Задачи (приоритет)
|
||||
|
||||
### P0 — exclusive + Telegram
|
||||
|
||||
| ID | Задача | Критерий |
|
||||
|----|--------|----------|
|
||||
| `notif-01` | Зафиксировать в `agent-integration.md` / runbook: при **exclusive** канал оповещений = SAC; рекомендуемый `TELEGRAM_MIN_SEVERITY=warning` | ✅ docs + `env.native.example` |
|
||||
| `notif-02` | Проверить на staging/prod: ingest `rdp.login.failed` (warning) → TG; `rdp.login.success` (info) → нет TG при `min=warning` | ✅ чеклист [testing-e2e-checklist.md](testing-e2e-checklist.md) § SAC Telegram |
|
||||
| `notif-03` | `notify_problem`: учитывать `telegram_min_severity` | ✅ unit-тест |
|
||||
|
||||
### P1 — UI «Настройки» (каналы)
|
||||
|
||||
| ID | Задача | Критерий |
|
||||
|----|--------|----------|
|
||||
| `notif-10` | Маршрут `/settings`, пункт в сайдбаре (только admin JWT) | ✅ страница + GET API |
|
||||
| `notif-11` | Блок **Telegram**: enabled, bot token, chat id, min severity | ✅ форма + GET/PUT |
|
||||
| `notif-12` | Хранение: **вариант A** — запись в БД `notification_channels` + fallback на env | ✅ миграция `004`, `PUT /notifications/telegram` |
|
||||
| `notif-13` | Секреты: токен не возвращать целиком в GET (маска `***…last4`) | ✅ GET settings |
|
||||
| `notif-14` | Кнопка «Проверить Telegram» → тестовое сообщение | ✅ `POST …/telegram/test` + UI |
|
||||
|
||||
### P2 — Email и webhook (после Telegram)
|
||||
|
||||
| ID | Задача | Критерий |
|
||||
|----|--------|----------|
|
||||
| `notif-20` | SMTP: host, port, user, from, to, TLS — по аналогии с RDP `login_monitor.settings` | ✅ PUT/test API + UI + ingest |
|
||||
| `notif-21` | Webhook: URL, optional secret header, JSON payload (event/problem) | ✅ PUT/test API + UI + ingest |
|
||||
| `notif-22` | TZ F-NOT-02 урезанно: правило «severity ≥ X → каналы» без сложного конструктора | ✅ `notification_policy` + UI «Правило оповещений» |
|
||||
|
||||
### P3 — Качество сообщений (можно сдвинуть)
|
||||
|
||||
| ID | Задача |
|
||||
|----|--------|
|
||||
| `notif-30` | Шаблон TG ближе к агенту (HTML, поля user/ip/logon_type из `details`) | ✅ `telegram_templates.py`, `parse_mode=HTML` |
|
||||
| `notif-31` | Cooldown/dedup на уровне SAC (F-NOT-03) — не дублировать problem при burst | ✅ `notification_cooldown`, env 90/300 с |
|
||||
| `notif-32` | F-NOT-05: daily report из SAC при exclusive (отдельный эпик) | ✅ `daily_report.py`, timer `sac-daily-report` |
|
||||
|
||||
---
|
||||
|
||||
## Связь с агентами
|
||||
|
||||
```text
|
||||
UseSAC=off → только агент (Telegram на хосте)
|
||||
UseSAC=dual → агент + SAC ingest (+ опционально SAC TG, риск дублей)
|
||||
UseSAC=exclusive→ только SAC ingest; TG/email = настройки SAC (UI/env)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Оценка на день
|
||||
|
||||
| Блок | Часы (оценка) |
|
||||
|------|----------------|
|
||||
| P0 док + notif-03 + smoke | 2–3 |
|
||||
| P1 UI Settings + API Telegram | 4–6 |
|
||||
| P2 webhook/email | +1 день |
|
||||
|
||||
**Минимум на завтра:** `notif-01` … `notif-03` + черновик `notif-10` … `notif-14` (хотя бы API без полировки UI).
|
||||
|
||||
---
|
||||
|
||||
## См. также
|
||||
|
||||
- [TZ.md](TZ.md) §4.6 F-NOT-01 … F-NOT-05
|
||||
- [agent-integration.md](agent-integration.md) — режимы UseSAC
|
||||
- [agent-update-backlog.md](agent-update-backlog.md) — **ToDo:** версии агентов и удалённое обновление из SAC
|
||||
- `backend/app/config.py` — `telegram_*`
|
||||
- `backend/app/services/telegram_notify.py`
|
||||
@@ -0,0 +1,171 @@
|
||||
# План работ — Security Alert Center
|
||||
|
||||
**Актуальный порядок:** сначала подготовка агентов (параллельно с минимальным SAC ingest), затем полный SAC MVP, затем prod rollout `UseSAC=exclusive`.
|
||||
|
||||
---
|
||||
|
||||
## Фаза 0. Документация ✅
|
||||
|
||||
| # | Задача | Статус |
|
||||
|---|--------|--------|
|
||||
| 0.1–0.3 | ТЗ, архитектура, схема, deployment | ✅ |
|
||||
| 0.5 | Репозиторий GitHub + зеркало kalinamall | ✅ |
|
||||
| 0.6 | Multi-root workspace | ✅ |
|
||||
|
||||
---
|
||||
|
||||
## Фаза 1A. Агенты — контракт SAC (параллельно с 1B)
|
||||
|
||||
**Репозитории:** `ssh-monitor`, `RDP-login-monitor`
|
||||
**Прод:** везде `UseSAC=off` по умолчанию.
|
||||
|
||||
| # | Задача | Статус |
|
||||
|---|--------|--------|
|
||||
| 1A.1 | Параметры `UseSAC`, `SAC_URL`, `SAC_API_KEY`, spool | ✅ ssh-monitor |
|
||||
| 1A.2 | `build_sac_event()` + `send_sac_event()` по schema v1 | ✅ `sac-client.sh` |
|
||||
| 1A.3 | `notify_or_sac()`: off / dual / exclusive / fallback | ✅ + маппинг событий |
|
||||
| 1A.4 | `--check-sac` / `Test-SacConnection` | ✅ ssh-monitor `--check-sac` |
|
||||
| 1A.5 | README агентов, first deploy | ✅ `first_deploy.sh`, `--deploy` |
|
||||
|
||||
**Выход:** на тестовом хосте `dual` шлёт JSON в SAC + Telegram.
|
||||
|
||||
---
|
||||
|
||||
## Фаза 1B. SAC — минимальный ingest ✅ (prod)
|
||||
|
||||
| # | Задача | Статус |
|
||||
|---|--------|--------|
|
||||
| 1B.1 | Scaffold backend FastAPI | ✅ |
|
||||
| 1B.2 | PostgreSQL + Alembic (hosts, events, api_keys) | ✅ |
|
||||
| 1B.3 | `POST /api/v1/events`, `GET /health` | ✅ prod `sac.kalinamall.ru` |
|
||||
| 1B.4 | systemd + nginx + TLS | ✅ |
|
||||
| 1B.5 | Валидация JSON Schema v1 | ✅ |
|
||||
|
||||
**Выход:** ingest с curl и UI на prod — достигнут.
|
||||
|
||||
---
|
||||
|
||||
## Фаза 1C. SAC — MVP UI и оповещения
|
||||
|
||||
| # | Задача | Статус |
|
||||
|---|--------|--------|
|
||||
| 1C.1 | Frontend Vue: Events, Hosts | ✅ prod |
|
||||
| 1C.2 | Auth JWT, admin bootstrap | ✅ prod |
|
||||
| 1C.3 | Problems (базовые правила) | ✅ API + UI (деплой ⏳) |
|
||||
| 1C.4 | Telegram из SAC | ✅ backend (деплой + TELEGRAM_* в env) |
|
||||
| 1C.5 | Dashboard (3 виджета), SSE | ✅ v0.2.0 |
|
||||
|
||||
**Выход:** тег `v0.2.0-mvp`.
|
||||
|
||||
---
|
||||
|
||||
## Фаза 2. Пилот и exclusive
|
||||
|
||||
| # | Задача |
|
||||
|---|--------|
|
||||
| 2.1 | E2E: 1 Linux + 1 Windows, `UseSAC=exclusive` | ✅ Linux [pilot-2.1-exclusive.md](pilot-2.1-exclusive.md) |
|
||||
| 2.2 | Daily report / heartbeat через SAC | ✅ [pilot-2.2-heartbeat-reports.md](pilot-2.2-heartbeat-reports.md) |
|
||||
| 2.3 | fallback на агентах | ✅ счётчик `SAC_FALLBACK_FAILURES` в sac-client |
|
||||
|
||||
**Выход:** `v0.2.0`.
|
||||
|
||||
---
|
||||
|
||||
## Фаза 3. Эксплуатация
|
||||
|
||||
См. [roadmap.md](roadmap.md).
|
||||
|
||||
---
|
||||
|
||||
## Ближайшие 2 дня (чеклист исполнения)
|
||||
|
||||
### День 1
|
||||
|
||||
- [x] `d1-1` Ingest: `event_id` UUID обязателен, UNIQUE индекс, коды duplicate, логи, docs/schema
|
||||
- [x] `d1-2` MVP Problems: модель, корреляция `host+type+окно`, API `GET/ack/resolve`
|
||||
- [x] `d1-3` Правила v1: `brute-force burst`, `privilege spike`, `host silence`
|
||||
|
||||
### День 2
|
||||
|
||||
- [x] `d2-1` UI Problems: список, фильтры, `Ack/Resolve`, карточка с таймлайном
|
||||
- [x] `d2-2` Dashboard: top hosts/types, `open vs resolved 24h`, drill-down
|
||||
- [x] `d2-3` Ops: retention, health checks, runbook backup/restore/deploy
|
||||
- [x] `dod` DoD: нет дублей `event_id`, Problems e2e, 3 правила, UI MVP, docs, push в kalinamall
|
||||
|
||||
### Отображение хостов (`display_name`, как `SERVER_DISPLAY_NAME` у ssh)
|
||||
|
||||
Сейчас: **ssh** — `SERVER_DISPLAY_NAME` только в Telegram; в SAC уходит `socket.gethostname()`. **RDP** — параметра нет, в SAC только `$env:COMPUTERNAME`. В SAC UI «Хосты» уже показывает `display_name || hostname`, если поле пришло в ingest.
|
||||
|
||||
- [x] `agent-display-rdp` **RDP-login-monitor:** `$ServerDisplayName` в `login_monitor.settings.ps1` / example; подпись в Telegram; в `Sac-Client.ps1` — `host.display_name` (и при необходимости согласовать `hostname`)
|
||||
- [x] `agent-display-ssh` **ssh-monitor:** в `sac-client.sh` передавать `SERVER_DISPLAY_NAME` как `host.display_name` в JSON ingest
|
||||
- [x] `sac-display-hosts` **SAC:** проверить ingest/обновление `Host.display_name`; колонка «Хосты» = человекочитаемое имя; поиск по `display_name`; `docs/agent-integration.md` + schema `host.display_name`
|
||||
|
||||
**Приёмка:** хост с `SERVER_DISPLAY_NAME="UNMS Kalina"` (или RDP `$ServerDisplayName`) в SAC → **Хосты** отображается как **UNMS Kalina**, а не только короткое имя ОС.
|
||||
|
||||
### Почасовой чеклист
|
||||
|
||||
#### День 1
|
||||
|
||||
- [x] `09:00–10:00` миграция `event_id` + UNIQUE, валидация ingest
|
||||
- [x] `10:00–11:00` поведение duplicate (`201/409`) и логирование reject
|
||||
- [x] `11:00–12:00` обновить `event-schema-v1.json` и `agent-integration.md` (в т.ч. `host.display_name` для агентов)
|
||||
- [x] `13:00–14:30` модель Problems + миграция
|
||||
- [x] `14:30–16:00` корреляция при ingest (`fingerprint`, `count`, `last_seen`)
|
||||
- [x] `16:00–17:30` API `GET /problems`, `ack`, `resolve` + smoke
|
||||
- [x] `18:00–19:00` правила `brute/privilege/silence` + unit tests
|
||||
|
||||
#### День 2
|
||||
|
||||
- [x] `09:00–11:00` UI Problems: таблица + фильтры (`status/severity/host`)
|
||||
- [x] `11:00–12:00` карточка проблемы + таймлайн событий
|
||||
- [x] `13:00–14:30` Dashboard: виджеты top hosts/types
|
||||
- [x] `14:30–16:00` Dashboard: `open/resolved 24h` + drill-down
|
||||
- [x] `16:00–17:00` retention job (`events 30–90d`, `problems 180d+`)
|
||||
- [x] `17:00–18:00` health checks (DB/worker/heartbeat stale)
|
||||
- [x] `18:00–19:00` runbook + финальный push в kalinamall + freeze dev
|
||||
|
||||
### Неделя после freeze (только тестирование)
|
||||
|
||||
Чеклист: [testing-e2e-checklist.md](testing-e2e-checklist.md)
|
||||
|
||||
- [ ] `дни 1–2` функциональные E2E (`RDP + SSH + mixed load`)
|
||||
- [ ] `дни 3–4` нагрузка, дубликаты, флаппинг heartbeat
|
||||
- [ ] `день 5` регресс + known issues
|
||||
- [ ] `дни 6–7` soak-test, только bugfix
|
||||
|
||||
---
|
||||
|
||||
## Gantt (упрощённо)
|
||||
|
||||
```mermaid
|
||||
gantt
|
||||
title SAC — актуальный план
|
||||
dateFormat YYYY-MM-DD
|
||||
section Документы
|
||||
Фаза 0 :done, 2026-05-26, 1d
|
||||
section SAC
|
||||
1B ingest+deploy :done, 2026-05-26, 1d
|
||||
1C UI базовый :done, 2026-05-26, 1d
|
||||
1C notify+dash :active, 2026-05-27, 14d
|
||||
section Агенты
|
||||
1A UseSAC dual :2026-05-26, 10d
|
||||
section Prod
|
||||
Пилот exclusive :2026-06-16, 7d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Следующий рабочий день (29.05.2026)
|
||||
|
||||
Оповещения SAC (**notif-01…32**) — ✅ см. [todo-2026-05-29.md](todo-2026-05-29.md). На prod: деплой, `notif-02` E2E, timer `sac-daily-report`.
|
||||
|
||||
Отложенная аналитика: **[analytics-backlog.md](analytics-backlog.md)**.
|
||||
|
||||
---
|
||||
|
||||
## См. также
|
||||
|
||||
- [install-ubuntu-24.04.md](install-ubuntu-24.04.md) — подготовка сервера
|
||||
- [operations-prod-status.md](operations-prod-status.md) — статус prod и деплой
|
||||
- [roadmap.md](roadmap.md)
|
||||
- [TZ.md](TZ.md)
|
||||
@@ -0,0 +1,76 @@
|
||||
# Multi-root workspace: три репозитория
|
||||
|
||||
Как работать в одном multi-root workspace над **ssh-monitor**, **RDP-login-monitor** и **security-alert-center** одновременно (VS Code или совместимый редактор).
|
||||
|
||||
---
|
||||
|
||||
## 1. Расположение репозиториев (пример)
|
||||
|
||||
| Имя в workspace | Путь (пример Windows) | Remote |
|
||||
|-----------------|----------------------|--------|
|
||||
| `ssh-monitor` | `D:\Soft\Git\ssh-monitor` | git.papatramp.ru/PapaTramp/ssh-monitor |
|
||||
| `rdp-monitor` | `D:\Soft\Git\RDP-login-monitor` | git.papatramp.ru/PapaTramp/RDP-login-monitor |
|
||||
| `security-alert-center` | `D:\Soft\Git\security-alert-center` | git.papatramp.ru/PapaTramp/security-alert-center |
|
||||
|
||||
Пути подставьте свои.
|
||||
|
||||
---
|
||||
|
||||
## 2. Файл workspace
|
||||
|
||||
Создайте `security-monitors.code-workspace`:
|
||||
|
||||
```json
|
||||
{
|
||||
"folders": [
|
||||
{ "path": "D:/Soft/Git/ssh-monitor", "name": "ssh-monitor" },
|
||||
{ "path": "D:/Soft/Git/RDP-login-monitor", "name": "rdp-monitor" },
|
||||
{ "path": "D:/Soft/Git/security-alert-center", "name": "security-alert-center" }
|
||||
],
|
||||
"settings": {
|
||||
"files.eol": "\n"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Открыть: **File → Open Workspace from File**.
|
||||
|
||||
---
|
||||
|
||||
## 3. Порядок работ по фазам
|
||||
|
||||
| Фаза | Где править |
|
||||
|------|-------------|
|
||||
| 0 — ТЗ | `security-alert-center/docs/` |
|
||||
| 1 — MVP SAC | `security-alert-center/backend`, `frontend` |
|
||||
| 2 — UseSAC | `ssh-monitor`, `RDP-login-monitor` + мелкие правки SAC при необходимости |
|
||||
|
||||
---
|
||||
|
||||
## 4. Соглашения
|
||||
|
||||
- Контракт событий: `security-alert-center/schemas/event-schema-v1.json` — **единственный источник истины**.
|
||||
- Изменение схемы → обновить ТЗ + версию `schema_version` + оба агента.
|
||||
- Коммиты в три репо **раздельные**; связь через теги/версии в README (см. [roadmap.md](roadmap.md)).
|
||||
|
||||
```bash
|
||||
git add …
|
||||
git commit -m "…"
|
||||
git push kalinamall main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. URL репозиториев
|
||||
|
||||
| Проект | URL |
|
||||
|--------|-----|
|
||||
| security-alert-center | `https://git.papatramp.ru/PapaTramp/security-alert-center.git` |
|
||||
| ssh-monitor | `https://git.papatramp.ru/PapaTramp/ssh-monitor.git` |
|
||||
| RDP-login-monitor | `https://git.papatramp.ru/PapaTramp/RDP-login-monitor.git` |
|
||||
|
||||
---
|
||||
|
||||
## См. также
|
||||
|
||||
- [work-plan.md](work-plan.md) фаза 0.6
|
||||
Reference in New Issue
Block a user