From 9289eb8a13b2e6a5b177be982c9f20a68ba45058 Mon Sep 17 00:00:00 2001 From: Ochenstarik Date: Wed, 15 Jul 2026 13:27:49 +0700 Subject: [PATCH] Add SSH monitoring server installer --- ochenstarik-server-monitor-manager.sh | 162 ++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 ochenstarik-server-monitor-manager.sh diff --git a/ochenstarik-server-monitor-manager.sh b/ochenstarik-server-monitor-manager.sh new file mode 100644 index 0000000..acd8289 --- /dev/null +++ b/ochenstarik-server-monitor-manager.sh @@ -0,0 +1,162 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +readonly APP_NAME="ochenstarik-server-monitor-manager" +readonly MONITOR_USER="ochenstarik-monitor" +readonly MONITOR_HOME="/var/lib/${APP_NAME}" +readonly MONITOR_COMMAND="/usr/local/libexec/ochenstarik-server-monitor" +readonly AUTHORIZED_KEYS="${MONITOR_HOME}/.ssh/authorized_keys" + +log() { printf '[+] %s\n' "$*"; } +warn() { printf '[!] %s\n' "$*" >&2; } +die() { printf '[x] %s\n' "$*" >&2; exit 1; } + +require_root() { + [[ "$EUID" -eq 0 ]] || die "Запустите скрипт через sudo" +} + +detect_system() { + [[ -r /etc/os-release ]] || die "Не найден /etc/os-release" + # shellcheck disable=SC1091 + . /etc/os-release + case "${ID:-}" in + ubuntu|debian) ;; + *) die "Поддерживаются Ubuntu и Debian; обнаружено: ${ID:-unknown}" ;; + esac + command -v systemctl >/dev/null 2>&1 || die "Требуется systemd" +} + +read_public_key() { + printf '\nВ Windows-приложении нажмите «SSH-ключ» → «Копировать».\n' + read -rp 'Вставьте публичный ключ: ' PUBLIC_KEY + PUBLIC_KEY="${PUBLIC_KEY//$'\r'/}" + [[ "$PUBLIC_KEY" =~ ^ssh-ed25519[[:space:]]+[A-Za-z0-9+/]+={0,3}([[:space:]].*)?$ ]] \ + || die "Ожидается публичный ключ формата ssh-ed25519 AAAA..." +} + +install_dependencies() { + apt-get update + DEBIAN_FRONTEND=noninteractive apt-get install -y \ + ca-certificates openssh-server openssh-client coreutils gawk + systemctl enable --now ssh +} + +verify_public_key() { + local key_file + key_file="$(mktemp)" + trap 'rm -f -- "${key_file:-}"' RETURN + printf '%s\n' "$PUBLIC_KEY" > "$key_file" + ssh-keygen -l -f "$key_file" >/dev/null \ + || die "ssh-keygen отклонил публичный ключ" + trap - RETURN + rm -f -- "$key_file" +} + +create_monitor_command() { + install -d -m 0755 -o root -g root "$(dirname "$MONITOR_COMMAND")" + [[ ! -L "$MONITOR_COMMAND" ]] \ + || die "Отказ от записи через символическую ссылку: $MONITOR_COMMAND" + cat > "$MONITOR_COMMAND" <<'EOF' +#!/usr/bin/env bash +set -Eeuo pipefail +export LC_ALL=C + +read_mem_value() { + awk -v key="$1" '$1 == key ":" { print $2; exit }' /proc/meminfo +} + +printf 'PROTOCOL=1\n' +printf 'HOSTNAME=%s\n' "$(hostname)" +printf 'UPTIME_SECONDS=%s\n' "$(cut -d. -f1 /proc/uptime)" +printf 'LOAD1=%s\n' "$(cut -d' ' -f1 /proc/loadavg)" +printf 'CPU_COUNT=%s\n' "$(getconf _NPROCESSORS_ONLN)" +printf 'MEM_TOTAL_KB=%s\n' "$(read_mem_value MemTotal)" +printf 'MEM_AVAILABLE_KB=%s\n' "$(read_mem_value MemAvailable)" +df -Pk / | awk 'NR == 2 { + printf "DISK_TOTAL_KB=%s\nDISK_AVAILABLE_KB=%s\n", $2, $4 +}' +printf 'KERNEL=%s\n' "$(uname -r)" +EOF + chown root:root "$MONITOR_COMMAND" + chmod 0755 "$MONITOR_COMMAND" +} + +create_monitor_user() { + if ! getent passwd "$MONITOR_USER" >/dev/null; then + useradd \ + --system \ + --create-home \ + --home-dir "$MONITOR_HOME" \ + --shell /bin/bash \ + "$MONITOR_USER" + fi + usermod --home "$MONITOR_HOME" --shell /bin/bash "$MONITOR_USER" + passwd -l "$MONITOR_USER" >/dev/null 2>&1 || true + + install -d -m 0750 -o "$MONITOR_USER" -g "$MONITOR_USER" "$MONITOR_HOME" + install -d -m 0700 -o "$MONITOR_USER" -g "$MONITOR_USER" "${MONITOR_HOME}/.ssh" + [[ ! -L "$AUTHORIZED_KEYS" ]] \ + || die "Отказ от записи через символическую ссылку: $AUTHORIZED_KEYS" + printf 'restrict,command="%s" %s\n' "$MONITOR_COMMAND" "$PUBLIC_KEY" > "$AUTHORIZED_KEYS" + chown "$MONITOR_USER:$MONITOR_USER" "$AUTHORIZED_KEYS" + chmod 0600 "$AUTHORIZED_KEYS" +} + +verify_sshd() { + sshd -t + sshd -T | grep -qi '^pubkeyauthentication yes$' \ + || die "В sshd отключена аутентификация по публичному ключу" +} + +show_status() { + local ssh_port="unknown" + if command -v sshd >/dev/null 2>&1; then + ssh_port="$(sshd -T 2>/dev/null | awk '$1 == "port" { print $2; exit }')" + fi + printf 'Пользователь: %s\n' "$MONITOR_USER" + printf 'SSH-порт: %s\n' "${ssh_port:-unknown}" + printf 'Команда: %s\n' "$MONITOR_COMMAND" + if [[ -x "$MONITOR_COMMAND" ]]; then + runuser -u "$MONITOR_USER" -- "$MONITOR_COMMAND" + else + warn "Серверная часть ещё не установлена" + fi +} + +install_server_part() { + read_public_key + install_dependencies + verify_public_key + create_monitor_command + create_monitor_user + verify_sshd + systemctl reload ssh + log "Серверная часть установлена" + log "Входящий порт не изменялся, новые правила UFW не создавались" + show_status +} + +uninstall_server_part() { + local answer + read -rp 'Удалить пользователя мониторинга и forced-command? [y/N]: ' answer + [[ "$answer" =~ ^[Yy]$ ]] || { log "Отменено"; return 0; } + rm -f -- "$MONITOR_COMMAND" + if getent passwd "$MONITOR_USER" >/dev/null; then + userdel --remove "$MONITOR_USER" 2>/dev/null || userdel "$MONITOR_USER" + fi + log "Серверная часть удалена" +} + +main() { + local action="${1:-install}" + require_root + detect_system + case "$action" in + install) install_server_part ;; + status) show_status ;; + uninstall) uninstall_server_part ;; + *) die "Использование: $0 [install|status|uninstall]" ;; + esac +} + +main "$@"