diff --git a/Makefile b/Makefile index e765202..26fa481 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ GO ?= $(shell which go || echo /usr/local/go/bin/go) MODULE := git.netcell-it.de/projekte/edgeguard-native -BINARIES := edgeguard-api edgeguard-scheduler edgeguard-ctl +BINARIES := edgeguard-api edgeguard-scheduler edgeguard-ctl edgeguard-waf VERSION := $(shell cat VERSION 2>/dev/null || echo 0.0.1-dev) LDFLAGS := -s -w -X main.version=$(VERSION) GOFLAGS := -trimpath -mod=readonly diff --git a/VERSION b/VERSION index 98c8dc5..f2254f4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.68 +1.2.69 diff --git a/deploy/systemd/edgeguard-waf.service b/deploy/systemd/edgeguard-waf.service new file mode 100644 index 0000000..faaebd8 --- /dev/null +++ b/deploy/systemd/edgeguard-waf.service @@ -0,0 +1,32 @@ +[Unit] +Description=EdgeGuard WAF SPOE Agent (Coraza/OWASP CRS) +Documentation=https://git.netcell-it.de/projekte/edgeguard-native +After=network-online.target postgresql.service edgeguard-api.service +Wants=network-online.target +Requires=postgresql.service + +[Service] +Type=simple +User=edgeguard +Group=edgeguard +ExecStart=/usr/bin/edgeguard-waf +Restart=on-failure +RestartSec=5 + +# Hardening — WAF agent only needs DB access and one TCP listen socket. +NoNewPrivileges=true +ProtectSystem=strict +ProtectHome=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectControlGroups=true +PrivateTmp=true +PrivateDevices=true +RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 +SystemCallFilter=@system-service +# CRS rules are read from /usr/share/edgeguard/waf/crs/ (read-only, OK). +# Alerts/logs are written to /var/log/edgeguard/. +ReadWritePaths=/var/log/edgeguard + +[Install] +WantedBy=multi-user.target diff --git a/internal/handlers/system.go b/internal/handlers/system.go index 9440dcc..c8c52e3 100644 --- a/internal/handlers/system.go +++ b/internal/handlers/system.go @@ -197,6 +197,7 @@ var servicesToCheck = []struct{ Label, Unit string }{ {"postgresql", "postgresql"}, {"crowdsec", "crowdsec"}, {"crowdsec-firewall-bouncer", "crowdsec-firewall-bouncer"}, + {"edgeguard-waf", "edgeguard-waf"}, } type serviceStatus struct { @@ -639,6 +640,7 @@ func (h *SystemHandler) ServiceRestart(c *gin.Context) { var toggleAllowlist = map[string]bool{ "crowdsec": true, "crowdsec-firewall-bouncer": true, + "edgeguard-waf": true, "squid": true, "unbound": true, } diff --git a/packaging/debian/edgeguard-api/DEBIAN/postinst b/packaging/debian/edgeguard-api/DEBIAN/postinst index 8e6fbd7..78a72c4 100755 --- a/packaging/debian/edgeguard-api/DEBIAN/postinst +++ b/packaging/debian/edgeguard-api/DEBIAN/postinst @@ -165,6 +165,12 @@ edgeguard ALL=(root) NOPASSWD: /usr/bin/cscli collections list -o json edgeguard ALL=(root) NOPASSWD: /usr/bin/cscli collections install * edgeguard ALL=(root) NOPASSWD: /usr/bin/cscli collections remove * edgeguard ALL=(root) NOPASSWD: /usr/bin/cscli version +# WAF agent service control +edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl start edgeguard-waf.service +edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl stop edgeguard-waf.service +edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl enable edgeguard-waf.service +edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl disable edgeguard-waf.service +edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl restart edgeguard-waf.service # CrowdSec service toggle (start/stop/enable/disable) edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl start crowdsec.service edgeguard ALL=(root) NOPASSWD: /usr/bin/systemctl stop crowdsec.service @@ -790,10 +796,38 @@ EOSQL /etc/systemd/system/haproxy.service.d/edgeguard.conf fi + # ── OWASP Core Rule Set (CRS) für edgeguard-waf ───────────────────── + # Nur beim Erstinstall — kein Überschreiben bei Upgrades damit + # admins angepasste crs-setup.conf behalten können. + WAF_CRS_DIR="/usr/share/edgeguard/waf/crs" + if [ "$1" = "configure" ] && [ -z "$2" ] && [ ! -d "$WAF_CRS_DIR/rules" ]; then + CRS_VERSION="4.7.0" + echo "postinst: installing OWASP CRS v${CRS_VERSION}..." + install -d -m 0755 "$WAF_CRS_DIR/rules" + CRS_TMP="$(mktemp -d)" + if curl -sL --max-time 60 \ + "https://github.com/coreruleset/coreruleset/archive/refs/tags/v${CRS_VERSION}.tar.gz" \ + -o "${CRS_TMP}/crs.tar.gz" 2>/dev/null; then + tar xzf "${CRS_TMP}/crs.tar.gz" -C "${CRS_TMP}" 2>/dev/null || true + CRS_SRC="${CRS_TMP}/coreruleset-${CRS_VERSION}" + if [ -f "${CRS_SRC}/crs-setup.conf.example" ]; then + install -m 0644 "${CRS_SRC}/crs-setup.conf.example" "${WAF_CRS_DIR}/crs-setup.conf" + install -m 0644 "${CRS_SRC}/rules/"*.conf "${WAF_CRS_DIR}/rules/" 2>/dev/null || true + chown -R "$EG_USER":"$EG_USER" "$WAF_CRS_DIR" + echo "postinst: OWASP CRS v${CRS_VERSION} installed to ${WAF_CRS_DIR}" + else + echo "postinst: CRS download succeeded but layout unexpected — skipping" >&2 + fi + else + echo "postinst: CRS download failed (no internet?) — WAF usable without CRS" >&2 + fi + rm -rf "${CRS_TMP}" + fi + # ── systemd: pick up new units + restart haproxy with our cfg systemctl daemon-reload systemctl restart haproxy.service || true - systemctl enable edgeguard-api.service edgeguard-scheduler.service || true + systemctl enable edgeguard-api.service edgeguard-scheduler.service edgeguard-waf.service || true # restart (NICHT enable --now): das neue Unit-File könnte ein # geänderter ReadWritePaths-Block sein (Befund 1.0.87: # /var/lib/apt fehlte → apt-get update aus dem Update-Banner- @@ -802,7 +836,7 @@ EOSQL # der laufende Daemon behält das alte Sandbox-Snapshot bis zum # restart. Bei Erst-Install ist nichts running, dann ist das # ein normaler Start. - systemctl restart edgeguard-api.service edgeguard-scheduler.service || true + systemctl restart edgeguard-api.service edgeguard-scheduler.service edgeguard-waf.service || true # WireGuard-Sicherung: enabled-aber-inaktive wg-quick@-Interfaces # nach dem API-Restart starten. Der API-Renderer kann wg-quick@ diff --git a/scripts/apt-repo/build-package.sh b/scripts/apt-repo/build-package.sh index b7b7078..6673c0b 100755 --- a/scripts/apt-repo/build-package.sh +++ b/scripts/apt-repo/build-package.sh @@ -61,7 +61,7 @@ build_api() { [ -f "$pkg_src/DEBIAN/conffiles" ] && cp "$pkg_src/DEBIAN/conffiles" "$build_dir/DEBIAN/" # binaries - for bin in edgeguard-api edgeguard-scheduler edgeguard-ctl; do + for bin in edgeguard-api edgeguard-scheduler edgeguard-ctl edgeguard-waf; do install -m 0755 "$REPO_ROOT/build/$ARCH/$bin" "$build_dir/usr/bin/$bin" done @@ -70,6 +70,8 @@ build_api() { "$build_dir/etc/systemd/system/" install -m 0644 "$REPO_ROOT/deploy/systemd/edgeguard-scheduler.service" \ "$build_dir/etc/systemd/system/" + install -m 0644 "$REPO_ROOT/deploy/systemd/edgeguard-waf.service" \ + "$build_dir/etc/systemd/system/" # systemd drop-in for HAProxy — postinst copies it into # /etc/systemd/system/haproxy.service.d/. Shipped under