govulncheck ab sofort fest im Release-Prozess. Baseline-Scan fand 6 aktiv aufgerufene Vulns (SSH-Backup-Pfad internal/services/backup/remote): - 5× golang.org/x/crypto (SSH DoS/Deadlock/Panic: GO-2026-5013/5017/5018/5019/5020) → x/crypto v0.51.0 => v0.52.0 - 1× golang.org/x/net (GO-2026-5026) → v0.53.0 => v0.55.0 Re-Scan danach: "No vulnerabilities found." Go-Quality-Baseline (Makefile + .golangci.yml, portabel): - release-check läuft autom. vor jedem deb/publish: vet → golangci-lint (Rollout: non-blocking) → govulncheck (HARTER Gate) → build → test -race. - make vulncheck / make test-race als eigene Targets. - .golangci.yml: staticcheck/govet/errcheck/ineffassign/unused/misspell + gosec/bodyclose/rowserrcheck/sqlclosecheck/noctx/contextcheck. - go test -race: aktuell 0 Races (Gate sicher). Doku in CLAUDE.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
12 KiB
⚠️ GOLDENE REGEL — NIEMALS RATEN. IMMER LESEN.
Nicht verhandelbar. Keine Ausnahmen.
Vor jeder Entscheidung über Feldwerte, API-Shapes, Dateinamen, Funktions-Signaturen, Konfigurationsparameter oder Architektur-Details: erst Original lesen, dann arbeiten.
- Referenz-Backend (Go-Patterns, Migrations, Cluster, Packaging) →
ac_search_code(project_id=6)oder direkt/var/www/mail-gateway - Referenz-UI/Bootstrap (React/AntD, i18n, Design-System, Install-Onliner) →
ac_search_code(project_id=5)oder direkt/var/www/netcell-webpanel - Alter Docker-Stack (nur für Feature-Scope-Referenz!) →
ac_search_code(project_id=3)oder/var/www/proxy-lb-waf - Im Zweifel → Rückfrage statt Annahme.
EdgeGuard Native (eg)
Native Neufassung des Docker-basierten EdgeGuard-Stacks. Kein Docker — alle Dienste nativ unter systemd. Zielplattform: Debian 13 (Trixie), amd64 + arm64. Auslieferung als signiertes
.deb.Hinweis: Mehrere ursprüngliche v1-Nicht-Ziele (WAF, IDS/IPS, DHCP, RADIUS) sind inzwischen umgesetzt — siehe „Feature-Stand" weiter unten.
Repository & Server
- Gitea: https://git.netcell-it.de/projekte/edgeguard-native
- SSH-Clone:
ssh://git@git.netcell-it.de:1922/projekte/edgeguard-native.git - Lokal (Dev):
/var/www/edgeguard-native·ssh linux@89.163.205.87 - Architect Center: Projekt ID 8
- Git-Server: git.netcell-it.de · SSH Port 1922 ·
git push origin main
MCP-Tools (Architect Center)
project_id: 8 · Session: $ARCHITECT_SESSION · MCP-Server: architect
Beim Session-Start (PFLICHT)
ac_recall(query="<aktuelle Aufgabe>", project_id=8, session_name="$(printenv ARCHITECT_SESSION)")
ac_search_code(query="<Stichworte>", project_id=8, session_name="$(printenv ARCHITECT_SESSION)", limit=6)
Alle Tools
| Tool | Wann verwenden |
|---|---|
ac_recall(query, project_id=8, session_name) |
Session-Start — relevante Memories laden |
ac_search_code(query, project_id=8, session_name, limit?) |
Vor JEDEM neuen Code schreiben |
ac_search_code_global(query, session_name, limit?) |
Suche über alle Projekte hinweg |
ac_remember(text, category, project_id=8, session_name) |
Jede neue Erkenntnis / Entscheidung |
ac_create_bug(title, description?, priority?, session_name?) |
Bug gefunden |
ac_create_feature(title, description?, priority?, session_name?) |
Feature-Idee |
ac_create_task(title, description?, priority?, status?, project_id?) |
Follow-up Arbeit |
ac_update_task(id, status?, priority?, title?) |
Task-Status ändern |
ac_add_decision(title, content, category?, project_id?) |
Architekturentscheidung |
ac_notify(message, title?, type?) |
Status-Update senden |
ac_get_project(session_name) |
project_id für Session ermitteln |
ac_research(query, context?) |
Doku / CVE / Libraries recherchieren |
ac_review(code, language?, focus?) |
Code-Review nach Fertigstellung |
ac_analyze(text, question?) |
Logs / Outputs analysieren |
ac_remember Kategorien: decision · pattern · bugfix · convention · architecture · general
Stack
| Schicht | Technologie |
|---|---|
| API | Go 1.26, Gin, GORM (Queries), goose (Migrations) |
| UI | React 19, TypeScript strict, Vite, Ant Design 6, TanStack Query 5 |
| DB | PostgreSQL 16 (Distro-Paket), goose-Migrations in migrations/ |
| State/HA | PostgreSQL Logical Replication + Cluster-Agent-Heartbeat (mTLS); KeyDB Active-Active nur optional (Recommends, für Lizenz-Leader-Election/Shared-Cache) |
| Proxy/LB | HAProxy (Distro) — TLS-Termination, L7-Routing, LB |
| WAF | Coraza v3 + OWASP CRS, via HAProxy SPOE (edgeguard-waf-Agent) |
| IDS/IPS | CrowdSec + crowdsec-firewall-bouncer (nftables) — managed-wenn-installiert (kein Depends) |
| VPN | WireGuard (Kernel-Modul ab 5.6, wireguard-tools) |
| DNS | Unbound (Distro) — Forwarder+Cache mit DNSSEC, Cluster-internes Split-Horizon |
| DHCP | Kea (kea-dhcp4-server) — managed, default-off |
| AAA/RADIUS | FreeRADIUS (PAP/CHAP, files-based) — managed, default-off |
| NTP | chrony (Distro) |
| VIP/HA | keepalived (VRRP) |
| FW | nftables (Distro) |
| Forward-Proxy | Squid (Distro) |
| Auth/SSO | JWT (lokal) + 2FA/TOTP + OIDC/OAuth2 (Keycloak u. a.) |
| TLS | certbot + webroot-Plugin |
| Packaging | dpkg-deb (direkt, wie mail-gateway + netcell-webpanel) |
| Plattform | Debian 13 Trixie · amd64 + arm64 |
Feature-Stand (Stand 2026-06)
Über den ursprünglichen v1-Scope hinaus inzwischen umgesetzt (waren mal Nicht-Ziele):
- WAF — Coraza v3 + OWASP CRS via HAProxy SPOE (
edgeguard-waf) - IDS/IPS — CrowdSec +
crowdsec-firewall-bouncer(nftables-Bouncer); managed-wenn-installiert, kein hartes Depends - DHCP — Kea
kea-dhcp4-server(managed, default-off) - RADIUS — FreeRADIUS PAP/CHAP, files-based (managed, default-off)
- SSO — OIDC/OAuth2 (additiv, Rolle aus DB, lokaler Login bleibt)
- 2FA — TOTP
- IPv6 — Firewall-Regeln + NAT familienbewusst
- HA — VIP via keepalived (VRRP), PG-Logical-Replication, bidirektionaler Cluster-Heartbeat
Damit ist die ursprüngliche v2-Roadmap (WAF, 2FA, IPv6-FW, OIDC, DHCP, RADIUS) abgearbeitet.
Nicht-Ziele (weiterhin)
- Kein Docker — alle Dienste nativ unter systemd
- Kein Network-IDS Suricata — Intrusion-Detection läuft über CrowdSec, nicht über Suricata-Paket-Inspektion
- Keine Mail-Verarbeitung (eigenes Produkt: mail-gateway)
- Keine Multi-Tenant-GuardZones
- Keine ISO-Builds (kein EdgeGuardOS-Klon — nur APT)
- Nur Debian 13 — kein Ubuntu, kein Debian 12, kein RHEL
Binaries & Ports
| Binary | Beschreibung | Bindet | User |
|---|---|---|---|
edgeguard-api |
REST Management-API | 127.0.0.1:9443 |
edgeguard |
edgeguard-scheduler |
Cron-Jobs (ACME-Renew, Backup, Health) | — | edgeguard |
edgeguard-ctl |
CLI: initdb migrate cluster-join promote dump-config |
— | root/edgeguard |
HAProxy terminiert TLS auf :443, routet per Host-Header an Backends und fällt für Management-FQDN/ACME-Webroot auf 127.0.0.1:9443 (edgeguard-api) zurück. Die Management-UI wird von edgeguard-api ausgeliefert (statisch aus /usr/share/edgeguard/ui/ oder embedded).
Build
make build # Host-Architektur (amd64)
make test # go test ./...
make test-race # go test -race ./... (Race-Detector)
make lint # go vet + golangci-lint
make vulncheck # govulncheck ./... (Go-Vuln-DB-Scan)
make release-check # Go-Quality-Baseline (läuft autom. vor jedem deb/publish)
make deb # amd64 + arm64 .deb (führt release-check aus)
make publish # deb + Upload Gitea Package Registry
make install-local # direkt auf Dev-Server installieren (kein .deb)
# UI
cd management-ui && bun install && bun run build
Go-Quality-Baseline (PFLICHT vor jedem Release)
make deb/make publish führen automatisch release-check aus — Reihenfolge:
go vet → golangci-lint run → govulncheck ./... → go build → go test -race.
govulncheckist ein HARTER Gate — Build bricht ab, wenn der Code eine bekannte CVE tatsächlich aufruft. Tool wird bei Bedarf autom. installiert. Zusätzlich sinnvoll: wöchentlicher CI-Cron (CVEs tauchen auch ohne Code-Änderung auf).golangci-lint(.golangci.yml: staticcheck, govet, errcheck, ineffassign, unused, misspell, gosec, bodyclose, rowserrcheck, sqlclosecheck, noctx, contextcheck) läuft im Rollout noch NON-BLOCKING (Bestand aufräumen), danach auf harten Gate stellen.go test -race— Race-Detector; findet Nebenläufigkeits-Bugs (Scheduler/Worker), die normale Tests durchlassen.- Portabel als „Go-Quality-Baseline" für weitere Go-Projekte gedacht.
Dev-Server Quickstart
# Abhängigkeiten installieren
sudo apt-get install -y postgresql-16 haproxy wireguard-tools squid unbound nftables certbot
# API starten (ohne systemd, für Entwicklung)
go run ./cmd/edgeguard-api/
# UI Dev-Server
cd management-ui && bun run dev
Projektstruktur
/var/www/edgeguard-native/
├── cmd/
│ ├── edgeguard-api/ # Management-API (Gin, 127.0.0.1:9443)
│ ├── edgeguard-scheduler/ # Cron-Jobs
│ └── edgeguard-ctl/ # CLI
├── internal/
│ ├── database/ # pgxpool + goose-Runner; migrations/ via go:embed
│ │ └── migrations/ # SQL (goose-Format) — embedded ins Binary
│ ├── models/ # GORM-Models
│ ├── handlers/ # HTTP-Handler (REST)
│ ├── services/ # Business-Logik
│ ├── haproxy/ # Config-Generator (TLS + Routing + LB)
│ ├── squid/ # Config-Generator
│ ├── wireguard/ # Config-Generator
│ ├── unbound/ # Config-Generator (Forwarder + Cluster-DNS)
│ ├── firewall/ # nftables-Generator
│ ├── cluster/ # Join/Promote/Peer-Discovery
│ ├── aggregator/ # Cluster-View APIs
│ └── license/ # Lizenz-Validierung
├── management-ui/ # React 19 + AntD 6 (1:1 enconf-Pattern)
├── packaging/debian/ # control, postinst, postrm, systemd-Units
├── deploy/
│ ├── systemd/ # *.service, *.target, *.timer
│ ├── haproxy/ # (Templates liegen jetzt neben Renderer in internal/<svc>/)
│ ├── squid/ # squid.conf.tpl
│ ├── unbound/ # unbound.conf.tpl
│ └── nftables/ # ruleset.nft.tpl
├── scripts/
│ ├── apt-repo/ # build-package.sh, publish.sh
│ └── install.sh # Bootstrap curl-Onliner
├── docs/
│ └── architecture.md # Vollständige Architektur-Spec
├── go.mod
├── Makefile
├── CLAUDE.md # Diese Datei
└── agent.md # Agent-Factory Pipeline
Key Conventions
Go-Code
- Migrations: goose SQL-Dateien in
internal/database/migrations/, via//go:embedins Binary — NICHT GORM AutoMigrate - ORM: GORM für Queries, nicht für Schema-Verwaltung
- Config-Generierung: Template-Datei in
deploy/*/, Generator ininternal/*/ - Config-Reload:
systemctl reload <service>nach Config-Schreiben - Cluster-Primary-Ermittlung: zuverlässig über
pg_publication(edgeguard_shared); Primary-URL aussetup.jsonPrimaryFQDNviaclusterjoin.NormalizePrimaryURL. Kein Write-Proxy — Schreibzugriffe auf geteilte Tabellen erfolgen am Primary. - Failover:
edgeguard-ctl promoteist Logical-Replication-aware (Subscription lösen →setupReplicationPrimary→ Publisher werden, inkl. PG-Restart fürwal_level=logical); erholte Nodes danach viacluster-setup-standby <neuer-primary>zurückhängen.
Packaging
dpkg-debdirekt (wie mail-gateway) — kein dh_make/debhelper/fpm- postinst: User anlegen → Dirs → initdb (idempotent) → migrate → systemctl
- postrm purge: nur bei
purgeDB + User entfernen
UI
- 100% enconf-Pattern (netcell-webpanel/management-ui/) — keine eigenen Design-Entscheidungen
import typefür alle Type-Imports (verbatimModuleSyntax!)- AntD 6, kein Tailwind, kein Material UI
Auth
- JWT-basiert (analog enconf), Secret in
/var/lib/edgeguard/.jwt_fingerprint - Admin-Check: immer aus DB-User-Row, nie aus JWT-Payload
Vollständige Architektur
→ docs/architecture.md
Vor jeder Änderung
- Referenz-Pattern in mail-gateway oder netcell-webpanel lesen
ac_search_codevor neuem Code — Pattern existiert meist schonmake testnach Backend-Änderungencd management-ui && npx tsc --noEmitnach Frontend-Änderungen