# CrowdSec BunnyCDN Bouncer CrowdSec LAPI에서 탐지한 악성 IP를 BunnyCDN 에지에서 선제 차단하는 bouncer. ## 아키텍처 ``` [CrowdSec LAPI (jp1, 10.253.100.240:8080)] ↓ 크론잡 (3분 간격) ↓ /v1/decisions/stream API ↓ [bouncer.py] → IP 목록 → Bloom filter 생성 → BunnyCDN Compute API로 Edge Script 코드 업데이트 ↓ [BunnyCDN Edge Script (middleware.ts)] → X-Real-Ip 헤더에서 클라이언트 IP 추출 → Bloom filter로 IP 매칭 → 매칭되면 Turnstile CAPTCHA 챌린지 → 캡차 통과하면 4시간 검증 (verified_ips DB) → Bloom filter에 없으면 오리진으로 통과 ``` ## 구성 요소 ### sync/bouncer.py CrowdSec LAPI → BunnyCDN Edge Script 동기화 스크립트. - CrowdSec LAPI stream endpoint에서 ban 결정 fetch - IP 목록을 bloom filter (FNV-1a 해시)로 변환 - BunnyCDN Compute API로 Edge Script 코드 내 `BLOOM_B64` 상수 교체 - 스크립트 퍼블리시 ### edge/middleware.ts BunnyCDN Edge Script 미들웨어 (현재 inouter 풀존에 배포됨, script ID: 64811). - `@bunny.net/edgescript-sdk` 사용 - Bloom filter 기반 IP 차단 - Cloudflare Turnstile CAPTCHA로 false positive 대응 - LibSQL DB로 verified IP 4시간 캐싱 - HMAC 서명 쿠키로 세션 유지 - Clean IP 캐시 (네거티브 캐시, 최대 50K) ## 환경 변수 ### bouncer.py | 변수 | 설명 | 기본값 | |------|------|--------| | `CROWDSEC_LAPI_URL` | CrowdSec LAPI URL | `http://10.253.100.240:8080` | | `CROWDSEC_BOUNCER_KEY` | Bouncer API key | (required) | | `BUNNY_API_KEY` | BunnyCDN account API key | (required) | | `BUNNY_SCRIPT_ID` | Edge Script ID | `64811` | | `STATE_FILE` | 상태 파일 경로 | `/var/lib/crowdsec-bouncer/state.json` | ### Edge Script Variables | 변수 | 설명 | |------|------| | `TURNSTILE_SITE_KEY` | Cloudflare Turnstile site key | | `TURNSTILE_SECRET_KEY` | Cloudflare Turnstile secret key | | `CACHE_MODE` | 캐시 모드 (auto) | | `BUNNY_DATABASE_URL` | LibSQL database URL | | `BUNNY_DATABASE_AUTH_TOKEN` | LibSQL auth token | ## 배포 ### 1. CrowdSec bouncer 등록 ```bash # jp1 crowdsec 컨테이너에서 cscli bouncers add bunny-cdn-bouncer # 출력된 API key를 Vault에 저장 ``` ### 2. Vault에 시크릿 저장 ```bash vault kv put secret/infra/crowdsec-bunny-bouncer \ bouncer_key= ``` ### 3. Incus 컨테이너에 배포 ```bash # jp1 infra-tool 컨테이너 pip3 install -r sync/requirements.txt cp sync/bouncer.py /opt/crowdsec-bouncer/bouncer.py ``` ### 4. Cron 설정 ```bash # /etc/cron.d/crowdsec-bunny-bouncer */3 * * * * root CROWDSEC_BOUNCER_KEY="..." BUNNY_API_KEY="..." /usr/bin/python3 /opt/crowdsec-bouncer/bouncer.py >> /var/log/crowdsec-bouncer.log 2>&1 # 매시 정각: 전체 동기화 (startup mode) 3 * * * * root CROWDSEC_BOUNCER_KEY="..." BUNNY_API_KEY="..." /usr/bin/python3 /opt/crowdsec-bouncer/bouncer.py --startup >> /var/log/crowdsec-bouncer.log 2>&1 ``` ## 테스트 ```bash # 테스트 IP 추가 ssh incus-jp1 "incus exec crowdsec -- cscli decisions add -i 198.51.100.1 -d 10m -R 'test'" # 동기화 실행 python3 sync/bouncer.py --startup -v # 테스트 IP 제거 ssh incus-jp1 "incus exec crowdsec -- cscli decisions delete -i 198.51.100.1" python3 sync/bouncer.py -v ``` ## 풀존 적용 현황 | 풀존 | ID | 미들웨어 | 상태 | |------|-----|---------|------| | inouter | 5316471 | 64811 | 적용됨 | | actions | 5330178 | - | 미적용 | ## Bloom Filter 세부 - 해시 함수: FNV-1a (32-bit) double hashing - False positive rate: 0.1% - 헤더: 8 bytes (m: uint32 LE, k: uint32 LE) - 페이로드: bit array - 버전: MD5 해시 앞 16자 (변경 감지용) ## Edge Script Pricing | 항목 | 단가 | |------|------| | 요청 | $0.20 / 1M | | CPU 시간 | $0.02 / 1,000초 | 처음 25M 요청은 무료. CDN 대역폭 비용은 별도. ## License MIT