No description
  • Go 65.7%
  • TypeScript 21.9%
  • HTML 5.5%
  • JavaScript 3.7%
  • PowerShell 1.3%
  • Other 1.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Manuel Gläser fec9eae1cd
All checks were successful
Image bauen / image (push) Successful in 50s
pfirewall-Parser: die Kopfzeile eines echten Hosts als Vorlage
Windows 10 25H2 fuehrt hinter „path" noch „pid" — ein Feld, das aeltere
Fassungen nicht haben und das in den meisten Beispielen fehlt. Aufgenommen
von einem laufenden Host.

Gedeutet wurde es von Anfang an richtig, weil der Parser die Positionen
aus der Kopfzeile liest. Der Test haelt genau das fest: Stuende die
Paketgroesse eine Stelle daneben, kaeme statt 363 eine Portnummer heraus.

Damit stehen drei Kopfzeilenformen nebeneinander im Test — mit pid, ohne
pid, und ganz ohne path. Alle drei gibt es im Bestand.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-02 21:17:09 +00:00
.forgejo/workflows latest nicht mehr zurückdrehen, Versionsvergleich ehrlich benennen 2026-08-01 22:52:59 +00:00
agent pfirewall-Parser: die Kopfzeile eines echten Hosts als Vorlage 2026-08-02 21:17:09 +00:00
deploy install.ps1 darf Umlaute tragen: UTF-8 mit BOM 2026-08-02 21:03:24 +00:00
design Hostliste über die volle Breite statt Seitenleiste 2026-08-01 09:56:08 +00:00
docs Selbst-Update mit der gehärteten Unit vertragen, danach nachfassen 2026-08-02 10:54:40 +00:00
server Selbst-Update: Server und Agent bilden den Binärnamen gemeinsam 2026-08-02 21:05:59 +00:00
shared Selbst-Update: Server und Agent bilden den Binärnamen gemeinsam 2026-08-02 21:05:59 +00:00
web Anmeldedialog: Fragezeichen in der Zeile, Inhalt fluchtend, Ansible raus 2026-08-02 21:13:38 +00:00
.dockerignore nfthub 0.0.1 2026-08-01 07:15:24 +00:00
.gitignore nfthub 0.0.1 2026-08-01 07:15:24 +00:00
CHANGELOG.md Changelog: die PowerShell-7-Lücke nachtragen 2026-08-02 20:44:33 +00:00
DECISIONS.md nfthub 0.0.1 2026-08-01 07:15:24 +00:00
go.mod Schnellaktion: bei ausgehendem Verkehr das Ziel eingrenzen 2026-08-02 10:19:11 +00:00
go.sum nfthub 0.0.1 2026-08-01 07:15:24 +00:00
Makefile Windows-Agent: Protokoll, Konfiguration, Bau und Anmeldung 2026-08-02 18:32:51 +00:00
README.md README auf den tatsächlichen Stand, tote Inventar-Schlüssel raus 2026-08-01 07:30:49 +00:00

nfthub

