From ffdabc994bac09de26af70a82f9a15b1e69e8cb0 Mon Sep 17 00:00:00 2001 From: kaffa Date: Sat, 25 Apr 2026 12:59:49 +0900 Subject: [PATCH] crowdsec: profile current state, distributed DDoS scenario notes, bouncer action mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - profile.yaml is ban-only — captcha/throttle decision은 emit 안 됨 - Hub 분산 DDoS 시나리오 (http-ddos-by-ASN/cn) 도입 시 profile 분기 필수 - cs-cf-worker-bouncer: default_action captcha (Turnstile) - netbis-cf-firewall: default_action managed_challenge (6 zone) - 두 bouncer 모두 LAPI decision type 무관하게 캡챠 페이지로 응답 --- infra/security/crowdsec-safeline.md | 63 +++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/infra/security/crowdsec-safeline.md b/infra/security/crowdsec-safeline.md index effcf6e..86aadc3 100644 --- a/infra/security/crowdsec-safeline.md +++ b/infra/security/crowdsec-safeline.md @@ -1,6 +1,6 @@ --- title: CrowdSec 및 SafeLine WAF -updated: 2026-04-23 +updated: 2026-04-25 --- ## CrowdSec LAPI @@ -181,6 +181,28 @@ ddos-detect AI 분석기 폐기 후 deterministic 패턴 매칭으로 대체. - `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 조정. +### 분산 DDoS 시나리오 (Hub, 도입 검토) + +per-IP 시나리오는 분산(여러 IP 합산) 패턴을 못 잡음. CrowdSec Hub에서 제공하는 공식 시나리오로 보완 가능. + +| 시나리오 | groupby | distinct | capacity | leakspeed | 의도 | +|---|---|---|---|---|---| +| `crowdsecurity/http-ddos-by-ASN` | `evt.Meta.ASNNumber` | `evt.Meta.source_ip` | 20 | 10s | 동일 ASN에서 distinct IP 20개가 10초 안에 도달 | +| `crowdsecurity/http-ddos-by-cn` | `evt.Meta.IsoCode` | `evt.Meta.source_ip` | 50 | 30s | 동일 국가에서 distinct IP 50개가 30초 안에 도달 | + +공식 필터에 false positive 회피책이 미리 깔려 있음: +- `http_status == '200'` → 백엔드 5xx 장애 시 자폭 차단 +- `static_ressource == 'false'` → CDN miss/이미지 burst 제외 +- `distinct: source_ip` → 단일 IP 반복이 아닌 IP 다양성으로 측정 + +CrowdSec 공식 가이드 명시 사항 ([blog](https://www.crowdsec.net/blog/mitigate-ddos-with-crowdsec)): +> "banning these given countries will mean false positives and collateral damage." + +→ **분산 시나리오는 ban이 아니라 `captcha` decision으로 emit하라는 게 공식 권장.** Hub 페이지에도 dos 계열은 "proper testing is advised" 경고가 직접 표기됨 (예: `http-dos-bypass-cache`). + +**도입 전 점검 필요 (2026-04-25 현재 상태)**: +- profile.yaml은 ban only — captcha decision을 emit하려면 분기 추가 필수 (아래 [#알림-notification] 참조). +- bouncer 측 액션 매핑은 이미 captcha 쪽이라 ban으로 emit해도 사용자 체감은 캡챠와 동일 (아래 bouncer 절 표 참조). 하지만 의미 일관성을 위해 profile에 captcha 분기 도입 권장. 과거 인시던트 및 변경 이력은 `history/` 참조. 예: `history/2026-04-10-edge-cleanup.md` (cf-audit-cleanup-2 3-incident chain, Turnstile sitekey 교체, 미들웨어 64811 `/__captcha/verify` 버그 수정 등), [[2026-04-15-apisix-http-logger-removal|2026-04-15 APISIX http-logger 레거시 제거]]. @@ -209,6 +231,7 @@ ddos-detect AI 분석기 폐기 후 deterministic 패턴 매칭으로 대체. | 정본 | `gitea.inouter.com/kaffa/k8s` → `configs/crowdsec/crowdsec-cloudflare-worker-bouncer.yaml` | | 동기화 | 10초 (decision stream polling) | | 방식 | LAPI → bouncer → Cloudflare Worker KV (bloom filter) → Worker에서 차단/captcha | +| **액션 매핑** | `default_action: captcha` (Turnstile). LAPI decision type이 ban이든 captcha든 모두 Turnstile 페이지로 처리됨 | | 보호 zone | keepanker.cv, actions.it.com, ironclad.it.com, servidor.it.com | | 비보호 zone | inouter.com, anvil.it.com — DNS `proxied: false` 라 CF 엣지를 거치지 않아 bouncer 라우트가 enforce 되지 않음. 보호는 BunnyCDN 미들웨어 64811 단독 | | Turnstile 위젯 | 4개 bouncer-managed (`crowdsec-cloudflare-worker-bouncer-widget` 이름, 168h rotation). BunnyCDN 미들웨어용 `inouter-bunny-middleware` 는 별도 수동 관리 — [[cloudflare#Turnstile 위젯]] | @@ -257,6 +280,7 @@ ssh incus-jp1 "incus exec cs-cf-worker-bouncer -- systemctl restart crowdsec-clo | 동작 | LAPI 폴링(10s) → CF Account IP List + Zone Firewall Rule 갱신 | | LAPI bouncer 이름 | `cs-cloudflare-bouncer-1777082222` (자동 생성, rename 보류) | | **origin filter** | `only_include_decisions_from: [crowdsec, cscli]` (CAPI/lists 30k+ 무시 → CF List 10k 한도 회피) | +| **액션 매핑** | `default_action: managed_challenge` (모든 6 zone 동일). LAPI decision type 무관하게 CF managed_challenge 액션으로 적용 → 사용자는 CF 캡챠 페이지 통과 후 진입. 분산 DDoS 시나리오 오탐 시에도 ban이 아니라 캡챠 | | CF 리소스 | IP List `crowdsec_managed_challenge` (`f728ad9d4653467396d32466902c9e52`), 6 zone × Firewall Rule (managed_challenge 액션) 자동 생성 | | 적용 zone | fall-vip / fall-mvp / fall-vip7 / psd777 / rss-555 / rss-7790 (Account ID `8fcf3c7876332aba33e974cbbfdad951`) | | API token | Vault `secret/cloud/cloudflare-netbis` (`firewall_bouncer_token`, `firewall_bouncer_token_id`). 권한: Account Firewall Access Rules Write + Account Rule Lists Write + Zone Firewall Services Write | @@ -337,6 +361,40 @@ APISIX 외부 인입 경로 (juiceshop SafeLine 통합 테스트 용도). APISIX 2026-04-17 추가: 기존에 `crowdsecurity/whitelists` 파서가 미설치 상태여서 내부 IP(192.168.9.1 OpenWrt)가 반복 밴됨. 설치 후 해결. +## Profile (decision 발급) + +`/etc/crowdsec/profiles.yaml` — 시나리오 매칭 시 LAPI에 emit할 decision type을 결정하는 단계. + +```yaml +name: default_ip_remediation +filters: [Alert.Remediation == true && Alert.GetScope() == "Ip"] +decisions: [{type: ban, duration: 4h}] +notifications: [http_default] +on_success: break +--- +name: default_range_remediation +filters: [Alert.Remediation == true && Alert.GetScope() == "Range"] +decisions: [{type: ban, duration: 4h}] +notifications: [http_default] +on_success: break +``` + +**현재 상태: ban-only**. captcha/throttle decision은 emit되지 않음. ASN/Country scope 핸들러도 없음 — 분산 DDoS 시나리오를 import하면 매칭은 되지만 어떤 profile에도 안 잡혀서 decision 자체가 발급 안 될 수 있음 (`on_success: break` 없는 fallthrough 동작 확인 필요). + +분산 DDoS 시나리오 도입 시 **상단에 captcha 분기 추가 필수** (예시): + +```yaml +name: distributed_ddos_captcha +filters: + - Alert.Remediation == true && Alert.GetScenario() matches "(?i)ddos-by-(asn|cn|country|range)" +decisions: + - type: captcha + duration: 1h +on_success: break +--- +# 기존 default_ip_remediation, default_range_remediation +``` + ## 알림 (Notification) | 항목 | 값 | @@ -344,11 +402,10 @@ APISIX 외부 인입 경로 (juiceshop SafeLine 통합 테스트 용도). APISIX | 타입 | HTTP (Discord Bot API) | | 이름 | `http_default` | | 채널 | Discord `#heimdall` (1488119168145555486) | -| 트리거 | remediation=true인 모든 ban (IP, Range) | +| 트리거 | remediation=true인 모든 decision (IP, Range) | | 그룹 | 30초 대기, 5건 이상 즉시 | | Bot 토큰 | Vault `secret/apps/discord` → `bot_token` | | 설정 | `/etc/crowdsec/notifications/http.yaml` | -| 프로필 | `/etc/crowdsec/profiles.yaml` — `default_ip_remediation`, `default_range_remediation` | ## 참고