feat(security): external IP blocklist sync for the local CrowdSec engine
Gitea Actions Runner Test / test-job (push) Successful in 0s
CI / check (push) Successful in 30s
CI / tests-integration (push) Successful in 1m42s
CI / tests-unit (push) Successful in 1m43s
CI / tests-ui (push) Successful in 2m35s
CI / preflight (push) Skipped
CI / deploy (push) Successful in 2m3s

This commit is contained in:
openhands committed 2026-09-24 18:39:38 +02:00
1 parent 84d53139a9
commit 9562a75378
6 files changed
+263 -2

No files matched your search

+12
View File
@@ -126,6 +126,18 @@ CROWDSEC_LAPI_PORT=18080
CROWDSEC_LAPI_URL=http://127.0.0.1:18080 CROWDSEC_LAPI_URL=http://127.0.0.1:18080
# Generated by `bash cms security`; keep in .env, never commit a value. # Generated by `bash cms security`; keep in .env, never commit a value.
CROWDSEC_LAPI_API_KEY= CROWDSEC_LAPI_API_KEY=
# IP blocklist sync (`bash cms security blocklists`): space-separated URLs, by
# default Spamhaus DROP/EDROP, DShield, CINS, Greensnow, StopForumSpam,
# blocklist.de, Emerging Threats, abuse.ch Feodo/SSLBL/URLhaus, IPsum,
# Firehol ipsets and Tor exit nodes. Requires internet to fetch; detection and
# blocking stay local.
#CROWDSEC_BLOCKLIST_SOURCES=https://www.spamhaus.org/drop/drop.txt https://example.org/list.txt
# Expiration for each blocklist decision (re-synced keeps them fresh).
#CROWDSEC_BLOCKLIST_DURATION=24h
# Combined cap per sync (safety valve against excessive decisions).
#CROWDSEC_BLOCKLIST_MAX_DECISIONS=250000
# Comma-separated IPs/CIDRs that a sync must always skip (allowlist).
#CROWDSEC_BLOCKLIST_ALLOW=1.2.3.4,10.0.0.0/8
# --- PATHS --- # --- PATHS ---
BADGE_UPLOAD_DIR=./public/assets/images/badges BADGE_UPLOAD_DIR=./public/assets/images/badges
+30
View File
@@ -827,6 +827,36 @@ bash cms security disable
Stops the container and sets `CROWDSEC_LOCAL_ENABLED=false`. Volumes and the Stops the container and sets `CROWDSEC_LOCAL_ENABLED=false`. Volumes and the
`.env` key are kept. `.env` key are kept.
### Step 5 — Load external IP blocklists (optional)
The engine has no built-in lists, so provide your own via a one-shot sync
(fetches the sources, replaces every previous `cscli-import` decision):
```bash
bash cms security blocklists
```
Defaults: Spamhaus DROP/EDROP, DShield, CINS, Greensnow, StopForumSpam,
Binary Defense, blocklist.de, Emerging Threats, BruteForceBlocker, abuse.ch
Feodo/SSLBL/URLhaus, Botvrij, IPsum, Firehol ipsets and Tor exit nodes
(26 sources). The largest commercial/crowdsourced lists (AbuseIPDB, MaxMind,
Cisco Talos, AlienVault OTX) are not included because they require an account
or API key; IPsum already aggregates ~30 additional feeds. No account is
needed, but internet access is — only for fetching; detection and blocking
remain local. Sync hourly as a cron job:
```bash
bash cms security blocklists-install-cron
```
Removal: `bash cms security blocklists-uninstall-cron`. Dry-run without
touching LAPI: `bash cms security blocklists --dry-run`. Override the sources,
duration, a combined cap or an allowlist in `.env`
(`CROWDSEC_BLOCKLIST_SOURCES`, `CROWDSEC_BLOCKLIST_DURATION`,
`CROWDSEC_BLOCKLIST_MAX_DECISIONS`, `CROWDSEC_BLOCKLIST_ALLOW`). Existing
`cscli-import` decisions are replaced on every sync, so removed entries
expire.
### Environment variables ### Environment variables
| Variable | Default | Purpose | | Variable | Default | Purpose |
+1 -1
View File
@@ -5,6 +5,6 @@ case "${1:-help}" in
install) shift; exec bash "$DIR/scripts/docker-install.sh" "$@" ;; install) shift; exec bash "$DIR/scripts/docker-install.sh" "$@" ;;
update) shift; exec bash "$DIR/scripts/docker-update.sh" "$@" ;; update) shift; exec bash "$DIR/scripts/docker-update.sh" "$@" ;;
security) shift; exec bash "$DIR/scripts/crowdsec-setup.sh" "$@" ;; security) shift; exec bash "$DIR/scripts/crowdsec-setup.sh" "$@" ;;
help|--help|-h) printf '%s\n' 'bash cms install Configure and install on a Linux Docker host' 'bash cms update Update using saved settings; --skip-pull uses checked-out release' 'bash cms security Configure the opt-in local CrowdSec stack (enable|status|disable)' ;; help|--help|-h) printf '%s\n' 'bash cms install Configure and install on a Linux Docker host' 'bash cms update Update using saved settings; --skip-pull uses checked-out release' 'bash cms security Configure the opt-in local CrowdSec stack (enable|status|disable|blocklists)' ;;
*) echo "Unknown command. Use: bash cms install | update | security" >&2; exit 1 ;; *) echo "Unknown command. Use: bash cms install | update | security" >&2; exit 1 ;;
esac esac
+2
View File
@@ -101,6 +101,8 @@ This bouncer is application-layer: it sheds known-bad IPs at the CMS process and
The running CMS loads the new env values on its next restart or deployment. For a CI-managed `epicnext-cms-app`, the next deploy (which sources `.env`) applies them; for a clone, `bash cms update --skip-pull` restarts it. `.env` now holds the LAPI key — keep its permissions restrictive. The running CMS loads the new env values on its next restart or deployment. For a CI-managed `epicnext-cms-app`, the next deploy (which sources `.env`) applies them; for a clone, `bash cms update --skip-pull` restarts it. `.env` now holds the LAPI key — keep its permissions restrictive.
External IP blocklists (Spamhaus, DShield, CINS, blocklist.de, abuse.ch, IPsum, Firehol, Tor exit nodes, …) can be synced into the local LAPI with `bash cms security blocklists`, and hourly with `bash cms security blocklists-install-cron` (no account, but internet to fetch). Configure via `CROWDSEC_BLOCKLIST_*`.
## Routine and selected-release updates ## Routine and selected-release updates
```sh ```sh
File diff suppressed because it is too large. Load diff
+8 -1
View File
@@ -13,7 +13,8 @@ case "$mode" in
enable|--enable) ;; enable|--enable) ;;
status|--status) ;; status|--status) ;;
disable|--disable) ;; disable|--disable) ;;
*) echo "Usage: bash cms security [enable|status|disable]" >&2; exit 1 ;; blocklists|blocklists-install-cron|blocklists-uninstall-cron) ;;
*) echo "Usage: bash cms security [enable|status|disable|blocklists|blocklists-install-cron|blocklists-uninstall-cron]" >&2; exit 1 ;;
esac esac
umask 077 umask 077
@@ -25,6 +26,12 @@ exec 9>"$DIR/.deploy.lock"
flock -w 30 9 || fail "Another installation or update is running." flock -w 30 9 || fail "Another installation or update is running."
[[ -f "$ENV_FILE" ]] || fail "Create .env first (bash cms install)." [[ -f "$ENV_FILE" ]] || fail "Create .env first (bash cms install)."
case "$mode" in
blocklists) exec bash "$DIR/scripts/blocklists-sync.sh" sync "${2:-}" ;;
blocklists-install-cron) exec bash "$DIR/scripts/blocklists-sync.sh" install-cron ;;
blocklists-uninstall-cron) exec bash "$DIR/scripts/blocklists-sync.sh" uninstall-cron ;;
esac
env_get() { env_get() {
local key="$1" line local key="$1" line
while IFS= read -r line || [[ -n "$line" ]]; do while IFS= read -r line || [[ -n "$line" ]]; do