diff --git a/infra/crowdsec-safeline.md b/infra/crowdsec-safeline.md index bfe99e2..398afb8 100644 --- a/infra/crowdsec-safeline.md +++ b/infra/crowdsec-safeline.md @@ -35,7 +35,7 @@ Traefik DaemonSet (stdout JSON accessLog) ### APISIX → CrowdSec (http-logger) ``` -APISIX (global_rules http-logger 플러그인) +APISIX K3s 서울 (apisix ns, global_rules http-logger 플러그인) → 배치 50건, 5초 buffer → CrowdSec HTTP acquisition (:8085/apisix-logs) → custom/apisix-json-logs 파서 @@ -43,10 +43,12 @@ APISIX (global_rules http-logger 플러그인) | 항목 | 값 | |------|-----| -| 설정 | APISIX Admin API global_rules/1 | +| 송신처 | **K3s 서울 APISIX 단독** (osaka는 송신 안 함, zlambda는 라우트 비어있음) | +| 설정 | K3s APISIX Admin API `global_rules/http-logger` (`uri: http://10.253.100.240:8085/apisix-logs`) | | CrowdSec 포트 | 8085 | | 인증 | `Authorization: apisix-crowdsec-log-2024` | | 파서 | `custom/apisix-json-logs` (로컬) | +| osaka의 처리 | 송신은 안 하고 `crowdsec-bouncer` 글로벌 플러그인으로 결정 **소비**만. `real-ip` 플러그인도 글로벌. | ### APISIX → log-collector → CrowdSec (sandbox-tokyo) @@ -139,8 +141,40 @@ Traefik values: `~/k8s/traefik/values.yaml` |------|---------|------| | HTTP | http-probing, http-crawl-non_statics, http-sensitive-files, http-backdoors-attempts, http-sqli-probing, http-xss-probing 등 | Hub | | SafeLine | custom/safeline-waf-blocked (trigger), custom/safeline-waf-repeated (3+/5min) | 로컬 | +| **APISIX** (2026-04-08 신규) | custom/apisix-high-rate-per-ip, custom/apisix-499-burst, custom/apisix-single-path-flood, custom/apisix-5xx-burst | 로컬 | | CAPI | http:dos, http:scan, ssh:bruteforce (커뮤니티) | 자동 | +### APISIX 시나리오 (4종, 2026-04-08 작성) + +ddos-detect AI 분석기 폐기 후 deterministic 패턴 매칭으로 대체. 모두 leaky bucket, ban 4h. **K3s 서울 APISIX 트래픽만 보고 판단** (osaka/zlambda는 http-logger 송신 안 함). + +| 시나리오 | 매개변수 | 의도 | filter | +|---|---|---|---| +| `apisix-high-rate-per-ip` | capacity 200, leakspeed 300ms (≈ 200req/60s sustained) | 일반 HTTP flood. APISIX 자체 limit-req(20 req/s)에 안 걸리는 sustained 패턴 | `log_type=http_access-log`, groupby `source_ip` | +| `apisix-499-burst` | capacity 30, leakspeed 2s | connection exhaustion / Slowloris (클라이언트 강제 끊김) | `http_status == "499"` | +| `apisix-single-path-flood` | capacity 50, leakspeed 600ms | 동일 path 반복 (CAPTCHA 우회, login bf, 동일 자원 폭격) | groupby `source_ip + ":" + http_path` | +| `apisix-5xx-burst` | capacity 20, leakspeed 3s | 백엔드 부하 유발성 공격, 취약점 스캔 | `http_status startsWith "5"` | + +⚠️ **운영 주의**: +- `5xx-burst`: 백엔드 장애 시 false positive 가능. 운영 알람과 분리해서 검토. +- `499-burst`: 모바일 클라이언트 끊김으로 정상 발생할 수 있어 30 임계값을 며칠 관찰 후 조정 권장. +- `high-rate-per-ip`: APISIX `limit-req` 글로벌 룰(20 req/s burst 10)을 통과한 트래픽만 도달 → 1차 통과 후 sustained pattern을 잡는 2차 layer. +- 현재 모두 `remediation: true` (즉시 ban). dry-run으로 시작 안 함 — false positive 발생 시 임계값 또는 ban duration 조정. + +### 발견 사항: K3s APISIX 글로벌 limit-req + +```json +{ + "key_type": "var", + "key": "remote_addr", + "rate": 20, + "burst": 10, + "rejected_code": 429 +} +``` + +`/apisix/global_rules/limit-req` (etcd). 모든 라우트에 적용. CrowdSec 시나리오는 이 1차 차단을 통과한 트래픽만 본다는 점을 고려해서 임계값 설계. + ## Bouncer ### cs-cf-worker-bouncer (Cloudflare Worker)