Part 6: Configuring CrowdSec Trusted IPs for Internal Pangolin Traffic
1. Understanding Trusted IPs Configuration
1.1 Types of Trusted IPs
- ForwardedHeaders: IPs trusted for X-Forwarded-For headers
- ClientTrusted: IPs exempt from CrowdSec checks
- Internal Networks: Private network ranges
- VPN Networks: Custom VPN subnets
1.2 Default Private Networks
Common private network ranges:
private_networks:
- "10.0.0.0/8" # Class A private network
- "172.16.0.0/12" # Class B private network
- "192.168.0.0/16" # Class C private network
- "100.64.0.0/10" # Carrier-grade NAT
- "fd00::/8" # Unique local IPv6
2. Traefik Configuration
2.1 Update Dynamic Config
Modify /config/traefik/dynamic_config.yml
:
http:
middlewares:
crowdsec:
plugin:
crowdsec:
enabled: true
forwardedHeadersTrustedIPs:
- "0.0.0.0/0" # Cloudflare/CDN IPs
clientTrustedIPs:
- "10.0.0.0/8" # Internal networks
- "172.16.0.0/12"
- "192.168.0.0/16"
- "100.89.137.0/20" # Pangolin VPN network
trustedForwardXFor: true
skipAuthPath:
- "/api/v1/health"
- "/metrics"
default-whitelist:
ipWhiteList:
sourceRange:
- "10.0.0.0/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
- "100.89.137.0/20"
2.2 Configure Security Headers
Add security headers configuration:
security-headers:
headers:
customResponseHeaders:
Server: ""
X-Powered-By: ""
sslProxyHeaders:
X-Forwarded-Proto: "https"
hostsProxyHeaders:
- "X-Forwarded-Host"
customFrameOptionsValue: "SAMEORIGIN"
contentTypeNosniff: true
forceSTSHeader: true
3. CrowdSec Configuration
3.1 Update Acquisition Configuration
Modify /config/crowdsec/acquis.yaml
:
filenames:
- /var/log/auth.log
- /var/log/syslog
labels:
type: syslog
---
filenames:
- /var/log/traefik/*.log
labels:
type: traefik
whitelists:
ips:
- "10.0.0.0/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
- "100.89.137.0/20"
3.2 Configure Trusted IPs in Profiles
Update /config/crowdsec/profiles.yaml
:
name: trusted_ips
filters:
- Source.IP in ipnets('10.0.0.0/8','172.16.0.0/12','192.168.0.0/16','100.89.137.0/20')
decisions:
- type: bypass
duration: 168h
on_success: break
---
name: captcha_remediation
filters:
- Alert.Remediation == true && Alert.GetScope() == "Ip" && Alert.GetScenario() contains "http"
- Source.IP not in ipnets('10.0.0.0/8','172.16.0.0/12','192.168.0.0/16','100.89.137.0/20')
decisions:
- type: captcha
duration: 4h
on_success: break
4. Network Security Configuration
4.1 Configure Internal Services
Update docker-compose.yml for internal services:
services:
pangolin:
networks:
- pangolin
labels:
- "traefik.http.routers.pangolin.middlewares=default-whitelist@docker"
gerbil:
networks:
- pangolin
extra_hosts:
- "pangolin:172.19.0.2"
- "crowdsec:172.19.0.4"
4.2 Service Discovery Configuration
Create /config/traefik/conf/service-discovery.yaml
:
tcp:
services:
pangolin:
loadBalancer:
servers:
- address: "172.19.0.2:3001"
crowdsec:
loadBalancer:
servers:
- address: "172.19.0.4:9090"
5. Testing and Verification
5.1 Test Internal Access
# Test internal network access
docker exec -it gerbil curl http://pangolin:3001/api/v1/health
# Test CrowdSec bypass
docker exec -it crowdsec cscli decisions add -i 10.0.0.1 -t ban -d 1h
curl -H "X-Forwarded-For: 10.0.0.1" https://pangolin.testing.hhf.technology
5.2 Verify IP Configurations
# Check trusted IPs
docker exec -it crowdsec cscli config show | grep -A 10 "trusted_ips"
# Test whitelist functionality
docker exec crowdsec cscli decisions add -i 172.16.0.1 -t ban -d 1h
curl -H "X-Forwarded-For: 172.16.0.1" https://pangolin.testing.hhf.technology
6. Monitoring and Logging
6.1 Configure Logging
Update Traefik logging configuration:
log:
level: "INFO"
format: "json"
accessLog:
filePath: "/var/log/traefik/access.log"
format: json
fields:
headers:
names:
X-Forwarded-For: keep
X-Real-IP: keep
6.2 Monitor Trusted IP Activity
Create monitoring script /config/scripts/monitor-trusted.sh
:
#!/bin/bash
echo "=== Monitoring Trusted IP Activity ==="
# Check CrowdSec decisions
echo "Current Decisions:"
docker exec -it crowdsec cscli decisions list
# Check Traefik logs for trusted IPs
echo "Trusted IP Access Logs:"
docker exec -it crowdsec tail -f /var/log/traefik/access.log | grep -E "10\.|172\.(1[6-9]|2[0-9]|3[0-1])\.|192\.168\.|100\.89\.137\."
7. Troubleshooting
7.1 Common Issues
- IP Forward Issues:
# Check X-Forwarded-For headers
docker compose logs traefik | grep "X-Forwarded-For"
# Verify trusted IP configuration
docker exec -it crowdsec cat /etc/crowdsec/config.yaml | grep -A 10 "trusted_ips"
- Network Connectivity:
# Test internal network connectivity
docker exec -it gerbil ping pangolin
docker exec -it gerbil ping crowdsec
# Check network configuration
docker network inspect pangolin
7.2 Debug Tools
Create debugging script /config/scripts/debug-trusted.sh
:
#!/bin/bash
echo "=== CrowdSec Trusted IP Debug ==="
# Check CrowdSec configuration
docker exec crowdsec cscli config show --debug
# Test internal network connectivity
for service in pangolin crowdsec gerbil; do
echo "Testing connectivity to $service"
docker exec -it gerbil ping -c 1 $service
done
# Check current decisions
docker exec crowdsec cscli decisions list
# Display trusted IP configurations
echo "Traefik trusted IPs:"
grep -r "trustedIPs" /config/traefik/
echo "CrowdSec trusted IPs:"
docker exec crowdsec cscli config show | grep -A 10 "trusted_ips"
Next Steps and Best Practices
-
Regular Maintenance:
- Review and update trusted IP lists
- Monitor for suspicious activity from trusted IPs
- Regular security audits
-
Security Recommendations:
- Use specific IP ranges instead of broad network ranges
- Implement regular IP whitelist reviews
- Monitor trusted IP access patterns
-
Documentation:
- Maintain documentation of trusted IP ranges
- Document reasons for IP trust
- Keep change logs for IP modifications
Part 1 Integrating Crowdsec with Pangolin - Networking - HHF Technology Forums
Part 2 Configuring Crowdsec and bouncer integration with pangolin - Networking - HHF Technology Forums
Part 3 Testing and advanced configuration of Crowdsec with Pangolin - Networking - HHF Technology Forums
Part 4 Implementing CrowdSec AppSec WAF with Pangolin - Networking - HHF Technology Forums
Part 5 Implementing CrowdSec Captcha Protection in Pangolin - Networking - HHF Technology Forums
All Files
docker-compose.yml
networks:
pangolin:
external: true
services:
pangolin:
image: fosrl/pangolin:1.0.0-beta.9
container_name: pangolin
restart: unless-stopped
networks:
- pangolin
volumes:
- ./config:/app/config
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3001/api/v1/"]
interval: "3s"
timeout: "3s"
retries: 5
gerbil:
image: fosrl/gerbil:1.0.0-beta.3
container_name: gerbil
restart: unless-stopped
depends_on:
pangolin:
condition: service_healthy
networks:
- pangolin
extra_hosts:
- "pangolin:172.19.0.2" # Add host mapping
- "crowdsec:172.19.0.4" # Add CrowdSec host mapping
command:
- --reachableAt=http://gerbil:3003
- --generateAndSaveKeyTo=/var/config/key
- --remoteConfig=http://pangolin:3001/api/v1/gerbil/get-config
- --reportBandwidthTo=http://pangolin:3001/api/v1/gerbil/receive-bandwidth
volumes:
- ./config/:/var/config
cap_add:
- NET_ADMIN
- SYS_MODULE
ports:
- 51820:51820/udp
- 443:443 # Port for traefik because of the network_mode
- 80:80 # Port for traefik because of the network_mode
# Add CrowdSec services
crowdsec:
image: crowdsecurity/crowdsec:latest
container_name: crowdsec
environment:
GID: "${GID-1000}"
COLLECTIONS: crowdsecurity/traefik crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-generic-rules
ENROLL_INSTANCE_NAME: "pangolin-crowdsec"
PARSERS: crowdsecurity/whitelists
ENROLL_KEY: your-key
ACQUIRE_FILES: "/var/log/traefik/*.log"
ENROLL_TAGS: docker
networks:
- pangolin
healthcheck:
test: ["CMD", "cscli", "capi", "status"]
depends_on:
- gerbil
labels:
- "traefik.enable=false"
volumes:
# crowdsec container data
- ./config/crowdsec:/etc/crowdsec
- ./config/crowdsec/db:/var/lib/crowdsec/data
# log bind mounts into crowdsec
- ./config/crowdsec_logs/auth.log:/var/log/auth.log:ro
- ./config/crowdsec_logs/syslog:/var/log/syslog:ro
- ./config/crowdsec_logs:/var/log
- ./config/traefik/logs:/var/log/traefik
ports:
- 9090:9090 # port mapping for local firewall bouncers
- 6060:6060 # metrics endpoint for prometheus
expose:
- 9090 # http api for bouncers
- 6060 # metrics endpoint for prometheus
- 7422 # appsec waf endpoint
restart: unless-stopped
command: -t # Add test config flag to verify configuration
traefik:
image: traefik:v3.1
container_name: traefik
restart: unless-stopped
network_mode: service:gerbil # Ports appear on the gerbil service
depends_on:
pangolin:
condition: service_healthy
command:
- --configFile=/etc/traefik/traefik_config.yml
volumes:
- ./config/traefik:/etc/traefik:ro # Volume to store the Traefik configuration
- ./config/letsencrypt:/letsencrypt # Volume to store the Let's Encrypt certificates
- ./config/traefik/logs:/var/log/traefik
- ./config/traefik/conf/:/etc/traefik/conf/
traefik_config.yml
api:
insecure: true
dashboard: true
providers:
http:
endpoint: "http://pangolin:3001/api/v1/traefik-config"
pollInterval: "5s"
file:
filename: "/etc/traefik/dynamic_config.yml"
experimental:
plugins:
badger:
moduleName: "github.com/fosrl/badger"
version: "v1.0.0-beta.3"
crowdsec:
moduleName: "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
version: "v1.3.5"
log:
level: "INFO"
format: "json"
accessLog:
filePath: "/var/log/traefik/access.log"
format: json
filters:
statusCodes:
- "200-299" # Success codes
- "400-499" # Client errors
- "500-599" # Server errors
retryAttempts: true
minDuration: "100ms" # Increased to focus on slower requests
bufferingSize: 100 # Add buffering for better performance
fields:
defaultMode: drop # Start with dropping all fields
names:
ClientAddr: keep
ClientHost: keep
RequestMethod: keep
RequestPath: keep
RequestProtocol: keep
DownstreamStatus: keep
DownstreamContentSize: keep
Duration: keep
ServiceName: keep
StartUTC: keep
TLSVersion: keep
TLSCipher: keep
RetryAttempts: keep
headers:
defaultMode: drop
names:
User-Agent: keep
X-Real-Ip: keep
X-Forwarded-For: keep
X-Forwarded-Proto: keep
Content-Type: keep
Authorization: redact # Redact sensitive information
Cookie: redact # Redact sensitive information
certificatesResolvers:
letsencrypt:
acme:
httpChallenge:
entryPoint: web
email: "discourse@hhf.technology"
storage: "/letsencrypt/acme.json"
caServer: "https://acme-v02.api.letsencrypt.org/directory"
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
transport:
respondingTimeouts:
readTimeout: "30m"
http:
tls:
certResolver: "letsencrypt"
middlewares: # CHANGE MADE HERE (BOUNCER ENABLED) !!!
- crowdsec@file
serversTransport:
insecureSkipVerify: true
dynamic_config.yml
http:
middlewares:
redirect-to-https:
redirectScheme:
scheme: https
default-whitelist:
ipWhiteList:
sourceRange:
- "10.0.0.0/8"
- "192.168.0.0/16"
- "172.16.0.0/12"
# Basic security headers
security-headers:
headers:
customResponseHeaders:
Server: ""
X-Powered-By: ""
X-Forwarded-Proto: "https"
sslProxyHeaders:
X-Forwarded-Proto: "https"
hostsProxyHeaders:
- "X-Forwarded-Host"
contentTypeNosniff: true
customFrameOptionsValue: "SAMEORIGIN"
referrerPolicy: "strict-origin-when-cross-origin"
forceSTSHeader: true
stsIncludeSubdomains: true
stsSeconds: 63072000
stsPreload: true
# CrowdSec configuration with proper IP forwarding
crowdsec:
plugin:
crowdsec:
enabled: true
logLevel: INFO
updateIntervalSeconds: 15
updateMaxFailure: 0
defaultDecisionSeconds: 15
httpTimeoutSeconds: 10
crowdsecMode: live
crowdsecAppsecEnabled: true
crowdsecAppsecHost: 172.19.0.4:7422
crowdsecAppsecFailureBlock: true
crowdsecAppsecUnreachableBlock: true
crowdsecLapiKey: "your-api-key"
crowdsecLapiHost: 172.19.0.4:9090
crowdsecLapiScheme: http
captchaProvider: turnstile
captchaSiteKey: "your-key"
captchaSecretKey: "your-key"
captchaGracePeriodSeconds: 1800
captchaHTMLFilePath: "/etc/traefik/conf/captcha.html"
forwardedHeadersTrustedIPs:
- "0.0.0.0/0" # Cloudflare tunnel IP address
clientTrustedIPs:
- "10.0.0.0/8" # Internal LAN IP addresses
- "172.16.0.0/12" # Internal LAN IP addresses
- "192.168.0.0/16" # Internal LAN IP addresses
- "100.89.137.0/20" # Internal LAN IP addresses
routers:
# HTTP to HTTPS redirect router
main-app-router-redirect:
rule: "Host(`pangolin.testing.hhf.technology`)"
service: next-service
entryPoints:
- web
middlewares:
- redirect-to-https
# Next.js router (handles everything except API and WebSocket paths)
next-router:
rule: "Host(`pangolin.testing.hhf.technology`) && !PathPrefix(`/api/v1`)"
service: next-service
entryPoints:
- websecure
middlewares:
- security-headers
tls:
certResolver: letsencrypt
# API router (handles /api/v1 paths)
api-router:
rule: "Host(`pangolin.testing.hhf.technology`) && PathPrefix(`/api/v1`)"
service: api-service
entryPoints:
- websecure
middlewares:
- security-headers
tls:
certResolver: letsencrypt
# WebSocket router
ws-router:
rule: "Host(`pangolin.testing.hhf.technology`)"
service: api-service
entryPoints:
- websecure
middlewares:
- security-headers
tls:
certResolver: letsencrypt
services:
next-service:
loadBalancer:
servers:
- url: "http://pangolin:3002" # Next.js server
api-service:
loadBalancer:
servers:
- url: "http://pangolin:3000" # API/WebSocket server