Files
obsidian/history/2026-04-23-netbis-firewall-bouncer-migration.md

7.1 KiB

date, topic, areas, tags
date topic areas tags
2026-04-23 Netbis Firewall Bouncer 도입 (Worker Bouncer 병행)
infra/security/crowdsec-safeline.md
services/netbis.md
infra/security/cloudflare.md
crowdsec
cloudflare
bouncer
netbis
cost-control

배경

Netbis 계정 2026-04 Cloudflare Workers 요금 $100 중 82%가 KV read 비용 오버. Worker Bouncer(netbis-cf) 구조는 요청이 CF에 도달 → Worker 실행 → KV.get으로 IP 확인 → 차단/통과 순서. 즉 Worker가 실행돼야 KV read가 발생. 악성 IP라 결국 차단해도 KV read 비용은 이미 청구됨.

기존 Bouncer는 제거하지 않고 병행. Worker Bouncer는 Turnstile/captcha 등 정교한 챌린지용 유지, Firewall Rule Bouncer는 엣지 즉시 차단으로 Worker 실행 자체를 회피해 비용 방어.

최종 구조

LAPI (jp1:crowdsec, 10.253.100.240:8080)
  ├─ netbis-cf           → CF Worker + KV  (기존, Turnstile/정교)
  └─ netbis-cf-firewall  → CF Rule List + Firewall Rule (신규, 엣지 차단)

CF 요청 평가 순서상 Firewall Rule → Worker. Firewall Rule에서 block되면 Worker는 실행되지 않아 KV read 없음.

실행 단계

1. 사전 조사 — CF 플랜 / IP List 용량

6개 zone 플랜 (scoped API 아님, global_api_key X-Auth 조회):

Zone Zone ID Plan
fall-vip.com 662312b0ca619d1d5c8f4c112150d749 Pro
fall-mvp.com 6c171579912a271c0fc89c8187493b0f Free
fall-vip7.com a8832b9d3b546f96505abeadea4750d1 Free
psd777.com a14533c2937b19e5b7ed19cbecd58679 Pro
rss-555.com 6d4b084940520c1f820927e5d8ade2c6 Pro
rss-7790.com d9db9e50e202339326498baa340a9d16 Pro

Free/Pro/Biz 공통 IP list 상한 = 10,000. total_ip_list_capacity: 10000 설정.

2. 컨테이너 패키지 설치

jp1:netbis-cf-bouncer (기존 Worker Bouncer 컨테이너 재사용, 서비스 분리).

incus exec jp1:netbis-cf-bouncer -- apt-get update
incus exec jp1:netbis-cf-bouncer -- apt-get install -y crowdsec-cloudflare-bouncer   # v0.3.0

3. LAPI 바우언서 등록

incus exec jp1:crowdsec -- cscli bouncers add netbis-cf-firewall
# API key 출력을 즉시 설정 파일에 주입

4. CF scoped API token 발급

v0.3.0 바우언서는 cloudflare.NewWithAPIToken(token) Bearer-only. Global API Key는 X-Auth 헤더 전용이라 token 필드에 그대로 못 넣음 (Bearer auth에서 Invalid request headers 거절 확인). 해결: global_api_key 경유로 scoped API token 신규 발급.

항목
Token 이름 crowdsec-cloudflare-bouncer-netbis
Account 스코프 Netbis (8fcf3c7876332aba33e974cbbfdad951) 전용, All zones
TTL 무기한
권한 Account Rule Lists Write + Account Settings Read + Zone Firewall Services Write + Zone WAF Write + Zone Read
저장 Vault secret/cloud/cloudflare-netbis api_token 필드 (기존 global_api_key 보존)

발급 시 CF API permission_group IDs:

  • 2edbf20661fd4661b0fe10e9e12f485c Account Rule Lists Write
  • c1fde68c7bcc44588cbb6ddbc16d6480 Account Settings Read
  • 43137f8d07884d3198dc0ee77ca6e79b Firewall Services Write
  • fb6778dc191143babbfaa57993f1d275 Zone WAF Write
  • c8fed203ed3043cba015a93ad1616f1f Zone Read

메모: Account.Account Filter Lists:Edit (user 스펙 명)은 현재 CF에서 Account Rule Lists Write로 이름 변경됨. 기능 동일. Rulesets API 경로 사용 시 403 발생하면 Account Rulesets:Edit (56907406c3d548ed902070ec4df0e328) 추가 후 재발급.

