diff --git a/infra/domain-boundaries.md b/infra/domain-boundaries.md index 86735d8..427987e 100644 --- a/infra/domain-boundaries.md +++ b/infra/domain-boundaries.md @@ -1,6 +1,6 @@ --- title: 도메인 경계 — netbis vs ironclad (cross-domain 운영) -updated: 2026-04-27 +updated: 2026-04-27 ironclad 자체 cycle 추가 (CF + BunnyCDN 병행, OpenWrt → K3s APISIX+SafeLine, enforce layer 재구축 미정) tags: [infra, domain, netbis, ironclad, zlambda, moc] --- @@ -18,7 +18,7 @@ ironclad 자체 인프라가 netbis의 보안 운영을 위탁받아 처리하 | **ironclad** | kappa CF account (`kappa@inouter.com`) | jp1/kr1/kr2/hp2 incus, K3s 서울/오사카, vl.inouter.com (VL), CrowdSec LAPI (jp1), netbis-cf-firewall, kappa CF zone (`keepanker.cv` / `actions.it.com` / `ironclad.it.com` / `servidor.it.com` / `inouter.com` / `anvil.it.com` 등) | 인프라 본체 + 분석 layer + 자체 워크로드 (Outline / Gitea / Vault / 등) | | **zlambda** | _(중립)_ | NixOS Tokyo 호스트, **Tailscale + Linode public IP 둘 다 보유** | 양 영역의 다리 — VL이 LAN-only(192.168.9.53)라 public NPM이 도달 못 함. HTTP relay로 투입 | -## 데이터 흐름 (cross-domain cyclic) +## 데이터 흐름 1 — netbis cycle (cross-domain cyclic) ``` [사용자 요청] @@ -65,20 +65,101 @@ ironclad 자체 인프라가 netbis의 보안 운영을 위탁받아 처리하 [사용자 요청 ← 차단/캡챠] ``` +## 데이터 흐름 2 — ironclad cycle (자체 워크로드) + +netbis와 달리 ironclad는 **CDN을 CF + BunnyCDN 병행**으로 운영한다. 두 엣지가 동일한 origin(K3s 서울 클러스터)으로 수렴하고, 분석/결정/enforce는 모두 ironclad 인프라 내부 cycle. + +``` +[사용자 요청] + │ + ├──────────────┬──────────────┐ + ▼ ▼ │ +[Cloudflare] [BunnyCDN 풀존] │ 병행 — proxied 패턴 별로 분기 + (proxy=on) (iron-kr/iron-jp) │ + kappa zone inouter.com 등 │ + │ │ │ + │ ※ enforce layer 현재 상태: + │ - CF bouncer (cs-cf-worker-bouncer) → 폐기 2026-04-26 + │ - BunnyCDN bouncer (Edge Script 64811) → 폐기 2026-04-26 + │ - 양쪽 모두 IP-list 기반 enforce 부재 (재구축 미완) + │ + └──────┬───────┘ + ▼ +[OpenWrt 라우터 (kr1 LAN, 192.168.9.1)] + - HAProxy frontend (KR 진입점) + - TCP 로드밸런싱 → MetalLB L2 (192.168.9.50/51) → K3s + │ + ▼ (MetalLB LB → K3s svc) +[K3s 서울 — APISIX (서울 ns) + SafeLine WAF (safeline ns)] + - 인입: APISIX가 ApisixRoute / Gateway API 처리 + - WAF: APISIX `chaitin-waf` plugin이 SafeLine detector를 in-line gRPC 호출 (10.43.253.244:8000) + - 1차 차단 layer: APISIX 글로벌 limit-req (rate 20, burst 10) + - 2차 차단 layer: SafeLine WAF (OWASP CRS + 커스텀 룰) + - origin 워크로드 (Outline / Gitea / Vault / 기타) 호출 + │ + │ access log (Vector DaemonSet) + ▼ +[vl.inouter.com (K3s logging ns)] + - APISIX/Traefik/SafeLine 로그 적재 + - netbis NPM 로그와 같은 VL이지만 다른 인덱스/program 라벨 + │ + ▼ (CrowdSec acquisition tail query, 통합 query OR) +[CrowdSec LAPI (jp1 incus crowdsec 컨테이너)] + - 시나리오: hub HTTP CVE 시나리오 + 자작 APISIX 4종 (high-rate-per-ip / 499-burst / single-path-flood / 5xx-burst) + safeline-waf-blocked + - 시나리오 매칭 → LAPI decision (origin: crowdsec) + │ + ├──────────────┬──────────────┐ + ▼ ▼ │ +[CF bouncer] [BunnyCDN bouncer] │ enforce 분기 (양쪽 모두 재구축 필요) + (재구축 미정) (재구축 미정) │ + │ │ │ + ▼ ▼ │ +[kappa CF zone] [BunnyCDN 풀존] │ + enforce enforce │ + │ + ▲ (다음 요청에 반영) +[사용자 요청 ← 차단] +``` + +### enforce layer 재구축 계획 (미정 / 진행 중) + +| 분기 | 현재 상태 | 후보 | +|---|---|---| +| Cloudflare (kappa CF zone) | bouncer 부재 | netbis-cf-firewall과 같은 패턴(`crowdsec-cloudflare-bouncer` apt 패키지)으로 별도 인스턴스 또는 동일 인스턴스에 kappa CF token 추가 운영 | +| BunnyCDN (iron-kr/iron-jp 등) | bouncer 부재 | Pull Zone `BlockedIps` 배열 push 또는 Shield Access List (Advanced 플랜) — 한도/방식은 [BunnyCDN 지원 Ticket 388529](https://dash.bunny.net/support/ticket/388529) 답변 후 결정 | +| OpenWrt 라우터 | DNAT 통과 layer (decision enforce 안 함) | 검토 필요 — DNAT 구조라 IP 기반 차단 적용 가능 여부 별건 | + ## 자산 → 도메인 매핑 (주요 노드) -| 노드 / 자산 | 도메인 | 비고 | -|---|---|---| -| netbis CF account (`8fcf3c…`) | netbis | 별도 계정 | -| netbis CF zone × 6 (`fall-vip` 등) | netbis | | -| NPM-1..6 (Linode Tokyo public) | netbis | 사용자 origin | -| zlambda (NixOS, `139.162.71.52` + Tailscale `100.108.39.107`) | bridge | Vector relay 전용 — 자체 트래픽 종착 아님 | -| Vault `secret/cloud/cloudflare-netbis` | bridge | netbis CF API token, ironclad Vault에 저장 | -| netbis-cf-firewall (`cs-cloudflare-bouncer-1777082222`) | bridge | jp1 ironclad 컨테이너에 동거하지만 netbis CF에 push | -| jp1 incus `crowdsec` 컨테이너 | ironclad | LAPI + netbis-cf-firewall 동거 | -| vl.inouter.com (K3s logging ns) | ironclad | LAN-only, public 도달 불가 | -| K3s 서울/오사카, kappa CF zone | ironclad | 자체 워크로드 (Outline / Gitea 등) | -| kappa CF account (`d8e5997e…`) | ironclad | | +### netbis 자산 +| 노드 / 자산 | 비고 | +|---|---| +| netbis CF account (`8fcf3c…`) | 별도 계정 | +| netbis CF zone × 6 (`fall-vip` / `fall-mvp` / `fall-vip7` / `psd777` / `rss-555` / `rss-7790`) | 사용자 노출 도메인 | +| NPM-1..6 (Linode Tokyo public) | nginx-proxy-manager origin 6대 | + +### ironclad 자산 +| 노드 / 자산 | 비고 | +|---|---| +| kappa CF account (`d8e5997e…`) | ironclad 자체 운영 | +| kappa CF zone (proxied=on: `keepanker.cv` / `actions.it.com` / `ironclad.it.com` / `servidor.it.com`) | CF 엣지 진입 | +| kappa CF zone (proxied=off: `inouter.com` / `anvil.it.com`) | CF 엣지 미경유 — BunnyCDN 단독 | +| BunnyCDN 풀존 (`iron-kr` 5555227 / `iron-jp` 5555247 / `iron-kr-waf` 5555224 / `iron-git` 5584382 등) | BunnyCDN 엣지 진입 | +| OpenWrt 라우터 (kr1 LAN `192.168.9.1`) | KR 진입점 + HAProxy TCP LB | +| MetalLB L2 (`192.168.9.50/51` 등) | OpenWrt → K3s svc bridge | +| K3s 서울 (4노드 클러스터) | 메인 워크로드 클러스터 | +| K3s `apisix` ns (서울 APISIX) | 인그레스 게이트웨이 | +| K3s `safeline` ns (SafeLine detector `10.43.253.244:8000`) | WAF 처리 (chaitin-waf in-line gRPC) | +| K3s 워크로드 ns (Outline / Gitea / Vault / n8n / 등) | 사용자 호출 종착점 | +| vl.inouter.com (K3s `logging` ns) | LAN-only, public 도달 불가 | +| jp1 incus `crowdsec` 컨테이너 | LAPI + netbis-cf-firewall 동거 | + +### bridge 자산 +| 노드 / 자산 | 비고 | +|---|---| +| zlambda (NixOS Tokyo, `139.162.71.52` + Tailscale `100.108.39.107`) | Vector relay 전용. netbis NPM → ironclad VL 도달용 다리 | +| Vault `secret/cloud/cloudflare-netbis` | netbis CF API token. ironclad Vault에 저장하지만 netbis 권한만 보유 | +| netbis-cf-firewall (`cs-cloudflare-bouncer-1777082222`) | jp1 ironclad 컨테이너에 동거하지만 netbis CF에 push (ironclad 인프라가 netbis 운영 위탁) | ## cross-domain 운영 패턴 @@ -113,10 +194,12 @@ netbis CF token은 **ironclad 인프라가 netbis CF에 푸시하기 위한 위 ## 추적 시 주의 (graphify / LLM 추론용) -- **CrowdSec 시나리오 매칭은 ironclad VL 데이터 위에서 일어남**. 시나리오 발동된 IP가 어떤 netbis zone을 노렸는지 알려면 VL `npm-netbis` 인덱스의 host/path 필드를 backward query 필요 -- **netbis-cf-firewall에 등록된 IP List는 netbis CF account에만 적용** — kappa CF zone에는 영향 없음 -- **kappa zone (keepanker / actions / ironclad / servidor / inouter / anvil)에는 IP-list 기반 enforce layer 부재** (2026-04-26 cs-cf-worker-bouncer + bunny-cdn-bouncer 폐기 후) — 별도 보호 검토 필요 -- **APISIX는 ironclad 인프라 자산** — netbis NPM 트래픽은 APISIX를 통과하지 않음. APISIX limit-req / chaitin-waf 등은 ironclad 자체 워크로드(Outline 등)에만 적용 +- **CrowdSec 시나리오 매칭은 ironclad VL 데이터 위에서 일어남**. netbis IP가 어떤 zone을 노렸는지는 VL `npm-netbis` 인덱스 host/path 필드 backward query 필요. ironclad 자체 트래픽은 program별(`apisix` / `traefik`) 라벨로 분리됨 +- **netbis-cf-firewall이 push하는 IP List는 netbis CF account에만 적용** — kappa CF zone에는 영향 없음 +- **kappa zone과 BunnyCDN 풀존은 IP-list 기반 enforce layer 부재** (2026-04-26 cs-cf-worker-bouncer + bunny-cdn-bouncer 폐기 후 재구축 미완) — CrowdSec 결정이 발급되어도 ironclad 트래픽 entry 단계에서 enforce되지 못함. SafeLine WAF / APISIX limit-req는 in-cluster에서 작동 (1차/2차 layer 유지) +- **APISIX는 ironclad 자산만** — netbis NPM 트래픽은 APISIX를 통과하지 않음. APISIX limit-req / chaitin-waf / 자작 4종 시나리오는 ironclad 자체 워크로드 트래픽에만 적용 +- **ironclad CDN은 CF + BunnyCDN 병행** — 같은 origin으로 수렴하지만 entry는 두 갈래. zone 별 proxied on/off로 어느 entry를 거치는지 결정 (`inouter.com` / `anvil.it.com`은 BunnyCDN 단독, 나머지 kappa zone은 CF) +- **OpenWrt 라우터(`192.168.9.1`)는 양 CDN 엣지에서 들어오는 ironclad 트래픽의 KR 진입점** — DNAT/HAProxy 통과 layer라 CrowdSec decision enforce 안 함 (별건 검토 필요) ## 관련 정본