diff --git a/docs/auto-update.ru.md b/docs/auto-update.ru.md index 79376e2..f7a1b9d 100644 --- a/docs/auto-update.ru.md +++ b/docs/auto-update.ru.md @@ -1,6 +1,8 @@ # Автообновление ssh-monitor -Скрипт **`update_ssh_monitor.sh`** в корне репозитория обновляет установленный **`/usr/local/bin/ssh-monitor`** из git-репозитория и перезапускает systemd-сервис. Конфиг **`/etc/ssh-monitor.conf`**, watchdog и таймеры **не изменяются**. +Скрипт **`update_ssh_monitor.sh`** в корне репозитория обновляет установленный **`/usr/local/bin/ssh-monitor`** из git-репозитория и перезапускает systemd-сервис. Watchdog и таймеры **не изменяются**. + +**Конфиг `/etc/ssh-monitor.conf`:** при первой установке копируется из `ssh-monitor.conf.example`. При каждом deploy/обновлении в **существующий** конфиг **дописываются** отсутствующие SAC-переменные (`UseSAC`, `SAC_URL`, `SAC_API_KEY`, spool, timeout и т.д.) и выставляется **`UseSAC=fallback`**. Telegram/SMTP и прочие ключи **не перезаписываются**. Установка самого монитора и unit-файлов: [README.md](../README.md), зависимости: [install-prerequisites.ru.md](install-prerequisites.ru.md). diff --git a/ssh-monitor b/ssh-monitor index d2540ab..79249a9 100644 --- a/ssh-monitor +++ b/ssh-monitor @@ -7,7 +7,7 @@ IFS=$'\n\t' # ============================================ CONFIG_FILE="/etc/ssh-monitor.conf" -SSH_MONITOR_VERSION="2.1.1-SAC" +SSH_MONITOR_VERSION="2.1.2-SAC" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [ -f "$SCRIPT_DIR/sac-client.sh" ]; then diff --git a/update_ssh_monitor.sh b/update_ssh_monitor.sh index 9cd7af5..b77c142 100755 --- a/update_ssh_monitor.sh +++ b/update_ssh_monitor.sh @@ -74,11 +74,24 @@ update_ssh_monitor.sh — обновление или первичная уст Лог действий: /var/log/update_script.log (в конце каждого прогона — блок «Итог обновления»). -При первой установке или апгрейде с UseSAC=off / пустым SAC_API_KEY / без sac-client.sh -example из git перезаписывает /etc/ssh-monitor.conf (старый файл — .bak.*). +При первой установке создаётся /etc/ssh-monitor.conf из example. +При обновлении в существующий конфиг дописываются отсутствующие SAC-переменные +и выставляется UseSAC=fallback (Telegram/SMTP не перезаписываются). EOF } +# Ключи SAC: дописываются из ssh-monitor.conf.example, если отсутствуют в /etc. +SAC_CONFIG_KEYS=( + UseSAC + SAC_URL + SAC_API_KEY + SAC_SPOOL_DIR + SAC_FAIL_COUNT_FILE + SAC_FALLBACK_FAILURES + SAC_TIMEOUT_SEC +) +SAC_USE_MODE_DEFAULT="fallback" + find_ssh_monitor_conf_example() { local example="$UPDATE_DIR/$SCRIPT_NAME/ssh-monitor.conf.example" if [ -f "$example" ]; then @@ -102,28 +115,20 @@ config_conf_value() { printf '%s\n' "$val" } -config_needs_sac_bootstrap() { - local sac_client use_sac api_key - - sac_client="${LOCAL_SCRIPT_PATH%/*}/sac-client.sh" - if [ ! -f "$sac_client" ]; then - return 0 - fi - if [ ! -f "$CONFIG_FILE" ]; then - return 0 - fi - - use_sac=$(config_conf_value "UseSAC" "$CONFIG_FILE" 2>/dev/null || true) - api_key=$(config_conf_value "SAC_API_KEY" "$CONFIG_FILE" 2>/dev/null || true) - - if [ -n "$use_sac" ] && [ "$use_sac" != "off" ] \ - && [ -n "$api_key" ] && [ "${api_key#sac_}" != "$api_key" ]; then - return 1 - fi - return 0 +config_example_value() { + local key="$1" example="$2" + config_conf_value "$key" "$example" 2>/dev/null || true } -ensure_ssh_monitor_config_from_example() { +backup_config_if_needed() { + local file="$1" flag_var="$2" + if [ -z "${!flag_var:-}" ] || [ "${!flag_var}" -eq 0 ]; then + cp "$file" "${file}.bak.$(date +%Y%m%d_%H%M%S)" 2>/dev/null || true + printf -v "$flag_var" '%s' 1 + fi +} + +ensure_ssh_monitor_config_file() { local example CONFIG_CHANGED=0 @@ -132,27 +137,17 @@ ensure_ssh_monitor_config_from_example() { return 0 } - if [ -f "$CONFIG_FILE" ] && ! config_needs_sac_bootstrap; then - log_message "INFO" "Config $CONFIG_FILE: SAC already configured, not overwriting." + if [ -f "$CONFIG_FILE" ]; then if [ "$DEPLOY_MODE" -eq 1 ]; then - say_info "Уже существует: $CONFIG_FILE (SAC настроен, не перезаписываем)" + say_info "Уже существует: $CONFIG_FILE (дополним SAC-переменные при необходимости)" fi return 0 fi - if [ -f "$CONFIG_FILE" ]; then - cp "$CONFIG_FILE" "${CONFIG_FILE}.bak.$(date +%Y%m%d_%H%M%S)" 2>/dev/null || true - log_message "INFO" "Upgrading config without SAC: backup created, applying ssh-monitor.conf.example from git." - if [ "$DEPLOY_MODE" -eq 1 ]; then - say_info "Апгрейд без SAC: резервная копия, применяем example (Telegram + fallback)." - fi - else - log_message "INFO" "Creating $CONFIG_FILE from ssh-monitor.conf.example" - if [ "$DEPLOY_MODE" -eq 1 ]; then - say_ok "Создан $CONFIG_FILE из ssh-monitor.conf.example" - fi + log_message "INFO" "Creating $CONFIG_FILE from ssh-monitor.conf.example" + if [ "$DEPLOY_MODE" -eq 1 ]; then + say_ok "Создан $CONFIG_FILE из ssh-monitor.conf.example" fi - if ! cp "$example" "$CONFIG_FILE"; then log_message "INFO" "ERROR: Failed to copy ssh-monitor.conf.example to $CONFIG_FILE" return 1 @@ -162,6 +157,72 @@ ensure_ssh_monitor_config_from_example() { return 0 } +sync_sac_config_keys() { + local file="$CONFIG_FILE" + local example backed_up=0 + local key val current changed=0 added=0 + + [ -f "$file" ] || return 1 + example=$(find_ssh_monitor_conf_example) || { + log_message "INFO" "WARNING: ssh-monitor.conf.example not found; SAC merge skipped" + return 0 + } + + if ! config_key_exists "UseSAC" "$file"; then + backup_config_if_needed "$file" backed_up + { + printf '\n# --- Security Alert Center (SAC) ---\n' + printf '# off | exclusive | dual | fallback — см. security-alert-center docs/agent-integration.md\n' + } >>"$file" + log_message "INFO" "Config $file: добавлен блок SAC (ключи отсутствовали)." + changed=1 + fi + + for key in "${SAC_CONFIG_KEYS[@]}"; do + if config_key_exists "$key" "$file"; then + continue + fi + val=$(config_example_value "$key" "$example") + if [ -z "$val" ] && [ "$key" != "SAC_API_KEY" ]; then + case "$key" in + UseSAC) val="$SAC_USE_MODE_DEFAULT" ;; + SAC_SPOOL_DIR) val="$SAC_SPOOL_DIR_DEFAULT" ;; + SAC_FAIL_COUNT_FILE) val="/var/lib/ssh-monitor/sac-fail.count" ;; + SAC_FALLBACK_FAILURES) val="5" ;; + SAC_TIMEOUT_SEC) val="12" ;; + SAC_URL) val="https://sac.kalinamall.ru" ;; + esac + fi + backup_config_if_needed "$file" backed_up + set_config_kv "$key" "$val" "$file" + log_message "INFO" "Config $file: добавлен ${key}=${val:-<пусто>}" + changed=1 + added=$((added + 1)) + done + + current=$(config_conf_value "UseSAC" "$file" 2>/dev/null || true) + if [ "$current" != "$SAC_USE_MODE_DEFAULT" ]; then + backup_config_if_needed "$file" backed_up + set_config_kv "UseSAC" "$SAC_USE_MODE_DEFAULT" "$file" + log_message "INFO" "Config $file: UseSAC ${current:-<нет>} → $SAC_USE_MODE_DEFAULT (deploy policy)." + changed=1 + fi + + if [ "$changed" -eq 0 ]; then + return 1 + fi + + if [ "$DEPLOY_MODE" -eq 1 ]; then + if [ "$added" -gt 0 ]; then + say_info "SAC: добавлено ключей — $added; UseSAC=$SAC_USE_MODE_DEFAULT." + else + say_info "SAC: UseSAC=$SAC_USE_MODE_DEFAULT." + fi + fi + CONFIG_CHANGED=1 + return 0 +} + set_config_kv() { local key="$1" val="$2" file="$3" if grep -qE "^[[:space:]]*${key}=" "$file" 2>/dev/null; then @@ -247,25 +308,6 @@ sync_heartbeat_interval_config() { return 0 } -sync_use_sac_fallback_mode() { - local file="$CONFIG_FILE" - [ -f "$file" ] || return 1 - if grep -qE '^[[:space:]]*UseSAC=[[:space:]]*["'"'"']?fallback["'"'"']?[[:space:]]*(#.*)?$' "$file" 2>/dev/null; then - return 1 - fi - if ! grep -qE '^[[:space:]]*UseSAC=' "$file" 2>/dev/null; then - return 1 - fi - cp "$file" "${file}.bak.$(date +%Y%m%d_%H%M%S)" 2>/dev/null || true - sed -i -E 's/^[[:space:]]*UseSAC=.*/UseSAC="fallback"/' "$file" - log_message "INFO" "Config $file: UseSAC set to fallback (deploy policy on script upgrade)." - if [ "$DEPLOY_MODE" -eq 1 ]; then - say_info "UseSAC=fallback (рабочий режим SAC + локальный fallback)." - fi - CONFIG_CHANGED=1 - return 0 -} - parse_command_line() { DEPLOY_MODE=0 while [ $# -gt 0 ]; do @@ -759,7 +801,9 @@ deploy_prepare_dirs() { deploy_install_config() { say_step "Конфигурация" - ensure_ssh_monitor_config_from_example || return 1 + ensure_ssh_monitor_config_file || return 1 + sync_sac_config_keys || true + sync_heartbeat_interval_config || true } deploy_install_systemd() { @@ -1103,14 +1147,20 @@ update_script() { fi CONFIG_CHANGED=0 - if ! ensure_ssh_monitor_config_from_example; then + if ! ensure_ssh_monitor_config_file; then log_update_summary return 1 fi - if [ "${CONFIG_CHANGED:-0}" -eq 1 ]; then - SUMMARY_CONFIG="обновлён из example" + if sync_sac_config_keys; then + SUMMARY_CONFIG="SAC-ключи дополнены, UseSAC=fallback" else - SUMMARY_CONFIG="без изменений" + SUMMARY_CONFIG="SAC без изменений" + fi + sync_heartbeat_interval_config || true + if [ "${CONFIG_CHANGED:-0}" -eq 1 ] && [ "$SUMMARY_CONFIG" = "SAC без изменений" ]; then + SUMMARY_CONFIG="heartbeat/watchdog выровнены" + elif [ "${CONFIG_CHANGED:-0}" -eq 1 ] && [ "$SUMMARY_CONFIG" != "SAC без изменений" ]; then + SUMMARY_CONFIG="${SUMMARY_CONFIG}; heartbeat при необходимости" fi if [ -n "$actual_script_path" ] && [ -f "$actual_script_path" ]; then @@ -1175,12 +1225,6 @@ update_script() { script_changed=1 fi - if [ "$script_changed" -eq 1 ]; then - sync_use_sac_fallback_mode || true - fi - # Выравнивать интервал heartbeat при каждом deploy, даже если бинарник не менялся. - sync_heartbeat_interval_config || true - if [ "$script_changed" -eq 1 ] || [ "${SAC_CLIENT_CHANGED:-0}" -eq 1 ] || [ "${CONFIG_CHANGED:-0}" -eq 1 ]; then restart_ssh_monitor_service else diff --git a/version.txt b/version.txt index ba0e30e..975d4d4 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.1.1-SAC +2.1.2-SAC