# Автообновление ssh-monitor Скрипт **`update_ssh_monitor.sh`** обновляет **`/usr/local/bin/ssh-monitor`** из git и перезапускает systemd-сервис. ## Основной путь: Security Alert Center На продакшен-хостах обновление идёт **через SAC**, без cron: 1. Админ нажимает **«Обновить ssh-monitor (SSH)»** в карточке хоста. 2. SAC по SSH запускает `/opt/scripts/update_ssh_monitor.sh` с `REPO_URL` / `GIT_BRANCH` из **Настройки → Обновления агентов**. 3. Updater сам выполняет `git pull`, синхронизирует `sac-client.sh` и watchdog, дописывает отсутствующие ключи в **`/etc/ssh-monitor.conf`**, **выставляет `chmod`/`chown`** на конфиг, SAC-spool, счётчики и state-файлы, перезапускает **`ssh-monitor.service`**. Участие админа на сервере **не требуется** (кроме первичной настройки `SAC_URL` / `SAC_API_KEY` в конфиге). При **первой установке** (нет updater на хосте) SAC выполняет bootstrap с **`--deploy`**: clone, ipset при необходимости, systemd unit, полный hardening. **Cron / systemd timer** — опциональная альтернатива с тем же скриптом и обязательным `REPO_URL` в окружении. Watchdog и таймеры watchdog **не изменяются** при обычном update (кроме синхронизации скрипта watchdog из git). **Конфиг `/etc/ssh-monitor.conf`:** при первой установке копируется из `ssh-monitor.conf.example`. При каждом update в **существующий** конфиг **дописываются** отсутствующие SAC-переменные и ключи безопасности; **`UseSAC=fallback`**. Telegram/SMTP и прочие ключи **не перезаписываются**. Установка монитора и unit-файлов: [README.md](../README.md), зависимости: [install-prerequisites.ru.md](install-prerequisites.ru.md). ## Что делает скрипт 1. Создаёт рабочий каталог **`UPDATE_DIR`** (по умолчанию `/opt/scripts/update`). 2. При **`--deploy`** / bootstrap SAC проверяет **`ipset`** и при отсутствии пытается установить через пакетный менеджер. Обычное обновление **не** вызывает `apt-get`. 3. В **`UPDATE_DIR`** выполняет **`git clone`** или **`git fetch` + checkout / `git pull --ff-only`** (без слепого `reset --hard`). 4. Проверяет **`release/manifest-VERSION.json`** (SHA256 файлов + commit) **до** копирования в `/usr/local/bin`. 5. Ищет **`ssh-monitor`** в клоне (GitLab layout или плоский репозиторий). 6. Сравнивает **SHA256** с **`LOCAL_SCRIPT_PATH`** (`/usr/local/bin/ssh-monitor`). 7. **Всегда** синхронизирует **`sac-client.sh`**, **`ssh-monitor-perms.sh`**, watchdog. 8. Дописывает ключи конфига; **`apply_runtime_security_hardening`**: `chmod 600` конфиг, `700` spool, `600` state/SAC-файлы, whitelist. 9. При изменении **`ssh-monitor`**, **`sac-client.sh`** или конфига — **`systemctl restart ssh-monitor.service`**. 10. Лог: **`/var/log/update_script.log`** (блок «Итог обновления», строки `manifest` и `security hardening`). ```mermaid flowchart LR A[SAC или cron] --> B[update_ssh_monitor.sh] B --> C[git fetch/checkout] C --> M{manifest OK?} M -->|нет| X[exit 1] M -->|да/skip| D[sync sac-client + perms lib] C --> E{SHA256 ssh-monitor?} D --> F[harden config/spool/state] E -->|да| G[backup + cp ssh-monitor] E -->|нет| F G --> F F --> H{что-то изменилось?} H -->|да| I[restart ssh-monitor.service] H -->|нет| J[без перезапуска] ``` ## Настройка перед первым запуском | Переменная | По умолчанию | Назначение | |------------|--------------|------------| | `UPDATE_DIR` | `/opt/scripts/update` | Каталог для git-клона | | `REPO_URL` | *(обязательно)* | URL git — задаётся SAC, export или `Environment=` в cron | | `GIT_BRANCH` | `main` | Ветка для clone/pull, если **`GIT_REF`** не задан | | `GIT_REF` | *(пусто)* | Тег (`2.2.0-SAC`), ветка или commit SHA для checkout | | `GIT_VERIFY_MODE` | `off` | `off` \| `tag` \| `commit` — см. раздел ниже | | `GIT_ALLOW_RESET` | `0` | `1` = разрешить `git reset --hard` при расхождении истории (риск) | | `RELEASE_MANIFEST_STRICT` | `0` | `1` = exit 1, если manifest для версии не найден | | `LOCAL_SCRIPT_PATH` | `/usr/local/bin/ssh-monitor` | Куда копировать монитор | | `LOG_FILE` | `/var/log/update_script.log` | Лог обновлений | | `UPDATE_VIA_SAC` | *(опционально)* | SAC выставляет `1`; при отсутствии бинарника включается `--deploy` | Требования: **root**, **git**, **python3** (manifest verify), доступ к репозиторию. ## Pinned ref и manifest (2.2.0+) Updater читает **`GIT_REF`**, **`GIT_VERIFY_MODE`**, **`GIT_ALLOW_RESET`** из env или `/etc/ssh-monitor.conf`. ### Режимы `GIT_VERIFY_MODE` | Режим | Поведение | Когда | |-------|-----------|-------| | **`off`** | После fetch принять ref как есть | Тест, legacy; дефолт в скрипте | | **`tag`** | `GIT_REF` должен существовать как тег | **Рекомендуется для прода** | | **`commit`** | `GIT_REF` = полный SHA commit | Жёсткий pin без тегов | Если **`GIT_REF`** пуст, используется **`GIT_BRANCH`** (`git pull --ff-only`). При невозможности fast-forward updater **не** делает `reset --hard` (только с **`GIT_ALLOW_RESET=1`**). ### Release manifest В репозитории: **`release/manifest-VERSION.json`** — SHA256 ключевых файлов и `git_commit`. Updater сверяет manifest **после** git sync и **до** копирования бинарников. - Файл найден и hash не совпал → **exit 1**, ничего не перезаписывается. - Файл не найден → WARN, update продолжается (или exit 1 при **`RELEASE_MANIFEST_STRICT=1`**). - Копирование **`update_ssh_monitor.sh`** в `/opt/scripts/` и re-exec — только если manifest для версии был и прошёл verify. Генерация при релизе (хеши **из git**, как на Linux после `checkout` — не с диска Windows): ```bash git add --renormalize ssh-monitor *.sh # при смене .gitattributes ./scripts/build-release-manifest.sh 2.2.2-SAC git add release/manifest-2.2.2-SAC.json && git commit -m "release: manifest 2.2.2-SAC" git tag 2.2.2-SAC ``` ### Примеры для прода **SAC / env на хосте** (через настройки SAC или unit): ```bash REPO_URL=https://git.kalinamall.ru/PapaTramp/ssh-monitor.git GIT_REF=2.2.0-SAC GIT_VERIFY_MODE=tag ``` **systemd timer** (`/etc/systemd/system/ssh-monitor-update.service`): ```ini [Service] Type=oneshot Environment=REPO_URL=https://git.kalinamall.ru/PapaTramp/ssh-monitor.git Environment=GIT_REF=2.2.0-SAC Environment=GIT_VERIFY_MODE=tag ExecStart=/opt/scripts/update_ssh_monitor.sh ``` При доверенном закрытом зеркале **manifest + `GIT_REF=tag`** — достаточный минимум; GPG-подписи тегов — backlog (см. [security-roadmap.ru.md](security-roadmap.ru.md)). ## Первичная установка (--deploy) ```bash sudo REPO_URL=https://git.kalinamall.ru/PapaTramp/ssh-monitor.git ./update_ssh_monitor.sh --deploy # или first_deploy.sh с REPO_URL в окружении ``` Через SAC bootstrap выполняется автоматически с **`--deploy`**. ## Установка updater (если не через SAC bootstrap) ```bash sudo mkdir -p /opt/scripts sudo cp update_ssh_monitor.sh /opt/scripts/update_ssh_monitor.sh sudo chmod 750 /opt/scripts/update_ssh_monitor.sh ``` Проверка: ```bash sudo REPO_URL=https://git.kalinamall.ru/PapaTramp/ssh-monitor.git /opt/scripts/update_ssh_monitor.sh sudo tail -30 /var/log/update_script.log ``` ## Запуск по расписанию (опционально) ### Cron ``` 0 4 * * * REPO_URL=https://git.kalinamall.ru/PapaTramp/ssh-monitor.git /opt/scripts/update_ssh_monitor.sh ``` ### systemd timer См. предыдущие примеры `ssh-monitor-update.service` / `.timer` с `Environment=REPO_URL=...`. ## Откат ```bash ls -la /usr/local/bin/ssh-monitor.backup.* sudo cp /usr/local/bin/ssh-monitor.backup.YYYYMMDD_HHMMSS /usr/local/bin/ssh-monitor sudo systemctl restart ssh-monitor.service ``` ## Ограничения - Секреты (`SAC_API_KEY`, Telegram) SAC **не** прописывает — только в `/etc/ssh-monitor.conf` на хосте. - При недоступном git **`git pull`** пишет предупреждение и продолжает с локальной копией. - **`REPO_URL`** без дефолта в скрипте — только доверенное зеркало (kalinamall / своё Gitea).