mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-09-14 18:56:52 +00:00
ProxMenux modifies the host: it rewrites configuration files, installs packages, enables services. Until now nobody could say afterwards what had changed, and showing the script does not answer that question — a four-hundred-line function may alter two values, and the reader has no way to know which two. This adds the two halves of an answer. The change journal records what ProxMenux does as it does it. Eleven bash primitives capture the previous state, apply the change and record it in the same step, writing to a spool that the Monitor reads back. One hundred and thirteen functions across twenty-five scripts are instrumented, covering post-install, shared storage, security tooling, container conversions, disk operations and the PVE 8 to 9 upgrade path. The page shows the difference — rotate 7 becoming rotate 14 — and never the script. Restore and backup scripts are deliberately left out: a restore puts the host back to a state some other script already recorded. The Audit and reports page answers the other half: what state is this host in, regardless of who put it there. Forty-three checks across seven areas read the host and classify each result as critical, warning, observation, conformant, unverified or not applicable, with the evidence they read attached to each one. A declared policy lets the reader say what this particular host is expected to do — which guests must have a backup, which storages are essential — so the report judges the host against its own intent rather than a generic template. An inventory records the hardware, network and guest topology behind those readings, a comparison shows what moved between two runs, and six report profiles produce a printable document scoped to what the reader needs. Everything is available in the eight supported languages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
509 lines
19 KiB
Bash
509 lines
19 KiB
Bash
#!/bin/bash
|
|
# ==========================================================
|
|
# ProxMenux - Fail2Ban Installer & Configurator
|
|
# ==========================================================
|
|
# Author : MacRimi
|
|
# Copyright : (c) 2024 MacRimi
|
|
# License : GPL-3.0
|
|
# https://github.com/MacRimi/ProxMenux/blob/main/LICENSE
|
|
# Version : 1.0
|
|
# ==========================================================
|
|
# Description:
|
|
# Installs and configures Fail2Ban to protect SSH, the Proxmox VE
|
|
# web UI (port 8006) and the ProxMenux Monitor (port 8008 + reverse
|
|
# proxy) against brute-force attacks. Hybrid runtime: works from
|
|
# terminal dialogs and from the ProxMenux web panel.
|
|
#
|
|
# Features:
|
|
# - Adjusts journald MaxLevelStore if Proxmox default ('warning')
|
|
# would silently drop SSH/PAM auth events.
|
|
# - Creates two journal-to-file logger services so Fail2Ban can use
|
|
# the reliable file backend instead of systemd journal (avoids
|
|
# known issues with pvedaemon worker / sshd journal reads).
|
|
# - Three jails: [sshd] (aggressive, 2 retries / 9h ban),
|
|
# [proxmox] (8006, 3 retries / 1h ban), [proxmenux] (8008 +
|
|
# http/https, 3 retries / 1h ban).
|
|
# - Auto-detects firewall backend (nftables preferred, iptables
|
|
# fallback) and sets the matching ban actions.
|
|
# - SSH hardening: sets MaxAuthTries=3 (Lynis SSH-7408 recommendation),
|
|
# backing up the original value for clean restore on uninstall.
|
|
# - Reinstall flow rewrites all jails with current defaults.
|
|
# - Clean uninstall: removes jails, logger services, journald drop-in
|
|
# and restores the original SSH MaxAuthTries.
|
|
# - Component status tracked in components_status.json.
|
|
# ==========================================================
|
|
# Hybrid script: works from terminal (dialog) and web panel (ScriptTerminalModal)
|
|
|
|
SCRIPT_TITLE="Fail2Ban Installer for Proxmox VE"
|
|
|
|
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
|
|
BASE_DIR="/usr/local/share/proxmenux"
|
|
UTILS_FILE="$BASE_DIR/utils.sh"
|
|
COMPONENTS_STATUS_FILE="$BASE_DIR/components_status.json"
|
|
|
|
export BASE_DIR
|
|
export COMPONENTS_STATUS_FILE
|
|
|
|
if [[ -f "$UTILS_FILE" ]]; then
|
|
source "$UTILS_FILE"
|
|
fi
|
|
|
|
if [[ -f "$LOCAL_SCRIPTS/global/pmx_journal.sh" ]]; then
|
|
source "$LOCAL_SCRIPTS/global/pmx_journal.sh"
|
|
fi
|
|
|
|
if [[ ! -f "$COMPONENTS_STATUS_FILE" ]]; then
|
|
echo "{}" > "$COMPONENTS_STATUS_FILE"
|
|
fi
|
|
|
|
load_language
|
|
initialize_cache
|
|
|
|
|
|
# ==========================================================
|
|
# Detection
|
|
# ==========================================================
|
|
detect_fail2ban() {
|
|
FAIL2BAN_INSTALLED=false
|
|
FAIL2BAN_VERSION=""
|
|
FAIL2BAN_ACTIVE=false
|
|
|
|
if command -v fail2ban-client >/dev/null 2>&1; then
|
|
FAIL2BAN_INSTALLED=true
|
|
FAIL2BAN_VERSION=$(fail2ban-client --version 2>/dev/null | head -n1 | tr -d '[:space:]' || echo "unknown")
|
|
|
|
if systemctl is-active --quiet fail2ban 2>/dev/null; then
|
|
FAIL2BAN_ACTIVE=true
|
|
fi
|
|
fi
|
|
}
|
|
|
|
|
|
# ==========================================================
|
|
# Installation
|
|
# ==========================================================
|
|
install_fail2ban() {
|
|
local FUNC_VERSION="1.0"
|
|
pmx_journal_context "install_fail2ban" "$FUNC_VERSION"
|
|
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "$SCRIPT_TITLE")"
|
|
msg_info2 "$(translate "Installing and configuring Fail2Ban to protect Proxmox web interface and SSH...")"
|
|
|
|
# Ensure Debian repositories are available
|
|
local deb_codename
|
|
deb_codename=$(grep -oP '^VERSION_CODENAME=\K.*' /etc/os-release 2>/dev/null)
|
|
|
|
if ! grep -RqsE "debian.*(bookworm|trixie)" /etc/apt/sources.list /etc/apt/sources.list.d 2>/dev/null; then
|
|
msg_warn "$(translate "Debian repositories missing; creating default source file")"
|
|
local src="/etc/apt/sources.list.d/debian.sources"
|
|
pmx_write_file "$src" <<EOF
|
|
Types: deb
|
|
URIs: http://deb.debian.org/debian
|
|
Suites: ${deb_codename} ${deb_codename}-updates
|
|
Components: main contrib non-free non-free-firmware
|
|
|
|
Types: deb
|
|
URIs: http://security.debian.org/debian-security
|
|
Suites: ${deb_codename}-security
|
|
Components: main contrib non-free non-free-firmware
|
|
EOF
|
|
msg_ok "$(translate "Debian repositories configured for ${deb_codename}")"
|
|
fi
|
|
|
|
# Install Fail2Ban
|
|
msg_info "$(translate "Installing Fail2Ban...")"
|
|
if ! DEBIAN_FRONTEND=noninteractive apt-get update -y >/dev/null 2>&1 || \
|
|
! pmx_install_pkg fail2ban; then
|
|
msg_error "$(translate "Failed to install Fail2Ban")"
|
|
return 1
|
|
fi
|
|
msg_ok "$(translate "Fail2Ban installed successfully")"
|
|
|
|
# ── Ensure journald stores auth-level messages ──
|
|
# Proxmox sets MaxLevelStore=warning by default, which silently drops
|
|
# info/notice messages. SSH auth failures (PAM) are logged at info/notice,
|
|
# so Fail2Ban with backend=systemd will never see them.
|
|
local journald_conf="/etc/systemd/journald.conf"
|
|
local journald_changed=false
|
|
|
|
if [[ -f "$journald_conf" ]]; then
|
|
local current_max
|
|
current_max=$(grep -i '^MaxLevelStore=' "$journald_conf" 2>/dev/null | tail -1 | cut -d= -f2 | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
|
|
|
|
# Levels that are too restrictive for auth logging (need at least info)
|
|
case "$current_max" in
|
|
emerg|alert|crit|err|warning)
|
|
msg_warn "$(translate "journald MaxLevelStore is '${current_max}' - SSH auth failures are not being stored")"
|
|
msg_info "$(translate "Updating journald to store info-level messages...")"
|
|
|
|
# Create a drop-in so we don't break other Proxmox settings
|
|
mkdir -p /etc/systemd/journald.conf.d
|
|
pmx_write_file /etc/systemd/journald.conf.d/proxmenux-loglevel.conf <<'JEOF'
|
|
# ProxMenux: Allow auth/info messages so Fail2Ban can detect SSH failures
|
|
# Proxmox default MaxLevelStore=warning drops PAM/SSH auth events
|
|
[Journal]
|
|
MaxLevelStore=info
|
|
MaxLevelSyslog=info
|
|
JEOF
|
|
journald_changed=true
|
|
msg_ok "$(translate "journald drop-in created: /etc/systemd/journald.conf.d/proxmenux-loglevel.conf")"
|
|
;;
|
|
*)
|
|
msg_ok "$(translate "journald MaxLevelStore is adequate for auth logging")"
|
|
;;
|
|
esac
|
|
|
|
if $journald_changed; then
|
|
pmx_record_execution "restart systemd-journald" "systemctl restart systemd-journald"
|
|
systemctl restart systemd-journald
|
|
sleep 1
|
|
msg_ok "$(translate "journald restarted - auth messages will now be stored")"
|
|
fi
|
|
fi
|
|
|
|
# ── Journal-to-file logger services for Fail2Ban ──
|
|
# Fail2Ban's systemd backend has a known issue: it cannot reliably read
|
|
# journal entries in real-time from certain services (pvedaemon workers,
|
|
# and intermittently sshd). The solution is to create small systemd services
|
|
# that tail the journal and write to log files, then fail2ban monitors those
|
|
# files with the reliable backend=auto.
|
|
|
|
# -- Proxmox UI auth logger (pvedaemon) --
|
|
msg_info "$(translate "Creating Proxmox auth logger service...")"
|
|
pmx_write_file /etc/systemd/system/proxmox-auth-logger.service <<'EOF'
|
|
[Unit]
|
|
Description=Proxmox Auth Logger for Fail2Ban
|
|
Documentation=https://github.com/MacRimi/ProxMenux
|
|
After=pvedaemon.service
|
|
PartOf=fail2ban.service
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=/bin/bash -c 'journalctl -f _SYSTEMD_UNIT=pvedaemon.service -o short-iso --no-pager >> /var/log/proxmox-auth.log'
|
|
Restart=always
|
|
RestartSec=5
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
touch /var/log/proxmox-auth.log
|
|
chmod 640 /var/log/proxmox-auth.log
|
|
chown root:adm /var/log/proxmox-auth.log 2>/dev/null || true
|
|
|
|
systemctl daemon-reload
|
|
pmx_enable_service proxmox-auth-logger.service
|
|
msg_ok "$(translate "Proxmox auth logger service created and started")"
|
|
|
|
# -- SSH auth logger --
|
|
msg_info "$(translate "Creating SSH auth logger service...")"
|
|
pmx_write_file /etc/systemd/system/ssh-auth-logger.service <<'EOF'
|
|
[Unit]
|
|
Description=SSH Auth Logger for Fail2Ban
|
|
Documentation=https://github.com/MacRimi/ProxMenux
|
|
After=ssh.service
|
|
PartOf=fail2ban.service
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=/bin/bash -c 'journalctl -f _SYSTEMD_UNIT=ssh.service -o short-iso --no-pager >> /var/log/ssh-auth.log'
|
|
Restart=always
|
|
RestartSec=5
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
EOF
|
|
|
|
touch /var/log/ssh-auth.log
|
|
chmod 640 /var/log/ssh-auth.log
|
|
chown root:adm /var/log/ssh-auth.log 2>/dev/null || true
|
|
|
|
systemctl daemon-reload
|
|
pmx_enable_service ssh-auth-logger.service
|
|
msg_ok "$(translate "SSH auth logger service created and started")"
|
|
|
|
# Configure Proxmox filter
|
|
mkdir -p /etc/fail2ban/filter.d /etc/fail2ban/jail.d
|
|
msg_info "$(translate "Configuring Proxmox filter...")"
|
|
pmx_write_file /etc/fail2ban/filter.d/proxmox.conf <<'EOF'
|
|
[Definition]
|
|
# The proxmox-auth-logger service writes journal lines to /var/log/proxmox-auth.log
|
|
# in short-iso format: 2026-02-10T19:36:08+01:00 host pvedaemon[PID]: message
|
|
# Proxmox logs IPs as ::ffff:x.x.x.x (IPv4-mapped IPv6).
|
|
failregex = authentication (failure|error); rhost=(::ffff:)?<HOST> user=.* msg=.*
|
|
ignoreregex =
|
|
datepattern = ^%%Y-%%m-%%dT%%H:%%M:%%S
|
|
EOF
|
|
msg_ok "$(translate "Proxmox filter configured")"
|
|
|
|
# Configure Proxmox jail (file-based backend)
|
|
msg_info "$(translate "Configuring Proxmox jail...")"
|
|
pmx_write_file /etc/fail2ban/jail.d/proxmox.conf <<'EOF'
|
|
[proxmox]
|
|
enabled = true
|
|
port = 8006
|
|
filter = proxmox
|
|
backend = auto
|
|
logpath = /var/log/proxmox-auth.log
|
|
maxretry = 3
|
|
bantime = 3600
|
|
findtime = 600
|
|
EOF
|
|
msg_ok "$(translate "Proxmox jail configured")"
|
|
|
|
# Configure ProxMenux Monitor filter
|
|
# This reads from a file written directly by the Flask app (not syslog/journal),
|
|
# so it uses a datepattern that matches Python's logging format.
|
|
msg_info "$(translate "Configuring ProxMenux Monitor filter...")"
|
|
pmx_write_file /etc/fail2ban/filter.d/proxmenux.conf <<'EOF'
|
|
[Definition]
|
|
failregex = ^.*proxmenux-auth: authentication failure; rhost=<HOST> user=.*$
|
|
ignoreregex =
|
|
datepattern = ^%%Y-%%m-%%d %%H:%%M:%%S
|
|
EOF
|
|
msg_ok "$(translate "ProxMenux Monitor filter configured")"
|
|
|
|
# Configure ProxMenux Monitor jail (port 8008 + http/https for reverse proxy)
|
|
# Uses backend=auto with logpath because the Flask app writes directly to this file.
|
|
msg_info "$(translate "Configuring ProxMenux Monitor jail...")"
|
|
pmx_write_file /etc/fail2ban/jail.d/proxmenux.conf <<'EOF'
|
|
[proxmenux]
|
|
enabled = true
|
|
port = 8008,http,https
|
|
filter = proxmenux
|
|
backend = auto
|
|
logpath = /var/log/proxmenux-auth.log
|
|
maxretry = 3
|
|
bantime = 3600
|
|
findtime = 600
|
|
EOF
|
|
msg_ok "$(translate "ProxMenux Monitor jail configured")"
|
|
|
|
# Ensure ProxMenux auth log exists (Flask writes here directly)
|
|
touch /var/log/proxmenux-auth.log
|
|
chmod 640 /var/log/proxmenux-auth.log 2>/dev/null || true
|
|
|
|
# Detect firewall backend (nftables preferred, fallback to iptables)
|
|
local ban_action="iptables-multiport"
|
|
local ban_action_all="iptables-allports"
|
|
if command -v nft >/dev/null 2>&1 && nft list ruleset >/dev/null 2>&1; then
|
|
ban_action="nftables"
|
|
ban_action_all="nftables[type=allports]"
|
|
msg_ok "$(translate "Detected nftables - using nftables ban action")"
|
|
else
|
|
msg_info "$(translate "nftables not available - using iptables ban action")"
|
|
fi
|
|
|
|
# Configure global settings and SSH jail
|
|
msg_info "$(translate "Configuring global Fail2Ban settings and SSH jail...")"
|
|
pmx_write_file /etc/fail2ban/jail.local <<EOF
|
|
[DEFAULT]
|
|
ignoreip = 127.0.0.1/8 ::1
|
|
ignoreself = true
|
|
bantime = 86400
|
|
maxretry = 2
|
|
findtime = 1800
|
|
backend = auto
|
|
banaction = ${ban_action}
|
|
banaction_allports = ${ban_action_all}
|
|
|
|
[sshd]
|
|
enabled = true
|
|
filter = sshd[mode=aggressive]
|
|
backend = auto
|
|
logpath = /var/log/ssh-auth.log
|
|
maxretry = 2
|
|
findtime = 3600
|
|
bantime = 32400
|
|
EOF
|
|
msg_ok "$(translate "Global settings and SSH jail configured")"
|
|
|
|
# ── SSH Hardening: MaxAuthTries ──
|
|
# Lynis (SSH-7408) recommends MaxAuthTries=3. With fail2ban maxretry=2,
|
|
# SSH will never reach 3 attempts, but setting it satisfies the audit
|
|
# and adds defense-in-depth. Backup original value for clean restore.
|
|
local sshd_config="/etc/ssh/sshd_config"
|
|
if [[ -f "$sshd_config" ]]; then
|
|
# Save original MaxAuthTries value for restore on uninstall
|
|
local original_max_auth
|
|
original_max_auth=$(grep -i '^MaxAuthTries' "$sshd_config" 2>/dev/null | awk '{print $2}' || echo "6")
|
|
if [[ -z "$original_max_auth" ]]; then
|
|
original_max_auth="6"
|
|
fi
|
|
|
|
# Store original value in our config directory
|
|
printf '%s\n' "$original_max_auth" | pmx_write_file "${BASE_DIR}/sshd_maxauthtries_backup"
|
|
|
|
msg_info "$(translate "Hardening SSH: setting MaxAuthTries to 3...")"
|
|
if grep -qi '^MaxAuthTries' "$sshd_config"; then
|
|
pmx_edit_file "$sshd_config" 's/^MaxAuthTries.*/MaxAuthTries 3/'
|
|
elif grep -qi '^#MaxAuthTries' "$sshd_config"; then
|
|
pmx_edit_file "$sshd_config" 's/^#MaxAuthTries.*/MaxAuthTries 3/'
|
|
else
|
|
echo "MaxAuthTries 3" | pmx_append_file "$sshd_config"
|
|
fi
|
|
|
|
# Reload SSH to apply the change (reload, not restart, to keep existing sessions)
|
|
pmx_record_execution "reload SSH service" "systemctl reload sshd or ssh"
|
|
systemctl reload sshd 2>/dev/null || systemctl reload ssh 2>/dev/null || true
|
|
msg_ok "$(translate "SSH MaxAuthTries set to 3 (original: ${original_max_auth})")"
|
|
fi
|
|
|
|
# Enable and restart the service (restart ensures new jails are loaded
|
|
# even if fail2ban was already running from a previous install)
|
|
systemctl daemon-reload
|
|
pmx_apply_setting "fail2ban enabled state" "systemctl is-enabled fail2ban 2>/dev/null || true" \
|
|
systemctl enable fail2ban
|
|
pmx_record_execution "restart fail2ban" "systemctl restart fail2ban"
|
|
systemctl restart fail2ban >/dev/null 2>&1
|
|
sleep 3
|
|
|
|
# Verify
|
|
if systemctl is-active --quiet fail2ban; then
|
|
msg_ok "$(translate "Fail2Ban is running correctly")"
|
|
else
|
|
msg_error "$(translate "Fail2Ban is NOT running!")"
|
|
journalctl -u fail2ban --no-pager -n 10
|
|
fi
|
|
|
|
if fail2ban-client ping >/dev/null 2>&1; then
|
|
msg_ok "$(translate "fail2ban-client successfully communicated with the server")"
|
|
else
|
|
msg_error "$(translate "fail2ban-client could not communicate with the server")"
|
|
fi
|
|
|
|
update_component_status "fail2ban" "installed" "$(fail2ban-client --version 2>/dev/null | head -n1)" "security" '{}'
|
|
|
|
msg_success "$(translate "Fail2Ban installation and configuration completed successfully!")"
|
|
}
|
|
|
|
|
|
# ==========================================================
|
|
# Uninstall
|
|
# ==========================================================
|
|
uninstall_fail2ban() {
|
|
local FUNC_VERSION="1.0"
|
|
pmx_journal_context "uninstall_fail2ban" "$FUNC_VERSION"
|
|
|
|
show_proxmenux_logo
|
|
msg_title "$(translate "$SCRIPT_TITLE")"
|
|
msg_info2 "$(translate "Removing Fail2Ban...")"
|
|
|
|
pmx_disable_service fail2ban 2>/dev/null || true
|
|
|
|
# Stop and remove the auth logger services
|
|
pmx_disable_service proxmox-auth-logger.service 2>/dev/null || true
|
|
pmx_remove_file /etc/systemd/system/proxmox-auth-logger.service
|
|
pmx_disable_service ssh-auth-logger.service 2>/dev/null || true
|
|
pmx_remove_file /etc/systemd/system/ssh-auth-logger.service
|
|
systemctl daemon-reload 2>/dev/null || true
|
|
pmx_record_execution "remove Fail2Ban auth logger files" \
|
|
"rm -f /var/log/proxmox-auth.log /var/log/ssh-auth.log"
|
|
rm -f /var/log/proxmox-auth.log /var/log/ssh-auth.log
|
|
|
|
pmx_record_execution "purge fail2ban package" "apt-get purge -y fail2ban"
|
|
DEBIAN_FRONTEND=noninteractive apt-get purge -y fail2ban >/dev/null 2>&1
|
|
pmx_remove_file /etc/fail2ban/jail.d/proxmox.conf
|
|
pmx_remove_file /etc/fail2ban/jail.d/proxmenux.conf
|
|
pmx_remove_file /etc/fail2ban/filter.d/proxmox.conf
|
|
pmx_remove_file /etc/fail2ban/filter.d/proxmenux.conf
|
|
pmx_remove_file /etc/fail2ban/jail.local
|
|
|
|
# ── Restore SSH MaxAuthTries to original value ──
|
|
local sshd_config="/etc/ssh/sshd_config"
|
|
local backup_file="${BASE_DIR}/sshd_maxauthtries_backup"
|
|
if [[ -f "$backup_file" && -f "$sshd_config" ]]; then
|
|
local original_val
|
|
original_val=$(cat "$backup_file" 2>/dev/null | tr -d '[:space:]')
|
|
if [[ -n "$original_val" ]]; then
|
|
msg_info "$(translate "Restoring SSH MaxAuthTries to ${original_val}...")"
|
|
if grep -qi '^MaxAuthTries' "$sshd_config"; then
|
|
pmx_edit_file "$sshd_config" "s/^MaxAuthTries.*/MaxAuthTries ${original_val}/"
|
|
fi
|
|
pmx_record_execution "reload SSH service" "systemctl reload sshd or ssh"
|
|
systemctl reload sshd 2>/dev/null || systemctl reload ssh 2>/dev/null || true
|
|
msg_ok "$(translate "SSH MaxAuthTries restored to ${original_val}")"
|
|
fi
|
|
pmx_remove_file "$backup_file"
|
|
fi
|
|
|
|
# Remove journald drop-in and restore original log level
|
|
if [[ -f /etc/systemd/journald.conf.d/proxmenux-loglevel.conf ]]; then
|
|
pmx_remove_file /etc/systemd/journald.conf.d/proxmenux-loglevel.conf
|
|
pmx_record_execution "restart systemd-journald" "systemctl restart systemd-journald"
|
|
systemctl restart systemd-journald 2>/dev/null || true
|
|
msg_ok "$(translate "journald log level restored")"
|
|
fi
|
|
|
|
update_component_status "fail2ban" "removed" "" "security" '{}'
|
|
|
|
msg_ok "$(translate "Fail2Ban has been removed")"
|
|
msg_success "$(translate "Uninstallation completed. Press Enter to continue...")"
|
|
read -r
|
|
}
|
|
|
|
|
|
# ==========================================================
|
|
# Main
|
|
# ==========================================================
|
|
main() {
|
|
detect_fail2ban
|
|
|
|
if $FAIL2BAN_INSTALLED; then
|
|
# Already installed - show action menu
|
|
local action_text
|
|
action_text="\n$(translate 'Fail2Ban is currently installed.')\n"
|
|
action_text+="$(translate 'Version:') $FAIL2BAN_VERSION\n"
|
|
action_text+="$(translate 'Status:') $(if $FAIL2BAN_ACTIVE; then translate 'Active'; else translate 'Inactive'; fi)\n\n"
|
|
action_text+="$(translate 'What would you like to do?')"
|
|
|
|
local ACTION
|
|
ACTION=$(hybrid_menu "$(translate 'Fail2Ban Management')" "$action_text" 18 70 3 \
|
|
"reinstall" "$(translate 'Reinstall and reconfigure Fail2Ban')" \
|
|
"remove" "$(translate 'Uninstall Fail2Ban')" \
|
|
"cancel" "$(translate 'Cancel')" \
|
|
) || ACTION="cancel"
|
|
|
|
case "$ACTION" in
|
|
reinstall)
|
|
if hybrid_yesno "$(translate 'Reinstall Fail2Ban')" \
|
|
"\n\n$(translate 'This will reinstall and reconfigure Fail2Ban with the default ProxMenux settings. Continue?')" 12 70; then
|
|
install_fail2ban
|
|
fi
|
|
;;
|
|
remove)
|
|
if hybrid_yesno "$(translate 'Remove Fail2Ban')" \
|
|
"\n\n$(translate 'This will completely remove Fail2Ban and its configuration. Continue?')" 12 70; then
|
|
uninstall_fail2ban
|
|
fi
|
|
;;
|
|
cancel|*)
|
|
exit 0
|
|
;;
|
|
esac
|
|
else
|
|
# Not installed - confirm and install
|
|
local info_text
|
|
info_text="\n$(translate 'Fail2Ban is not installed on this system.')\n\n"
|
|
info_text+="$(translate 'This will install and configure Fail2Ban with:')\n\n"
|
|
info_text+=" - $(translate 'SSH protection (aggressive mode)') (max 2 $(translate 'retries'), 9h $(translate 'ban'))\n"
|
|
info_text+=" - $(translate 'Proxmox web interface protection') ($(translate 'port') 8006, max 3 $(translate 'retries'), 1h $(translate 'ban'))\n"
|
|
info_text+=" - $(translate 'ProxMenux Monitor protection') ($(translate 'port') 8008 + $(translate 'reverse proxy'), max 3 $(translate 'retries'), 1h $(translate 'ban'))\n"
|
|
info_text+=" - $(translate 'Auto-detected firewall backend (nftables/iptables)')\n"
|
|
info_text+=" - $(translate 'Adjusts journald log level if needed (Proxmox defaults may block auth logs)')\n"
|
|
info_text+=" - $(translate 'SSH hardening: MaxAuthTries set to 3 (Lynis recommendation)')\n\n"
|
|
info_text+="$(translate 'Do you want to proceed?')"
|
|
|
|
if hybrid_yesno "$(translate 'Install Fail2Ban')" "$info_text" 20 70; then
|
|
install_fail2ban
|
|
else
|
|
exit 0
|
|
fi
|
|
fi
|
|
}
|
|
|
|
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
|
|
main
|
|
fi
|