merge: sync github roadmap with kalinamall 0.9.11
This commit is contained in:
@@ -8,10 +8,10 @@
|
|||||||
|
|
||||||
| Репозиторий | Назначение |
|
| Репозиторий | Назначение |
|
||||||
|-------------|------------|
|
|-------------|------------|
|
||||||
| [ssh-monitor](https://github.com/PTah/ssh-monitor) | Linux: SSH, sudo, logind, брутфорс, баны IP |
|
| [ssh-monitor](https://git.kalinamall.ru/PapaTramp/ssh-monitor) | Linux: SSH, sudo, logind, брутфорс, баны IP |
|
||||||
| [RDP-login-monitor](https://github.com/PTah/RDP-login-monitor) | Windows: RDP/RDS, RD Gateway, WinRM, admin share C$/ADMIN$ |
|
| [RDP-login-monitor](https://git.kalinamall.ru/PapaTramp/RDP-login-monitor) | Windows: RDP/RDS, RD Gateway, WinRM, admin share C$/ADMIN$ |
|
||||||
| **security-alert-center** (этот репозиторий) | Ubuntu 24.04: API, БД, UI, оповещения |
|
| **security-alert-center** (этот репозиторий) | Ubuntu 24.04: API, БД, UI, оповещения |
|
||||||
| [seaca](https://github.com/PTah/seaca) | Android: мобильный клиент SAC, push (FCM) |
|
| [seaca](https://git.kalinamall.ru/PapaTramp/seaca) | Android: мобильный клиент SAC, push (FCM) |
|
||||||
|
|
||||||
## Статус
|
## Статус
|
||||||
|
|
||||||
@@ -29,8 +29,8 @@
|
|||||||
|
|
||||||
События приходят от агентов по [контракту ingest](docs/agent-integration.md) (`type`, `severity`, `details`):
|
События приходят от агентов по [контракту ingest](docs/agent-integration.md) (`type`, `severity`, `details`):
|
||||||
|
|
||||||
- **Linux — [ssh-monitor](https://github.com/PTah/ssh-monitor):** SSH (успех/неудача), **sudo**, **systemd-logind**, брутфорс и баны IP (ipset), пороги без бана, ежедневный отчёт, heartbeat.
|
- **Linux — [ssh-monitor](https://git.kalinamall.ru/PapaTramp/ssh-monitor):** SSH (успех/неудача), **sudo**, **systemd-logind**, брутфорс и баны IP (ipset), пороги без бана, ежедневный отчёт, heartbeat.
|
||||||
- **Windows — [RDP-login-monitor](https://github.com/PTah/RDP-login-monitor):**
|
- **Windows — [RDP-login-monitor](https://git.kalinamall.ru/PapaTramp/RDP-login-monitor):**
|
||||||
- **RDP/RDS** (4624/4625);
|
- **RDP/RDS** (4624/4625);
|
||||||
- **RD Gateway** (302/303), **WinRM / PowerShell Remoting** (Enter-PSSession, ID 91);
|
- **RD Gateway** (302/303), **WinRM / PowerShell Remoting** (Enter-PSSession, ID 91);
|
||||||
- **админ-шары `C$` / `ADMIN$`** (Security **5140**, `smb.admin_share.access`);
|
- **админ-шары `C$` / `ADMIN$`** (Security **5140**, `smb.admin_share.access`);
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
## Быстрый старт (native)
|
## Быстрый старт (native)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/PTah/security-alert-center.git /opt/security-alert-center
|
git clone https://git.kalinamall.ru/PapaTramp/security-alert-center.git /opt/security-alert-center
|
||||||
# deploy/env.native.example -> config/sac-api.env
|
# deploy/env.native.example -> config/sac-api.env
|
||||||
cd /opt/security-alert-center/backend
|
cd /opt/security-alert-center/backend
|
||||||
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
|
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
|
||||||
|
|||||||
+5
-5
@@ -8,8 +8,8 @@ Self-hosted hub for collecting, storing, and displaying security events from Lin
|
|||||||
|
|
||||||
| Repository | Role |
|
| Repository | Role |
|
||||||
|------------|------|
|
|------------|------|
|
||||||
| [ssh-monitor](https://github.com/PTah/ssh-monitor) | Linux: SSH, sudo, logind, brute-force, IP ban |
|
| [ssh-monitor](https://git.kalinamall.ru/PapaTramp/ssh-monitor) | Linux: SSH, sudo, logind, brute-force, IP ban |
|
||||||
| [RDP-login-monitor](https://github.com/PTah/RDP-login-monitor) | Windows: RDP/RDS, RD Gateway, WinRM, admin share C$/ADMIN$ |
|
| [RDP-login-monitor](https://git.kalinamall.ru/PapaTramp/RDP-login-monitor) | Windows: RDP/RDS, RD Gateway, WinRM, admin share C$/ADMIN$ |
|
||||||
| **security-alert-center** (this repo) | Ubuntu 24.04: API, database, UI, notifications |
|
| **security-alert-center** (this repo) | Ubuntu 24.04: API, database, UI, notifications |
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
@@ -28,8 +28,8 @@ Self-hosted hub for collecting, storing, and displaying security events from Lin
|
|||||||
|
|
||||||
Agents send events via the [ingest contract](docs/agent-integration.md) (`type`, `severity`, `details`):
|
Agents send events via the [ingest contract](docs/agent-integration.md) (`type`, `severity`, `details`):
|
||||||
|
|
||||||
- **Linux — [ssh-monitor](https://github.com/PTah/ssh-monitor):** SSH success/failure, **sudo**, **systemd-logind**, brute-force and IP ban (ipset), thresholds without ban, daily report, heartbeat.
|
- **Linux — [ssh-monitor](https://git.kalinamall.ru/PapaTramp/ssh-monitor):** SSH success/failure, **sudo**, **systemd-logind**, brute-force and IP ban (ipset), thresholds without ban, daily report, heartbeat.
|
||||||
- **Windows — [RDP-login-monitor](https://github.com/PTah/RDP-login-monitor):**
|
- **Windows — [RDP-login-monitor](https://git.kalinamall.ru/PapaTramp/RDP-login-monitor):**
|
||||||
- **RDP/RDS** (4624/4625);
|
- **RDP/RDS** (4624/4625);
|
||||||
- **RD Gateway** (302/303), **WinRM / PowerShell Remoting** (Enter-PSSession, event ID 91);
|
- **RD Gateway** (302/303), **WinRM / PowerShell Remoting** (Enter-PSSession, event ID 91);
|
||||||
- **admin shares `C$` / `ADMIN$`** (Security **5140**, `smb.admin_share.access`);
|
- **admin shares `C$` / `ADMIN$`** (Security **5140**, `smb.admin_share.access`);
|
||||||
@@ -64,7 +64,7 @@ Agents send events via the [ingest contract](docs/agent-integration.md) (`type`,
|
|||||||
## Quick start (native)
|
## Quick start (native)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/PTah/security-alert-center.git /opt/security-alert-center
|
git clone https://git.kalinamall.ru/PapaTramp/security-alert-center.git /opt/security-alert-center
|
||||||
# deploy/env.native.example -> config/sac-api.env
|
# deploy/env.native.example -> config/sac-api.env
|
||||||
cd /opt/security-alert-center/backend
|
cd /opt/security-alert-center/backend
|
||||||
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
|
python3 -m venv .venv && .venv/bin/pip install -r requirements.txt
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from app.models import Event, Problem
|
|||||||
from app.models.mobile_device import MobileDevice
|
from app.models.mobile_device import MobileDevice
|
||||||
from app.services.notification_severity import severity_meets_minimum
|
from app.services.notification_severity import severity_meets_minimum
|
||||||
from app.services.notification_policy import get_effective_notification_policy
|
from app.services.notification_policy import get_effective_notification_policy
|
||||||
|
from app.services.telegram_templates import format_event_mobile_push
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -170,8 +171,7 @@ def _send_fcm_data(
|
|||||||
|
|
||||||
|
|
||||||
def _event_payload(event: Event) -> tuple[str, str, dict[str, str]]:
|
def _event_payload(event: Event) -> tuple[str, str, dict[str, str]]:
|
||||||
title = f"[{event.severity}] {event.title}"
|
title, body = format_event_mobile_push(event)
|
||||||
body = (event.summary or "")[:200]
|
|
||||||
data = {
|
data = {
|
||||||
"kind": "event",
|
"kind": "event",
|
||||||
"id": str(event.id),
|
"id": str(event.id),
|
||||||
|
|||||||
@@ -506,6 +506,43 @@ def format_event_telegram_html(event: Event) -> str:
|
|||||||
return _append_event_source(_format_event_body_html(event), event)
|
return _append_event_source(_format_event_body_html(event), event)
|
||||||
|
|
||||||
|
|
||||||
|
_TELEGRAM_INLINE_TAGS = re.compile(r"</?(?:b|i|u|s|code|pre|tg-spoiler)(\s[^>]*)?>", re.I)
|
||||||
|
_TELEGRAM_ANCHOR_OPEN = re.compile(r"<a\b[^>]*>", re.I)
|
||||||
|
_TELEGRAM_ANCHOR_CLOSE = re.compile(r"</a>", re.I)
|
||||||
|
|
||||||
|
_MOBILE_PUSH_BODY_MAX = 3500
|
||||||
|
|
||||||
|
|
||||||
|
def telegram_html_to_plaintext(text: str) -> str:
|
||||||
|
"""Plain text for Seaca push from the same HTML templates as Telegram."""
|
||||||
|
out = sanitize_telegram_html(text)
|
||||||
|
out = _TELEGRAM_INLINE_TAGS.sub("", out)
|
||||||
|
out = _TELEGRAM_ANCHOR_OPEN.sub("", out)
|
||||||
|
out = _TELEGRAM_ANCHOR_CLOSE.sub("", out)
|
||||||
|
out = html.unescape(out)
|
||||||
|
out = re.sub(r"\n{3,}", "\n\n", out)
|
||||||
|
return out.strip()
|
||||||
|
|
||||||
|
|
||||||
|
def format_event_mobile_push(event: Event) -> tuple[str, str]:
|
||||||
|
"""Title + body for FCM data payload (mirrors Telegram wording)."""
|
||||||
|
plain = telegram_html_to_plaintext(format_event_telegram_html(event))
|
||||||
|
lines = [line.strip() for line in plain.split("\n") if line.strip()]
|
||||||
|
if lines:
|
||||||
|
title = lines[0]
|
||||||
|
body = "\n".join(lines[1:]).strip()
|
||||||
|
if not body:
|
||||||
|
body = (event.summary or "").strip()
|
||||||
|
else:
|
||||||
|
title = f"[{event.severity}] {event.title}"
|
||||||
|
body = (event.summary or "").strip()
|
||||||
|
if len(title) > 120:
|
||||||
|
title = title[:117] + "…"
|
||||||
|
if len(body) > _MOBILE_PUSH_BODY_MAX:
|
||||||
|
body = body[: _MOBILE_PUSH_BODY_MAX - 1] + "…"
|
||||||
|
return title, body
|
||||||
|
|
||||||
|
|
||||||
def _format_rdg_html(event: Event) -> str:
|
def _format_rdg_html(event: Event) -> str:
|
||||||
details = _details_dict(event)
|
details = _details_dict(event)
|
||||||
if event.type.endswith(".success"):
|
if event.type.endswith(".success"):
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
"""Единый источник версии SAC (API, health, логи, OpenAPI)."""
|
"""Единый источник версии SAC (API, health, логи, OpenAPI)."""
|
||||||
|
|
||||||
APP_NAME = "Security Alert Center"
|
APP_NAME = "Security Alert Center"
|
||||||
APP_VERSION = "0.9.10"
|
APP_VERSION = "0.9.11"
|
||||||
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"
|
APP_VERSION_LABEL = f"{APP_NAME} v.{APP_VERSION}"
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ from app.version import APP_NAME, APP_VERSION, APP_VERSION_LABEL
|
|||||||
|
|
||||||
|
|
||||||
def test_version_constants():
|
def test_version_constants():
|
||||||
assert APP_VERSION == "0.9.10"
|
assert APP_VERSION == "0.9.11"
|
||||||
assert APP_NAME == "Security Alert Center"
|
assert APP_NAME == "Security Alert Center"
|
||||||
assert APP_VERSION_LABEL == "Security Alert Center v.0.9.10"
|
assert APP_VERSION_LABEL == "Security Alert Center v.0.9.11"
|
||||||
|
|||||||
@@ -1,10 +1,33 @@
|
|||||||
"""FCM push must not break event ingest."""
|
"""FCM push must not break event ingest."""
|
||||||
|
|
||||||
|
from datetime import datetime, timezone
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from app.services.mobile_notify import MobileNotConfiguredError, _send_fcm_data
|
from app.models import Event, Host
|
||||||
|
from app.services.mobile_notify import MobileNotConfiguredError, _event_payload, _send_fcm_data
|
||||||
|
|
||||||
|
|
||||||
|
def test_event_payload_lifecycle_uses_telegram_wording():
|
||||||
|
host = Host(hostname="WIN01", display_name="K6A-DC3", os_family="windows")
|
||||||
|
event = Event(
|
||||||
|
event_id="00000000-0000-4000-8000-000000000511",
|
||||||
|
host_id=1,
|
||||||
|
host=host,
|
||||||
|
occurred_at=datetime(2026, 5, 29, 9, 0, tzinfo=timezone.utc),
|
||||||
|
category="agent",
|
||||||
|
type="agent.lifecycle",
|
||||||
|
severity="info",
|
||||||
|
title="started",
|
||||||
|
summary="short",
|
||||||
|
details={"lifecycle": "started", "trigger": "settings_reload", "telegram_via": "sac"},
|
||||||
|
payload={"source": {"product": "ssh-monitor", "product_version": "1.4.0-SAC"}},
|
||||||
|
)
|
||||||
|
title, body, data = _event_payload(event)
|
||||||
|
assert title == "✅ Агент запущен"
|
||||||
|
assert "graceful restart" in body
|
||||||
|
assert data["type"] == "agent.lifecycle"
|
||||||
|
|
||||||
|
|
||||||
def test_send_fcm_data_swallows_token_errors_by_default():
|
def test_send_fcm_data_swallows_token_errors_by_default():
|
||||||
|
|||||||
@@ -3,7 +3,13 @@
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
from app.models import Event, Host
|
from app.models import Event, Host
|
||||||
from app.services.telegram_templates import format_event_telegram_html, format_rdp_login_html, html_escape
|
from app.services.telegram_templates import (
|
||||||
|
format_event_mobile_push,
|
||||||
|
format_event_telegram_html,
|
||||||
|
format_rdp_login_html,
|
||||||
|
html_escape,
|
||||||
|
telegram_html_to_plaintext,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_html_escape_special_chars():
|
def test_html_escape_special_chars():
|
||||||
@@ -145,6 +151,61 @@ def test_event_telegram_includes_sac_source_for_sac_daily_report():
|
|||||||
assert "📡 Оповещение: SAC (Security Alert Center)" in text
|
assert "📡 Оповещение: SAC (Security Alert Center)" in text
|
||||||
|
|
||||||
|
|
||||||
|
def test_telegram_html_to_plaintext_strips_tags():
|
||||||
|
assert telegram_html_to_plaintext("<b>✅ Агент запущен</b>\n🏢 Хост: WIN01") == (
|
||||||
|
"✅ Агент запущен\n🏢 Хост: WIN01"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_event_mobile_push_lifecycle_includes_trigger():
|
||||||
|
host = Host(hostname="WIN01", display_name="K6A-DC3", os_family="windows")
|
||||||
|
event = Event(
|
||||||
|
event_id="00000000-0000-4000-8000-000000000509",
|
||||||
|
host_id=1,
|
||||||
|
host=host,
|
||||||
|
occurred_at=datetime(2026, 5, 29, 9, 0, tzinfo=timezone.utc),
|
||||||
|
category="agent",
|
||||||
|
type="agent.lifecycle",
|
||||||
|
severity="info",
|
||||||
|
title="started",
|
||||||
|
summary="Мониторинг запущен",
|
||||||
|
details={"lifecycle": "started", "trigger": "deploy_recycle", "telegram_via": "sac"},
|
||||||
|
payload={"source": {"product": "rdp-login-monitor", "product_version": "1.2.30-SAC"}},
|
||||||
|
)
|
||||||
|
title, body = format_event_mobile_push(event)
|
||||||
|
assert title == "✅ Агент запущен"
|
||||||
|
assert "K6A-DC3" in body
|
||||||
|
assert "1.2.30-SAC" in body
|
||||||
|
assert "обновление скрипта" in body
|
||||||
|
assert "📡 Оповещение: SAC" in body
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_event_mobile_push_uses_notification_body():
|
||||||
|
host = Host(hostname="WIN01", display_name="K6A-DC3", os_family="windows")
|
||||||
|
body_text = "✅ Мониторинг логинов ЗАПУЩЕН\n🖥️ Сервер: K6A-DC3 (10.0.0.1)"
|
||||||
|
event = Event(
|
||||||
|
event_id="00000000-0000-4000-8000-000000000510",
|
||||||
|
host_id=1,
|
||||||
|
host=host,
|
||||||
|
occurred_at=datetime(2026, 5, 29, 9, 0, tzinfo=timezone.utc),
|
||||||
|
category="agent",
|
||||||
|
type="agent.lifecycle",
|
||||||
|
severity="info",
|
||||||
|
title="started",
|
||||||
|
summary="Мониторинг запущен",
|
||||||
|
details={
|
||||||
|
"lifecycle": "started",
|
||||||
|
"trigger": "boot",
|
||||||
|
"notification_body": body_text,
|
||||||
|
"telegram_via": "sac",
|
||||||
|
},
|
||||||
|
payload={"source": {"product": "rdp-login-monitor", "product_version": "1.2.31-SAC"}},
|
||||||
|
)
|
||||||
|
title, body = format_event_mobile_push(event)
|
||||||
|
assert title == "✅ Мониторинг логинов ЗАПУЩЕН"
|
||||||
|
assert "K6A-DC3 (10.0.0.1)" in body
|
||||||
|
|
||||||
|
|
||||||
def test_lifecycle_started_template():
|
def test_lifecycle_started_template():
|
||||||
host = Host(hostname="WIN01", display_name="K6A-DC3", os_family="windows")
|
host = Host(hostname="WIN01", display_name="K6A-DC3", os_family="windows")
|
||||||
event = Event(
|
event = Event(
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ POSTGRES_PASSWORD=change-me-long-random
|
|||||||
POSTGRES_DB=sac
|
POSTGRES_DB=sac
|
||||||
|
|
||||||
# API (публичный URL для ссылок в ответах ingest)
|
# API (публичный URL для ссылок в ответах ingest)
|
||||||
SAC_PUBLIC_URL=https://sac.example.com
|
SAC_PUBLIC_URL=https://sac.kalinamall.ru
|
||||||
SAC_API_PORT=8000
|
SAC_API_PORT=8000
|
||||||
|
|
||||||
# JWT (UI — позже)
|
# JWT (UI — позже)
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
1. [docs/install-ubuntu-24.04-native.md](../docs/install-ubuntu-24.04-native.md)
|
1. [docs/install-ubuntu-24.04-native.md](../docs/install-ubuntu-24.04-native.md)
|
||||||
2. `deploy/env.native.example` → `/opt/security-alert-center/config/sac-api.env`
|
2. `deploy/env.native.example` → `/opt/security-alert-center/config/sac-api.env`
|
||||||
3. `deploy/systemd/sac-api.service` → `/etc/systemd/system/`
|
3. `deploy/systemd/sac-api.service` → `/etc/systemd/system/`
|
||||||
4. `deploy/nginx/sac.conf.tls.example` → `/etc/nginx/sites-available/sac` (wildcard TLS; только `sac.example.com`, чужие Host → 444)
|
4. `deploy/nginx/sac.conf.tls.example` → `/etc/nginx/sites-available/sac` (wildcard TLS; только `sac.kalinamall.ru`, чужие Host → 444)
|
||||||
или `sac.conf.example` — только HTTP / отладка
|
или `sac.conf.example` — только HTTP / отладка
|
||||||
5. `deploy/sac-deploy.sh` → `/opt/sac-deploy.sh` — полное обновление после `git pull`
|
5. `deploy/sac-deploy.sh` → `/opt/sac-deploy.sh` — полное обновление после `git pull`
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
DATABASE_URL=postgresql+psycopg2://sac:CHANGE_ME_POSTGRES_PASSWORD@127.0.0.1:5432/sac
|
DATABASE_URL=postgresql+psycopg2://sac:CHANGE_ME_POSTGRES_PASSWORD@127.0.0.1:5432/sac
|
||||||
|
|
||||||
SAC_PUBLIC_URL=https://sac.example.com
|
SAC_PUBLIC_URL=https://sac.kalinamall.ru
|
||||||
JWT_SECRET=CHANGE_ME_openssl_rand_hex_32
|
JWT_SECRET=CHANGE_ME_openssl_rand_hex_32
|
||||||
|
|
||||||
# API key для агентов: Authorization: Bearer <ключ>
|
# API key для агентов: Authorization: Bearer <ключ>
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
# /etc/nginx/sites-available/sac
|
# /etc/nginx/sites-available/sac
|
||||||
# Production FQDN: sac.example.com
|
# Production FQDN: sac.kalinamall.ru
|
||||||
# API: 127.0.0.1:8000 (systemd sac-api)
|
# API: 127.0.0.1:8000 (systemd sac-api)
|
||||||
#
|
#
|
||||||
# Hostname: только sac.example.com; остальные Host → 444 (см. default_server ниже).
|
# Hostname: только sac.kalinamall.ru; остальные Host → 444 (см. default_server ниже).
|
||||||
#
|
#
|
||||||
# Порядок: 1) этот конфиг (только :80) → nginx -t → reload
|
# Порядок: 1) этот конфиг (только :80) → nginx -t → reload
|
||||||
# 2) certbot --nginx -d sac.example.com (добавит :443 и сертификаты)
|
# 2) certbot --nginx -d sac.kalinamall.ru (добавит :443 и сертификаты)
|
||||||
|
|
||||||
upstream sac_api {
|
upstream sac_api {
|
||||||
server 127.0.0.1:8000;
|
server 127.0.0.1:8000;
|
||||||
keepalive 8;
|
keepalive 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- default: отклонить чужие Host (не sac.example.com) ---
|
# --- default: отклонить чужие Host (не sac.kalinamall.ru) ---
|
||||||
server {
|
server {
|
||||||
listen 80 default_server;
|
listen 80 default_server;
|
||||||
listen [::]:80 default_server;
|
listen [::]:80 default_server;
|
||||||
@@ -23,7 +23,7 @@ server {
|
|||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
listen [::]:80;
|
listen [::]:80;
|
||||||
server_name sac.example.com;
|
server_name sac.kalinamall.ru;
|
||||||
|
|
||||||
location /.well-known/acme-challenge/ {
|
location /.well-known/acme-challenge/ {
|
||||||
root /var/www/html;
|
root /var/www/html;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# /etc/nginx/sites-available/sac
|
# /etc/nginx/sites-available/sac
|
||||||
# HTTPS с корпоративным wildcard-сертификатом (например VeriSign / DigiCert).
|
# HTTPS с корпоративным wildcard-сертификатом (например VeriSign / DigiCert).
|
||||||
# Покрывает sac.example.com при CN/SAN *.example.com или sac.example.com
|
# Покрывает sac.kalinamall.ru при CN/SAN *.kalinamall.ru или sac.kalinamall.ru
|
||||||
#
|
#
|
||||||
# Hostname: только sac.example.com. Любой другой Host (например ext.example.com
|
# Hostname: только sac.kalinamall.ru. Любой другой Host (например ext.kalinamall.ru
|
||||||
# при ошибке DNS/маршрутизации на IP SAC) получает 444 / reject handshake —
|
# при ошибке DNS/маршрутизации на IP SAC) получает 444 / reject handshake —
|
||||||
# форма входа SAC не отдаётся на «чужом» имени.
|
# форма входа SAC не отдаётся на «чужом» имени.
|
||||||
#
|
#
|
||||||
@@ -32,18 +32,18 @@ server {
|
|||||||
ssl_reject_handshake on;
|
ssl_reject_handshake on;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Редирект HTTP → HTTPS (только sac.example.com)
|
# Редирект HTTP → HTTPS (только sac.kalinamall.ru)
|
||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
listen [::]:80;
|
listen [::]:80;
|
||||||
server_name sac.example.com;
|
server_name sac.kalinamall.ru;
|
||||||
return 301 https://$host$request_uri;
|
return 301 https://$host$request_uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
server {
|
server {
|
||||||
listen 443 ssl http2;
|
listen 443 ssl http2;
|
||||||
listen [::]:443 ssl http2;
|
listen [::]:443 ssl http2;
|
||||||
server_name sac.example.com;
|
server_name sac.kalinamall.ru;
|
||||||
|
|
||||||
# --- замените пути на ваши файлы wildcard ---
|
# --- замените пути на ваши файлы wildcard ---
|
||||||
ssl_certificate /etc/ssl/sac/fullchain.pem;
|
ssl_certificate /etc/ssl/sac/fullchain.pem;
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ else
|
|||||||
if [ -z "${UPSTREAM}" ]; then
|
if [ -z "${UPSTREAM}" ]; then
|
||||||
UPSTREAM="origin/main"
|
UPSTREAM="origin/main"
|
||||||
fi
|
fi
|
||||||
log "WARN: fast-forward невозможен (часто после force-push на upstream) — reset --hard ${UPSTREAM}"
|
log "WARN: fast-forward невозможен (часто после force-push на kalinamall) — reset --hard ${UPSTREAM}"
|
||||||
sudo -u "${APP_USER}" git -C "${APP_ROOT}" reset --hard "${UPSTREAM}"
|
sudo -u "${APP_USER}" git -C "${APP_ROOT}" reset --hard "${UPSTREAM}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Security Alert Center API (FastAPI)
|
Description=Security Alert Center API (FastAPI)
|
||||||
Documentation=https://github.com/PTah/security-alert-center
|
Documentation=https://git.kalinamall.ru/PapaTramp/security-alert-center
|
||||||
After=network-online.target postgresql.service
|
After=network-online.target postgresql.service
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
Requires=postgresql.service
|
Requires=postgresql.service
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
| [seaca-mobile.md](seaca-mobile.md) | **Seaca**: коды, устройства, сессия, API |
|
| [seaca-mobile.md](seaca-mobile.md) | **Seaca**: коды, устройства, сессия, API |
|
||||||
| [seaca-fcm.md](seaca-fcm.md) | **Seaca push**: Firebase и `SAC_FCM_*` |
|
| [seaca-fcm.md](seaca-fcm.md) | **Seaca push**: Firebase и `SAC_FCM_*` |
|
||||||
| [workspace-three-repos.md](workspace-three-repos.md) | Multi-root workspace (три репо) |
|
| [workspace-three-repos.md](workspace-three-repos.md) | Multi-root workspace (три репо) |
|
||||||
|
| [agent-update-backlog.md](agent-update-backlog.md) | **ToDo:** версии агентов, удалённое обновление |
|
||||||
|
|
||||||
## Порядок чтения
|
## Порядок чтения
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
```ini
|
```ini
|
||||||
# off | exclusive | dual | fallback
|
# off | exclusive | dual | fallback
|
||||||
UseSAC="exclusive"
|
UseSAC="exclusive"
|
||||||
SAC_URL="https://sac.example.com/api/v1/events"
|
SAC_URL="https://sac.kalinamall.ru/api/v1/events"
|
||||||
SAC_API_KEY="sac_xxxxxxxx"
|
SAC_API_KEY="sac_xxxxxxxx"
|
||||||
SAC_SPOOL_DIR="/var/lib/ssh-monitor/sac-spool"
|
SAC_SPOOL_DIR="/var/lib/ssh-monitor/sac-spool"
|
||||||
SAC_SEND_HEARTBEAT="1"
|
SAC_SEND_HEARTBEAT="1"
|
||||||
@@ -26,7 +26,7 @@ SAC_TIMEOUT_SEC="12"
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
$UseSAC = "exclusive" # off | exclusive | dual | fallback
|
$UseSAC = "exclusive" # off | exclusive | dual | fallback
|
||||||
$SacUrl = "https://sac.example.com/api/v1/events"
|
$SacUrl = "https://sac.kalinamall.ru/api/v1/events"
|
||||||
$SacApiKey = "sac_xxxxxxxx"
|
$SacApiKey = "sac_xxxxxxxx"
|
||||||
$SacSpoolDir = "D:\Soft\Logs\sac-spool"
|
$SacSpoolDir = "D:\Soft\Logs\sac-spool"
|
||||||
```
|
```
|
||||||
@@ -74,7 +74,7 @@ UI **Настройки** (`/settings`) — правило + параметры
|
|||||||
|
|
||||||
### 1.4. Версии и доставка обновлений
|
### 1.4. Версии и доставка обновлений
|
||||||
|
|
||||||
При **любом** изменении агента, влияющем на SAC или поведение на хосте, поднимайте версию и пушьте в **GitHub** (`github.com/PTah`):
|
При **любом** изменении агента, влияющем на SAC или поведение на хосте, поднимайте версию и пушьте в **GitHub** (`github.com/PTah`); для зеркала kalinamall — `.\scripts\Push-Mirror.ps1 kalinamall`:
|
||||||
|
|
||||||
| Агент | Маркер версии | Как хост узнаёт о новой версии |
|
| Агент | Маркер версии | Как хост узнаёт о новой версии |
|
||||||
|-------|---------------|--------------------------------|
|
|-------|---------------|--------------------------------|
|
||||||
@@ -113,7 +113,7 @@ UI **Настройки** (`/settings`) — правило + параметры
|
|||||||
|
|
||||||
```http
|
```http
|
||||||
POST /api/v1/events HTTP/1.1
|
POST /api/v1/events HTTP/1.1
|
||||||
Host: sac.example.com
|
Host: sac.kalinamall.ru
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
Authorization: Bearer sac_xxxxxxxx
|
Authorization: Bearer sac_xxxxxxxx
|
||||||
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
|
Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
|
||||||
@@ -136,7 +136,7 @@ Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000
|
|||||||
"event_id": "550e8400-e29b-41d4-a716-446655440000",
|
"event_id": "550e8400-e29b-41d4-a716-446655440000",
|
||||||
"created": true,
|
"created": true,
|
||||||
"sac_event_url": "https://sac.kalinamall.ru/api/v1/events/12345",
|
"sac_event_url": "https://sac.kalinamall.ru/api/v1/events/12345",
|
||||||
"problem_id": null
|
"problem_id": null
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
# ToDo — управление версиями агентов и удалённое обновление
|
||||||
|
|
||||||
|
**Статус:** идея, требует проработки архитектуры.
|
||||||
|
**Связано:** [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`
|
||||||
+3
-3
@@ -21,7 +21,7 @@ deploy/
|
|||||||
sac-deploy.sh → /opt/sac-deploy.sh (полное обновление)
|
sac-deploy.sh → /opt/sac-deploy.sh (полное обновление)
|
||||||
```
|
```
|
||||||
|
|
||||||
**Production URL:** `https://sac.example.com`
|
**Production URL:** `https://sac.kalinamall.ru`
|
||||||
**Конфиг:** `/opt/security-alert-center/config/sac-api.env` (владелец `sac:sac`, chmod 600).
|
**Конфиг:** `/opt/security-alert-center/config/sac-api.env` (владелец `sac:sac`, chmod 600).
|
||||||
**UI:** статика `frontend/dist`, раздаётся через FastAPI (после `npm run build`).
|
**UI:** статика `frontend/dist`, раздаётся через FastAPI (после `npm run build`).
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ deploy/
|
|||||||
|
|
||||||
## 2. Сетевые правила
|
## 2. Сетевые правила
|
||||||
|
|
||||||
**Агенты →** `https://sac.example.com/api/v1/events`
|
**Агенты →** `https://sac.kalinamall.ru/api/v1/events`
|
||||||
**SAC →** Telegram, SMTP (исходящие)
|
**SAC →** Telegram, SMTP (исходящие)
|
||||||
**Админы →** 443 (UI/API через nginx)
|
**Админы →** 443 (UI/API через nginx)
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ deploy/
|
|||||||
```bash
|
```bash
|
||||||
systemctl status sac-api
|
systemctl status sac-api
|
||||||
curl -sS http://127.0.0.1:8000/health
|
curl -sS http://127.0.0.1:8000/health
|
||||||
curl -sS https://sac.example.com/health
|
curl -sS https://sac.kalinamall.ru/health
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "https://github.com/PTah/security-alert-center/schemas/event-v1.json",
|
"$id": "https://git.kalinamall.ru/PapaTramp/security-alert-center/schemas/event-v1.json",
|
||||||
"title": "Security Alert Center Event v1",
|
"title": "Security Alert Center Event v1",
|
||||||
"description": "Каноническое событие от ssh-monitor или RDP-login-monitor",
|
"description": "Каноническое событие от ssh-monitor или RDP-login-monitor",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ Docker удобен для локальной отладки или изолир
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt install -y git
|
sudo apt install -y git
|
||||||
sudo git clone https://github.com/PTah/security-alert-center.git /opt/security-alert-center
|
sudo git clone https://git.kalinamall.ru/PapaTramp/security-alert-center.git /opt/security-alert-center
|
||||||
sudo chown -R "$USER:$USER" /opt/security-alert-center
|
sudo chown -R "$USER:$USER" /opt/security-alert-center
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
| Параметр | Пример |
|
| Параметр | Пример |
|
||||||
|----------|--------|
|
|----------|--------|
|
||||||
| FQDN | `sac.example.com` |
|
| FQDN | `sac.kalinamall.ru` |
|
||||||
| IP | `10.0.0.50` |
|
| IP | `10.0.0.50` |
|
||||||
| Каталог | `/opt/security-alert-center` |
|
| Каталог | `/opt/security-alert-center` |
|
||||||
| Пользователь сервиса | `sac` |
|
| Пользователь сервиса | `sac` |
|
||||||
@@ -71,7 +71,7 @@ nginx -v
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo mkdir -p /opt
|
sudo mkdir -p /opt
|
||||||
sudo git clone https://github.com/PTah/security-alert-center.git /opt/security-alert-center
|
sudo git clone https://git.kalinamall.ru/PapaTramp/security-alert-center.git /opt/security-alert-center
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -144,7 +144,7 @@ sudo chmod 600 /opt/security-alert-center/config/sac-api.env
|
|||||||
|
|
||||||
- `DATABASE_URL` — с паролем PostgreSQL из шага 4 (если в пароле есть `#`, `@`, `%` — возьмите значение в **кавычки**: `DATABASE_URL="postgresql+psycopg2://..."`)
|
- `DATABASE_URL` — с паролем PostgreSQL из шага 4 (если в пароле есть `#`, `@`, `%` — возьмите значение в **кавычки**: `DATABASE_URL="postgresql+psycopg2://..."`)
|
||||||
- `JWT_SECRET` — `openssl rand -hex 32`
|
- `JWT_SECRET` — `openssl rand -hex 32`
|
||||||
- `SAC_PUBLIC_URL` — `https://sac.example.com`
|
- `SAC_PUBLIC_URL` — `https://sac.kalinamall.ru`
|
||||||
- `SAC_BOOTSTRAP_API_KEY` — `python3.12 -c "import secrets; print('sac_'+secrets.token_urlsafe(32))"`
|
- `SAC_BOOTSTRAP_API_KEY` — `python3.12 -c "import secrets; print('sac_'+secrets.token_urlsafe(32))"`
|
||||||
- `SAC_ADMIN_PASSWORD` — пароль входа в веб-UI (отдельно от API key агентов)
|
- `SAC_ADMIN_PASSWORD` — пароль входа в веб-UI (отдельно от API key агентов)
|
||||||
- `EVENT_SCHEMA_PATH=/opt/security-alert-center/schemas/event-schema-v1.json`
|
- `EVENT_SCHEMA_PATH=/opt/security-alert-center/schemas/event-schema-v1.json`
|
||||||
@@ -195,7 +195,7 @@ journalctl -u sac-api -f
|
|||||||
## 9. nginx и TLS
|
## 9. nginx и TLS
|
||||||
|
|
||||||
Для KalinaMall: **корпоративный wildcard VeriSign** (или DigiCert), не Let's Encrypt.
|
Для KalinaMall: **корпоративный wildcard VeriSign** (или DigiCert), не Let's Encrypt.
|
||||||
Хост `sac.example.com` должен попадать под `*.example.com`.
|
Хост `sac.kalinamall.ru` должен попадать под `*.kalinamall.ru`.
|
||||||
|
|
||||||
**Подробно:** форматы, scp с Windows/Linux, `.pfx` → PEM, права — **[ssl-certificate.md](ssl-certificate.md)**.
|
**Подробно:** форматы, scp с Windows/Linux, `.pfx` → PEM, права — **[ssl-certificate.md](ssl-certificate.md)**.
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ sudo usermod -aG ssl-cert www-data
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# с вашего компьютера:
|
# с вашего компьютера:
|
||||||
scp fullchain.pem privkey.pem deploy@<IP_SAC>:/tmp/
|
scp fullchain.pem privkey.pem papatramp@<IP_SAC>:/tmp/
|
||||||
|
|
||||||
# на сервере:
|
# на сервере:
|
||||||
sudo mv /tmp/fullchain.pem /tmp/privkey.pem /etc/ssl/sac/
|
sudo mv /tmp/fullchain.pem /tmp/privkey.pem /etc/ssl/sac/
|
||||||
@@ -263,28 +263,28 @@ sudo nginx -t
|
|||||||
sudo systemctl reload nginx
|
sudo systemctl reload nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
Шаблон `sac.conf.tls.example` содержит **default_server** с `return 444` (:80) и `ssl_reject_handshake` (:443) для любого Host, кроме `sac.example.com`. Это защищает от ситуации, когда на IP SAC (например `<SAC_SERVER_IP>`) по ошибке DNS попадает `ext.example.com` и открывается форма входа SAC.
|
Шаблон `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:
|
Проверка после reload:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -sS -o /dev/null -w '%{http_code}\n' --resolve sac.example.com:443:127.0.0.1 https://sac.example.com/health
|
curl -sS -o /dev/null -w '%{http_code}\n' --resolve sac.kalinamall.ru:443:127.0.0.1 https://sac.kalinamall.ru/health
|
||||||
# ожидается 200
|
# ожидается 200
|
||||||
|
|
||||||
curl -sS -o /dev/null -w '%{http_code}\n' --resolve ext.example.com:443:127.0.0.1 https://ext.example.com/ 2>/dev/null || echo "connection closed (444/reject OK)"
|
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
|
```bash
|
||||||
curl -sS https://sac.example.com/health | jq .
|
curl -sS https://sac.kalinamall.ru/health | jq .
|
||||||
```
|
```
|
||||||
|
|
||||||
В `config/sac-api.env` должно быть: `SAC_PUBLIC_URL=https://sac.example.com`
|
В `config/sac-api.env` должно быть: `SAC_PUBLIC_URL=https://sac.kalinamall.ru`
|
||||||
|
|
||||||
### 9.3. Агенты (ssh-monitor, RDP) и доверие к CA
|
### 9.3. Агенты (ssh-monitor, RDP) и доверие к CA
|
||||||
|
|
||||||
- Агенты ходят на `https://sac.example.com/api/v1/events`.
|
- Агенты ходят на `https://sac.kalinamall.ru/api/v1/events`.
|
||||||
- Если используется **внутренний корневой CA**, а не публичный VeriSign/DigiCert в системном store — на Linux/Windows может понадобиться установка корневого сертификата в доверенные (или корпоративный прокси с подменой TLS).
|
- Если используется **внутренний корневой CA**, а не публичный VeriSign/DigiCert в системном store — на Linux/Windows может понадобиться установка корневого сертификата в доверенные (или корпоративный прокси с подменой TLS).
|
||||||
- Для публичного коммерческого wildcard от известного УЦ обычно **дополнительных действий на агентах не нужно**.
|
- Для публичного коммерческого wildcard от известного УЦ обычно **дополнительных действий на агентах не нужно**.
|
||||||
|
|
||||||
@@ -299,7 +299,7 @@ curl -sS https://sac.example.com/health | jq .
|
|||||||
```bash
|
```bash
|
||||||
sudo cp deploy/nginx/sac.conf.example /etc/nginx/sites-available/sac
|
sudo cp deploy/nginx/sac.conf.example /etc/nginx/sites-available/sac
|
||||||
# ... nginx -t, reload, затем:
|
# ... nginx -t, reload, затем:
|
||||||
sudo certbot --nginx -d sac.example.com
|
sudo certbot --nginx -d sac.kalinamall.ru
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -317,7 +317,7 @@ ls -la dist/index.html
|
|||||||
sudo systemctl restart sac-api
|
sudo systemctl restart sac-api
|
||||||
```
|
```
|
||||||
|
|
||||||
В `config/sac-api.env` задайте `SAC_ADMIN_PASSWORD`, затем откройте `https://sac.example.com/` (логин `SAC_ADMIN_USERNAME`, по умолчанию `admin`).
|
В `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` пуста.
|
После обновления с multi-user (миграция `009_sac_users`): выполните `alembic upgrade head` в каталоге `backend/`. При первом старте API создаст пользователя **admin** из `SAC_ADMIN_*`, если таблица `sac_users` пуста.
|
||||||
|
|
||||||
@@ -343,7 +343,7 @@ curl -sS http://127.0.0.1:8000/health | jq .
|
|||||||
Через nginx (после TLS):
|
Через nginx (после TLS):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -sS https://sac.example.com/health | jq .
|
curl -sS https://sac.kalinamall.ru/health | jq .
|
||||||
```
|
```
|
||||||
|
|
||||||
Тест ingest (подставьте `SAC_BOOTSTRAP_API_KEY`):
|
Тест ingest (подставьте `SAC_BOOTSTRAP_API_KEY`):
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
```bash
|
```bash
|
||||||
# см. полный чеклист в native-руководстве
|
# см. полный чеклист в native-руководстве
|
||||||
sudo apt update && sudo apt install -y git postgresql nginx python3.12 python3.12-venv
|
sudo apt update && sudo apt install -y git postgresql nginx python3.12 python3.12-venv
|
||||||
sudo git clone https://github.com/PTah/security-alert-center.git /opt/security-alert-center
|
sudo git clone https://git.kalinamall.ru/PapaTramp/security-alert-center.git /opt/security-alert-center
|
||||||
# … PostgreSQL, venv, config/sac-api.env, systemd, nginx
|
# … PostgreSQL, venv, config/sac-api.env, systemd, nginx
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# SAC production — пример статуса развёртывания
|
# SAC production — текущий статус (KalinaMall)
|
||||||
|
|
||||||
Ориентир для продолжения работ. Обновляйте при смене этапа.
|
Ориентир для продолжения работ. Обновляйте при смене этапа.
|
||||||
|
|
||||||
**Сервер:** Ubuntu 24.04, FQDN `sac.example.com`
|
**Сервер:** Ubuntu 24.04, FQDN `sac.kalinamall.ru`
|
||||||
**Каталог:** `/opt/security-alert-center`
|
**Каталог:** `/opt/security-alert-center`
|
||||||
**Пользователь сервиса:** `sac` (git, venv, npm — только от него)
|
**Пользователь сервиса:** `sac` (git, venv, npm — только от него)
|
||||||
**Конфиг:** `/opt/security-alert-center/config/sac-api.env`
|
**Конфиг:** `/opt/security-alert-center/config/sac-api.env`
|
||||||
@@ -39,7 +39,7 @@ sudo /opt/sac-deploy.sh
|
|||||||
| Параметр | Значение |
|
| Параметр | Значение |
|
||||||
|----------|----------|
|
|----------|----------|
|
||||||
| Хост | `ubabuba` / `10.10.36.9` |
|
| Хост | `ubabuba` / `10.10.36.9` |
|
||||||
| Репозиторий | `github.com/PTah/ssh-monitor` (`main`, есть `sac-client.sh`) |
|
| Репозиторий | `git.kalinamall.ru/PapaTramp/ssh-monitor` (`main`, есть `sac-client.sh`) |
|
||||||
| `UseSAC` | пилот **exclusive** — см. [pilot-2.1-exclusive.md](pilot-2.1-exclusive.md) |
|
| `UseSAC` | пилот **exclusive** — см. [pilot-2.1-exclusive.md](pilot-2.1-exclusive.md) |
|
||||||
| Сервис | `ssh-monitor.service` — **active** |
|
| Сервис | `ssh-monitor.service` — **active** |
|
||||||
| `--check-sac` | OK (health + ingest `agent.test` 202) |
|
| `--check-sac` | OK (health + ingest `agent.test` 202) |
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ sudo /opt/scripts/update_ssh_monitor.sh
|
|||||||
|
|
||||||
```ini
|
```ini
|
||||||
UseSAC=exclusive
|
UseSAC=exclusive
|
||||||
SAC_URL=https://sac.example.com
|
SAC_URL=https://sac.kalinamall.ru
|
||||||
SAC_API_KEY=sac_xxxxxxxx
|
SAC_API_KEY=sac_xxxxxxxx
|
||||||
SAC_TLS_SKIP_VERIFY=0
|
SAC_TLS_SKIP_VERIFY=0
|
||||||
SAC_SPOOL_DIR=/var/lib/ssh-monitor/sac-spool
|
SAC_SPOOL_DIR=/var/lib/ssh-monitor/sac-spool
|
||||||
|
|||||||
+17
-3
@@ -66,7 +66,7 @@
|
|||||||
|
|
||||||
**Цель:** нативный Android-клиент и push по тем же правилам оповещений, что Telegram/email/webhook.
|
**Цель:** нативный Android-клиент и push по тем же правилам оповещений, что Telegram/email/webhook.
|
||||||
|
|
||||||
Репозиторий клиента: [seaca](https://github.com/PTah/seaca) (Kotlin, Jetpack Compose, FCM).
|
Репозиторий клиента: [seaca](https://git.kalinamall.ru/PapaTramp/seaca) (Kotlin, Jetpack Compose, FCM).
|
||||||
|
|
||||||
**Сервер SAC:**
|
**Сервер SAC:**
|
||||||
|
|
||||||
@@ -77,7 +77,21 @@
|
|||||||
|
|
||||||
**Не в мобильном клиенте:** пользователи SAC, каналы Telegram/SMTP/webhook, админ-настройки.
|
**Не в мобильном клиенте:** пользователи SAC, каналы Telegram/SMTP/webhook, админ-настройки.
|
||||||
|
|
||||||
Подробный план клиента — [seaca/docs/ROADMAP.md](https://github.com/PTah/seaca/blob/main/docs/ROADMAP.md).
|
Подробный план клиента — [seaca/docs/ROADMAP.md](https://git.kalinamall.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-update-backlog.md](agent-update-backlog.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -96,7 +110,7 @@
|
|||||||
| v0.1 | — (не требуется) | — |
|
| v0.1 | — (не требуется) | — |
|
||||||
| v0.2 | TBD (тег с UseSAC) | TBD |
|
| v0.2 | TBD (тег с UseSAC) | TBD |
|
||||||
| v0.3+ | совместимость schema 1.0 | совместимость schema 1.0 |
|
| v0.3+ | совместимость schema 1.0 | совместимость schema 1.0 |
|
||||||
| v0.6 | — | — (мобильный клиент [seaca](https://github.com/PTah/seaca), не агент) |
|
| v0.6 | — | — (мобильный клиент [seaca](https://git.kalinamall.ru/PapaTramp/seaca), не агент) |
|
||||||
|
|
||||||
При breaking change схемы — `schema_version: 1.1` с поддержкой 1.0 на ingest.
|
При breaking change схемы — `schema_version: 1.1` с поддержкой 1.0 на ingest.
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
# Runbook: эксплуатация SAC
|
# Runbook: эксплуатация SAC
|
||||||
|
|
||||||
Краткие процедуры для prod (`sac.example.com`, native install в `/opt/security-alert-center`).
|
Краткие процедуры для prod (`sac.kalinamall.ru`, native install в `/opt/security-alert-center`).
|
||||||
|
|
||||||
## Деплой приложения
|
## Деплой приложения
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ sudo /opt/sac-deploy.sh
|
|||||||
Проверка:
|
Проверка:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -sS https://sac.example.com/health | jq .
|
curl -sS https://sac.kalinamall.ru/health | jq .
|
||||||
```
|
```
|
||||||
|
|
||||||
Ожидается `status: ok`, `database: ok`. При устаревших heartbeat агентов — `status: degraded`, поле `hosts_stale` > 0.
|
Ожидается `status: ok`, `database: ok`. При устаревших heartbeat агентов — `status: degraded`, поле `hosts_stale` > 0.
|
||||||
@@ -101,4 +101,4 @@ sudo -u sac bash -lc 'cd /opt/security-alert-center/backend && .venv/bin/python
|
|||||||
|
|
||||||
**Устаревший heartbeat** — увеличить `SAC_HEARTBEAT_STALE_MINUTES` или проверить `agent.heartbeat` на хосте.
|
**Устаревший heartbeat** — увеличить `SAC_HEARTBEAT_STALE_MINUTES` или проверить `agent.heartbeat` на хосте.
|
||||||
|
|
||||||
**Чужой Host на IP SAC (форма SAC на ext.example.com)** — в nginx только `server_name sac.example.com`; default_server → 444 / `ssl_reject_handshake`. Обновить конфиг из `deploy/nginx/sac.conf.tls.example`, `sudo nginx -t && sudo systemctl reload nginx`. HAProxy на этом не решается — правка на **<SAC_SERVER_IP>** (nginx SAC).
|
**Чужой 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).
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Seaca — мобильный клиент SAC
|
# Seaca — мобильный клиент SAC
|
||||||
|
|
||||||
Репозиторий приложения: [seaca](https://github.com/PTah/seaca).
|
Репозиторий приложения: [seaca](https://git.kalinamall.ru/PapaTramp/seaca).
|
||||||
Требуется SAC **≥ 0.9.0** с применённой миграцией `014`.
|
Требуется SAC **≥ 0.9.0** с применённой миграцией `014`.
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
| Способ входа | **Логин и пароль + код** — в приложении нужны учётные данные SAC; **Только код** — пароль не нужен, пользователь должен быть выбран в форме |
|
| Способ входа | **Логин и пароль + код** — в приложении нужны учётные данные SAC; **Только код** — пароль не нужен, пользователь должен быть выбран в форме |
|
||||||
| Срок (часов) | Код перестаёт принимать **новые** привязки; уже подключённые телефоны не отключаются |
|
| Срок (часов) | Код перестаёт принимать **новые** привязки; уже подключённые телефоны не отключаются |
|
||||||
|
|
||||||
Код показывается **один раз** после «Выдать код». Передайте оператору: URL сервера (**`https://sac-api.example.com`** для Seaca; веб-админка — `https://sac.example.com`), код `sacmob_…`, при режиме password — логин/пароль SAC.
|
Код показывается **один раз** после «Выдать код». Передайте оператору: URL сервера (**`https://sac-api.kalinamall.ru`** для Seaca; веб-админка — `https://sac.kalinamall.ru`), код `sacmob_…`, при режиме password — логин/пароль SAC.
|
||||||
|
|
||||||
### Подключённые устройства
|
### Подключённые устройства
|
||||||
|
|
||||||
@@ -81,10 +81,10 @@ SAC_FCM_SERVICE_ACCOUNT_JSON=/etc/security-alert-center/fcm-service-account.json
|
|||||||
|
|
||||||
| Hostname | Clients | IP allowlist |
|
| Hostname | Clients | IP allowlist |
|
||||||
|----------|---------|--------------|
|
|----------|---------|--------------|
|
||||||
| `sac.example.com` | Web UI | yes (`git-sac-allowed`) |
|
| `sac.kalinamall.ru` | Web UI | yes (`git-sac-allowed`) |
|
||||||
| `sac-api.example.com` | Seaca, `/api/v1/mobile/*` | no (enroll + JWT) |
|
| `sac-api.kalinamall.ru` | Seaca, `/api/v1/mobile/*` | no (enroll + JWT) |
|
||||||
|
|
||||||
Both resolve to the same SAC server (**<SAC_SERVER_IP>**). nginx must accept both names in `server_name`. See [reverse-proxy/docs/sac-access.md](https://github.com/PTah/reverse-proxy/blob/main/docs/sac-access.md).
|
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.kalinamall.ru/PapaTramp/reverse-proxy/src/branch/main/docs/sac-access.md).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+20
-20
@@ -1,6 +1,6 @@
|
|||||||
# TLS-сертификат для SAC (wildcard VeriSign / DigiCert)
|
# TLS-сертификат для SAC (wildcard VeriSign / DigiCert)
|
||||||
|
|
||||||
Куда положить файлы, в каком формате, как скопировать на сервер `sac.example.com`.
|
Куда положить файлы, в каком формате, как скопировать на сервер `sac.kalinamall.ru`.
|
||||||
|
|
||||||
Связано: [install-ubuntu-24.04-native.md](install-ubuntu-24.04-native.md) §9, шаблон `deploy/nginx/sac.conf.tls.example`.
|
Связано: [install-ubuntu-24.04-native.md](install-ubuntu-24.04-native.md) §9, шаблон `deploy/nginx/sac.conf.tls.example`.
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ nginx читает **два PEM-файла** (текст, начинается
|
|||||||
|
|
||||||
Имена файлов можно другие, если пути совпадают с `ssl_certificate` / `ssl_certificate_key` в `/etc/nginx/sites-available/sac`.
|
Имена файлов можно другие, если пути совпадают с `ssl_certificate` / `ssl_certificate_key` в `/etc/nginx/sites-available/sac`.
|
||||||
|
|
||||||
**Покрытие имени:** в сертификате должен быть CN или SAN вида `*.example.com` (wildcard) или `sac.example.com`.
|
**Покрытие имени:** в сертификате должен быть CN или SAN вида `*.kalinamall.ru` (wildcard) или `sac.kalinamall.ru`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ sudo -u www-data test -r /etc/ssl/sac/privkey.pem && echo "key OK" || echo "key
|
|||||||
Если уже есть `fullchain.pem` и `privkey.pem` на ПК:
|
Если уже есть `fullchain.pem` и `privkey.pem` на ПК:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
scp fullchain.pem privkey.pem deploy@SAC_SERVER:/tmp/
|
scp fullchain.pem privkey.pem papatramp@SAC_SERVER:/tmp/
|
||||||
```
|
```
|
||||||
|
|
||||||
На сервере:
|
На сервере:
|
||||||
@@ -103,11 +103,11 @@ sudo rm -f /tmp/fullchain.pem /tmp/privkey.pem
|
|||||||
|
|
||||||
### 4.2. С Windows (PowerShell / pscp)
|
### 4.2. С Windows (PowerShell / pscp)
|
||||||
|
|
||||||
Файлы, например, в `D:\Certs\example\`:
|
Файлы, например, в `D:\Certs\kalinamall\`:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
scp D:\Certs\example\fullchain.pem deploy@SAC_SERVER:/tmp/
|
scp D:\Certs\kalinamall\fullchain.pem papatramp@SAC_SERVER:/tmp/
|
||||||
scp D:\Certs\example\privkey.pem deploy@SAC_SERVER:/tmp/
|
scp D:\Certs\kalinamall\privkey.pem papatramp@SAC_SERVER:/tmp/
|
||||||
```
|
```
|
||||||
|
|
||||||
Дальше на сервере — те же `sudo mv` и `chown`, что в §4.1.
|
Дальше на сервере — те же `sudo mv` и `chown`, что в §4.1.
|
||||||
@@ -115,7 +115,7 @@ scp D:\Certs\example\privkey.pem deploy@SAC_SERVER:/tmp/
|
|||||||
Если есть только **`wildcard.pfx`**:
|
Если есть только **`wildcard.pfx`**:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
scp D:\Certs\example\wildcard.pfx deploy@SAC_SERVER:/tmp/
|
scp D:\Certs\kalinamall\wildcard.pfx papatramp@SAC_SERVER:/tmp/
|
||||||
```
|
```
|
||||||
|
|
||||||
Распаковка на **сервере** (§4.3).
|
Распаковка на **сервере** (§4.3).
|
||||||
@@ -128,19 +128,19 @@ scp D:\Certs\example\wildcard.pfx deploy@SAC_SERVER:/tmp/
|
|||||||
mkdir -p /tmp/certs
|
mkdir -p /tmp/certs
|
||||||
|
|
||||||
# один файл
|
# один файл
|
||||||
scp user@certs-host.example.com:/path/to/wildcard_example_com.pfx /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/
|
scp user@certs-host:/path/to/fullchain.pem user@certs-host:/path/to/privkey.pem /tmp/certs/
|
||||||
|
|
||||||
# нестандартный SSH-порт (у scp заглавная P)
|
# нестандартный SSH-порт (у scp заглавная P)
|
||||||
scp -P 2222 user@certs-host:/path/to/wildcard_example_com.pfx /tmp/certs/
|
scp -P 2222 user@certs-host:/path/to/wildcard_kalinamall_ru.pfx /tmp/certs/
|
||||||
```
|
```
|
||||||
|
|
||||||
С другого сервера **отдать** на SAC (push — команда на сервере-источнике):
|
С другого сервера **отдать** на SAC (push — команда на сервере-источнике):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
scp /path/to/wildcard_example_com.pfx deploy@<IP_SAC>:/tmp/certs/
|
scp /path/to/wildcard_kalinamall_ru.pfx papatramp@<IP_SAC>:/tmp/certs/
|
||||||
```
|
```
|
||||||
|
|
||||||
Нужен SSH-доступ и право **читать** файл на источнике.
|
Нужен SSH-доступ и право **читать** файл на источнике.
|
||||||
@@ -162,13 +162,13 @@ sudo mkdir -p /tmp/certs
|
|||||||
cd /tmp/certs
|
cd /tmp/certs
|
||||||
# замените имя PFX; Enter Import Password: — пароль от PFX (не sudo)
|
# замените имя PFX; Enter Import Password: — пароль от PFX (не sudo)
|
||||||
|
|
||||||
sudo openssl pkcs12 -legacy -in wildcard_example_com.pfx -nocerts -nodes \
|
sudo openssl pkcs12 -legacy -in wildcard_kalinamall_ru.pfx -nocerts -nodes \
|
||||||
-out privkey.pem
|
-out privkey.pem
|
||||||
|
|
||||||
sudo openssl pkcs12 -legacy -in wildcard_example_com.pfx -clcerts -nokeys \
|
sudo openssl pkcs12 -legacy -in wildcard_kalinamall_ru.pfx -clcerts -nokeys \
|
||||||
-out server.crt
|
-out server.crt
|
||||||
|
|
||||||
sudo openssl pkcs12 -legacy -in wildcard_example_com.pfx -cacerts -nokeys \
|
sudo openssl pkcs12 -legacy -in wildcard_kalinamall_ru.pfx -cacerts -nokeys \
|
||||||
-out ca-chain.crt
|
-out ca-chain.crt
|
||||||
|
|
||||||
# fullchain = сервер + промежуточные (порядок важен)
|
# fullchain = сервер + промежуточные (порядок важен)
|
||||||
@@ -183,20 +183,20 @@ sudo chmod 750 /etc/ssl/sac
|
|||||||
|
|
||||||
# очистка временных файлов
|
# очистка временных файлов
|
||||||
sudo shred -u server.crt ca-chain.crt privkey.pem 2>/dev/null
|
sudo shred -u server.crt ca-chain.crt privkey.pem 2>/dev/null
|
||||||
sudo rm -f /tmp/certs/wildcard_example_com.pfx
|
sudo rm -f /tmp/certs/wildcard_kalinamall_ru.pfx
|
||||||
```
|
```
|
||||||
|
|
||||||
Если `-legacy` недостаточно:
|
Если `-legacy` недостаточно:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo openssl pkcs12 -provider legacy -provider default \
|
sudo openssl pkcs12 -provider legacy -provider default \
|
||||||
-in wildcard_example_com.pfx -nocerts -nodes -out privkey.pem
|
-in wildcard_kalinamall_ru.pfx -nocerts -nodes -out privkey.pem
|
||||||
```
|
```
|
||||||
|
|
||||||
Проверить содержимое PFX:
|
Проверить содержимое PFX:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo openssl pkcs12 -legacy -in wildcard_example_com.pfx -info -noout
|
sudo openssl pkcs12 -legacy -in wildcard_kalinamall_ru.pfx -info -noout
|
||||||
```
|
```
|
||||||
|
|
||||||
Пароль PFX вводится интерактивно (`Enter Import Password`). **Не** коммитьте PFX и ключ в git.
|
Пароль PFX вводится интерактивно (`Enter Import Password`). **Не** коммитьте PFX и ключ в git.
|
||||||
@@ -207,13 +207,13 @@ sudo openssl pkcs12 -legacy -in wildcard_example_com.pfx -info -noout
|
|||||||
|
|
||||||
Типичный набор от VeriSign / DigiCert:
|
Типичный набор от VeriSign / DigiCert:
|
||||||
|
|
||||||
- `star_example_com.crt` — ваш wildcard
|
- `star_kalinamall_ru.crt` — ваш wildcard
|
||||||
- `DigiCertCA.crt` / `intermediate.crt` — промежуточный
|
- `DigiCertCA.crt` / `intermediate.crt` — промежуточный
|
||||||
- (иногда) `TrustedRoot.crt` — корневой **не** добавляйте в fullchain для nginx
|
- (иногда) `TrustedRoot.crt` — корневой **не** добавляйте в fullchain для nginx
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# на ПК или на сервере, в каталоге с исходниками:
|
# на ПК или на сервере, в каталоге с исходниками:
|
||||||
cat star_example_com.crt intermediate.crt > fullchain.pem
|
cat star_kalinamall_ru.crt intermediate.crt > fullchain.pem
|
||||||
# ключ переименовать:
|
# ключ переименовать:
|
||||||
cp private.key privkey.pem
|
cp private.key privkey.pem
|
||||||
```
|
```
|
||||||
@@ -269,13 +269,13 @@ ssl_certificate_key /etc/ssl/sac/privkey.pem;
|
|||||||
sudo ln -sf /etc/nginx/sites-available/sac /etc/nginx/sites-enabled/sac
|
sudo ln -sf /etc/nginx/sites-available/sac /etc/nginx/sites-enabled/sac
|
||||||
sudo nginx -t
|
sudo nginx -t
|
||||||
sudo systemctl reload nginx
|
sudo systemctl reload nginx
|
||||||
curl -sS https://sac.example.com/health | jq .
|
curl -sS https://sac.kalinamall.ru/health | jq .
|
||||||
```
|
```
|
||||||
|
|
||||||
В приложении SAC (`/opt/security-alert-center/config/sac-api.env`):
|
В приложении SAC (`/opt/security-alert-center/config/sac-api.env`):
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
SAC_PUBLIC_URL=https://sac.example.com
|
SAC_PUBLIC_URL=https://sac.kalinamall.ru
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -45,7 +45,7 @@
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
API_KEY="sac_…"
|
API_KEY="sac_…"
|
||||||
BASE="https://sac.example.com"
|
BASE="https://sac.kalinamall.ru"
|
||||||
|
|
||||||
# warning → должен уйти в TG при min=warning
|
# warning → должен уйти в TG при min=warning
|
||||||
curl -sS -X POST "$BASE/api/v1/events" \
|
curl -sS -X POST "$BASE/api/v1/events" \
|
||||||
|
|||||||
@@ -84,5 +84,6 @@ UseSAC=exclusive→ только SAC ingest; TG/email = настройки SAC (
|
|||||||
|
|
||||||
- [TZ.md](TZ.md) §4.6 F-NOT-01 … F-NOT-05
|
- [TZ.md](TZ.md) §4.6 F-NOT-01 … F-NOT-05
|
||||||
- [agent-integration.md](agent-integration.md) — режимы UseSAC
|
- [agent-integration.md](agent-integration.md) — режимы UseSAC
|
||||||
|
- [agent-update-backlog.md](agent-update-backlog.md) — **ToDo:** версии агентов и удалённое обновление из SAC
|
||||||
- `backend/app/config.py` — `telegram_*`
|
- `backend/app/config.py` — `telegram_*`
|
||||||
- `backend/app/services/telegram_notify.py`
|
- `backend/app/services/telegram_notify.py`
|
||||||
|
|||||||
+4
-4
@@ -9,7 +9,7 @@
|
|||||||
| # | Задача | Статус |
|
| # | Задача | Статус |
|
||||||
|---|--------|--------|
|
|---|--------|--------|
|
||||||
| 0.1–0.3 | ТЗ, архитектура, схема, deployment | ✅ |
|
| 0.1–0.3 | ТЗ, архитектура, схема, deployment | ✅ |
|
||||||
| 0.5 | Репозиторий GitHub + prod deployment | ✅ |
|
| 0.5 | Репозиторий GitHub + зеркало kalinamall | ✅ |
|
||||||
| 0.6 | Multi-root workspace | ✅ |
|
| 0.6 | Multi-root workspace | ✅ |
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
|---|--------|--------|
|
|---|--------|--------|
|
||||||
| 1B.1 | Scaffold backend FastAPI | ✅ |
|
| 1B.1 | Scaffold backend FastAPI | ✅ |
|
||||||
| 1B.2 | PostgreSQL + Alembic (hosts, events, api_keys) | ✅ |
|
| 1B.2 | PostgreSQL + Alembic (hosts, events, api_keys) | ✅ |
|
||||||
| 1B.3 | `POST /api/v1/events`, `GET /health` | ✅ prod `sac.example.com` |
|
| 1B.3 | `POST /api/v1/events`, `GET /health` | ✅ prod `sac.kalinamall.ru` |
|
||||||
| 1B.4 | systemd + nginx + TLS | ✅ |
|
| 1B.4 | systemd + nginx + TLS | ✅ |
|
||||||
| 1B.5 | Валидация JSON Schema v1 | ✅ |
|
| 1B.5 | Валидация JSON Schema v1 | ✅ |
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@
|
|||||||
- [x] `d2-1` UI Problems: список, фильтры, `Ack/Resolve`, карточка с таймлайном
|
- [x] `d2-1` UI Problems: список, фильтры, `Ack/Resolve`, карточка с таймлайном
|
||||||
- [x] `d2-2` Dashboard: top hosts/types, `open vs resolved 24h`, drill-down
|
- [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] `d2-3` Ops: retention, health checks, runbook backup/restore/deploy
|
||||||
- [x] `dod` DoD: нет дублей `event_id`, Problems e2e, 3 правила, UI MVP, docs, push в prod
|
- [x] `dod` DoD: нет дублей `event_id`, Problems e2e, 3 правила, UI MVP, docs, push в kalinamall
|
||||||
|
|
||||||
### Отображение хостов (`display_name`, как `SERVER_DISPLAY_NAME` у ssh)
|
### Отображение хостов (`display_name`, как `SERVER_DISPLAY_NAME` у ssh)
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@
|
|||||||
- [x] `14:30–16:00` Dashboard: `open/resolved 24h` + drill-down
|
- [x] `14:30–16:00` Dashboard: `open/resolved 24h` + drill-down
|
||||||
- [x] `16:00–17:00` retention job (`events 30–90d`, `problems 180d+`)
|
- [x] `16:00–17:00` retention job (`events 30–90d`, `problems 180d+`)
|
||||||
- [x] `17:00–18:00` health checks (DB/worker/heartbeat stale)
|
- [x] `17:00–18:00` health checks (DB/worker/heartbeat stale)
|
||||||
- [x] `18:00–19:00` runbook + финальный push в prod + freeze dev
|
- [x] `18:00–19:00` runbook + финальный push в kalinamall + freeze dev
|
||||||
|
|
||||||
### Неделя после freeze (только тестирование)
|
### Неделя после freeze (только тестирование)
|
||||||
|
|
||||||
|
|||||||
@@ -6,22 +6,26 @@
|
|||||||
|
|
||||||
## 1. Расположение репозиториев (пример)
|
## 1. Расположение репозиториев (пример)
|
||||||
|
|
||||||
| Имя в workspace | Публичный remote |
|
| Имя в workspace | Путь (пример Windows) | Remote |
|
||||||
|-----------------|------------------|
|
|-----------------|----------------------|--------|
|
||||||
| `ssh-monitor` | github.com/PTah/ssh-monitor |
|
| `ssh-monitor` | `D:\Soft\Git\ssh-monitor` | git.kalinamall.ru/PapaTramp/ssh-monitor |
|
||||||
| `rdp-monitor` | github.com/PTah/RDP-login-monitor |
|
| `rdp-monitor` | `D:\Soft\Git\RDP-login-monitor` | git.kalinamall.ru/PapaTramp/RDP-login-monitor |
|
||||||
| `security-alert-center` | github.com/PTah/security-alert-center |
|
| `security-alert-center` | `D:\Soft\Git\security-alert-center` | git.kalinamall.ru/PapaTramp/security-alert-center |
|
||||||
|
|
||||||
|
Пути подставьте свои.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. Файл workspace
|
## 2. Файл workspace
|
||||||
|
|
||||||
|
Создайте `security-monitors.code-workspace`:
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"folders": [
|
"folders": [
|
||||||
{ "path": "ssh-monitor", "name": "ssh-monitor" },
|
{ "path": "D:/Soft/Git/ssh-monitor", "name": "ssh-monitor" },
|
||||||
{ "path": "RDP-login-monitor", "name": "rdp-monitor" },
|
{ "path": "D:/Soft/Git/RDP-login-monitor", "name": "rdp-monitor" },
|
||||||
{ "path": "security-alert-center", "name": "security-alert-center" }
|
{ "path": "D:/Soft/Git/security-alert-center", "name": "security-alert-center" }
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"files.eol": "\n"
|
"files.eol": "\n"
|
||||||
@@ -29,22 +33,44 @@
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Открыть: **File → Open Workspace from File**.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Соглашения
|
## 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` — **единственный источник истины**.
|
- Контракт событий: `security-alert-center/schemas/event-schema-v1.json` — **единственный источник истины**.
|
||||||
- Изменение схемы → обновить ТЗ + версию `schema_version` + оба агента.
|
- Изменение схемы → обновить ТЗ + версию `schema_version` + оба агента.
|
||||||
- Коммиты в три репо **раздельные**; связь через теги/версии в README.
|
- Коммиты в три репо **раздельные**; связь через теги/версии в README (см. [roadmap.md](roadmap.md)).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/PTah/security-alert-center.git
|
git add …
|
||||||
git clone https://github.com/PTah/ssh-monitor.git
|
git commit -m "…"
|
||||||
git clone https://github.com/PTah/RDP-login-monitor.git
|
git push kalinamall main
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 5. URL репозиториев
|
||||||
|
|
||||||
|
| Проект | URL |
|
||||||
|
|--------|-----|
|
||||||
|
| security-alert-center | `https://git.kalinamall.ru/PapaTramp/security-alert-center.git` |
|
||||||
|
| ssh-monitor | `https://git.kalinamall.ru/PapaTramp/ssh-monitor.git` |
|
||||||
|
| RDP-login-monitor | `https://git.kalinamall.ru/PapaTramp/RDP-login-monitor.git` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## См. также
|
## См. также
|
||||||
|
|
||||||
- [work-plan.md](work-plan.md)
|
- [work-plan.md](work-plan.md) фаза 0.6
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/** Fallback до загрузки /health; при релизе держите в sync с backend/app/version.py */
|
/** Fallback до загрузки /health; при релизе держите в sync с backend/app/version.py */
|
||||||
export const APP_NAME = "Security Alert Center";
|
export const APP_NAME = "Security Alert Center";
|
||||||
export const APP_VERSION = "0.9.10";
|
export const APP_VERSION = "0.9.11";
|
||||||
export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`;
|
export const APP_VERSION_LABEL = `${APP_NAME} v.${APP_VERSION}`;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "https://github.com/PTah/security-alert-center/schemas/event-v1.json",
|
"$id": "https://git.kalinamall.ru/PapaTramp/security-alert-center/schemas/event-v1.json",
|
||||||
"title": "Security Alert Center Event v1",
|
"title": "Security Alert Center Event v1",
|
||||||
"description": "Каноническое событие от ssh-monitor или RDP-login-monitor",
|
"description": "Каноническое событие от ssh-monitor или RDP-login-monitor",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
|||||||
Reference in New Issue
Block a user