5. Config 파일 전송

/etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml — 전체 파일 push (sed -i 금지, Incus 컨테이너 내 in-place 편집 피함):

incus exec jp1:netbis-cf-bouncer --mode=non-interactive -- \
  bash -c 'cat > /etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml && chmod 600 /etc/crowdsec/bouncers/crowdsec-cloudflare-bouncer.yaml' \
  < /tmp/crowdsec-cloudflare-bouncer.yaml

주요 값:

  • crowdsec_lapi_url: http://10.253.100.240:8080
  • crowdsec_lapi_key: cscli bouncers add 출력
  • cloudflare_config.accounts[0].token: 위에서 발급한 scoped token
  • ip_list_prefix: crowdsec
  • default_action: block, 모든 zone actions: [block] 단일
  • total_ip_list_capacity: 10000

6. 서비스 기동 + CF 리소스 자동 생성

incus exec jp1:netbis-cf-bouncer -- systemctl enable --now crowdsec-cloudflare-bouncer

바우언서 부팅 직후:

  • CF IP List crowdsec (ID b14745a3306a4f81b46d96593135f78b) 생성 — Account Rule List
  • 6개 zone에 firewall rule 자동 생성 (ip.src in $crowdsec → block)
  • LAPI 스트림 첫 풀: 28,885건 decision 수신, 10,000건 CF로 push

7. E2E 검증

  • 추가 경로: cscli decisions add --ip 203.0.113.99 --duration 2m --type ban → LAPI 기록 확인 → 바우언서 다음 사이클에 처리. 단 LAPI 총량 > 10k 상황에서 신규 IP는 용량 우선순위 밀려 CF 반영 보장 안 됨. 실제 테스트에서 1 IPs won't be inserted/kept to avoid exceeding IP list limit 경고 발생
  • 삭제 경로: CF 리스트 내 IP (1.14.7.100) LAPI decision 삭제 → 다음 사이클 제거. CF API 레이트리밋(10040) 영향으로 즉시 반영 아닌 다음 rate-limit window 이후 반영
  • 실제 push 성공 증거: 바우언서 로그 added 10000 new IPs and deleted 0 IPs — 초기 sync 정상

8. Obsidian 커밋 + graphify

  • infra/security/crowdsec-safeline.md### netbis-cf-firewall 서브섹션 추가, 바우언서 역할 분담 도식
  • history/2026-04-23-netbis-firewall-bouncer-migration.md — 이 문서
  • commit: netbis: crowdsec-cloudflare-bouncer (firewall rule) 추가 — worker bouncer와 병행
  • /graphify update ~/obsidian

운영 관찰 사항

IP List 용량 제약

LAPI 전체 decision 수가 ~29k, CF Pro 제한 10k. 바우언서는 10k 초과분을 우선순위 선별해 push하지 않음. 결과:

  • 오래된/높은 우선순위 decision은 CF 반영 (일관성 있는 차단)
  • 신규 short-TTL decision은 CF 반영 불확실 (커뮤니티 CAPI 결정 다수 + 큰 TTL 누적 영향)
  • 운영상 Worker Bouncer 경로가 여전히 필요한 이유 — Firewall Rule로 못 잡는 부분은 Worker Bouncer가 KV 조회로 커버

CF API 레이트리밋 (10040)

바우언서 update_frequency: 30s에서 매 사이클 신규 IP 1~수건 push 시도. CF Rule List items API 제한(분당 N건)에 금방 도달. 로그에 you have been ratelimited 출력, 다음 사이클에서 자동 재시도.

향후 개선 후보

  • CrowdSec LAPI only_include_decisions_from 필터로 CAPI 커뮤니티 feed 제외 → 차단 quality 향상하고 CF 10k 용량 효율화
  • include_scenarios_containing: ["http"] 등 시나리오 필터로 포커스
  • Enterprise zone 업그레이드 시 total_ip_list_capacity: 50000 가능

영향 및 롤백

  • Worker Bouncer netbis-cf 무변경 — 병행 운영, 기존 Turnstile/captcha 동작 그대로
  • 롤백: systemctl stop crowdsec-cloudflare-bouncer && cscli bouncers delete netbis-cf-firewall + CF IP List/Firewall Rule 수동 삭제 (Rule List crowdsec + 6 zone firewall rules)
  • CF 요금 방어 효과는 다음 월 청구서에서 확인 가능