Files
obsidian/infra/security/crowdsec-safeline.md
kaffa e5c6b4deab netbis CF firewall bouncer 재구축 (origin filter) + VL acquisition 통합 + sigmatch v2.4
- 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 12:43:47 +09:00

359 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: CrowdSec 및 SafeLine WAF
updated: 2026-04-23
---
## CrowdSec LAPI
| 항목 | 값 |
|------|-----|
| 위치 | jp1 Incus `crowdsec` 컨테이너 |
| LAPI | `http://10.253.100.240:8080` |
| 관리 | `ssh incus-jp1 "incus exec crowdsec -- cscli ..."` |
| 버전 | v1.7.7 (최신, 2026-04-17 확인) |
## 로그 수집 (Acquisition)
### Traefik → CrowdSec (Vector)
```
Traefik DaemonSet (stdout JSON accessLog)
→ Vector Agent DaemonSet (K3s logging ns, kubernetes_logs source)
→ VRL transform (access log만 필터, non-JSON abort)
→ HTTP sink (배치 50건, 5초)
→ CrowdSec HTTP acquisition (:8086/traefik-logs)
→ crowdsecurity/traefik-logs 파서
```
| 항목 | 값 |
|------|-----|
| Vector | Helm `vector/vector` 0.51.0, Agent DaemonSet (3노드) |
| Values | `~/k8s/vector/values.yaml` |
| CrowdSec 포트 | 8086 |
| 인증 | `Authorization: traefik-crowdsec-log-2024` |
| 파서 | `crowdsecurity/nginx-logs` (Hub, 표준 nginx combined). Vector에서 모든 로그를 표준 포맷으로 변환 후 VictoriaLogs 저장 |
### APISIX + Traefik + NPM → VictoriaLogs → CrowdSec (통합 acquisition, 2026-04-25)
```
서울 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) |
| 통합 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)
```
sandbox-tokyo APISIX http-logger
→ log-collector (jp1 crowdsec 컨테이너, :8087)
→ SQLite (/var/lib/log-collector/requests.db)
→ CrowdSec HTTP acquisition (:8085/apisix-logs) 포워딩
```
| 항목 | 값 |
|------|-----|
| log-collector | Go HTTP 서버, `/usr/local/bin/log-collector` (jp1 crowdsec 컨테이너) |
| 소스 | jp1 `~/log-collector/main.go` |
| 수신 포트 | 8087 |
| 인증 | `Authorization: apisix-crowdsec-log-2024` |
| SQLite | `/var/lib/log-collector/requests.db` |
| 기능 | APISIX 로그 수신 → SQLite 저장 → CrowdSec 포워딩, 타임스탬프 밀리초 보정 |
### 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]]
**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)
```
SafeLine WAF 차단 → mgt_detect_log_basic INSERT
→ PG 트리거 (notify_detect_log) → pg_notify('safeline_detect', JSON)
→ safeline-listener (kr2, Go) → detail 테이블 enrichment (x-real-ip, user-agent)
→ CrowdSec HTTP acquisition (:8088/safeline-logs)
→ custom/safeline-http-logs 파서
→ custom/safeline-waf-blocked 시나리오 (trigger, 즉시 밴)
```
| 항목 | 값 |
|------|-----|
| safeline-listener | Go, `/usr/local/bin/safeline-listener` (kr2) |
| 소스 | kr2 `~/safeline-listener/main.go` |
| systemd | `safeline-listener.service` (kr2) |
| PG DSN | SafeLine CE DB (10.43.8.243:5432, safeline-ce) |
| CrowdSec 포트 | 8088 |
| 인증 | `Authorization: safeline-crowdsec-2026` |
| acquis 설정 | `/etc/crowdsec/acquis.d/safeline-http.yaml` |
| 파서 | `custom/safeline-http-logs` (`/etc/crowdsec/parsers/s01-parse/safeline-http-logs.yaml`) |
| 시나리오 | `custom/safeline-waf-blocked` (trigger 타입, 즉시 밴) |
| enrichment | req_header에서 `x-real-ip`, `user-agent` 추출, detail 테이블에서 method/payload 조회 |
PG 트리거 (SafeLine CE DB에 설치):
```sql
CREATE OR REPLACE FUNCTION notify_detect_log() RETURNS trigger AS $$
BEGIN
PERFORM pg_notify('safeline_detect', json_build_object(
'id', NEW.id, 'ts', NEW.created_at,
'src_ip', NEW.src_ip, 'host', NEW.host,
'url_path', NEW.url_path, 'attack_type', NEW.attack_type
)::text);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_detect_log
AFTER INSERT ON mgt_detect_log_basic
FOR EACH ROW EXECUTE FUNCTION notify_detect_log();
```
### ~~ddos-detect (AI 행위 분석)~~ — 폐기 (2026-04-08)
> [!warning] 폐기됨
> 2026-04-08 분석기 서비스 정지 + 삭제. "이 방식으로는 안 될 것 같다"는 판단 (60초 폴링 + Claude CLI 동기 호출 구조의 한계). 새로운 AI 분석 아키텍처는 [[victorialogs|VictoriaLogs]] 기반으로 재설계 예정.
>
> **제거된 항목**: `ddos-detect.service` (systemd), `/var/lib/log-collector/ddos-detect/` Go 바이너리 + 소스, `ddos-detect.sh`, `extract_behavior.py`, `ddos-logs/` (분석 결과 markdown). `requests.db`는 별개의 `log-collector` 데몬이 사용 중이라 보존. Gitea repo `kaffa/ddos-detect`는 보존 (코드 reference).
이전 동작 (참고):
| 항목 | 값 |
|------|-----|
| 위치 | jp1 crowdsec 컨테이너 `/var/lib/log-collector/ddos-detect/` |
| Gitea | `gitea.inouter.com/kaffa/ddos-detect` |
| 기능 | SQLite 폴링 → IP별 행위 패턴 추출 → Claude AI 분석 → cscli 자동 밴 |
| 설정 | `config.yaml` (poll 60s, Claude sonnet, ban 4h, max_workers 3) |
### 리얼 IP 처리
| 경로 | 설정 | source IP 추출 |
|------|------|---------------|
| BunnyCDN → HAProxy → **Traefik** | `forwardedHeaders.trustedIPs: 127/8, 10/8, 172.16/12, 192.168/16` + `externalTrafficPolicy: Local` | `ClientHost` (X-Forwarded-For에서 추출) |
| BunnyCDN → HAProxy → **APISIX** | `real_ip_header: X-Forwarded-For` + `real_ip_from: 127/8, 10.42/16, 10.43/16, 192.168.9/24, 100.64/10` | `client_ip` (nginx real_ip 모듈) |
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 1000, leakspeed 100ms (≈ sustained 10 req/s, burst 1000) | 일반 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 조정.
과거 인시던트 및 변경 이력은 `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 레거시 제거]].
### 발견 사항: 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)
| 항목 | 값 |
|------|-----|
| 위치 | jp1 Incus `cs-cf-worker-bouncer` 컨테이너 |
| 설정 | `/etc/crowdsec/bouncers/crowdsec-cloudflare-worker-bouncer.yaml` |
| 정본 | `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 |
| 보호 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 위젯]] |
| yaml writer | `cfb-manager` 단일 (K8s `default/cfb-manager` REST API). 과거 `/etc/cron.d/cf-zone-sync` + `auto-add-cf-zones.sh` 자동 쓰기는 coordination 문제로 제거됨 — 신규 zone 추가는 `cfb-manager POST /domains` 또는 수동 yaml edit + systemctl restart |
#### Decision 수동 관리
bouncer의 `lapi_key`**읽기 전용**. decision 추가/삭제는 `crowdsec` 컨테이너에서 `cscli`로:
```bash
# ban 추가
ssh incus-jp1 "incus exec crowdsec -- cscli decisions add --ip 1.2.3.4 --duration 2m --reason 'manual ban' --type ban"
# 확인
ssh incus-jp1 "incus exec crowdsec -- cscli decisions list --ip 1.2.3.4"
# 삭제
ssh incus-jp1 "incus exec crowdsec -- cscli decisions delete --ip 1.2.3.4"
```
bouncer 컨테이너에서 `curl POST /v1/decisions`로 직접 넣으면 등록 안 됨 — API 키 권한 제한.
#### 설정 변경 시 주의
**`sed -i` 사용 금지** — Incus 컨테이너 내에서 `sed -i`로 수정 시 이전 내용이 파일 끝에 남아 YAML 깨짐. 반드시 전체 파일 덮어쓰기:
```bash
cat updated-config.yaml | ssh incus-jp1 "incus file push - cs-cf-worker-bouncer/etc/crowdsec/bouncers/crowdsec-cloudflare-worker-bouncer.yaml"
ssh incus-jp1 "incus exec cs-cf-worker-bouncer -- systemctl restart crowdsec-cloudflare-worker-bouncer"
```
> **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)
| 항목 | 값 |
|------|-----|
| 동기화 | jp1 `infra-tool` 컨테이너, `/opt/crowdsec-bouncer/bouncer.py` |
| 크론 | 3분 delta sync, 매시 full sync |
| 방식 | LAPI → Bloom filter → BunnyCDN Edge Script 임베딩 → 퍼블리시 |
| Edge Script | ID 64811 (`crowdsec-bouncer-middleware`), FNV-1a bloom filter |
| 차단 시 | Cloudflare Turnstile CAPTCHA + LibSQL verified IP 캐싱(4h) |
| 적용 풀존 | iron-jp (5555247), iron-kr (5555227) — 두 풀존 모두 `MiddlewareScriptId: 64811` |
| API 키 | Vault `secret/infra/crowdsec-bunny-bouncer` |
| 소스 | `~/crowdsec-bunny-bouncer/` |
## 보안 구조
```
클라이언트 → BunnyCDN Edge Script (CrowdSec bouncer, 0차)
→ BunnyCDN WAF (OWASP CRS, 1차)
→ Traefik / APISIX + SafeLine WAF (2차)
→ CrowdSec 로그 분석 (3차) → bouncer 피드백 루프
```
### 0차: BunnyCDN Edge Script (CrowdSec bouncer)
- Bloom filter로 악성 IP 즉시 차단
- false positive 시 Turnstile CAPTCHA로 구제
### 1차: BunnyCDN WAF (OWASP CRS)
- CDN 에지에서 오리진 도달 전 차단
- 차단: SQLi, XSS, CMDi, SSRF, Shellshock, Log4j
- 비활성화: DATA LEAKAGES SQL (id=911) — NocoDB 오탐 방지
- 통과: Request Smuggling, NoSQLi, 경로 스캔
### 2차: SafeLine WAF (chaitin-waf)
- APISIX plugin_metadata → detector `10.43.253.244:8000`
- SafeLine v9.3.2, K3s safeline ns
- 관리: safeline.inouter.com, API 헤더 `X-SLCE-API-TOKEN`
- 토큰: Vault `secret/infra/safeline`
- tengine 미사용, APISIX 직접 연동
### 3차: CrowdSec 로그 분석
- Traefik / APISIX 로그: Vector → VictoriaLogs(`vl.inouter.com`) → CrowdSec `victorialogs` acquisition (tail 모드)
- SafeLine 차단: PG NOTIFY → safeline-listener → CrowdSec HTTP acquisition(`:8088`)
- sandbox-tokyo APISIX: http-logger → log-collector(`:8087`) → CrowdSec
- HTTP 시나리오 매칭 → decision → bouncer 피드백
## iron-kr-waf BunnyCDN Pull Zone (구 waf-kr)
APISIX 외부 인입 경로 (juiceshop SafeLine 통합 테스트 용도). APISIX 자체는 독립 LoadBalancer gateway (MetalLB 192.168.9.50) 이지 "SafeLine 전용" 이 아님 — 현재 1 route 가 SafeLine 용일 뿐.
| 항목 | 값 |
|------|-----|
| Zone ID | 5555224 |
| Name | iron-kr-waf |
| Origin | https://220.120.65.245:9443 |
| 경로 | 인터넷 → BunnyCDN(iron-kr-waf) → OpenWrt HAProxy(:9443) → MetalLB 192.168.9.50:443 → APISIX(K3s 서울) → chaitin-waf → SafeLine detector → K3s svc |
등록 호스트: `iron-kr-waf.b-cdn.net`, `juiceshop.keepanker.cv` (WAF 테스트용). ApisixRoute `juiceshop` (chaitin-waf block) → juiceshop:3000.
> 옛 메모의 `waf-kr (5554681)` 는 더 이상 존재하지 않음 — `iron-kr-waf (5555224)` 로 통합·재명명됨.
## 화이트리스트
| 파서 | 대역 | 이유 |
|------|------|------|
| `crowdsecurity/whitelists` (Hub) | 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12, ::1, 127.0.0.0/8 | RFC1918 사설 IP |
| `custom/tailscale-whitelist` (로컬) | 100.64.0.0/10 | Tailscale CGNAT |
2026-04-17 추가: 기존에 `crowdsecurity/whitelists` 파서가 미설치 상태여서 내부 IP(192.168.9.1 OpenWrt)가 반복 밴됨. 설치 후 해결.
## 알림 (Notification)
| 항목 | 값 |
|------|-----|
| 타입 | HTTP (Discord Bot API) |
| 이름 | `http_default` |
| 채널 | Discord `#heimdall` (1488119168145555486) |
| 트리거 | remediation=true인 모든 ban (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` |
## 참고
- BunnyCDN WAF 차단 시 오리진에 로그 안 옴 → CrowdSec에 미수신
- OpenWrt CrowdSec firewall bouncer는 DNAT 구조라 리얼 IP 매칭 불가
- chaitin-waf 플러그인은 `plugin_attr`이 아닌 **`plugin_metadata`(etcd)**에서 detector 노드를 읽음
- Incus 컨테이너에서 `sed -i`로 설정 수정 시 파일 손상 주의 (전체 파일 push 사용)