Files
security-alert-center/backend/app/config.py
T
PTah b148b558c3 feat: ingest burst hardening — defer lifecycle/auth, workers, nginx (v0.5.5)
Defer notify_lifecycle and notify_auth_login after commit; SAC_UVICORN_WORKERS via sac-api-start.sh; nginx /api/v1/events timeout; mass-update confirm in Hosts UI.
2026-07-08 13:16:13 +10:00

171 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
from functools import lru_cache
from pathlib import Path
from pydantic_settings import BaseSettings, SettingsConfigDict
ROOT = Path(__file__).resolve().parents[2]
SCHEMA_PATH = ROOT / "schemas" / "event-schema-v1.json"
DEFAULT_CONFIG_FILE = Path("/opt/security-alert-center/config/sac-api.env")
def _resolve_config_files() -> tuple[str, ...]:
"""Файлы конфигурации для pydantic (корректный разбор кавычек и URL)."""
candidates: list[Path] = []
explicit = os.environ.get("SAC_CONFIG_FILE", "").strip()
if explicit:
candidates.append(Path(explicit))
else:
candidates.append(DEFAULT_CONFIG_FILE)
candidates.append(Path(".env"))
return tuple(str(p) for p in candidates if p.is_file())
def _settings_config() -> SettingsConfigDict:
files = _resolve_config_files()
return SettingsConfigDict(
env_file=files if files else None,
env_file_encoding="utf-8",
extra="ignore",
)
class Settings(BaseSettings):
model_config = _settings_config()
database_url: str = "postgresql+psycopg2://sac:sac@localhost:5432/sac"
sac_db_pool_size: int = 15
sac_db_max_overflow: int = 25
sac_uvicorn_workers: int = 4
sac_public_url: str = "http://localhost:8000"
# URL для скачивания RDP bundle с ПК (WinRM). По умолчанию = SAC_PUBLIC_URL.
sac_agent_bundle_base_url: str = ""
jwt_secret: str = "change-me-in-production"
jwt_algorithm: str = "HS256"
jwt_expire_minutes: int = 60 * 24
# Fail-fast on weak JWT/CORS defaults (disable only for local dev/tests).
sac_security_enforce: bool = True
sac_ingest_max_body_bytes: int = 2_097_152
sac_bootstrap_api_key: str = ""
sac_admin_username: str = "admin"
sac_admin_password: str = ""
event_schema_path: str = str(SCHEMA_PATH)
cors_origins: str = "*"
telegram_enabled: bool = False
telegram_bot_token: str = ""
telegram_chat_id: str = ""
telegram_min_severity: str = "high"
webhook_enabled: bool = False
webhook_url: str = ""
webhook_secret_header: str = ""
webhook_secret: str = ""
webhook_min_severity: str = "high"
smtp_enabled: bool = False
smtp_host: str = ""
smtp_port: int = 587
smtp_user: str = ""
smtp_password: str = ""
smtp_from: str = ""
smtp_to: str = ""
smtp_starttls: bool = True
smtp_ssl: bool = False
smtp_min_severity: str = "high"
notify_min_severity: str = "warning"
notify_channels: str = "telegram,webhook,email"
# F-NOT-03: cooldown исходящих оповещений (dedup_key / fingerprint)
sac_notify_cooldown_enabled: bool = True
sac_notify_event_cooldown_sec: int = 90
sac_notify_problem_cooldown_sec: int = 300
# F-NOT-05: суточные отчёты из агрегации событий SAC (для exclusive / без отчёта агента)
sac_daily_report_enabled: bool = True
sac_daily_report_hour: int = 9
sac_daily_report_timezone: str = "Europe/Moscow"
sac_daily_report_skip_if_agent_sent: bool = True
sac_daily_report_require_activity: bool = True
# Порог «живости» агента
sac_heartbeat_stale_minutes: int = 300
# Периодическое сканирование stale heartbeat (proactive host_silence)
sac_host_silence_scan_enabled: bool = True
sac_host_silence_scan_interval_minutes: int = 5
# После ручного закрытия host_silence не открывать снова раньше N часов (auto-close по heartbeat — без паузы).
sac_host_silence_manual_resolve_cooldown_hours: int = 12
# Окно корреляции Problems: host + type + rule в одном open Problem
sac_problem_correlation_window_minutes: int = 60
# rule:brute_force_burst — ssh.login.failed / rdp.login.failed
sac_brute_force_window_minutes: int = 15
sac_brute_force_threshold: int = 30
# rule:privilege_spike — privilege.sudo.command
sac_privilege_spike_window_minutes: int = 10
sac_privilege_spike_threshold: int = 10
# rule:rdg_session_flap — RD Gateway 302→303 within window
sac_rdg_flap_window_min_sec: int = 1
sac_rdg_flap_window_max_sec: int = 10
sac_rdg_flap_dedup_sec: int = 30
# Внешние IP HAProxy/RDG-прокси: если external_ip в списке — путь Haproxy-RDG-Comp, иначе RDG-Comp
sac_rdg_haproxy_external_ips: str = ""
# Windows admin for agent qwinsta/logoff (domain-wide)
sac_win_admin_user: str = ""
sac_win_admin_password: str = ""
sac_winrm_use_https: bool = False
sac_winrm_server_cert_validation: str = "validate"
# Linux SSH admin for remote agent update (fallback SSH, phase 5)
sac_linux_admin_user: str = ""
sac_linux_admin_password: str = ""
sac_ssh_known_hosts_file: str = "/opt/security-alert-center/config/ssh_known_hosts"
sac_ssh_auto_add_host_key: bool = False
# Agent updates (mode gpo|sac, recommended versions, WinRM fallback script)
sac_agent_update_mode: str = "gpo"
sac_agent_update_fallback_enabled: bool = True
sac_agent_update_fallback_minutes: int = 15
sac_agent_recommended_rdp_version: str = ""
sac_agent_recommended_ssh_version: str = ""
sac_agent_min_rdp_version: str = ""
sac_agent_min_ssh_version: str = ""
sac_win_agent_update_script: str = ""
sac_agent_rdp_git_repo_url: str = "https://git.kalinamall.ru/PapaTramp/RDP-login-monitor.git"
sac_agent_ssh_git_repo_url: str = "https://git.kalinamall.ru/PapaTramp/ssh-monitor.git"
sac_agent_git_branch: str = "main"
sac_agent_git_cache_dir: str = "/opt/security-alert-center/cache/agent-repos"
sac_agent_git_cache_ttl_minutes: int = 30
sac_agent_git_token: str = ""
# Retention (app.jobs.retention / systemd timer)
sac_events_retention_days: int = 90
sac_problems_retention_days: int = 180
# UI login brute-force protection
sac_login_max_failures: int = 3
sac_login_failure_window_minutes: int = 15
sac_login_alert_telegram: bool = True
sac_login_ip_whitelist: str = ""
sac_fail2ban_ssh_jail: str = "sshd"
sac_fail2ban_sync_enabled: bool = False
sac_fail2ban_ignoreip_file: str = "/etc/fail2ban/jail.d/sac-login-whitelist.local"
# Seaca mobile (FCM push)
sac_fcm_enabled: bool = False
sac_fcm_project_id: str = ""
sac_fcm_service_account_json: str = ""
sac_mobile_refresh_expire_days: int = 90
@lru_cache
def get_settings() -> Settings:
return Settings()