Add SSH monitoring server installer

This commit is contained in:
Ochenstarik 2026-07-15 13:27:49 +07:00
parent 5e64d33a35
commit 9289eb8a13

View file

@ -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 "$@"