From c50bd6e9d814c04dfebce4a3ae661c06d1ecff29 Mon Sep 17 00:00:00 2001 From: PTah Date: Sat, 25 Jul 2026 13:20:05 +1000 Subject: [PATCH] fix: never chmod 700 system dirs like /var/log (2.3.3-SAC) Hardening state files under /var/log was applying chmod 700 to the parent directory, which broke syslog/logrotate and other services after agent update. --- README.md | 2 +- contrib/test-system-dir-hardening.sh | 50 ++++++++++++++++++++++++++++ docs/auto-update.ru.md | 2 +- docs/security-roadmap.ru.md | 1 + release/manifest-2.3.3-SAC.json | 11 ++++++ ssh-monitor | 2 +- ssh-monitor-perms.sh | 27 ++++++++++++++- version.txt | 2 +- 8 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 contrib/test-system-dir-hardening.sh create mode 100644 release/manifest-2.3.3-SAC.json diff --git a/README.md b/README.md index a99eddd..a910f5e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ssh-monitor -**Версия:** `2.3.0-SAC` +**Версия:** `2.3.3-SAC` Bash-мониторинг **SSH**, **sudo**, **systemd-logind**: Telegram/email, бан IP (ipset), ежедневный отчёт, heartbeat. diff --git a/contrib/test-system-dir-hardening.sh b/contrib/test-system-dir-hardening.sh new file mode 100644 index 0000000..d1b98f7 --- /dev/null +++ b/contrib/test-system-dir-hardening.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# Smoke-test: hardening must not chmod system dirs like /var/log. +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +# shellcheck source=/dev/null +source "$ROOT/ssh-monitor-perms.sh" + +fail=0 +assert_true() { + if "$@"; then + return 0 + fi + printf 'FAIL: expected true: %s\n' "$*" >&2 + fail=1 +} +assert_false() { + if "$@"; then + printf 'FAIL: expected false: %s\n' "$*" >&2 + fail=1 + return 0 + fi + return 0 +} + +assert_true ssh_monitor_is_system_dir /var/log +assert_true ssh_monitor_is_system_dir /var/log/ +assert_true ssh_monitor_is_system_dir /etc +assert_true ssh_monitor_is_system_dir /var +assert_true ssh_monitor_is_system_dir / +assert_false ssh_monitor_is_system_dir /var/lib/ssh-monitor +assert_false ssh_monitor_is_system_dir /var/lib/ssh-monitor/sac-spool + +tmpdir="$(mktemp -d)" +trap 'rm -rf "$tmpdir"' EXIT +# Private dir still gets 700 (на настоящем Linux; в Git Bash/Windows mode может не примениться) +ssh_monitor_secure_dir "$tmpdir/owned" +mode="$(stat -c '%a' "$tmpdir/owned" 2>/dev/null || stat -f '%OLp' "$tmpdir/owned" 2>/dev/null || echo "")" +if [ -n "$mode" ] && [ "$mode" != "700" ] && [ "$mode" != "0700" ]; then + if [[ "$(uname -s 2>/dev/null || true)" == Linux ]]; then + printf 'FAIL: owned dir mode=%s (want 700)\n' "$mode" >&2 + fail=1 + else + printf 'WARN: skip mode assert on non-Linux (mode=%s)\n' "$mode" >&2 + fi +fi + +if [ "$fail" -ne 0 ]; then + exit 1 +fi +printf 'OK: system-dir hardening guards\n' diff --git a/docs/auto-update.ru.md b/docs/auto-update.ru.md index b15ae36..5a49430 100644 --- a/docs/auto-update.ru.md +++ b/docs/auto-update.ru.md @@ -31,7 +31,7 @@ Watchdog и таймеры watchdog **не изменяются** при обы 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. +8. Дописывает ключи конфига; **`apply_runtime_security_hardening`**: `chmod 600` конфиг, `700` spool (`/var/lib/ssh-monitor`), `600` state/SAC-файлы (в т.ч. под `/var/log/` **без** `chmod` на сам `/var/log`), whitelist. 9. При изменении **`ssh-monitor`**, **`sac-client.sh`** или конфига — **`systemctl restart ssh-monitor.service`**. 10. Лог: **`/var/log/update_script.log`** (блок «Итог обновления», строки `manifest` и `security hardening`). diff --git a/docs/security-roadmap.ru.md b/docs/security-roadmap.ru.md index 8cc15cc..147e210 100644 --- a/docs/security-roadmap.ru.md +++ b/docs/security-roadmap.ru.md @@ -44,6 +44,7 @@ Backlog по ingest при массовом update (SAC + ops): [ingest-mass-upd ### 1.1 Права на state / spool (M4) - [x] При создании каталогов и файлов состояния: `chown root:root`, каталоги `chmod 700`, файлы `chmod 600` +- [x] **2.3.3:** не делать `chmod 700` на системные каталоги (`/var/log`, `/etc`, …) при hardening файлов вроде `/var/log/last_heartbeat.txt` - [x] Затронуть: `SAC_SPOOL_DIR`, `SAC_FAIL_COUNT_FILE`, heartbeat / last_* (где создаёт `ssh-monitor` / `sac-client.sh` / deploy) - [x] **2.1.8:** `update_ssh_monitor.sh` → `apply_runtime_security_hardening` на **каждом** update (SAC, cron, вручную): retrofit `chmod`/`chown` существующих путей из конфига - [x] В `--check-config`: предупреждение, если существующие пути с ослабленными правами diff --git a/release/manifest-2.3.3-SAC.json b/release/manifest-2.3.3-SAC.json new file mode 100644 index 0000000..d2ac352 --- /dev/null +++ b/release/manifest-2.3.3-SAC.json @@ -0,0 +1,11 @@ +{ + "version": "2.3.3-SAC", + "git_commit": "", + "files": { + "ssh-monitor": "sha256:589ae92dc0e9656d51ca35f1eace1941ff8e292f8d5f0a4b8d2a72060610414c", + "sac-client.sh": "sha256:e3b561280d1c146f565a1fa73e4df29f07b4ffdf149c2b30074fac98722ee9b3", + "update_ssh_monitor.sh": "sha256:76c610ed229d510c41ddd0d10db2b68d48c08b89eb1c8252341ce85f088bf6cd", + "ssh-monitor-watchdog": "sha256:c03c50162b552a7790dd0a63eecec08d672ee04955281b5ec434ed92af5e0e2f", + "ssh-monitor-perms.sh": "sha256:3e411951f25fb8d708c11775925985bc45a861c28eb97932fe04012d3c9ffe5b" + } +} diff --git a/ssh-monitor b/ssh-monitor index d9a8067..413e930 100644 --- a/ssh-monitor +++ b/ssh-monitor @@ -7,7 +7,7 @@ IFS=$'\n\t' # ============================================ CONFIG_FILE="/etc/ssh-monitor.conf" -SSH_MONITOR_VERSION="2.3.2-SAC" +SSH_MONITOR_VERSION="2.3.3-SAC" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [ -f "$SCRIPT_DIR/ssh-monitor-perms.sh" ]; then diff --git a/ssh-monitor-perms.sh b/ssh-monitor-perms.sh index b963af2..d467026 100644 --- a/ssh-monitor-perms.sh +++ b/ssh-monitor-perms.sh @@ -260,10 +260,33 @@ ssh_monitor_is_root_owned() { [ "$own" = "root:root" ] } +# Каталоги ОС: не chmod 700 / chown при hardening файлов вроде /var/log/last_heartbeat.txt. +# Иначе update ломает /var/log (syslog, logrotate, чужие сервисы). +ssh_monitor_is_system_dir() { + local dir="$1" + [ -n "$dir" ] || return 1 + while [ "$dir" != "/" ] && [[ "$dir" == */ ]]; do + dir="${dir%/}" + done + case "$dir" in + / | /bin | /boot | /dev | /etc | /home | /lib | /lib32 | /lib64 | /libx32 | \ + /media | /mnt | /opt | /proc | /root | /run | /sbin | /srv | /sys | /tmp | \ + /usr | /usr/bin | /usr/sbin | /usr/local | /usr/local/bin | /usr/local/sbin | \ + /var | /var/log | /var/tmp | /var/cache | /var/run | /var/spool) + return 0 + ;; + esac + return 1 +} + ssh_monitor_secure_dir() { local dir="$1" [ -n "$dir" ] || return 1 mkdir -p "$dir" 2>/dev/null || return 1 + # Только «свои» каталоги (spool, /var/lib/ssh-monitor, …). /var/log и т.п. не трогаем. + if ssh_monitor_is_system_dir "$dir"; then + return 0 + fi chmod 700 "$dir" 2>/dev/null || true chown root:root "$dir" 2>/dev/null || true } @@ -273,6 +296,7 @@ ssh_monitor_secure_file() { local dir [ -n "$file" ] || return 1 dir="$(dirname "$file")" + # mkdir родителя; chmod 700 — только если родитель не системный (/var/log, /etc, …). ssh_monitor_secure_dir "$dir" || true if [ ! -f "$file" ]; then : >"$file" 2>/dev/null || touch "$file" 2>/dev/null || return 1 @@ -281,7 +305,8 @@ ssh_monitor_secure_file() { chown root:root "$file" 2>/dev/null || true } -# Существующий файл или каталог: 600/700 root:root; для отсутствующего пути — только родительский каталог. +# Существующий файл или каталог: 600/700 root:root; для отсутствующего пути — только родительский каталог +# (без chmod 700 на системных родителях вроде /var/log). ssh_monitor_harden_path() { local path="$1" [ -n "$path" ] || return 0 diff --git a/version.txt b/version.txt index 4579786..91d5324 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -2.3.2-SAC +2.3.3-SAC