# Part 6 Configuring CrowdSec Trusted IPs for Internal Pangolin Traffic

**URL:** <https://forum.hhf.technology/t/part-6-configuring-crowdsec-trusted-ips-for-internal-pangolin-traffic/444>\
**Category:** Networking\
**Tags:** reverse-proxy, tunnels, vpn, crowdsec, pangolin\
**Created:** [January 31, 2025, 11:32am UTC](https://forum.hhf.technology/t/part-6-configuring-crowdsec-trusted-ips-for-internal-pangolin-traffic/444 "2025-01-31T11:32:59Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![hhf.technoloy](https://forum.hhf.technology/user_avatar/forum.hhf.technology/hhf.technoloy/32/68_2.png) [@hhf.technoloy](https://forum.hhf.technology/u/hhf.technoloy)\
**Post date:** [January 31, 2025, 11:32am UTC](https://forum.hhf.technology/t/part-6-configuring-crowdsec-trusted-ips-for-internal-pangolin-traffic/444/1 "2025-01-31T11:32:59Z")

</div>

# 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:

```yaml
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`:

```yaml
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:

```yaml
    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`:

```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`:

```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:

```yaml
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`:

```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

```bash
# 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

```bash
# 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:

```yaml
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`:

```bash
#!/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

1. IP Forward Issues:

```bash
# 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"

```

1. Network Connectivity:

```bash
# 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`:

```bash
#!/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

1. Regular Maintenance:

2. Security Recommendations:

3. Documentation:

[Part 1 Integrating Crowdsec with Pangolin - Networking - HHF Technology Forums](https://forum.hhf.technology/t/part-1-integrating-crowdsec-with-pangolin/439)  
[Part 2 Configuring Crowdsec and bouncer integration with pangolin - Networking - HHF Technology Forums](https://forum.hhf.technology/t/part-2-configuring-crowdsec-and-bouncer-integration-with-pangolin/440)  
[Part 3 Testing and advanced configuration of Crowdsec with Pangolin - Networking - HHF Technology Forums](https://forum.hhf.technology/t/part-3-testing-and-advanced-configuration-of-crowdsec-with-pangolin/441)  
[Part 4 Implementing CrowdSec AppSec WAF with Pangolin - Networking - HHF Technology Forums](https://forum.hhf.technology/t/part-4-implementing-crowdsec-appsec-waf-with-pangolin/442)  
[Part 5 Implementing CrowdSec Captcha Protection in Pangolin - Networking - HHF Technology Forums](https://forum.hhf.technology/t/part-5-implementing-crowdsec-captcha-protection-in-pangolin/443)

# All Files

docker-compose.yml

```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

```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

```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

```
