From e5c6b4deabb377ba545ee6e87e198305dc003a3f Mon Sep 17 00:00:00 2001 From: kaffa Date: Sat, 25 Apr 2026 12:43:47 +0900 Subject: [PATCH] =?UTF-8?q?netbis=20CF=20firewall=20bouncer=20=EC=9E=AC?= =?UTF-8?q?=EA=B5=AC=EC=B6=95=20(origin=20filter)=20+=20VL=20acquisition?= =?UTF-8?q?=20=ED=86=B5=ED=95=A9=20+=20sigmatch=20v2.4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - crowdsec-safeline.md: VL → CrowdSec acquisition 3개(apisix/traefik/npm) → 1개 통합 (victorialogs-nginx.yaml, query OR 결합). Netbis NPM CrowdSec 연동 활성. netbis-cf-firewall 재구축 섹션 추가. - services/netbis.md: bouncer 폐기 → 재구축 정정. firewall_bouncer_token 정보 갱신. Worker bouncer는 트래픽 비례 비용으로 재구축 안 함 명시. - history/2026-04-25-netbis-cf-firewall-rebuild.md: 오늘 작업 종합 (sigmatch v2.4 MP 제거, VL 통합, CrowdSec 연동, CF Firewall bouncer 재구축, origin filter로 10k 한도 회피). origin filter [crowdsec, cscli] 적용으로 2026-04-23 폐기 사유였던 CF IP List 10k 한도 회피. Worker bouncer는 origin filter로 회피 불가 (트래픽 비례 비용) 이라 재구축 안 함. --- .../2026-04-25-netbis-cf-firewall-rebuild.md | 90 +++++++++++++++++++ infra/security/crowdsec-safeline.md | 57 +++++++++--- services/netbis.md | 30 ++++--- 3 files changed, 155 insertions(+), 22 deletions(-) create mode 100644 history/2026-04-25-netbis-cf-firewall-rebuild.md diff --git a/history/2026-04-25-netbis-cf-firewall-rebuild.md b/history/2026-04-25-netbis-cf-firewall-rebuild.md new file mode 100644 index 0000000..1b2ef6e --- /dev/null +++ b/history/2026-04-25-netbis-cf-firewall-rebuild.md @@ -0,0 +1,90 @@ +--- +title: Netbis CF Firewall Bouncer 재구축 + sigmatch v2.4 + VL acquisition 통합 +updated: 2026-04-25 +tags: [netbis, crowdsec, cloudflare, sigmatch, vector, history] +--- + +## 배경 + +2026-04-23 [[2026-04-23-netbis-bouncer-removal|netbis bouncer 전량 폐기]] 이후 netbis CF 측엔 enforcement 컴포넌트가 비어 있었음. 그동안 [[../projects/netbis-sigmatch|netbis-sigmatch]]가 자체 detect + 자체 enforcement (CF Account-level IP Access Rules 직접 호출) 모델로 차단을 시도했으나, 다음 문제들로 LIVE 전환 보류: + +1. **2026-04-24 webhook callback 오탐**: 베팅 프로바이더 webhook (`/vinus/cback?bet_`)이 path entropy 기반 scanner_shape에 매칭. 어제 fix 적용 (path normalize, query string 제거) +2. **2026-04-25 attack_contributor 누적 오탐**: A4 Matrix Profile trigger의 1% false positive가 단순 volume top 차단 단계에서 증폭되어 18시간 동안 99 distinct IP 누적 차단 (webhook 4~5개 + KR 일반 유저 + IPv6 모바일 240/4 가짜 IP). LIVE였으면 베팅 콜백 중단 사고 + +이로 인해 sigmatch 자체 detect 모델 한계 확인 → CrowdSec 시나리오 기반 공식 도구로 enforcement 이전 결정. + +## 변경 요약 + +### 1. sigmatch v2.4 — A4 Matrix Profile 트리거 제거 + +- `loop.py`에서 `compute_mp_trigger` 호출 제거. `mp_seg` 로그 포맷 제거. `--mp-*` argparse 옵션은 deprecated 표기로 호환만 유지 +- `matrix_profile.py` 모듈은 보존 (관찰/연구용 수동 호출 가능) +- 활성 103건 sqlite 정리 후 재시작 +- 사유: MP self-similar 시계열 가정이 daily seasonality 트래픽과 안 맞고, 단일 시그널이 attack_contributor 단계의 단순 volume top 차단으로 증폭되는 위험 패턴 + +상세: [[../projects/netbis-sigmatch|projects/netbis-sigmatch.md]] + +### 2. VL → CrowdSec acquisition 통합 + +기존 분리: +- `victorialogs-apisix.yaml` +- `victorialogs-traefik.yaml` + +신규 통합 (단일 파일): +- `/etc/crowdsec/acquis.d/victorialogs-nginx.yaml` +- query: `(program:apisix AND log_type:access) OR program:traefik OR (program:npm AND log_type:access)` +- labels: `type: nginx` +- 이전 파일 3개는 `.bak`로 보존 (롤백 가능) + +같은 VL endpoint에 같은 label, query만 OR 결합 가능했음. connection 1개 + 메트릭 단일 source. + +### 3. Netbis NPM 로그 → CrowdSec 신규 연동 + +- 기존: NPM → Vector → zlambda → VL (수집만) +- 신규: 위 통합 acquisition에 합류 → nginx-logs parser → 시나리오 → LAPI decision +- nginx-logs parser는 NPM proxy format 호환 (cscli explain 결과 s01-parse 정상, 시나리오 매칭됨) + +### 4. CF Firewall Rule Bouncer 재구축 + +| 항목 | 값 | +|---|---| +| 패키지 | `crowdsec-cloudflare-bouncer 0.3.0` (apt) | +| 컨테이너 | jp1 incus `crowdsec` (LAPI 동거) | +| LAPI bouncer 이름 | `cs-cloudflare-bouncer-1777082222` | +| origin filter | `[crowdsec, cscli]` | +| API token | Vault `secret/cloud/cloudflare-netbis.firewall_bouncer_token` (Bearer cfut_…). global_api_key는 사용 불가 (`6003 Invalid request headers`) | +| Token 권한 | Account Firewall Access Rules Write, Account Rule Lists Write, 6 zone Firewall Services Write | +| CF 리소스 | IP List `crowdsec_managed_challenge`(`f728ad9d…`) + 6 zone Firewall Rule (managed_challenge) | + +### 5. 폐기 사유 회피 검증 + +2026-04-23 폐기 사유였던 **CF IP List 10k 한도**가 origin filter로 회피됨: + +| origin | LAPI 24h 누적 | CF List 푸시 | +|---|---|---| +| CAPI (커뮤니티) | 30k+ | ❌ 제외 | +| lists (tor 등) | 2,195 | ❌ 제외 | +| crowdsec (로컬) | 30+ | ✅ 푸시 | +| cscli (수동) | 0 | ✅ 푸시 | + +→ CF IP List에 한도 (10k) 이내로만 push. 향후 로컬 시나리오 폭주에 대비 sigmatch처럼 max_rules 안전장치 검토 가치 있음. + +Worker bouncer는 트래픽 비례 비용 ($14~50/월 추정)이라 origin filter로 회피 불가 → **재구축 안 함**. + +## 영향 받은 정본 + +- [[../projects/netbis-sigmatch|projects/netbis-sigmatch.md]] — v2.4 +- [[../infra/security/crowdsec-safeline|infra/security/crowdsec-safeline.md]] — VL 통합 acquisition + netbis-cf-firewall 섹션 +- [[../services/netbis|services/netbis.md]] — bouncer 재구축 정정, API token 정보 + +## 미해결 / 다음 결정 + +- **sigmatch 역할 재정의**: 자체 detect + enforcement → CrowdSec이 이걸 담당하므로 sigmatch는 (a) 폐기, (b) 관측/대시보드 전용, (c) 분포 anomaly 보조 (CrowdSec 시나리오로 못 잡는 영역) 중 결정 필요 +- **분산 DDoS 시나리오 미설치**: `http-ddos-by-asn`, `http-ddos-by-country` 같은 AS/Country 단위 시나리오 미설치. 필요 시 추가 +- **bouncer rename**: `cs-cloudflare-bouncer-1777082222` → `netbis-cf-firewall` 같은 의미 있는 이름. cscli 또는 config 수정으로 가능 + +## 운영 검증 시점 (작업 직후) + +- LAPI bouncer list: `cs-cloudflare-bouncer-1777082222` ✔️ valid +- CF IP List `crowdsec_managed_challenge` count: 1 (origin filter 정상 — 30k+ CAPI 제외 확인) +- 6 zone Firewall Rule 모두 `managed_challenge` 액션으로 생성됨 diff --git a/infra/security/crowdsec-safeline.md b/infra/security/crowdsec-safeline.md index 98ac81a..effcf6e 100644 --- a/infra/security/crowdsec-safeline.md +++ b/infra/security/crowdsec-safeline.md @@ -33,23 +33,28 @@ Traefik DaemonSet (stdout JSON accessLog) | 인증 | `Authorization: traefik-crowdsec-log-2024` | | 파서 | `crowdsecurity/nginx-logs` (Hub, 표준 nginx combined). Vector에서 모든 로그를 표준 포맷으로 변환 후 VictoriaLogs 저장 | -### APISIX → VictoriaLogs → CrowdSec (서울+오사카 통합) +### APISIX + Traefik + NPM → VictoriaLogs → CrowdSec (통합 acquisition, 2026-04-25) ``` -서울 APISIX (K3s) stdout → Vector DaemonSet → VictoriaLogs (ES bulk API) -오사카 APISIX (Docker) stdout → Vector (Docker) → VictoriaLogs (ES bulk API) - → CrowdSec victorialogs acquisition (tail 모드, 실시간) - → custom/apisix-json-logs 파서 +서울 APISIX (K3s) stdout → Vector DaemonSet ─┐ +오사카 APISIX (Docker) stdout → Vector ────────┤ +K3s Traefik stdout → Vector DaemonSet ────────┤→ VictoriaLogs (ES bulk API) +Netbis NPM 6대 nginx file → Vector → zlambda─┘ + ↓ + CrowdSec victorialogs acquisition (tail, 실시간, 단일 query OR로 통합) + → custom/apisix-json-logs 파서 + crowdsecurity/nginx-logs (NPM 호환) + anomaly-detect (5분 폴링, AI 분석) ``` | 항목 | 값 | |------|-----| | VictoriaLogs | `vl.inouter.com` (K3s logging ns, Traefik IngressRoute) | -| CrowdSec acquisition | `/etc/crowdsec/acquis.d/victorialogs-apisix.yaml` (`source: victorialogs`, `mode: tail`, `query: program:apisix log_type:access`) | -| 서울 Vector | K3s DaemonSet (Helm `vector/vector`), `parse_apisix` transform → `vlogs` ES sink | -| 오사카 Vector | Docker `timberio/vector:0.45.0-debian`, `/etc/vector/vector.yaml`, `docker_logs` source → `parse_apisix` → `vlogs` ES sink. `location: osaka` 필드 추가 | -| 파서 | `crowdsecurity/nginx-logs` (Vector가 표준 nginx combined로 변환) | +| 통합 acquisition | `/etc/crowdsec/acquis.d/victorialogs-nginx.yaml` (`source: victorialogs`, query: `(program:apisix AND log_type:access) OR program:traefik OR (program:npm AND log_type:access)`, `labels: type: nginx`) | +| 이전 분리 파일 | `victorialogs-apisix.yaml.bak`, `victorialogs-traefik.yaml.bak`, `victorialogs-npm-netbis.yaml.bak` (롤백용 보존) | +| 서울 Vector | K3s DaemonSet (Helm `vector/vector`), `parse_apisix` / `parse_traefik` transform → `vlogs` ES sink | +| 오사카 Vector | Docker `timberio/vector:0.45.0-debian`, `parse_apisix` → `vlogs`. `location: osaka` 필드 추가 | +| Netbis NPM 경로 | NPM 호스트 Vector → zlambda vector-relay → VL `npm-netbis` 인덱스. nginx-logs parser가 NPM proxy format 호환 (cscli explain 검증) | +| 파서 | `crowdsecurity/nginx-logs` (Vector가 표준 nginx combined로 변환). NPM은 raw proxy format도 grok으로 핵심 필드 추출 정상 | ### APISIX → log-collector → CrowdSec (sandbox-tokyo) @@ -69,17 +74,19 @@ sandbox-tokyo APISIX http-logger | SQLite | `/var/lib/log-collector/requests.db` | | 기능 | APISIX 로그 수신 → SQLite 저장 → CrowdSec 포워딩, 타임스탬프 밀리초 보정 | -### Netbis NPM → zlambda → VictoriaLogs (6대 오리진, 2026-04-23) +### Netbis NPM → zlambda → VictoriaLogs (6대 오리진, 2026-04-23 수집 / 2026-04-25 CrowdSec 연동) ``` NPM-1..6 (Linode Tokyo public) Vector 0.55 file→http → zlambda(Tailscale+public) Vector-relay 0.45 http_server→elasticsearch → vl.inouter.com (index `npm-netbis`) + → CrowdSec victorialogs acquisition (위 통합 파일에 query OR로 합류, 2026-04-25 연동) + → nginx-logs parser → 시나리오 매칭 → LAPI decision (origin: crowdsec) ``` Netbis 오리진(NPM) nginx access/error 로그 수집. VL 은 LAN-only(192.168.9.53) 이므로 public NPM이 도달할 수 없어 zlambda 를 HTTP 중계로 투입. 상세: [[../../services/netbis#로그-수집-vector-→-zlambda-→-victorialogs|netbis]], [[../../history/2026-04-23-netbis-npm-vl-collection|history]] -CrowdSec acquisition 쪽 추후 연동 가능 — VL LogsQL `service:npm log_type:access` 에 `victorialogs` acquisition 추가하면 APISIX 파이프라인과 동일하게 처리 가능. +**2026-04-25 CrowdSec 연동 완료.** 통합 acquisition `/etc/crowdsec/acquis.d/victorialogs-nginx.yaml` 의 query에 `(program:npm AND log_type:access)` 추가. nginx-logs parser가 NPM proxy format도 호환 처리 (grok이 충분히 lenient하여 핵심 필드 추출). `cscli explain --type nginx` 로 한 줄 시뮬 결과 s00-raw → s01-parse(nginx-logs +22 ~2) → s02-enrich → 시나리오(`custom/apisix-high-rate-per-ip`, `custom/apisix-single-path-flood`) 매칭 확인. ### SafeLine → CrowdSec (실시간, PG LISTEN/NOTIFY) @@ -233,7 +240,33 @@ cat updated-config.yaml | ssh incus-jp1 "incus file push - cs-cf-worker-bouncer/ ssh incus-jp1 "incus exec cs-cf-worker-bouncer -- systemctl restart crowdsec-cloudflare-worker-bouncer" ``` -> **Netbis CF 바운서 전량 제거 (2026-04-23)** — Worker Bouncer (`netbis-cf`) + Firewall Rule Bouncer (`netbis-cf-firewall`) 모두 폐기. Worker/KV 비용 구조 + CF IP List 10k 한도의 이중 한계로 두 방식 모두 비용 대비 효과 불충분 판단. 컨테이너·패키지·LAPI 엔트리·CF 리소스(Worker/KV/Routes/Turnstile/Rule List/Firewall Rules)·API 토큰 모두 삭제. 상세: [[../../history/2026-04-23-netbis-bouncer-removal|history]] +> **Netbis CF 바운서 (2026-04-23 폐기 → 2026-04-25 Firewall Rule 단독 재구축)** +> +> 2026-04-23: Worker + Firewall Rule 두 종류 모두 폐기 (Worker/KV 비용 + CF IP List 10k 한도). [[../../history/2026-04-23-netbis-bouncer-removal|history]] +> +> 2026-04-25: **`netbis-cf-firewall` 만 재구축**. 폐기 사유였던 10k 한도는 **origin filter `[crowdsec, cscli]`** 적용으로 회피 (CAPI/lists 30k+ 무시, 로컬 시나리오 발동만 푸시). Worker bouncer는 트래픽 비례 비용 구조라 origin filter로 회피 불가, **재구축 안 함**. +> +> 자세한 배경 및 구성: [[../../history/2026-04-25-netbis-cf-firewall-rebuild|history]], [[../../services/netbis#cloudflare-firewall-bouncer-재구축-2026-04-25|netbis 정본]] + +### netbis-cf-firewall (Cloudflare Firewall Rule Bouncer, 재구축 2026-04-25) + +| 항목 | 값 | +|------|-----| +| 컨테이너 | jp1 incus `crowdsec` (LAPI와 같은 컨테이너에 동거) | +| 패키지 | `crowdsec-cloudflare-bouncer 0.3.0` (apt) | +| 동작 | 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 한도 회피) | +| 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 | +| 인증 방식 | Bearer (`Authorization: Bearer cfut_...`). global_api_key는 `Invalid request headers (6003)` 라 **사용 불가** — 신규 token 발급 필수 | +| config | `/etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml` | +| systemd | `crowdsec-cloudflare-bouncer.service` | +| 비용 | $0 (Free plan 영역, IP List + Firewall Rule). Worker bouncer 대비 비용 구조 우월 | +| 한계 | CF 공식 deprecation 표기 ("isn't actively supported anymore"). 동작은 정상이나 향후 호환성 변화 가능 | + +cs-cf-worker-bouncer (kappa 계정용)는 별도 컨테이너에서 그대로 운영. netbis는 비용 구조 차이로 firewall bouncer만 사용. ### bunny-cdn-bouncer (BunnyCDN Edge Script) diff --git a/services/netbis.md b/services/netbis.md index 3f1969f..f859f27 100644 --- a/services/netbis.md +++ b/services/netbis.md @@ -68,8 +68,9 @@ NixOS `virtualisation.oci-containers`로 선언 — `~/nixos-infra/apisix.nix`. | Account ID | 8fcf3c7876332aba33e974cbbfdad951 | | Global API Key | Vault `secret/cloud/cloudflare-netbis` (`global_api_key`) | | Linode API Key | `e7cd3103ca76b865df2533b32eee5c8d7799c963fb29848274245dee142d21b0` | -| API Token (바운서용) | `crowdsec-cf-bouncer-netbis` (Workers, Turnstile, WAF, Zone 권한) | -| Workers 플랜 | Paid ($5/월, 1000만 요청 포함) | +| ~~API Token (Worker bouncer용)~~ | ~~`crowdsec-cf-bouncer-netbis`~~ → 2026-04-23 Worker bouncer 폐기 시 token 삭제됨 | +| API Token (Firewall bouncer용) | Vault `secret/cloud/cloudflare-netbis` (`firewall_bouncer_token`, id `firewall_bouncer_token_id`). 2026-04-25 발급. 권한: Account Firewall Access Rules Write + Account Rule Lists Write + 6 zone Firewall Services Write | +| Workers 플랜 | Paid ($5/월, 1000만 요청 포함) — 현재 미사용 (Worker bouncer 폐기 후 재구축 안 함) | ### Zone 목록 @@ -126,18 +127,27 @@ APISIX global_rule로 모든 요청 로그를 CrowdSec(jp1)로 전송. - 인증: `auth_header: apisix-crowdsec-log-2024` - 파서: `custom/apisix-json-logs` (기존 파서 공유) -### Cloudflare Worker Bouncer (netbis-cf) +### Cloudflare Firewall Bouncer 재구축 (2026-04-25) + +2026-04-23에 두 종류 bouncer (Worker + Firewall Rule) 모두 폐기됐다가 ([[../history/2026-04-23-netbis-bouncer-removal|history]]), 2026-04-25에 **Firewall Rule bouncer만 재구축**. | 항목 | 값 | |------|-----| -| 컨테이너 | jp1 incus `netbis-cf-bouncer` (10.253.103.33) | -| 바운서 이름 | netbis-cf (CrowdSec LAPI 등록) | -| LAPI 키 | `FR/PbHA110b6+m/gkByp9itNOaQMdbM8BwKR3DerCTI` | -| 설정 파일 | `/etc/crowdsec/bouncers/crowdsec-cloudflare-worker-bouncer.yaml` | -| 동작 | CrowdSec ban → Cloudflare Worker + Turnstile captcha | -| 적용 범위 | Netbis 계정 전체 6개 zone | +| 컨테이너 | jp1 incus `crowdsec` (LAPI와 동거. 별도 컨테이너 X) | +| 패키지 | `crowdsec-cloudflare-bouncer 0.3.0` (apt) | +| LAPI bouncer 이름 | `cs-cloudflare-bouncer-1777082222` (자동 생성) | +| 설정 파일 | `/etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml` | +| origin filter | `[crowdsec, cscli]` — CAPI 30k+/lists 무시 (10k 한도 회피 핵심) | +| 적용 범위 | netbis 계정 전체 6개 zone, managed_challenge 액션 | +| CF 리소스 | IP List `crowdsec_managed_challenge` + 6 Zone Firewall Rule 자동 생성 | +| API token | Vault `secret/cloud/cloudflare-netbis` 의 `firewall_bouncer_token`, `firewall_bouncer_token_id` | +| Token 권한 | Account Firewall Access Rules Write, Account Rule Lists Write, 6 zone Firewall Services Write | +| 인증 방식 | Bearer token. global_api_key는 `Invalid request headers (6003)`로 거부 | +| 비용 | $0 (Free plan IP List + Firewall Rule 사용) | -기존 `cs-cf-worker-bouncer` (Kappa 계정용)와 별도 컨테이너로 분리 운영. +2026-04-23에 Worker Bouncer (`netbis-cf`) 도 폐기됐고 **2026-04-25 재구축에는 포함 안 됨** — Worker는 트래픽 비례 비용($14~50/월 추정)이라 origin filter로 회피 불가. + +상세 history: [[../history/2026-04-25-netbis-cf-firewall-rebuild|2026-04-25 재구축]] ## Cloudflare 보안 설정