fix: Audit-Bugfixes (Auth/WAF/Firewall/Cluster/Renderer) — v1.2.94
Verifizierte Bugs aus dem Code-Audit behoben (je mit Test/Build/nft -c geprüft):
- session: IssueWithRoleTTL mutierte geteiltes s.TTL (Data-Race + falsche TTL) → interne issue(); -race-Test.
- auth: Fallback/Federation leiteten role/TOTP nicht aus DB ab (2FA-Bypass auf Secondary, Rolle aus Remote) → viaDB-Flag + DB-Re-Lookup.
- waf: TrustedProxies waren No-op (bogus-Direktive) → XFF-Auflösung im SPOE-Agent (rightmostXFF/ipMatchesAny); RuleExclusions/TrustedProxies validiert (Direktiven-Injection); GetForHost via net.SplitHostPort.
- firewall: Auto-Rule mit IPv6-DstIP erzeugte 'ip daddr <v6>' → bricht ganzes nft-Ruleset; jetzt familienbewusst (ip/ip6, ungültige raus).
- kea: 'interfaces': null bei 0 Subnets → leeres Array.
- cluster_repair: nodeHasPublication schluckte DB-Fehler (Resync auf falschem Node) → (bool,error) fail-closed; IPv6-Primary-URL via net.JoinHostPort.
- cluster_replication: Replikations-Passwort via stdin statt psql -c (nicht mehr in argv/Logs).
- wireguard: Config (Private Key) jetzt configgen.AtomicWrite VOR Symlink/enable; SkipReload-Feld.
- render.go: --no-reload jetzt für alle Renderer (squid/unbound/chrony/wireguard).
- radius: leeres Secret/Passwort + Newlines abgelehnt; freeradius confEscape strippt CR/LF.
- configorch: continue-on-error + errors.Join statt Abbruch mitten in der Sequenz.
- i18n: fehlender Key common.status (de/en).
Verworfen als kein Bug: WAF detection-'blocked' (DetectionOnly liefert keine Interruption), render secrets.New('') (nutzt Default-Masterkey), FanOut-Sort (nur Kommentar), pg_hba (durch nft abgesichert).
Offen/bewusst zurückgestellt (low/risk): AlertWriter-Close (langlebiger Worker, vernachlässigbar), Rolling-Update-Kleinkram (sudoers-gebundener Script-Pfad / GET-State).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,7 @@ import (
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
|
||||
"git.netcell-it.de/projekte/edgeguard-native/internal/configgen"
|
||||
"git.netcell-it.de/projekte/edgeguard-native/internal/models"
|
||||
"git.netcell-it.de/projekte/edgeguard-native/internal/services/secrets"
|
||||
wgsvc "git.netcell-it.de/projekte/edgeguard-native/internal/services/wireguard"
|
||||
@@ -27,10 +28,11 @@ import (
|
||||
const ConfDir = "/etc/edgeguard/wireguard"
|
||||
|
||||
type Generator struct {
|
||||
Pool *pgxpool.Pool
|
||||
Box *secrets.Box
|
||||
Ifaces *wgsvc.InterfacesRepo
|
||||
Peers *wgsvc.PeersRepo
|
||||
Pool *pgxpool.Pool
|
||||
Box *secrets.Box
|
||||
Ifaces *wgsvc.InterfacesRepo
|
||||
Peers *wgsvc.PeersRepo
|
||||
SkipReload bool // nur Configs schreiben, keine wg-quick@-Service-Aktionen
|
||||
}
|
||||
|
||||
func New(pool *pgxpool.Pool, box *secrets.Box) *Generator {
|
||||
@@ -151,8 +153,10 @@ func (g *Generator) Render(ctx context.Context) error {
|
||||
continue
|
||||
}
|
||||
_ = os.Remove(filepath.Join(ConfDir, e.Name()))
|
||||
_ = stopWGQuick(ifaceName)
|
||||
_ = disableWGQuick(ifaceName)
|
||||
if !g.SkipReload {
|
||||
_ = stopWGQuick(ifaceName)
|
||||
_ = disableWGQuick(ifaceName)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -228,21 +232,31 @@ func (g *Generator) renderIface(ctx context.Context, ifc models.WireguardInterfa
|
||||
}
|
||||
|
||||
path := filepath.Join(ConfDir, ifc.Name+".conf")
|
||||
// Config (enthält den Private Key) ZUERST atomar schreiben — vorher
|
||||
// keinen Symlink/Service auf eine evtl. fehlende/abgeschnittene Datei
|
||||
// zeigen lassen. AtomicWrite = temp+fsync+rename, 0600.
|
||||
changed := true
|
||||
if existing, err := os.ReadFile(path); err == nil && bytes.Equal(existing, body.Bytes()) {
|
||||
changed = false
|
||||
}
|
||||
if changed {
|
||||
if err := configgen.AtomicWrite(path, body.Bytes(), 0o600); err != nil {
|
||||
return fmt.Errorf("write %s: %w", path, err)
|
||||
}
|
||||
}
|
||||
if g.SkipReload {
|
||||
return nil
|
||||
}
|
||||
// wg-quick@<iface>.service liest /etc/wireguard/<iface>.conf (Distro-
|
||||
// Default), nicht unseren ConfDir. Wir lassen die Quelle of truth in
|
||||
// /etc/edgeguard/wireguard/ und symlinken via sudo — /etc/wireguard/
|
||||
// ist root:root 700, daher braucht es sudo /bin/ln. Das sudoers-Entry
|
||||
// wird von postinst angelegt.
|
||||
// Default), nicht unseren ConfDir. Symlink via sudo (/etc/wireguard/
|
||||
// ist root:root 700). Das sudoers-Entry wird von postinst angelegt.
|
||||
if err := symlinkWGQuickConf(ifc.Name, path); err != nil {
|
||||
return fmt.Errorf("symlink: %w", err)
|
||||
}
|
||||
_ = enableWGQuick(ifc.Name)
|
||||
if existing, err := os.ReadFile(path); err == nil && bytes.Equal(existing, body.Bytes()) {
|
||||
if !changed {
|
||||
return startWGQuick(ifc.Name)
|
||||
}
|
||||
if err := os.WriteFile(path, body.Bytes(), 0o600); err != nil {
|
||||
return fmt.Errorf("write %s: %w", path, err)
|
||||
}
|
||||
return restartWGQuick(ifc.Name)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user