Preparations for crowdsec-firewall-bouncer-nftables install#41
Open
the-buezi wants to merge 3 commits into
Open
Preparations for crowdsec-firewall-bouncer-nftables install#41the-buezi wants to merge 3 commits into
the-buezi wants to merge 3 commits into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Protect host SSH with CrowdSec firewall bouncer while reusing existing CrowdSec Docker container
Problem
The current Docker setup already runs CrowdSec as a containerized WAF/threat-intelligence engine and integrates it with Traefik. Web traffic is routed through Traefik and protected by the CrowdSec Traefik bouncer/AppSec setup.
However, the host SSH service is outside Traefik and is therefore not protected by the Traefik/WAF bouncer. UFW allows SSH on the host, but UFW is a static allow/deny firewall and does not dynamically block IPs that CrowdSec has identified as abusive.
Goal: protect the host SSH service with CrowdSec decisions without installing a second full CrowdSec Security Engine on the host.
Current compose observations
The
wafservice already runscrowdsecurity/crowdsec:${CROWDSEC_VERSION:-latest}and persists its configuration/database via named volumes:It exposes LAPI and AppSec only inside Docker networks:
It already registers the Traefik bouncer key at container startup:
It currently installs web/AppSec-oriented collections only:
- COLLECTIONS=crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rulesIt currently mounts Traefik logs and WAF configuration files, but does not mount host SSH/auth logs:
Recommended concept
Reuse the existing
wafcontainer as the single CrowdSec Security Engine/LAPI.Install only the firewall bouncer on the host:
The host firewall bouncer should connect to the containerized CrowdSec LAPI and enforce decisions in host nftables. This keeps one central decision database and avoids running a second CrowdSec engine on the host.
Target architecture:
Required compose changes
1. Expose CrowdSec LAPI to the host only
The host-installed firewall bouncer needs to reach LAPI. Currently the
wafservice only usesexpose, which is visible to other Docker containers but not to host services.Add a localhost-only port mapping to the
wafservice:Do not expose this port publicly.
Recommended result:
2. Add SSH collection to the CrowdSec container
Extend the
COLLECTIONSvariable:- COLLECTIONS=crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules crowdsecurity/sshd3. Mount host SSH logs read-only
On Debian, SSH authentication events are usually available in
/var/log/auth.logif rsyslog is active.Add:
- /var/log/auth.log:/var/log/auth.log:roIf
/var/log/auth.logdoes not exist or does not contain SSH events, use journald acquisition instead or enable rsyslog-based auth logging first.4. Add SSH acquisition config
Create a new file, for example:
Suggested content:
Mount it into the CrowdSec container:
- "${HOST_PATH_WAF_CONFIG_FILES:-${HOST_DOCKER_WORKING_DIR:-.}/resources/waf}/acquis-sshd.yaml:/etc/crowdsec/acquis.d/sshd.yaml:ro"5. Register a dedicated firewall-bouncer API key
Do not reuse the Traefik bouncer key. Add a separate key for the host firewall bouncer.
Preferred: create a new secret in
.env:Then add to the
wafservice environment:- BOUNCER_KEY_host_firewall=${CROWDSEC_FIREWALL_BOUNCER_KEY:-changeme-in-dotenv}The official CrowdSec Docker image supports automatic bouncer registration with environment variables of the format
BOUNCER_KEY_<name>=<key>.Host-side firewall bouncer configuration
Install the nftables bouncer on the host, not in Docker:
Configure the bouncer to use the containerized LAPI:
Recommended nftables scope for the first rollout:
Do not enable
forwardinitially. The goal of this issue is SSH protection, not Docker-forwarded service filtering. Docker/Traefik traffic should remain protected by the Traefik/WAF bouncer for now.Validation steps
Before change:
After compose change:
After host bouncer install:
Functional test from a non-critical test IP:
Then attempt SSH from
<TEST_CLIENT_IP>. Expected result: SSH is blocked while the decision exists.Remove test decision:
Rollout precautions
127.0.0.1.Open checks before implementation
/var/log/auth.logexists on the host and contains SSH login/failure events.0.0.0.0:8080inside the container so the host localhost port mapping works.127.0.0.1:8080.Expected result
After implementation, SSH remains allowed by UFW for normal clients, but IPs banned by CrowdSec are dropped by nftables before they reach
sshd.Web traffic continues to be handled by Traefik and the existing CrowdSec WAF/AppSec bouncer. SSH protection is added without introducing a second CrowdSec Security Engine.