Skip to content

Commit 2a63ef0

Browse files
Merge main into refactor-captcha-stateless
Resolved conflicts while maintaining stateless captcha design: - Adopted new dropmorepackets/haproxy-go SPOP library from main - Kept stateless JWT-based captcha tokens (CaptchaToken) - Removed session-based captcha handling - Integrated duration metrics (CaptchaValidationDuration, GeoLookupDuration) - Updated captcha handling to use encoding.ActionWriter API - Kept CookieGenerator.GenerateUnsetCookie for clearing cookies on Allow
2 parents f1074ba + 983c22b commit 2a63ef0

35 files changed

+4413
-916
lines changed

Dockerfile

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,53 @@ FROM golang:${GOVERSION}-alpine AS build
44

55
WORKDIR /go/src/cs-spoa-bouncer
66

7-
RUN apk add --update --no-cache make git
7+
RUN apk add --update --no-cache make git ca-certificates
88
COPY . .
99

1010
RUN make build DOCKER_BUILD=1
1111

12-
FROM alpine:latest
13-
COPY --from=build /go/src/cs-spoa-bouncer/crowdsec-spoa-bouncer /usr/local/bin/crowdsec-spoa-bouncer
14-
COPY --from=build /go/src/cs-spoa-bouncer/config/crowdsec-spoa-bouncer.yaml /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml
15-
COPY --from=build /go/src/cs-spoa-bouncer/docker/docker_start.sh /docker_start.sh
12+
# Create directory structure for scratch image (with .keep files so COPY works)
13+
RUN mkdir -p /run/crowdsec-spoa /var/log/crowdsec-spoa && \
14+
touch /run/crowdsec-spoa/.keep /var/log/crowdsec-spoa/.keep
1615

17-
# Set permissions for config file and binary
18-
RUN chmod 644 /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml && \
19-
chmod 755 /usr/local/bin/crowdsec-spoa-bouncer
16+
# Final minimal image
17+
FROM scratch
2018

21-
## Add the same haproxy user as the official haproxy image
22-
RUN addgroup -g 99 -S haproxy && adduser -S -D -H -u 99 -h /var/lib/haproxy -s /sbin/nologin -G haproxy -g haproxy haproxy
23-
## Add worker user
24-
RUN addgroup -S crowdsec-spoa && adduser -S -D -H -s /sbin/nologin -g crowdsec-spoa crowdsec-spoa
19+
# Default environment variables (can be overridden at runtime)
20+
ENV LOG_MODE=stdout \
21+
LOG_LEVEL=info \
22+
CROWDSEC_URL=http://crowdsec:8080/ \
23+
UPDATE_FREQUENCY=10s \
24+
INSECURE_SKIP_VERIFY=false \
25+
LISTEN_TCP=0.0.0.0:9000 \
26+
PROMETHEUS_ENABLED=true \
27+
PROMETHEUS_ADDR=0.0.0.0 \
28+
PROMETHEUS_PORT=6060
2529

26-
## Create a socket for the spoa to inherit crowdsec-spoa:haproxy user from official haproxy image
27-
RUN mkdir -p /run/crowdsec-spoa/ && chown crowdsec-spoa:haproxy /run/crowdsec-spoa/ && chmod 770 /run/crowdsec-spoa/
30+
# Copy CA certificates for HTTPS connections to LAPI
31+
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
2832