Zentrale Verwaltung der nftables-Firewalls mehrerer Linux-Hosts. Mehrere Besitzer („Owner") verwalten jeweils ausschließlich ihre eigenen Hosts: Firewall-Ereignisse einsehen und geblockten Verkehr per Quick-Action freischalten. Administratoren sehen und verwalten alles.

Kein SSH vom Server zu den Hosts, keine zentral hinterlegten Host-Zugangsdaten. Stattdessen verbindet sich ein Agent von jedem Host aus nach außen zum Server.

Frühe Alpha. Im eigenen Netz im Einsatz, aber weder im Funktionsumfang noch in den Schnittstellen festgelegt. Solange die Hauptversion 0 ist, kann sich in jeder Nebenversion alles ändern — auch das Datenbankschema und das Agent-Protokoll. Siehe CHANGELOG.md.


Architektur

flowchart TB
    browser["Browser<br/>OIDC-Sitzung"]
    server["nfthub-server<br/>REST-API + WebSocket<br/>Regelrenderer<br/>Weboberfläche (eingebettet)"]

    agent1["nfthub-agent<br/>pve01"]
    agent2["nfthub-agent<br/>docker01"]
    agent3["nfthub-agent<br/>mail01"]

    tab1["table inet nfthub<br/>NFLOG → Ereignisse"]
    tab2["table inet nfthub<br/>NFLOG → Ereignisse"]
    tab3["table inet nfthub<br/>NFLOG → Ereignisse"]

    browser -- HTTPS --> server
    agent1 -- "TLS, vom Host aufgebaut" --> server
    agent2 --> server
    agent3 --> server

    agent1 --- tab1
    agent2 --- tab2
    agent3 --- tab3

Die Pfeile zeigen die Richtung des Verbindungsaufbaus, und sie ist bewusst so gewählt: Der Agent verbindet sich nach außen zum Server. Kein Host braucht einen eingehenden Port für die Verwaltung, und der Server hält keine Zugangsdaten zu den Hosts vor. Über dieselbe Verbindung fließen Ereignisse nach oben und Regeländerungen nach unten.

Drei Bestandteile in einem Repository:

  • server/ — Go, ein einzelnes Binary. REST-API, OIDC-Anmeldung, Agent-Anbindung samt Freigabe, Regelrenderer. Die Weboberfläche und die Agent-Binaries sind per go:embed eingebettet; es gibt nichts getrennt auszuliefern.
  • agent/ — Go, statisch gelinkt, ohne cgo. Läuft als Dienst auf jedem Host, liest Firewall-Ereignisse über NFLOG und wendet Regeln an.
  • web/ — React 19 mit TypeScript, Vite, TailwindCSS v4.

Wie ein Host dazukommt

Hosts werden nicht vorab angelegt. Sie entstehen dadurch, dass sich ein Agent meldet:

  1. In der Oberfläche unter Hosts → Host hinzufügen stehen das Instanz-Token und — bei eigenem TLS — der Agent-TLS-Pin. Das Instanz-Token ist dauerhaft und mehrfach nutzbar; es meldet beliebig viele Hosts an.

  2. Auf dem Host läuft das Einrichtungsskript:

    curl -fsSL https://nfthub.example.org/download/install.sh \
      | sh -s -- --server wss://nfthub.example.org:8443/agent/connect --token TOKEN
    

    Es erkennt Debian/Ubuntu, die RHEL-Familie und Alpine, dazu systemd und OpenRC, wählt das passende Binary, prüft die Prüfsumme, legt Dienst und Konfiguration an und startet ihn. Wer die Schritte einzeln gehen will, findet sie im selben Dialog.

  3. Der Agent tauscht das Enrollment-Token gegen ein dauerhaftes, host-gebundenes Token, das serverseitig nur als Hash liegt.

  4. Der neue Host erscheint als ausstehend und bekommt erst nach der Freigabe durch einen Administrator Regeln. Bis dahin liefert er nichts und empfängt nichts.

Danach hält der Agent eine ausgehende TLS-Verbindung offen, sendet alle 30 Sekunden einen Heartbeat und empfängt darüber Regeländerungen. Fällt die Verbindung aus, wendet er beim nächsten Start den zuletzt bestätigten Regelstand aus seinem Zustand an — der Host steht also nie ungefiltert da, nur weil der Server gerade nicht erreichbar ist.

Entfernen geht denselben Weg zurück: install.sh --uninstall hält den Dienst an, löscht die eigene nft-Table und räumt Binary, Konfiguration und Zustand ab.


Regeln

Regeln entstehen in der Oberfläche, nicht in einer Datei. Sie tragen einen Geltungsbereich — Instanz, Owner oder einzelner Host — und werden in dieser Reihenfolge zusammengeführt; das Speziellere gewinnt. Aus dem Ergebnis rendert der Server eine vollständige table inet nfthub und schickt sie an den Agent, der sie mit nft -f atomar anwendet und bei einem Fehler zurückrollt.

Zwei Betriebsarten je Host:

  • Monitor — es wird nichts verworfen, nur protokolliert. Was eine Regel blockieren würde, erscheint als Ereignis. Der Weg, ein Regelwerk gefahrlos einzufahren.
  • Enforce — die Regeln greifen.

Unantastbar sind zwei Dinge, die keine Regel überschreiben kann: die Management-Ports (Vorgabe 22) und der Weg des Agents zum Server. Steht die Grundregel auf „ausgehend alles verwerfen", setzt der Renderer die nötigen Ausnahmen selbst an den Anfang der Kette — inklusive Namensauflösung, ohne die ein Agent seinen Server nach einem Neustart nicht wiederfände. Ist der Weg zum Server nicht bekannt, verweigert er die Konfiguration lieber, als den Host abzuschneiden.

Geblockter Verkehr lässt sich direkt an der Ereigniszeile freischalten (Quick-Action): Umfang, Dauer und Geltungsbereich wählen, fertig. Die Rückmeldung nennt den tatsächlichen Rollout-Ausgang und bietet „Rückgängig" an.


Voraussetzungen

  • Go ≥ 1.25 und Node ≥ 24 zum Bauen
  • Ein OIDC-Provider (entwickelt und getestet gegen Authentik)
  • Optional PostgreSQL ≥ 18; ohne Angabe wird SQLite verwendet
  • Auf den Hosts: nft und conntrack — das Einrichtungsskript installiert beides

Schnellstart

make build          # Frontend bauen, einbetten, Binaries erzeugen
./dist/nfthub-server

Beim ersten Start läuft der Server im Einrichtungsmodus und gibt ein Setup-Token aus:

────────────────────────────────────────────────────────────────────────
  nfthub läuft im Einrichtungsmodus.

  Oberfläche:   http://localhost:8080/setup
  Setup-Token:  BXGoqfyFD6Wj0B7v4o4nXDWZxryNNYwT
────────────────────────────────────────────────────────────────────────

Das Token gilt nur für diesen Prozess. Der Wizard führt durch fünf Schritte:

  1. Datenbank — SQLite (eine Datei) oder PostgreSQL (DSN), auf Wunsch mit mTLS. Die Migrationen laufen automatisch; ein Wechsel ist ohne Neustart möglich.
  2. Anmeldung — externe Basis-URL, Issuer, Client-ID und -Secret, Claims und Bootstrap-Admin-Gruppe. Die einzutragende Redirect-URI steht zum Kopieren bereit.
  3. Basis-Policy — Management-Ports und die Vorgabe für ausgehenden Verkehr.
  4. Benachrichtigung — SMTP für die Meldung, dass ein Host auf Freigabe wartet. Überspringbar.
  5. Abschluss — Konfiguration festschreiben, Einrichtungsmodus sperren.

Für die vollständige Inbetriebnahme — Server mit Docker oder systemd, eigenes TLS, Reverse Proxy, Agent-Verteilung per Ansible — siehe docs/deployment.md. Ergänzend: Authentik einrichten.

Entwicklung

make dev            # Server auf :8080 plus Vite auf :5173 mit Hot Reload
make dev-seed       # dasselbe mit erzeugten Fake-Ereignissen, ohne echte Hosts
make test           # Go- und Frontend-Tests
make check          # Formatierung, go vet, Typecheck, Tests
make test-postgres  # dieselben Tests gegen eine echte PostgreSQL-Instanz

make test-postgres erwartet eine erreichbare Datenbank (PG_DSN=postgres://… überschreibt das Ziel) und legt für jeden Test ein eigenes Schema an, das danach wieder verschwindet. Ohne NFTHUB_TEST_PG_DSN laufen alle Tests gegen SQLite. Beides zu fahren lohnt sich: Der PostgreSQL-Lauf hat mehrfach Fehler aufgedeckt, die unter SQLite nicht auftreten können — zuletzt eine Ganzzahl in einer BOOLEAN-Spalte, die dort jede Host-Anmeldung scheitern ließ.


Einrichtung ohne Wizard

Für Infrastructure-as-Code lässt sich alles per Umgebung vorgeben. Ist die Konfiguration vollständig, wird der Wizard übersprungen. Halb ausgefüllt startet der Server bewusst nicht — lieber ein klarer Abbruch als eine Instanz, die teilweise konfiguriert ins Netz geht.

NFTHUB_BASE_URL=https://nfthub.example.org
NFTHUB_LISTEN=:8080
NFTHUB_DATA_DIR=/var/lib/nfthub
NFTHUB_MASTER_KEY_FILE=/run/secrets/nfthub-master-key
NFTHUB_TRUSTED_PROXIES=10.0.0.0/8

NFTHUB_DB_DRIVER=postgres
NFTHUB_DB_DSN=postgres://nfthub@db.example.org:5432/nfthub

NFTHUB_OIDC_ISSUER=https://auth.example.org/application/o/nfthub/
NFTHUB_OIDC_CLIENT_ID=NFTHUB_OIDC_CLIENT_SECRET=NFTHUB_OIDC_ADMIN_GROUPS=nfthub-admins
NFTHUB_OIDC_USERNAME_CLAIM=preferred_username
NFTHUB_OIDC_GROUPS_CLAIM=groups

NFTHUB_MGMT_TCP_PORTS=22

Alternativ nimmt NFTHUB_CONFIG=/etc/nfthub/nfthub.env dieselben Schlüssel aus einer Datei entgegen; echte Umgebungsvariablen haben Vorrang.

Einen Master-Key erzeugen:

./dist/nfthub-server -master-key

Wird keiner angegeben, legt der Server beim ersten Start selbst einen unter $NFTHUB_DATA_DIR/master.key an und weist deutlich darauf hin. Geht diese Datei verloren, sind alle verschlüsselt gespeicherten Secrets unlesbar.


Sicherheitsmodell

Owner-Trennung wird serverseitig erzwungen, nicht im Frontend. Jede Abfrage, die Hosts, Ereignisse, Regeln oder Audit-Einträge liest oder verändert, nimmt einen Zugriffsbereich entgegen und baut die Einschränkung selbst in das SQL ein. Es gibt keine Variante ohne Zugriffsbereich, die man versehentlich verwenden könnte. Zugriffe auf fremde Objekte werden mit „nicht gefunden" beantwortet — mit derselben Antwort wie für nicht existierende Objekte, damit deren Existenz nicht durchsickert. Tests prüfen genau diese Grenze.

Anmeldung ausschließlich über OIDC, mit PKCE (S256), Nonce-Prüfung und einem state, der genau einmal eingelöst werden kann. Die Rolle wird bei jeder Anmeldung aus dem Gruppen-Claim neu bestimmt.

Sitzungen liegen serverseitig und sind damit widerrufbar. In der Datenbank steht nur der SHA-256 des Cookie-Werts — ein Datenbankleck liefert keine verwendbaren Sitzungen. Das Cookie ist HttpOnly und SameSite=Lax; das Secure-Flag richtet sich nach dem Schema der konfigurierten Basis-URL. Verändernde Anfragen brauchen zusätzlich das CSRF-Token der Sitzung.

Agent-Anmeldung: Ein neuer Host bleibt „ausstehend", bis ein Administrator ihn freigibt — der Besitz des Instanz-Tokens allein reicht nicht, um verwaltet zu werden. Das dauerhafte Agent-Token liegt serverseitig nur als Hash.

IP-Zugriffsbeschränkung wird bei jeder Anfrage geprüft, nicht nur bei der Anmeldung — eine bestehende Sitzung soll einen Standortwechsel nicht überdauern. X-Forwarded-For wird nur ausgewertet, wenn die direkte Gegenstelle in der Liste vertrauenswürdiger Proxys steht; sonst zählt allein die Verbindungsadresse.

Aussperrschutz auf zwei Ebenen: Der letzte aktive Administrator lässt sich weder herabstufen noch sperren. Und der Regelrenderer verweigert Konfigurationen, die dem Agent den Weg zum Server abschneiden würden.

Secrets at rest: OIDC-Client-Secret und SMTP-Passwort werden mit AES-256-GCM verschlüsselt gespeichert. Der Master-Key kommt aus der Umgebung, aus einer Datei oder wird beim ersten Start erzeugt.

Content-Security-Policy ohne externe Quellen. Schriften sind lokal gebündelt, es gibt keine CDN-Abhängigkeit. script-src kommt ohne unsafe-inline aus: Der Server berechnet beim Start den SHA-256 des einen Inline-Skripts aus der eingebetteten index.html und nimmt genau diesen Hash auf.

Der Server läuft unprivilegiert. Nur der Agent braucht Rechte auf dem Host, und er führt niemals Nutzereingaben als Shell-Befehl aus.


Konfigurationsschlüssel

Variable Vorgabe Bedeutung
NFTHUB_LISTEN :8080 Adresse des HTTP-Servers
NFTHUB_DATA_DIR ./data SQLite-Datei, Master-Key, Zustand
NFTHUB_BASE_URL Externe Adresse; Grundlage für Redirect-URI und Cookies
NFTHUB_TRUSTED_PROXIES leer CIDRs, deren X-Forwarded-For ausgewertet wird
NFTHUB_DB_DRIVER sqlite sqlite oder postgres
NFTHUB_DB_DSN Datei im Datenverzeichnis Verbindungszeichenfolge
NFTHUB_DB_SSL* sslmode und Zertifikate für PostgreSQL-mTLS
NFTHUB_DB_TLS_DIR /etc/nfthub/db-tls Wird nach vorbereiteten DB-Zertifikaten abgesucht
NFTHUB_MASTER_KEY / _FILE wird erzeugt Schlüssel für Secrets at rest
NFTHUB_OIDC_* Issuer, Client, Claims, Admin-Gruppen
NFTHUB_TLS_MODE leer file, selfsigned oder acme — eigenes HTTPS ohne Proxy
NFTHUB_TLS_LISTEN Adresse des HTTPS-Servers, etwa :8443
NFTHUB_MGMT_TCP_PORTS 22 Management-Ports der Basis-Policy
NFTHUB_SETUP_TOKEN_DISABLED false Setup-Token abschalten
NFTHUB_LOG_LEVEL info debug, info, warn, error
NFTHUB_DEV false Frontend vom Vite-Server beziehen

Die vollständige Liste mit allen TLS- und SMTP-Schlüsseln steht kommentiert in deploy/docker/.env.example.


Betrieb hinter einem Reverse-Proxy

nfthub kann TLS selbst terminieren (NFTHUB_TLS_MODE) oder es einem Proxy überlassen. Bei einem Proxy sind zwei Punkte wichtig:

  1. NFTHUB_BASE_URL muss die öffentliche Adresse sein. Sie bestimmt die Redirect-URI und entscheidet, ob Sitzungscookies das Secure-Flag tragen.
  2. NFTHUB_TRUSTED_PROXIES muss die Adresse des Proxys enthalten. Ohne diesen Eintrag sieht nfthub bei jedem Aufruf die Proxy-Adresse als Client-IP — die IP-Beschränkung liefe ins Leere, und das Audit-Log wäre wertlos.

Die Agents gehen üblicherweise am Proxy vorbei direkt auf den TLS-Port, damit zwischen Host und Server nichts vermittelt. Bei selbstsigniertem Zertifikat sichert der Agent-TLS-Pin diese Verbindung.


Projektstruktur

server/
  cmd/nfthub-server/     Einstiegspunkt
  internal/
    agenthub/            Agent-Verbindungen, Handshake, Heartbeat
    api/                 Router, Handler, Auslieferung von Frontend und Agent
    app/                 Laufzeitverdrahtung, austauschbare Datenbank
    auth/                OIDC, Sitzungen, CSRF, IP-Beschränkung
    config/              Konfiguration aus Umgebung und Datei
    db/                  SQLite/PostgreSQL, Migrationen je Dialekt
    dbtest/              Testdatenbanken für beide Dialekte
    demo/                erzeugte Ereignisse für die Oberflächenentwicklung
    live/                Verteilung der Ereignisse an die Browser
    notify/              SMTP-Benachrichtigung
    rollout/             Ausrollen der gerenderten Regeln
    rules/               Regelmodell, Merge-Reihenfolge, nft-Renderer
    secret/              Verschlüsselung der Secrets at rest
    setup/               First-Run-Wizard
    store/               Datenmodelle, Abfragen mit Owner-Scoping
    tlsserve/            eigenes HTTPS: file, selfsigned, ACME
agent/
  cmd/nfthub-agent/      Einstiegspunkt, -check, -version, -uninstall
  internal/
    agent/               Verdrahtung, Zustand über Neustarts hinweg
    detect/              Firewall-Stack und Fähigkeiten des Hosts
    events/              NFLOG über Netlink, /dev/kmsg als Rückfall
    nft/                 Anwenden mit Bestätigung und Rücknahme
    selfupdate/          Selbstaktualisierung mit Rückfall
    transport/           ausgehende TLS-Verbindung zum Server
    uninstall/           restloses Entfernen vom Host
web/                     React-Oberfläche
design/                  Design-Referenz und destillierte Design-Tokens
deploy/
  install.sh             Einrichtungsskript für Debian, RHEL und Alpine
  systemd/               Units für Server und Agent
  openrc/                Init-Skript und conf.d für Alpine
  docker/                Dockerfile, compose (SQLite und PostgreSQL), .env
  ansible/               Rolle und Beispiel-Playbook für das Agent-Rollout
docs/                    Inbetriebnahme, Authentik

Getroffene Annahmen und ihre Begründung stehen in DECISIONS.md.


Lizenz

Noch nicht festgelegt.