# PoE Manager — Modern UI Rebuild Webbasierte Verwaltung und Monitoring von PoE-Devices und Aruba-Switchen — funktionales Rebuild von [Aruba-PoE](https://gitea.int.eertmoed.net/WiS/Aruba-PoE) mit komplett neuem, modernem Frontend und einem granularen Rechtesystem. **Das Projekt ist ausschließlich für Linux ausgelegt** (Zielsystem: eine Linux-VM). Entwickelt wird unter WSL2 (Ubuntu) unter Windows — siehe [Entwicklung unter WSL](#entwicklung-unter-wsl) weiter unten. Die App ermöglicht: - **Öffentliches Kachel-Dashboard ohne Login** — zeigt nur aktive (nicht deaktivierte) Geräte, nur Online/Offline/Gesamt-Statistik; volle Verwaltung, Aktivieren/Deaktivieren und PoE-Neustart bleiben hinter dem Login. Eingeloggt sind zusätzlich deaktivierte Geräte sichtbar (eigene Kachel-Sektion). Alle Kacheln sind durchsuchbar und in drei Abschnitten sortiert: Offline, Online, Deaktiviert — jeweils alphabetisch - Verwaltung von Devices und Switches - **Zugangsdaten als eigene, wiederverwendbare Entität**: SSH-Logins werden einmal angelegt und können mehreren Switchen zugeordnet werden; beim Anlegen eines Switches lassen sich bestehende Zugangsdaten auswählen oder direkt neue hinterlegen, ohne vorher zu „Zugangsdaten“ wechseln zu müssen - **Browser-SSH-Terminal beim Anlegen/Bearbeiten eines Switches**, um den Host-Key zu bestätigen und die Zugangsdaten direkt zu prüfen, bevor der Switch gespeichert wird — funktioniert auf jedem Betriebssystem, die SSH-Verbindung wird dabei immer vom PoE-Server aus aufgebaut - Manueller PoE-Neustart einzelner Geräte per Klick; bei deaktivierten Geräten bietet das Detail-Popup stattdessen direkt eine Aktivieren-Option - Einstellbares Prüfintervall (steuert den Hintergrund-Check-Dienst) — der Countdown „Nächste Prüfung“ wird aus dem tatsächlichen letzten Log-Eintrag berechnet, nicht bei jedem Seitenaufruf neu gestartet - Live-Log-Ansicht mit farblicher Hervorhebung (online/offline) - **Rechtesystem mit Gruppen**: Admins dürfen immer alles (als Gruppe „Admin“ überall mit aufgeführt); normalen Benutzern lassen sich über Gruppen einzelne Verwaltungsrechte gezielt zuweisen, inkl. reiner Ansichtsrechte (siehe [Rechtesystem](#rechtesystem-gruppen--berechtigungen)) - Einklappbare Sidebar (Desktop: dauerhaft, über Neuladen hinweg gemerkt; mobil: temporäres Überlagern) - **Änderungslog**: jede Anlage/Bearbeitung/Löschung sowie Aktivieren/ Deaktivieren von Geräten, Switchen, Zugangsdaten, Benutzern und Gruppen wird protokolliert (wer, wann, was) — einsehbar unter „Logs → Änderungslog“; Geräte und Switche merken sich zusätzlich direkt am Datensatz, wer sie zuletzt geändert hat. PoE-Neustarts werden bewusst **nicht** geloggt (siehe [Änderungslog](#änderungslog)) - **Verschlüsselter Import/Export**: Geräte, Switche und Zugangsdaten lassen sich unter Einstellungen als ein mit selbstgewählter Passphrase verschlüsseltes Bundle exportieren und auf einer neuen Umgebung wieder importieren (siehe [Import/Export](#importexport)) - **Eigenes Profil**: jeder Benutzer kann über einen Klick auf seinen Namen in der Sidebar Vor-/Nachname, eigenes Passwort und ein Profilbild pflegen (siehe [Eigenes Profil](#eigenes-profil--profilbild)) - **Anpassbare Navigation**: Admins können die Reihenfolge der Sidebar- Menüpunkte unter Einstellungen per Auf/Ab-Buttons festlegen; jeder Benutzer sieht davon ohnehin nur, wofür er berechtigt ist (siehe [Navigation anpassen](#navigation-anpassen)) ## Was ist neu gegenüber dem Original? - **Komplett neues Frontend**: eigenes Design-System (kein Bootstrap mehr), Logo mittig in der Topbar (auf jeder Seite, skaliert auf die Balkenhöhe), Sidebar-Navigation (nur für eingeloggte Nutzer sichtbar), Dark/Light- Umschalter, Karten-Dashboard mit Live-Zählern, moderne Modals/Toasts statt Browser-`confirm()` und Bootstrap-Alerts. - **Dashboard jetzt teilweise öffentlich**: `/` ist ohne Login erreichbar und zeigt eine reduzierte Lese-Ansicht (Hostname, IP, Status, letzte Prüfung) mit Login-Button; alle Verwaltungsseiten und der PoE-Neustart bleiben `@login_required` und zusätzlich rechtebasiert (s.u.). - **Browser-SSH-Terminal für Switche**, implementiert mit **paramiko** (reines Python) statt eines lokalen pty + System-`ssh`-Client — läuft dadurch plattformunabhängig. Die SSH-Verbindung zum Switch wird immer serverseitig (vom PoE-Server) aufgebaut, nie vom Browser/Client aus. - **Granulares Rechtesystem mit Gruppen** (neu, siehe unten) statt der ursprünglichen reinen Admin/User-Unterscheidung. - **Gleiche Kernlogik**: Datenbankschema (erweitert um Gruppen/Rechte), Login, PoE-Restart-Mechanismus (`poe.sh` per SSH/`expect` auf die Aruba-Switche) sind ansonsten unverändert. - **Aufgeräumtes Backend**: konsistente, konfigurierbare Pfade (`POE_DB_PATH`, `POE_SCRIPT`, `POE_LOG_GLOB`, …) statt hart codierter/inkonsistenter Pfade; Secret-Key und Fernet-Key werden beim ersten Start automatisch generiert statt im Repo zu liegen. > ⚠️ **Sicherheitshinweis zum Original-Repo:** Im Original sind `sqlite.db` > (Nutzer-Passwort-Hashes, verschlüsselte Switch-Passwörter) und `fernet.key` > (der zugehörige Schlüssel) mit im Git-Repo eingecheckt — die `.gitignore` > dort schließt sie über die `!`-Regeln versehentlich wieder ein. In diesem > Rebuild sind beide Dateien in `.gitignore` ausgeschlossen und werden beim > ersten Start frisch erzeugt. Empfehlung fürs Original-Repo: beide Dateien > aus der Git-Historie entfernen und Fernet-Key sowie alle Switch-/User- > Passwörter rotieren. ## Rechtesystem (Gruppen & Berechtigungen) Admins dürfen wie bisher alles, inklusive Benutzer-/Gruppen-/ Settingsverwaltung — das bleibt exklusiv Admins vorbehalten. Zusätzlich gibt es **Gruppen**: eine Gruppe bündelt einzelne Verwaltungsrechte, die dann normalen Benutzern zugewiesen werden können, ohne sie zu Admins zu machen. Ein Benutzer kann nur einer Gruppe/Rolle gleichzeitig zugeordnet sein (über den Button „Gruppe zuweisen“, analog zur Switch-Zuordnung bei Devices) — technisch sind mehrere Gruppen pro Benutzer möglich (Rechte würden sich addieren), die UI bildet aber bewusst nur eine 1:1-Zuordnung ab. Auf der **Gruppen**-Seite (nur für Admins) werden zur Übersicht immer auch die beiden Systemrollen mit aufgeführt: - **Admin** — eine feste, nicht editierbare Zeile mit allen Rechten; Mitgliedschaft wird direkt hier verwaltet (Button „Mitglieder verwalten“), intern über den `is_admin`-Schalter der Benutzer. Mindestens ein Admin muss immer bestehen bleiben (serverseitig erzwungen). - **Benutzer** — die **Standardgruppe**, mit der alle Ansichtsrechte (`devices.view`, `switches.view`) vorbelegt sind. Jeder neu angelegte, nicht-admin Benutzer wird ihr automatisch zugeordnet; sie kann nicht gelöscht werden. Jede Gruppe lässt sich über „Rechte anzeigen/bearbeiten“ aufklappen (wie ein Akkordeon) und zeigt dort die volle Checkbox-Liste; Mitglieder werden über einen eigenen Button/Modal verwaltet (nur die Anzahl steht in der Tabelle). Verfügbare Rechte: | Bereich | Recht | Bedeutung | |----------|---------------------|-----------------------------------------------| | Devices | `devices.view` | Devices-Seite ansehen | | Devices | `devices.toggle` | Geräte aktivieren/deaktivieren | | Devices | `devices.create` | Geräte anlegen | | Devices | `devices.edit` | Geräte bearbeiten (inkl. Switch-Zuordnung) | | Devices | `devices.delete` | Geräte löschen | | Devices | `devices.restart` | PoE-Neustart/Aktivieren über das Dashboard | | Switches | `switches.view` | Switches- und Zugangsdaten-Seite ansehen | | Switches | `switches.create` | Switche und Zugangsdaten anlegen | | Switches | `switches.edit` | Switche und Zugangsdaten bearbeiten | | Switches | `switches.delete` | Switche und Zugangsdaten löschen | Sowohl das Anzeigen der Devices-/Switches-Seiten als auch jede einzelne Aktion (Buttons, Toggle-Switches, Formulare) ist an das jeweilige Recht gekoppelt — im Frontend ausgeblendet **und** im Backend serverseitig durchgesetzt, unabhängig vom Frontend. Datenmodell: `groups` (inkl. `is_default`-Flag), `group_permissions` (Gruppe → Recht), `user_groups` (Benutzer → Gruppe). Bestehende Datenbanken werden beim App-Start automatisch migriert (`_ensure_schema()` in `app.py`, inkl. Nachrüsten der Standardgruppe und Zuordnung bestehender Benutzer ohne Gruppe) — kein manuelles Migrations-Skript nötig. ## Zugangsdaten (wiederverwendbare SSH-Logins) Switch-Zugangsdaten (Username + verschlüsseltes Passwort) sind eine eigene Entität (`credentials`-Tabelle) statt direkt am Switch zu hängen — mehrere Switche mit demselben Login teilen sich einen Eintrag. Beim Anlegen/Bearbeiten eines Switches lässt sich per Dropdown ein bestehender Eintrag auswählen oder über „+ Neue Zugangsdaten anlegen“ direkt im selben Formular ein neuer anlegen, ohne vorher zur eigenen **Zugangsdaten**-Seite wechseln zu müssen. Löschen ist nur möglich, wenn kein Switch mehr auf den Eintrag verweist. Bestehende Datenbanken aus einer älteren Version (Username/Passwort direkt am Switch) werden beim ersten Start automatisch migriert. ## Änderungslog Jede Anlage, Bearbeitung, Löschung sowie jedes Aktivieren/Deaktivieren von Geräten, Switchen, Zugangsdaten, Benutzern und Gruppen wird in der Tabelle `audit_log` protokolliert (Zeitpunkt, Benutzer, Aktion, Ziel, Details) — einsehbar unter **Logs → Änderungslog** (nur für Admins). Zusätzlich merken sich Geräte und Switche direkt am Datensatz (`last_modified_by`, `last_modified_at`), wer sie zuletzt geändert hat, damit man das nicht erst im Log nachschlagen muss. PoE-Neustarts werden **bewusst nicht** im Änderungslog erfasst — die stehen bereits im Live-Log von `poe.sh`. Eine Ausnahme ist die Änderung des Prüfintervalls selbst (eine Einstellungsänderung, kein Neustart), die wird mitprotokolliert. ## Import/Export Unter **Einstellungen** lassen sich Geräte, Switche und Zugangsdaten (inkl. entschlüsselter Passwörter) als ein einziges JSON-Bundle exportieren. Das Bundle wird mit einem aus einer selbstgewählten Passphrase abgeleiteten Schlüssel verschlüsselt (PBKDF2-HMAC-SHA256 + Fernet) — unabhängig vom `fernet.key` dieser Installation, damit die Datei auf einer komplett neuen Umgebung (mit eigenem, neu generiertem `fernet.key`) wieder eingelesen werden kann. Gedacht für einen Umzug auf einen neuen Server. Beim Import wird dieselbe Passphrase erneut abgefragt; Zugangsdaten werden nach Name, Switche nach Hostname und Geräte nach MAC-Adresse abgeglichen — bestehende Einträge mit gleichem Schlüssel werden aktualisiert, neue werden angelegt. Switche referenzieren ihre Zugangsdaten dabei über den Namen (nicht die interne ID), damit der Import auch bei abweichender ID-Vergabe auf dem Zielsystem korrekt verknüpft. ## Eigenes Profil & Profilbild Ein Klick auf den eigenen Namen unten in der Sidebar öffnet „Mein Profil“: Vor-/Nachname ändern, ein Profilbild hochladen (PNG/JPG/GIF/WEBP) und das eigene Passwort ändern (erfordert Eingabe des aktuellen Passworts). Das ist bewusst getrennt vom Admin-Bereich „Benutzer“, der andere Konten verwaltet. Ist ein Profilbild hinterlegt, erscheint es statt der Initialen sowohl in der Sidebar als auch im Änderungslog neben dem Benutzernamen. ## Navigation anpassen Die Reihenfolge der Sidebar-Menüpunkte ist unter **Einstellungen** per Auf-/Ab-Buttons konfigurierbar (gespeichert als JSON-Liste unter `settings.nav_order`) und gilt global für alle Benutzer. Unabhängig von der Reihenfolge sieht jeder Benutzer ohnehin nur die Punkte, für die er auch berechtigt ist — ein Benutzer ohne jede Gruppe sieht z.B. nur „Dashboard“. „Logs“ ist dabei eine aufklappbare Gruppe mit den Unterpunkten „Live-Log“ und „Änderungslog“. ## Entwicklung unter WSL Da das Projekt ausschließlich für Linux gebaut ist, empfiehlt sich die Entwicklung direkt unter WSL2 (Ubuntu), auch wenn der Editor unter Windows läuft — das Projektverzeichnis liegt dabei ganz normal unter `C:\...\aruba-poe-modern` und wird aus WSL über `/mnt/c/...` erreicht: ```bash wsl --install -d Ubuntu # einmalig, falls noch nicht vorhanden wsl -d Ubuntu sudo apt update && sudo apt install -y python3 python3-venv python3-pip sqlite3 expect openssh-client cd /mnt/c/Users//aruba-poe-modern/srv/poe_manager python3 -m venv venv ./venv/bin/pip install -r requirements.txt ./venv/bin/python create_db.py ./venv/bin/python create_admin.py ./venv/bin/python app.py # http://localhost:5000 — via WSL2-Portweiterleitung # auch aus dem Windows-Browser erreichbar ``` ## Lokal starten (Entwicklung) ```bash cd srv/poe_manager python3 -m venv venv source venv/bin/activate pip install -r requirements.txt python create_db.py # legt sqlite.db + Tabellen an python create_admin.py # legt ersten Admin-Benutzer an python app.py # http://localhost:5000 ``` ## Produktiv-Deployment (auf der Ziel-VM, App landet unter `/srv/poe_manager`) Das Repo wird bewusst **nicht** direkt nach `/srv/poe_manager` geklont — `install.sh` kopiert (`rsync`) den Inhalt von `srv/poe_manager/` aus dem Repo gezielt dorthin und lässt Quell-Checkout und Zielverzeichnis damit sauber getrennt (kein doppeltes `/srv/poe_manager/srv/poe_manager/…`): ```bash sudo git clone /opt/aruba-poe-modern-src cd /opt/aruba-poe-modern-src sudo bash install.sh sudo /srv/poe_manager/venv/bin/python3 /srv/poe_manager/create_admin.py ``` Nach der Installation liegt die laufende App vollständig unter **`/srv/poe_manager`** (so wie es `poe_web.service`, `rpi-check.service` und `POE_SCRIPT`/`POE_DB_PATH` als Default erwarten) — `/opt/aruba-poe-modern-src` wird nur als Checkout-Quelle für `install.sh` gebraucht und kann danach liegen bleiben (für spätere Updates: `git pull` dort, dann `install.sh` erneut ausführen) oder gelöscht werden. `install.sh` installiert Systempakete, richtet die venv ein, initialisiert die Datenbank (falls nicht vorhanden), kopiert `poe.sh` nach `/usr/local/bin/custom/`, registriert die systemd-Units (`poe_web.service`, `rpi-check.service`, `rpi-check-restart.timer`) und konfiguriert nginx als Reverse-Proxy auf Port 80. ### Relevante Umgebungsvariablen (optional) | Variable | Zweck | Default | |-----------------------|------------------------------------------|---------------------------------------| | `POE_DB_PATH` | Pfad zur SQLite-DB | `/sqlite.db` | | `POE_SCRIPT` | Pfad zum PoE-Restart-Skript | `/usr/local/bin/custom/poe.sh` | | `POE_LOG_GLOB` | Glob-Pattern der Check-Logs | `/var/log/rpi-*.log` | | `POE_FERNET_KEY` | Pfad zum Fernet-Schlüssel | `/fernet.key` (auto-erzeugt)| | `POE_KNOWN_HOSTS` | Pfad zur SSH-known_hosts-Datei des Terminals| `/known_hosts` (auto-erzeugt)| | `POE_SECRET_KEY` | Flask Secret Key (überschreibt Datei) | zufällig, in `secret.key` gespeichert| | `PORT`, `FLASK_DEBUG` | Flask-Serverport / Debug-Modus | `5000` / aus | ## Browser-SSH-Terminal (Switch-Verbindungstest) „Verbindung testen“ im Switch-Modal öffnet eine WebSocket-Verbindung zu `/ws/ssh_terminal`. Serverseitig baut **paramiko** eine echte SSH-Sitzung zum Switch auf (inkl. interaktiver Host-Key-Bestätigung beim Erstkontakt, danach dauerhaft in `known_hosts` gemerkt) und reicht eine interaktive Shell 1:1 an ein xterm.js-Terminal im Browser durch. Die Zugangsdaten aus dem Formular werden direkt für die SSH-Authentifizierung verwendet (nicht als Tastatureingabe in die Shell getippt) — Erfolg/Fehlschlag der Anmeldung wird sofort und eindeutig im Terminal angezeigt. Ein Klick auf „Passwort einfügen“ sendet den aktuell im Formular eingetragenen Wert zusätzlich als Tastatureingabe (z.B. für ein `sudo`-Passwort in der geöffneten Sitzung). Voraussetzungen: - Läuft auf **jedem Betriebssystem** (paramiko ist reines Python) — die SSH-Verbindung wird dabei immer vom PoE-Server aus aufgebaut, nie vom Browser/Client. - Nur für eingeloggte **Admins** erreichbar. - Der Flask-Entwicklungsserver muss mit `threaded=True` laufen (ist bereits so konfiguriert) — für einen echten Produktivbetrieb empfiehlt sich ohnehin ein WSGI-Server mit WebSocket-Unterstützung (z.B. Gunicorn mit `gevent`- oder `eventlet`-Worker) statt des eingebauten Dev-Servers. - Da `poe_web.service` (wie im Original) als `root` läuft, kann über dieses Terminal im Prinzip jeder erreichbare Host per SSH kontaktiert werden — bewusst so gewählt, da Admins über die App ohnehin schon vollen Zugriff auf alle hinterlegten Switch-Zugangsdaten haben. Für eine strengere Trennung empfiehlt es sich, `poe_web.service` künftig unter einem eigenen, unprivilegierten Systembenutzer laufen zu lassen (im Original wie auch hier aktuell `root`, um Änderungen am produktiven Setup nicht zu vergrößern). ## Projektstruktur ``` srv/poe_manager/ Flask-App (Backend + Templates + Static-Assets) usr/local/bin/custom/ poe.sh — Ping-Check & PoE-Restart per SSH (expect) etc/systemd/system/ Service-/Timer-Units (Web-App + Check-Dienst) etc/nginx/ Reverse-Proxy-Konfiguration install.sh Produktiv-Installer ```