Files
obsidian/infra/crowdsec-safeline.md

5.0 KiB

title, updated
title updated
CrowdSec 및 SafeLine WAF 2026-03-18

DB 테이블

DB 테이블은 blocklist (ip PK, reason, origin, expires_at), verified_ips, metadata

시나리오

시나리오: safeline/xml-injection, safeline/command-injection, custom/safeline-waf-blocked (trigger), custom/safeline-waf-repeated (leaky bucket 3+/5min)

Bouncer

Bouncer 목록: apisix-waf-bouncer, bunny-cdn-bouncer, cs-cloudflare-worker-bouncer

bunny-cdn-bouncer 상세

  • 동기화: jp1 infra-tool 컨테이너, /opt/crowdsec-bouncer/bouncer.py
  • 크론: 3분 간격 delta sync, 매시 정각 full sync (/etc/cron.d/crowdsec-bunny-bouncer)
  • 방식: CrowdSec LAPI → Bloom filter 생성 → BunnyCDN Edge Script 코드에 임베딩 → 퍼블리시
  • Edge Script: BunnyCDN Compute Script ID 64811 (crowdsec-bouncer-middleware)
    • Bloom filter (FNV-1a) 기반 IP 차단
    • 차단 시 Cloudflare Turnstile CAPTCHA 챌린지 (false positive 대응)
    • LibSQL DB로 verified IP 4시간 캐싱 + HMAC 서명 쿠키
    • Clean IP 네거티브 캐시 (최대 50K)
  • 적용 풀존: inouter (5316471) — actions (5330178)은 미적용
  • API 키: Vault secret/infra/crowdsec-bunny-bouncer (bouncer_key)
  • 소스 코드: ~/crowdsec-bunny-bouncer/

3중 보안 구조 (KR존, 2026-03-15)

클라이언트 → BunnyCDN Edge Script (CrowdSec bouncer, 0차)
          → BunnyCDN WAF (1차)
          → APISIX + SafeLine WAF (2차)
          → CrowdSec (분석/3차) → bunny-cdn-bouncer로 피드백 루프

1차: BunnyCDN WAF (OWASP CRS)

  • 위치: CDN 에지 (오리진 도달 전 차단)
  • 차단: SQLi, XSS, CMDi, SSRF, Shellshock, Log4j
  • 비활성화한 룰: DATA LEAKAGES SQL (id=911) — NocoDB API 응답 오탐 방지
  • 통과: Request Smuggling, NoSQLi, 일반 경로 스캔

2차: SafeLine WAF (chaitin-waf 플러그인)

  • 위치: APISIX 내부 플러그인 → K3s safeline ns의 detector (safeline-detector.safeline.svc.cluster.local:8000)
  • APISIX plugin_metadata로 detector 주소 설정 (etcd 저장)
  • BunnyCDN을 통과한 공격 차단
  • 라우트별 개별 적용 (gitea는 .git/ 경로 제외, 바이너리 프로토콜 파싱 불가)
  • SafeLine v9.3.2, Helm chart yaencn/safeline 10.1.0
  • tengine 미사용 (replicas: 0), APISIX가 직접 detector 연동
  • 관리 콘솔: safeline.inouter.com (IngressRoute + ServersTransport insecureSkipVerify)
  • API 토큰: vault secret/infra/safeline (api_token)
  • API 문서: https://safeline.inouter.com/swagger/index.html
  • API 헤더: X-SLCE-API-TOKEN
  • 이전: kr2 Incus VM → K3s safeline ns로 이전 (2026-03-18)

3차: CrowdSec (로그 분석)

  • 위치: jp1 CrowdSec (10.253.100.240:8080)
  • APISIX http-logger → CrowdSec HTTP acquisition (global_rules)
  • 파서: custom/apisix-json-logs (APISIX http-logger JSON 파싱)
  • 반복 공격자 패턴 탐지 (시나리오 매칭)
  • 인증: Authorization: apisix-crowdsec-log-2024

공격 테스트 결과 (sandbox-tokyo → nocodb.inouter.com)

공격 결과 차단 위치
SQLi (OR 1=1) 403 BunnyCDN WAF
SQLi (대소문자 혼합) 403 BunnyCDN WAF
SQLi (더블 인코딩) 403 BunnyCDN WAF
SQLi (POST body) 403 BunnyCDN WAF
XSS (<script>) 403 BunnyCDN WAF
XSS (img onerror) 403 BunnyCDN WAF
CMDi 403 BunnyCDN WAF
SSRF 403 BunnyCDN WAF
Shellshock 403 BunnyCDN WAF
Log4j (JNDI) 403 BunnyCDN WAF
Path Traversal 404 경로 정규화 (무해)
Request Smuggling 302 통과 (CDN 정규화로 실제 smuggling 불가)
NoSQLi (JSON) 401 통과 (PostgreSQL이라 무효, 인증에서 차단)
WP scan 404 통과 (존재하지 않는 경로)

waf-kr BunnyCDN Pull Zone (2026-03-25)

APISIX SafeLine WAF 전용 CDN zone.

항목
Zone ID 5554681
Name waf-kr
Origin https://220.120.65.245:9443
경로 인터넷 → BunnyCDN(waf-kr) → OpenWrt HAProxy(:9443) → APISIX NodePort(31137) → SafeLine WAF → K3s 서비스

등록된 호스트: juiceshop.keepanker.cv (OWASP Juice Shop, WAF 테스트용)

Juice Shop WAF 테스트 결과 (2026-03-25)

요청 결과 WAF Action
일반 GET / 200 pass
SQLi (?id=1 OR 1=1) 403 reject (SafeLine)
XSS (?q=<script>alert(1)</script>) 403 reject (SafeLine)

다음 단계: CrowdSec 자동 차단

계획: SafeLine WAF 차단 로그 → APISIX http-logger → jp1 CrowdSec → 커스텀 시나리오 (3회 차단 시 ban) → bouncer로 APISIX ip-restriction 적용

참고

  • BunnyCDN WAF 차단 시 오리진에 로그 안 옴 → CrowdSec에 미수신
  • 리얼 IP: 외부 트래픽은 X-Forwarded-For로 정상 전달, LAN은 127.0.0.1
  • OpenWrt에 CrowdSec firewall bouncer 설치 가능하나 DNAT 구조라 리얼 IP 매칭 불가
  • chaitin-waf 플러그인은 plugin_attr이 아닌 **plugin_metadata(etcd)**에서 detector 노드를 읽음 — 주의