From f78ada7732f5baffd6dc095e570125d29c07bbac Mon Sep 17 00:00:00 2001 From: Debian Date: Mon, 11 May 2026 07:04:45 +0200 Subject: [PATCH] fix(api): Service-Mutationen rendern jetzt auch FW automatisch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: Wenn der Operator eine NTP/DNS/Squid/WG-Mutation gemacht hat, wurde nur der Service neu konfiguriert + reloadet — die Auto-FW- Rules (udp/123, udp/tcp 53, tcp 3128, udp/) blieben aber auf dem Stand des letzten firewall-renders. Operator musste manuell 'edgeguard-ctl render-config --only=nftables' fahren. Fix: withFW-Wrapper in main.go der nach jedem Service-Reloader auch den firewall-Renderer aufruft. Service-Reload-Errors propagieren weiterhin (Aktion gilt als gescheitert), FW-Render-Errors werden nur geloggt (DB-Row ist commited, FW kann nachgezogen werden). Wirkt für: WG, Squid, DNS, NTP. (HAProxy nicht — Domains/Backends generieren keine Auto-FW-Rules.) Version 1.0.41. Co-Authored-By: Claude Opus 4.7 (1M context) --- VERSION | 2 +- cmd/edgeguard-api/main.go | 41 ++++++++++++++----- cmd/edgeguard-ctl/main.go | 2 +- cmd/edgeguard-scheduler/main.go | 2 +- management-ui/package.json | 2 +- .../src/components/Layout/Sidebar.tsx | 2 +- 6 files changed, 36 insertions(+), 15 deletions(-) diff --git a/VERSION b/VERSION index 42de374..7cb055c 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.0.40 +1.0.41 diff --git a/cmd/edgeguard-api/main.go b/cmd/edgeguard-api/main.go index 4196888..b4d4dce 100644 --- a/cmd/edgeguard-api/main.go +++ b/cmd/edgeguard-api/main.go @@ -45,7 +45,7 @@ import ( wgsvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/wireguard" ) -var version = "1.0.40" +var version = "1.0.41" func main() { addr := os.Getenv("EDGEGUARD_API_ADDR") @@ -184,33 +184,54 @@ func main() { } handlers.NewFirewallHandler(fwZones, fwAddrObj, fwAddrGrp, fwSvc, fwSvcGrp, fwRules, fwNAT, auditRepo, nodeID, fwReloader, pool).Register(authed) + // withFW wraps a service-reloader so that AFTER the service is + // reloaded, the firewall is also re-rendered. Necessary for + // services whose state feeds the auto-FW-rule generator (DNS + // listen-IPs, Squid ACL count, WG listen-port, NTP serve-clients). + // Service-Reload-Errors propagieren; FW-Errors werden nur + // geloggt (DB-Row ist commited, FW kann nachgezogen werden). + withFW := func(svc func(context.Context) error) func(context.Context) error { + return func(ctx context.Context) error { + if err := svc(ctx); err != nil { + return err + } + if err := fwReloader(ctx); err != nil { + slog.Warn("firewall: re-render after service mutation failed", "error", err) + } + return nil + } + } + // WireGuard reload: re-render /etc/edgeguard/wireguard/*.conf // + restart wg-quick@. Same pattern as the haproxy + - // firewall reloaders. + // firewall reloaders. WG braucht FW-Trigger (server-mode + // listen-port wird Auto-Rule). wgReloader := func(ctx context.Context) error { return wgrender.New(pool, secretsBox).Render(ctx) } - handlers.NewWireguardHandler(wgIfaces, wgPeers, secretsBox, auditRepo, nodeID, wgReloader).Register(authed) + handlers.NewWireguardHandler(wgIfaces, wgPeers, secretsBox, auditRepo, nodeID, withFW(wgReloader)).Register(authed) // Squid forward-proxy reload — re-render squid.conf + reload - // squid.service. sudoers im postinst whitelistet das. + // squid.service. sudoers im postinst whitelistet das. ACL-Count + // triggert Auto-FW-Rule für tcp/3128. squidReloader := func(ctx context.Context) error { return squidrender.New(pool).Render(ctx) } - handlers.NewForwardProxyHandler(fwdProxyRepo, auditRepo, nodeID, squidReloader).Register(authed) + handlers.NewForwardProxyHandler(fwdProxyRepo, auditRepo, nodeID, withFW(squidReloader)).Register(authed) - // Unbound DNS reload — re-render edgeguard.conf + reload - // unbound.service. + // Unbound DNS reload — re-render edgeguard.conf + restart + // unbound. Listen-IPs triggern Auto-FW-Rule für udp/tcp 53. unboundReloader := func(ctx context.Context) error { return unboundrender.New(pool).Render(ctx) } - handlers.NewDNSHandler(dnsRepo, auditRepo, nodeID, unboundReloader).Register(authed) + handlers.NewDNSHandler(dnsRepo, auditRepo, nodeID, withFW(unboundReloader)).Register(authed) - // Chrony NTP reload — re-render edgeguard.conf + reload chrony. + // Chrony NTP reload — re-render edgeguard.conf + restart chrony. + // Listen-IPs + serve_clients triggern Auto-FW-Rule für udp/123. chronyReloader := func(ctx context.Context) error { return chronyrender.New(pool).Render(ctx) } - handlers.NewNTPHandler(ntpRepo, auditRepo, nodeID, chronyReloader).Register(authed) + handlers.NewNTPHandler(ntpRepo, auditRepo, nodeID, withFW(chronyReloader)).Register(authed) } mountUI(r) diff --git a/cmd/edgeguard-ctl/main.go b/cmd/edgeguard-ctl/main.go index c4d3abf..dff1ad1 100644 --- a/cmd/edgeguard-ctl/main.go +++ b/cmd/edgeguard-ctl/main.go @@ -9,7 +9,7 @@ import ( "os" ) -var version = "1.0.40" +var version = "1.0.41" const usage = `edgeguard-ctl — EdgeGuard CLI diff --git a/cmd/edgeguard-scheduler/main.go b/cmd/edgeguard-scheduler/main.go index 209317c..41fa490 100644 --- a/cmd/edgeguard-scheduler/main.go +++ b/cmd/edgeguard-scheduler/main.go @@ -21,7 +21,7 @@ import ( "git.netcell-it.de/projekte/edgeguard-native/internal/services/tlscerts" ) -var version = "1.0.40" +var version = "1.0.41" const ( // renewTickInterval — how often we re-evaluate expiring certs. diff --git a/management-ui/package.json b/management-ui/package.json index f814ef4..5c74d5f 100644 --- a/management-ui/package.json +++ b/management-ui/package.json @@ -1,7 +1,7 @@ { "name": "edgeguard-management-ui", "private": true, - "version": "1.0.40", + "version": "1.0.41", "type": "module", "scripts": { "dev": "vite", diff --git a/management-ui/src/components/Layout/Sidebar.tsx b/management-ui/src/components/Layout/Sidebar.tsx index bf5b468..5b0a220 100644 --- a/management-ui/src/components/Layout/Sidebar.tsx +++ b/management-ui/src/components/Layout/Sidebar.tsx @@ -75,7 +75,7 @@ const NAV: NavSection[] = [ }, ] -const VERSION = '1.0.40' +const VERSION = '1.0.41' export default function Sidebar({ isOpen, onClose }: SidebarProps) { const { t } = useTranslation()