mirror of
https://github.com/swissmakers/fail2ban-ui.git
synced 2026-03-26 11:03:24 +01:00
17 KiB
17 KiB
Architecture overview
Fail2Ban UI consists of :
- a Go HTTP API (Gin)
- a single-template web frontend (with static assets)
- an embedded SQLite database for state and event history
- optional integrations (alert providers, GeoIP/Whois, firewall-integrations)
Data flows
- User -> UI -> API
- Browser communicates with the backend via HTTP and WebSocket.
- When OIDC is enabled, most UI routes require authentication.
- Fail2Ban host -> UI callbacks
- A custom Fail2Ban action posts ban/unban events to the UI.
- The UI validates the callback secret, enriches (optional), stores, and broadcasts events.
- UI -> Fail2Ban host (management operations)
- Local: uses the Fail2Ban socket and local filesystem.
- SSH: runs
fail2ban-clientand manages files via SSH. - Agent (preview): HTTP-based control plane (limited, in progress).
Components (high level)
- REST API: server management, jail/filter config read/write, ban/unban actions, settings, data management (clear events/blocks)
- WebSocket hub: streams real-time ban/unban events and (optional) debug console logs, protected by origin validation and session auth
- Storage: server definitions, settings, ban history, permanent block records
- Alert providers: pluggable notification dispatch (Email/SMTP, Webhook, Elasticsearch) with country-based filtering and GeoIP enrichment
- Integrations: MikroTik (SSH), pfSense (REST API), OPNsense (REST API) with input validation on all parameters
- Ban Insights: country-level analytics with interactive 3D threat globe visualization
Additional resources:
- Alert provider documentation:
docs/alert-providers.md - Threat intelligence documentation:
docs/threat-intel.md - Container deployment guide:
deployment/container/README.md - systemd setup guide:
deployment/systemd/README.md
More detailed diagrams
Browser (Frontend) ↔ Backend (HTTP / WebSocket) communication
┌───────────────────────────────────────────────────────────────────────────────────┐
│ FRONTEND (Vanilla JS + Tailwind CSS) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Dashboard │ │ Filter Debug│ │ Settings │ │ (index) │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
│ └────────────────┴────────────────┴────────────────┘ │
│ │ │
│ Communication to backend: │ HTTP/HTTPS (REST) │
│ • GET / │ • All /api/* (except callbacks) use your │
│ • GET /api/summary │ session when OIDC is enabled │
│ • GET /api/events/bans │ • X-F2B-Server header for server selection │
│ • GET /api/version │ │
│ • POST /api/jails/:jail/unban/:ip │ WebSocket: GET /api/ws (upgrade) │
│ • POST /api/jails/:jail/ban/:ip │ • Same origin, same cookies as HTTP │◀-┐
│ • POST /api/settings │ • Receives: heartbeat, console_log, │ │
│ • … (see diagram 2) │ ban_event, unban_event │ │
└────────────────────────────────────┼──────────────────────────────────────────────┘ │ W
│ │ e
▼ │ b
┌─────────────────────────────────────────────────────────────────────────────────┐ │ s
│ GO BACKEND (Gin) │ │ o
│ ┌───────────────────────────────────────────────────────────────────────────┐ │ │ c
│ │ PUBLIC (no OIDC-auth session needed for access): │ │ │ k
│ │ • /auth/login | /auth/callback | /auth/logout │ │ │ e
│ │ • /auth/status | /auth/user │ │ │ t
│ │ • POST /api/ban | POST /api/unban ← Fail2ban callbacks (a valid Callback │ │ │
│ │ • /static/* | /locales/* Secret is needed) │ │----┘
│ └───────────────────────────────────────────────────────────────────────────┘ │
│ ┌───────────────────────────────────────────────────────────────────────────┐ │
│ │ PROTECTED (when OIDC enabled): │ │
│ │ GET / | all other /api/* | GET /api/ws (WebSocket, same-origin only) │ │
│ └───────────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────────┘
Backend internals: API routes, WebSocket hub, storage, connectors
┌──────────────────────────────────────────────────────────────────────────────────┐
│ GIN SERVER │
│ ┌────────────────────────────────────────────────────────────────────────────┐ │
│ │ REST API (group /api) │ │
│ │ • GET /summary → Connector(s) → Fail2ban(jails, banned IPs) │ │
│ │ • GET /jails/:jail/config • POST /jails/:jail/config │ │
│ │ • GET /jails/manage • POST /jails/manage | POST /jails │ │
│ │ • POST /jails/:jail/unban/:ip • POST /jails/:jail/ban/:ip │ │
│ │ • GET /settings • POST /settings │ │
│ │ • GET /events/bans • GET /events/bans/stats | /insights │ │
│ │ • DELETE /events/bans • DELETE /advanced-actions/blocks │ │
│ │ • GET /version (optional GitHub request if UPDATE_CHECK) │ │
│ │ • GET /servers | POST/DELETE /servers | POST /servers/:id/test │ │
│ │ • GET /filters/* • POST /filters/test | POST/DELETE /filters │ │
│ │ • POST /fail2ban/restart • GET/POST /advanced-actions/* │ │
│ │ • POST /ban (callback) • POST /unban (callback) │ │
│ │ All IP inputs validated via net.ParseIP / net.ParseCIDR │ │
│ └────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────────────┴──────────────────────────────────────────┐ │
│ │ WebSocket Hub (GET /api/ws — same-origin, auth required with OIDC) │ │
│ │ • register / unregister clients │ │
│ │ • Origin header validated against Host (rejects cross-site connections) │ │
│ │ • broadcast to all clients: │ │
│ │ - type: "heartbeat" (every ~30s) │ │
│ │ - type: "console_log" (debug console lines) │ │
│ │ - type: "ban_event" (after POST /api/ban → store → broadcast) │ │
│ │ - type: "unban_event" (after POST /api/unban → store → broadcast) │ │
│ └────────────────────────────────────────────────────────────────────────────┘ │
│ ┌────────────────────────────┐ ┌────────────────────────────┐ │
│ │ SQLite Storage │ │ Whois / GeoIP │ │
│ │ • ban_events │ │ • IP → country/hostname │ │
│ │ • app_settings, servers │ │ MaxMind or ip-api.com │ │
│ │ • permanent_blocks │ │ • Used in UI and alerts │ │
│ └────────────────────────────┘ └────────────────────────────┘ │
│ ┌────────────────────────────┐ ┌────────────────────────────┐ │
│ │ Connector Manager │ │ Integrations + Alerts │ │
│ │ • Local (fail2ban.sock) │ │ • Mikrotik / pfSense / │ │
│ │ • SSH (exec on remote) │ │ OPNsense (block/unblock)│ │
│ │ • Agent (HTTP to agent) │ │ • Input validated (IP + │ │
│ │ • New server init: ensure │ │ identifiers sanitized) │ │
│ │ │ │ • Alert dispatch (Email / │ │
│ │ │ │ Webhook / Elasticsearch)│ │
│ │ │ └────────────────────────────┘ │
│ │ action.d (ui-custom- │ │
│ │ action.conf) │ │
│ └────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────────┘
Fail2ban instances → Fail2ban-UI (callbacks) and Fail2ban-UI → Fail2ban (via connectors)
┌──────────────────────────────────────────────────────────────────────────────────┐
│ FAIL2BAN INSTANCES (one per server: local, SSH host, or agent host) │
│ On each host: Fail2ban + action script (ui-custom-action.conf) │
│ On ban/unban → action runs → HTTP POST to Fail2ban-UI callback URL │
│ │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ Outbound to Fail2ban-UI (from each Fail2ban host) │ │
│ │ POST <CallbackURL>/api/ban or /api/unban │ │
│ │ Header: X-Callback-Secret: <configured secret> │ │
│ │ Body: JSON { serverId, ip, jail, hostname, failures, logs } │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────────────────┐ │
│ │ Fail2ban-UI Backend │ │
│ │ 1. Validate X-Callback-Secret → 401 if missing/invalid │ │
│ │ 2. Resolve server (serverId or hostname) │ │
│ │ 3. Whois/GeoIP enrichment │ │
│ │ 4. Store event in SQLite DB (ban_events) if nothing was invalid │ │
│ │ 5. Broadcast current event to WebSocket clients (ban_event / unban_event) │ │
│ │ 6. Optional: dispatch alert (Email / Webhook / Elasticsearch) │ │
│ │ 7 Run additional actions (e.g. block on pfSense for recurring offenders) │ │
│ │ 8. Respond status 200 OK - if all above was without an error │ │
│ └────────────────────────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────┐
│ INBOUND from Fail2ban-UI to Fail2ban (per connector type) │
│ • Local: fail2ban-client over Unix socket (/var/run/fail2ban/fail2ban.sock) │
│ • SSH: SSH + fail2ban-client on remote host │
│ • Agent: HTTP to agent API (e.g. /v1/jails/:jail/unban, /v1/jails/:jail/ban) │
│ Used for: summary (jails, banned IPs), unban/ban from UI, config read/write, │
│ filter test, jail create/delete, restart/reload, logpath test │
└─────────────────────────────────────────────────────────────────────────────────┘