mirror of
https://github.com/furyhawk/cloudy.git
synced 2026-07-20 09:45:56 +00:00
feat: integrate CrowdSec with Traefik and add deployment instructions
This commit is contained in:
@@ -84,6 +84,13 @@ AUTHENTIK_EMAIL__FROM=authentik@localhost
|
||||
COMPOSE_PORT_HTTP=80
|
||||
COMPOSE_PORT_HTTPS=443
|
||||
|
||||
# CrowdSec (Swarm)
|
||||
# Generate a value with: openssl rand -base64 32
|
||||
CROWDSEC_LAPI_KEY=change-me
|
||||
# Must match a bouncer key registered in CrowdSec, for example:
|
||||
# cscli bouncers add traefik-bouncer --key <value>
|
||||
CROWDSEC_BOUNCER_KEY=change-me
|
||||
|
||||
#=====================================================================#
|
||||
# LibreChat Configuration #
|
||||
#=====================================================================#
|
||||
|
||||
@@ -44,6 +44,56 @@ make deploy-core
|
||||
docker service logs core_traefik --details
|
||||
```
|
||||
|
||||
## CrowdSec Runbook (Swarm + Traefik)
|
||||
|
||||
### 1) Set keys in swarm env
|
||||
In `swarm/.env`, set:
|
||||
|
||||
```env
|
||||
CROWDSEC_LAPI_KEY=<openssl rand -base64 32>
|
||||
CROWDSEC_BOUNCER_KEY=<openssl rand -base64 32>
|
||||
```
|
||||
|
||||
### 2) Deploy CrowdSec stack
|
||||
```bash
|
||||
make deploy-crowdsec
|
||||
```
|
||||
|
||||
### 3) Register the Traefik bouncer
|
||||
```bash
|
||||
make register-crowdsec-bouncer
|
||||
```
|
||||
|
||||
### 4) (Re)deploy Traefik core
|
||||
This ensures the global HTTPS forwardAuth middleware is active.
|
||||
|
||||
```bash
|
||||
make deploy-core
|
||||
```
|
||||
|
||||
### 5) Verify health and wiring
|
||||
```bash
|
||||
docker service ls | grep crowdsec
|
||||
docker service logs --since 10m crowdsec_traefik-bouncer
|
||||
docker service logs --since 10m core_traefik
|
||||
docker ps --filter label=com.docker.swarm.service.name=crowdsec_crowdsec
|
||||
```
|
||||
|
||||
### 6) Verify decisions and blocking
|
||||
```bash
|
||||
# Show parser/scenario metrics
|
||||
docker exec -it $(docker ps --filter label=com.docker.swarm.service.name=crowdsec_crowdsec -q | head -n1) cscli metrics
|
||||
|
||||
# Add a temporary test decision for your client IP and verify HTTPS returns 403
|
||||
docker exec -it $(docker ps --filter label=com.docker.swarm.service.name=crowdsec_crowdsec -q | head -n1) cscli decisions add --ip <YOUR_TEST_IP>
|
||||
```
|
||||
|
||||
Cleanup test decision when done:
|
||||
|
||||
```bash
|
||||
docker exec -it $(docker ps --filter label=com.docker.swarm.service.name=crowdsec_crowdsec -q | head -n1) cscli decisions delete --ip <YOUR_TEST_IP>
|
||||
```
|
||||
|
||||
### Notes:
|
||||
```yaml
|
||||
# Declaring the user list
|
||||
|
||||
@@ -33,6 +33,37 @@ deploy-core: pull
|
||||
remove-core:
|
||||
docker stack rm core
|
||||
|
||||
setup-crowdsec:
|
||||
{ \
|
||||
echo "Setting up crowdsec config on host..." ;\
|
||||
mkdir -p /var/data/crowdsec ;\
|
||||
cmp -s ./swarm/crowdsec/acquis.yaml /var/data/crowdsec/acquis.yaml 2>/dev/null || cp ./swarm/crowdsec/acquis.yaml /var/data/crowdsec/acquis.yaml ;\
|
||||
}
|
||||
|
||||
deploy-crowdsec: pull setup-crowdsec
|
||||
{ \
|
||||
echo "Deploying the crowdsec stack..." ;\
|
||||
set -a ;\
|
||||
. ./swarm/.env ;\
|
||||
set +a ;\
|
||||
docker stack deploy --compose-file ./swarm/crowdsec.yml crowdsec ;\
|
||||
}
|
||||
|
||||
register-crowdsec-bouncer:
|
||||
{ \
|
||||
echo "Registering crowdsec traefik bouncer..." ;\
|
||||
set -a ;\
|
||||
. ./swarm/.env ;\
|
||||
set +a ;\
|
||||
bash ./scripts/register-crowdsec-bouncer.sh ;\
|
||||
}
|
||||
|
||||
deploy-crowdsec-all: deploy-crowdsec register-crowdsec-bouncer deploy-core
|
||||
@echo "CrowdSec + bouncer registration + core deploy completed."
|
||||
|
||||
remove-crowdsec:
|
||||
docker stack rm crowdsec
|
||||
|
||||
deploy-portainer: pull
|
||||
{ \
|
||||
echo "Deploying the portainer stack..." ;\
|
||||
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
BOUNCER_NAME="${CROWDSEC_BOUNCER_NAME:-traefik-bouncer}"
|
||||
BOUNCER_KEY="${CROWDSEC_BOUNCER_KEY:-}"
|
||||
SERVICE_NAME="crowdsec_crowdsec"
|
||||
|
||||
if [[ -z "$BOUNCER_KEY" ]]; then
|
||||
echo "CROWDSEC_BOUNCER_KEY is not set. Export it or source swarm/.env first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
echo "docker command not found in PATH."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
container_id="$(docker ps --filter "label=com.docker.swarm.service.name=${SERVICE_NAME}" --format '{{.ID}}' | head -n1)"
|
||||
|
||||
if [[ -z "$container_id" ]]; then
|
||||
echo "No running CrowdSec LAPI task found for service ${SERVICE_NAME}."
|
||||
echo "Deploy CrowdSec first: make deploy-crowdsec"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if docker exec "$container_id" cscli bouncers list 2>/dev/null | grep -q "$BOUNCER_NAME"; then
|
||||
echo "Bouncer '${BOUNCER_NAME}' is already registered."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Registering bouncer '${BOUNCER_NAME}' on ${SERVICE_NAME}..."
|
||||
docker exec "$container_id" cscli bouncers add "$BOUNCER_NAME" --key "$BOUNCER_KEY"
|
||||
echo "Bouncer registration complete."
|
||||
+7
-2
@@ -91,6 +91,8 @@ services:
|
||||
- traefik.http.middlewares.xbot.headers.stsIncludeSubdomains=true
|
||||
- traefik.http.middlewares.xbot.headers.permissionsPolicy="accelerometer=(), ambient-light-sensor=(), autoplay=(), battery=(), camera=(), display-capture=(), document-domain=(), encrypted-media=(), execution-while-not-rendered=(), execution-while-out-of-viewport=(), fullscreen=(), geolocation=(), gyroscope=(), layout-animations=(), legacy-image-formats=(), magnetometer=(), microphone=(), midi=(), oversized-images=(), payment=(), picture-in-picture=(), publickey-credentials-get=(), sync-xhr=(), usb=(), wake-lock=(), xr-spatial-tracking=()"
|
||||
- traefik.http.middlewares.xbot.headers.referrerPolicy="no-referrer"
|
||||
- traefik.http.middlewares.crowdsec-bouncer.forwardauth.address=http://traefik-bouncer:8080/api/v1/forwardAuth
|
||||
- traefik.http.middlewares.crowdsec-bouncer.forwardauth.trustForwardHeader=true
|
||||
- treafik.http.middlewares.neo4j_strip.stripprefix.prefixes=/neo4j
|
||||
# traefik-https the actual router using HTTPS
|
||||
- traefik.http.routers.traefik-public-https.rule=Host(`dashboard.${DOMAIN?Variable not set}`)
|
||||
@@ -106,8 +108,9 @@ services:
|
||||
- traefik.http.services.traefik-public.loadbalancer.server.port=8080
|
||||
# Pass the original Host header to the backend
|
||||
# - "traefik.http.services.dashboard.loadbalancer.passhostheader=true"
|
||||
# - crowdsec.enable=true
|
||||
# - crowdsec.labels.type=nginx
|
||||
# CrowdSec log acquisition for Traefik is label-based via docker source.
|
||||
- crowdsec.enable=true
|
||||
- crowdsec.labels.type=traefik
|
||||
volumes:
|
||||
# Add Docker as a mounted volume, so that Traefik can read the labels of other services
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
@@ -132,6 +135,8 @@ services:
|
||||
- --entrypoints.http.address=:80
|
||||
# Create an entrypoint "https" listening on port 443
|
||||
- --entrypoints.https.address=:443
|
||||
# Apply CrowdSec bouncer globally to all HTTPS routers discovered by Traefik.
|
||||
- --entrypoints.https.http.middlewares=crowdsec-bouncer@swarm
|
||||
# Redirect HTTP to HTTPS
|
||||
- --entrypoints.http.http.redirections.entrypoint.to=https
|
||||
- --entrypoints.http.http.redirections.entrypoint.scheme=https
|
||||
|
||||
+32
-15
@@ -1,27 +1,38 @@
|
||||
services:
|
||||
crowdsec:
|
||||
image: crowdsecurity/crowdsec:slim
|
||||
restart: always
|
||||
networks:
|
||||
crowdsec:
|
||||
- crowdsec-internal
|
||||
environment:
|
||||
DOCKER_HOST: tcp://socket-proxy:2375
|
||||
COLLECTIONS: "crowdsecurity/nginx"
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
depends_on:
|
||||
- 'socket-proxy'
|
||||
COLLECTIONS: "crowdsecurity/traefik"
|
||||
CUSTOM_CS_LAPI_KEY: ${CROWDSEC_LAPI_KEY:?Variable not set}
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: any
|
||||
volumes:
|
||||
- ./crowdsec/acquis.yaml:/etc/crowdsec/acquis.yaml
|
||||
- /var/data/crowdsec/acquis.yaml:/etc/crowdsec/acquis.yaml:ro
|
||||
- crowdsec-db:/var/lib/crowdsec/data/
|
||||
- crowdsec-config:/etc/crowdsec/
|
||||
|
||||
socket-proxy:
|
||||
traefik-bouncer:
|
||||
image: crowdsecurity/traefik-bouncer:latest
|
||||
environment:
|
||||
CROWDSEC_LAPI_URL: http://crowdsec:8080
|
||||
CROWDSEC_LAPI_KEY: ${CROWDSEC_BOUNCER_KEY:?Variable not set}
|
||||
expose:
|
||||
- "8080"
|
||||
networks:
|
||||
crowdsec:
|
||||
restart: always
|
||||
- crowdsec-internal
|
||||
- traefik-public
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: any
|
||||
|
||||
socket-proxy:
|
||||
image: lscr.io/linuxserver/socket-proxy:latest
|
||||
container_name: socket-proxy
|
||||
networks:
|
||||
- crowdsec-internal
|
||||
environment:
|
||||
INFO: 1
|
||||
CONTAINERS: 1
|
||||
@@ -38,10 +49,13 @@ services:
|
||||
PLUGINS: 0
|
||||
SERVICES: 0
|
||||
SESSION: 0
|
||||
SWARM: 0
|
||||
SWARM: 1
|
||||
SYSTEM: 0
|
||||
TASKS: 0
|
||||
VOLUMES: 0
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: any
|
||||
volumes:
|
||||
- '/var/run/docker.sock:/var/run/docker.sock:ro'
|
||||
read_only: true
|
||||
@@ -53,5 +67,8 @@ volumes:
|
||||
crowdsec-config:
|
||||
|
||||
networks:
|
||||
crowdsec:
|
||||
driver: bridge
|
||||
crowdsec-internal:
|
||||
driver: overlay
|
||||
attachable: true
|
||||
traefik-public:
|
||||
external: true
|
||||
@@ -1,3 +1,6 @@
|
||||
source: docker
|
||||
use_container_labels: true ## https://docs.crowdsec.net/docs/next/data_sources/docker#use_container_labels
|
||||
# Traefik service must set these docker labels so CrowdSec can classify logs correctly:
|
||||
# - crowdsec.enable=true
|
||||
# - crowdsec.labels.type=traefik
|
||||
check_interval: 10s ## How often to check for new containers https://docs.crowdsec.net/docs/next/appsec/quickstart/traefik
|
||||
Reference in New Issue
Block a user