Files
fail2ban-webui/agent/uninstall.sh
T
schiwagoaandClaude Opus 5.5 2e3f79236c Initial version of fail2ban-webui
Web interface to view, ban and unban fail2ban IPs on several hosts via
SSH, generalised from the private f2b-web tool.

- Web UI (Flask/Waitress): hosts.yaml, local/OIDC/proxy authentication,
  English/German UI, origin map, optional Loki/Grafana/GeoIP, CLI helpers
- Agent f2b-webctl with install.sh/uninstall.sh (dedicated user + sudo,
  from= restriction, protected networks, manual jail)
- Hardened Docker image, examples, documentation, smoke test, testbed

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 15:38:17 +01:00

126 lines
4.9 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# =====================================================================
# fail2ban-webui agent – uninstaller
#
# Removes the key entry, the sudo rule, f2b-webctl and its config.
# The user and the manual jail are only removed on request, because
# removing the jail also lifts all manual bans.
# Every removed file is backed up to --backup-dir first.
# =====================================================================
set -euo pipefail
AGENT_BIN=/usr/local/sbin/f2b-webctl
CONF_FILE=/etc/f2b-webctl.conf
SUDOERS_FILE=/etc/sudoers.d/f2b-webctl
USER_NAME=f2bweb
AK_FILE=""
MANUAL_JAIL=""
REMOVE_USER=0
REMOVE_JAIL=0
BACKUP_DIR=/var/backups/fail2ban-webui-agent
DRY_RUN=0
YES=0
usage() {
cat <<'EOF'
Usage: uninstall.sh [options]
--user NAME SSH user of the agent (default: f2bweb)
--authorized-keys-file PATH file with the key entry (default: ~USER/.ssh/authorized_keys)
--remove-user also delete the user (not possible for root)
--remove-jail also delete the manual jail – lifts all its bans!
--manual-jail NAME name of the manual jail (default: from /etc/f2b-webctl.conf)
--backup-dir DIR backups (default: /var/backups/fail2ban-webui-agent)
--dry-run only show what would be done
-y, --yes do not ask for confirmation
EOF
}
die() { echo "ERROR: $*" >&2; exit 1; }
info() { echo "==> $*"; }
need() { [ $# -ge 2 ] && [ -n "$2" ] || die "option $1 needs a value"; }
while [ $# -gt 0 ]; do
case "$1" in
--user) need "$@"; USER_NAME="$2"; shift 2 ;;
--authorized-keys-file) need "$@"; AK_FILE="$2"; shift 2 ;;
--remove-user) REMOVE_USER=1; shift ;;
--remove-jail) REMOVE_JAIL=1; shift ;;
--manual-jail) need "$@"; MANUAL_JAIL="$2"; shift 2 ;;
--backup-dir) need "$@"; BACKUP_DIR="$2"; shift 2 ;;
--dry-run) DRY_RUN=1; shift ;;
-y|--yes) YES=1; shift ;;
-h|--help) usage; exit 0 ;;
*) usage >&2; die "unknown option: $1" ;;
esac
done
[ "$(id -u)" -eq 0 ] || die "please run as root"
[[ "$USER_NAME" =~ ^[a-z_][a-z0-9_-]{0,31}$ ]] || die "invalid user name: $USER_NAME"
[ "$USER_NAME" != root ] || [ $REMOVE_USER -eq 0 ] || die "root cannot be removed"
if [ -z "$MANUAL_JAIL" ]; then
MANUAL_JAIL=$(sed -n 's/^MANUAL_JAIL=//p' "$CONF_FILE" 2>/dev/null | tail -n1)
MANUAL_JAIL=${MANUAL_JAIL:-manual-block}
fi
[[ "$MANUAL_JAIL" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]{0,40}$ ]] || die "invalid jail name: $MANUAL_JAIL"
HOME_DIR=$(getent passwd "$USER_NAME" | cut -d: -f6 || true)
AK_FILE=${AK_FILE:-${HOME_DIR:-/nonexistent}/.ssh/authorized_keys}
JAIL_FILES=("/etc/fail2ban/jail.d/$MANUAL_JAIL.local" "/etc/fail2ban/filter.d/$MANUAL_JAIL.conf")
KEY_LINES=0
[ -f "$AK_FILE" ] && KEY_LINES=$(grep -c 'command="[^"]*f2b-webctl"' "$AK_FILE" || true)
echo
echo "fail2ban-webui agent – removing from $(hostname -f 2>/dev/null || hostname):"
echo " key entries $KEY_LINES in $AK_FILE"
for f in "$SUDOERS_FILE" "$AGENT_BIN" "$CONF_FILE"; do
[ -e "$f" ] && echo " file $f"
done
[ $REMOVE_JAIL -eq 1 ] && for f in "${JAIL_FILES[@]}"; do [ -e "$f" ] && echo " jail file $f"; done
[ $REMOVE_USER -eq 1 ] && id "$USER_NAME" >/dev/null 2>&1 && echo " user $USER_NAME (with home directory)"
echo " backups $BACKUP_DIR"
echo
if [ $REMOVE_JAIL -eq 1 ]; then
echo "WARNING: removing jail $MANUAL_JAIL lifts all manual bans!" >&2
if fail2ban-client get "$MANUAL_JAIL" banip >/dev/null 2>&1; then
echo " currently banned: $(fail2ban-client get "$MANUAL_JAIL" banip | tr '\n' ' ')" >&2
fi
fi
[ $DRY_RUN -eq 0 ] || { info "dry run – nothing changed"; exit 0; }
if [ $YES -eq 0 ]; then
[ -t 0 ] || die "no terminal for the confirmation – use --yes"
read -r -p "Remove? [y/N] " answer
[[ "$answer" =~ ^[yYjJ] ]] || die "aborted, nothing changed"
fi
STAMP=$(date +%Y-%m-%d_%H-%M-%S)
BK="$BACKUP_DIR/uninstall_$STAMP"
mkdir -p "$BK"; chmod 700 "$BACKUP_DIR" "$BK"
for f in "$AK_FILE" "$SUDOERS_FILE" "$AGENT_BIN" "$CONF_FILE" "${JAIL_FILES[@]}"; do
[ -e "$f" ] && cp -a --parents "$f" "$BK/"
done
info "backup: $BK"
if [ "$KEY_LINES" -gt 0 ]; then
info "removing key entries from $AK_FILE"
tmp=$(mktemp)
grep -v 'command="[^"]*f2b-webctl"' "$AK_FILE" > "$tmp" || true
cat "$tmp" > "$AK_FILE"
rm -f "$tmp"
fi
for f in "$SUDOERS_FILE" "$AGENT_BIN" "$CONF_FILE"; do
[ -e "$f" ] && { info "removing $f"; rm -f "$f"; }
done
if [ $REMOVE_JAIL -eq 1 ]; then
for f in "${JAIL_FILES[@]}"; do
[ -e "$f" ] && { info "removing $f"; rm -f "$f"; }
done
fail2ban-client reload >/dev/null || echo "WARNING: fail2ban reload failed – check: fail2ban-client -t" >&2
fi
if [ $REMOVE_USER -eq 1 ] && id "$USER_NAME" >/dev/null 2>&1; then
info "removing user $USER_NAME"
userdel -r "$USER_NAME" 2>/dev/null || userdel "$USER_NAME"
fi
info "done"