29-
## Copy Lua files (matching Debian/RPM paths)
30-
RUN mkdir -p /usr/lib/crowdsec-haproxy-spoa-bouncer/lua
31-
COPY --from=build /go/src/cs-spoa-bouncer/lua/* /usr/lib/crowdsec-haproxy-spoa-bouncer/lua/
33+
# Copy the static binary
34+
COPY --from=build /go/src/cs-spoa-bouncer/crowdsec-spoa-bouncer /crowdsec-spoa-bouncer
3235

33-
## Copy templates (matching Debian/RPM paths)
34-
RUN mkdir -p /var/lib/crowdsec-haproxy-spoa-bouncer/html
35-
COPY --from=build /go/src/cs-spoa-bouncer/templates/* /var/lib/crowdsec-haproxy-spoa-bouncer/html/
36+
# Copy Docker-optimized config file
37+
COPY --from=build /go/src/cs-spoa-bouncer/config/crowdsec-spoa-bouncer.docker.yaml /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml
3638

37-
RUN chown -R root:haproxy /usr/lib/crowdsec-haproxy-spoa-bouncer/lua /var/lib/crowdsec-haproxy-spoa-bouncer/html
39+
# Copy Lua files for HAProxy integration
40+
COPY --from=build /go/src/cs-spoa-bouncer/lua/ /usr/lib/crowdsec-haproxy-spoa-bouncer/lua/
3841

39-
VOLUME [ "/usr/lib/crowdsec-haproxy-spoa-bouncer/lua/", "/var/lib/crowdsec-haproxy-spoa-bouncer/html/" ]
42+
# Copy HTML templates for ban/captcha pages
43+
COPY --from=build /go/src/cs-spoa-bouncer/templates/ /var/lib/crowdsec-haproxy-spoa-bouncer/html/
4044

41-
RUN chmod +x /docker_start.sh
45+
# Copy runtime directories (required for Unix socket and logs)
46+
COPY --from=build /run/crowdsec-spoa/ /run/crowdsec-spoa/
47+
COPY --from=build /var/log/crowdsec-spoa/ /var/log/crowdsec-spoa/
4248

43-
# Run as user
44-
USER crowdsec-spoa
49+
# Declare volumes for customizable content
50+
VOLUME /usr/lib/crowdsec-haproxy-spoa-bouncer/lua/
51+
VOLUME /var/lib/crowdsec-haproxy-spoa-bouncer/html/
4552

46-
ENTRYPOINT ["/docker_start.sh"]
53+
EXPOSE 9000 6060
54+
55+
ENTRYPOINT ["/crowdsec-spoa-bouncer"]
56+
CMD ["-c", "/etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml"]

Vagrantfile

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# -*- mode: ruby -*-
2+
# vi: set ft=ruby :
3+
4+
Vagrant.configure("2") do |config|
5+
config.vm.define "dev" do |vm|
6+
vm.vm.box = "debian/bookworm64"
7+
vm.vm.hostname = "crowdsec-spoa-test"
8+
vm.vm.network "private_network", ip: "192.168.56.10"
9+
vm.vm.network "forwarded_port", guest: 9090, host: 9090
10+
11+
vm.vm.provider "libvirt" do |lv|
12+
lv.memory = "4096"
13+
lv.cpus = 2
14+
end
15+
16+
vm.vm.synced_folder ".", "/vagrant", type: "rsync", rsync__exclude: [".git/", "node_modules/", "*.log"]
17+
18+
vm.vm.provision "shell", inline: <<-SHELL
19+
set -e
20+
21+
# Update system and install base packages
22+
apt-get update && apt-get upgrade -y
23+
apt-get install -y tcpdump vim curl wget git build-essential ca-certificates \
24+
gnupg lsb-release apt-transport-https software-properties-common nginx unzip
25+
26+
# Install HAProxy 3.1
27+
curl -fsSL https://haproxy.debian.net/haproxy-archive-keyring.gpg \
28+
--create-dirs --output /etc/apt/keyrings/haproxy-archive-keyring.gpg
29+
echo "deb [signed-by=/etc/apt/keyrings/haproxy-archive-keyring.gpg]" \
30+
https://haproxy.debian.net bookworm-backports-3.1 main > /etc/apt/sources.list.d/haproxy.list
31+
apt-get update && apt-get install -y haproxy=3.1.*
32+
33+
# Install Go 1.25.2
34+
GO_VERSION="1.25.2"
35+
wget -qO- "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar -xzC /usr/local
36+
echo 'export PATH=$PATH:/usr/local/go/bin' >> /etc/profile
37+
echo 'export PATH=$PATH:/usr/local/go/bin' >> /home/vagrant/.bashrc
38+
39+
# Install CrowdSec
40+
curl -s https://install.crowdsec.net | sh
41+
apt-get install -y crowdsec
42+
43+
# Install Nuclei for AppSec testing
44+
NUCLEI_VERSION="3.1.7"
45+
wget -qO /tmp/nuclei.zip "https://github.com/projectdiscovery/nuclei/releases/download/v${NUCLEI_VERSION}/nuclei_${NUCLEI_VERSION}_linux_amd64.zip"
46+
unzip -q /tmp/nuclei.zip -d /tmp && mv /tmp/nuclei /usr/local/bin/nuclei && chmod +x /usr/local/bin/nuclei
47+
rm -f /tmp/nuclei.zip
48+
nuclei -update-templates -silent 2>/dev/null || true
49+
50+
# Clone CrowdSec Hub
51+
git clone -q https://github.com/crowdsecurity/hub.git /opt/hub || true
52+
53+
# Create user and directories
54+
groupadd -r crowdsec-spoa 2>/dev/null || true
55+
useradd -r -g crowdsec-spoa -d /opt/crowdsec-spoa-bouncer -s /bin/false crowdsec-spoa 2>/dev/null || true
56+
mkdir -p /opt/crowdsec-spoa-bouncer /etc/crowdsec/bouncers /var/log/crowdsec-spoa-bouncer \
57+
/run/crowdsec-spoa /usr/lib/crowdsec-haproxy-spoa-bouncer/lua /var/lib/crowdsec-haproxy-spoa-bouncer/html
58+
chown -R crowdsec-spoa:crowdsec-spoa /opt/crowdsec-spoa-bouncer /var/log/crowdsec-spoa-bouncer /run/crowdsec-spoa
59+
60+
# Copy Lua scripts and templates
61+
mkdir -p /usr/lib/crowdsec-haproxy-spoa-bouncer/lua /var/lib/crowdsec-haproxy-spoa-bouncer/html
62+
cp /vagrant/lua/*.lua /usr/lib/crowdsec-haproxy-spoa-bouncer/lua/ 2>/dev/null || true
63+
cp /vagrant/templates/*.html /var/lib/crowdsec-haproxy-spoa-bouncer/html/ 2>/dev/null || true
64+
chmod 644 /usr/lib/crowdsec-haproxy-spoa-bouncer/lua/*.lua 2>/dev/null || true
65+
chmod 644 /var/lib/crowdsec-haproxy-spoa-bouncer/html/*.html 2>/dev/null || true
66+
67+
# Configure nginx
68+
cat > /etc/nginx/sites-available/default << 'EOF'
69+
server {
70+
listen 4444 default_server;
71+
listen [::]:4444 default_server;
72+
73+
root /var/www/html;
74+
index index.html index.htm index.nginx-debian.html;
75+
76+
server_name _;
77+
78+
location / {
79+
try_files $uri $uri/ =404;
80+
}
81+
}
82+
EOF
83+
84+
# Copy and configure HAProxy
85+
cp /vagrant/config/haproxy.cfg /etc/haproxy/haproxy.cfg 2>/dev/null || true
86+
cp /vagrant/config/crowdsec.cfg /etc/haproxy/crowdsec.cfg 2>/dev/null || true
87+
# Update server addresses and remove the second SPOA server (port 9001 doesn't exist)
88+
sed -i 's/whoami:2020/127.0.0.1:4444/g; s/spoa:9000/127.0.0.1:9000/g; /server s3 spoa:9001/d' \
89+
/etc/haproxy/haproxy.cfg 2>/dev/null || true
90+
# Increase SPOA processing timeout to accommodate AppSec calls (AppSec has 5s timeout)
91+
sed -i 's/timeout\s\+processing\s\+500ms/timeout processing 6s/' \
92+
/etc/haproxy/crowdsec.cfg 2>/dev/null || true
93+
94+
# Copy and configure bouncer
95+
cp /vagrant/config/crowdsec-spoa-bouncer.yaml.local /etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml 2>/dev/null || true
96+
# Update URLs (match with or without trailing slash) and API key
97+
sed -i 's|http://crowdsec:8080|http://127.0.0.1:8080|g; s|http://crowdsec:7422|http://127.0.0.1:4241|g; s|api_key:.*|api_key: this_is_a_bad_password|g' \
98+
/etc/crowdsec/bouncers/crowdsec-spoa-bouncer.yaml 2>/dev/null || true
99+
100+
# Configure AppSec before starting CrowdSec
101+
# Install AppSec collections first
102+
cscli collections install crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules || true
103+
104+
# Configure AppSec acquisition
105+
mkdir -p /etc/crowdsec/acquis.d
106+
cat > /etc/crowdsec/acquis.d/appsec.yaml << 'EOF'
107+
appsec_config: crowdsecurity/appsec-default
108+
labels:
109+
type: appsec
110+
listen_addr: 0.0.0.0:4241
111+
source: appsec
112+
EOF
113+
114+
# Now start all services with CrowdSec properly configured
115+
systemctl enable --now nginx haproxy crowdsec
116+
sleep 5
117+
cscli bouncers add crowdsec-spoa-bouncer --key this_is_a_bad_password 2>/dev/null || true
118+
SHELL
119+
120+
vm.vm.provision "shell", run: "always", inline: <<-SHELL
121+
set -e
122+
export PATH=$PATH:/usr/local/go/bin
123+
124+
# Build SPOA bouncer
125+
if [ -f "/vagrant/main.go" ]; then
126+
cd /vagrant
127+
if go build -ldflags="-s -w" -o /opt/crowdsec-spoa-bouncer/crowdsec-spoa-bouncer .; then
128+
chown crowdsec-spoa:crowdsec-spoa /opt/crowdsec-spoa-bouncer/crowdsec-spoa-bouncer
129+
chmod +x /opt/crowdsec-spoa-bouncer/crowdsec-spoa-bouncer
130+
131+
# Install systemd service
132+
cp /vagrant/config/crowdsec-spoa-bouncer.service /etc/systemd/system/crowdsec-spoa-bouncer.service
133+
sed -i 's|${BIN}|/opt/crowdsec-spoa-bouncer/crowdsec-spoa-bouncer|g; s|${CFG}|/etc/crowdsec/bouncers|g' \
134+
/etc/systemd/system/crowdsec-spoa-bouncer.service
135+
sed -i 's|Type=notify|Type=simple|g; /ExecStartPre=/d' \
136+
/etc/systemd/system/crowdsec-spoa-bouncer.service
137+
138+
systemctl daemon-reload
139+
systemctl enable --now crowdsec-spoa-bouncer
140+
fi
141+
fi
142+
143+
# Restart services in order
144+
systemctl restart nginx
145+
sleep 2
146+
systemctl restart crowdsec-spoa-bouncer 2>/dev/null || true
147+
sleep 3
148+
systemctl restart haproxy
149+
150+
# Verify services
151+
for svc in nginx crowdsec-spoa-bouncer haproxy; do
152+
systemctl is-active --quiet $svc && echo "✅ $svc: running" || echo "❌ $svc: failed"
153+
done
154+
SHELL
155+
end
156+
end

0 commit comments

Comments
 (0)