obsidian: 정본에서 변경 이력 분리, history/ 도입
- history/README.md: 변경 이력/인시던트 기록 규약 - history/2026-04-10-edge-cleanup.md: 오늘의 엣지 정리·인시던트·복구 전체 연대기 - infra/cloudflare.md: 연대기 주석/strikethrough/인시던트 서사 제거, 현재 사실만 - infra/crowdsec-safeline.md: 인시던트 bullet 제거, 과거 이력은 history/ 참조 - services/bunnycdn-security.md: sitekey 이력표 제거, 현재 위젯 정보만 - infra/nas-storage.md: reverse proxy 섹션의 날짜 주석 제거
This commit is contained in:
@@ -4,133 +4,122 @@ updated: 2026-04-10
|
||||
tags: [cdn, bunnycdn, security, crowdsec, edge-script]
|
||||
---
|
||||
|
||||
> 2026-04-10 전수 감사 (Outline `agent-qna` doc `51b963c3-b251-48b5-a57a-a2305959c470`) 결과 반영. 5개 풀존, 17개 호스트네임, 미들웨어 64811 attach 매트릭스를 모두 정본화.
|
||||
|
||||
## 구성
|
||||
|
||||
- 엣지 스크립트: `crowdsec-bouncer-middleware` (ID: 64811, ScriptType=2 Middleware)
|
||||
- **연결된 Pull Zone (2026-04-09 실측)**: **iron-kr (5555227)**, **iron-jp (5555247)** — `MiddlewareScriptId: 64811`. 두 풀존 모두 동일 미들웨어 공유.
|
||||
- 미장착 풀존: iron-git (5584382, gitea.inouter.com), iron-kr-waf (5555224, SafeLine 자체 보호), i-gate (5557897, 미사용)
|
||||
- 관리·동기화: jp1 `infra-tool` 컨테이너 `/opt/crowdsec-bouncer/bouncer.py` (3분 delta + 매시 full sync). cfb-manager 는 **Cloudflare Worker** bouncer 관리이며 BunnyCDN 미들웨어와 무관.
|
||||
- 소스: [[crowdsec-safeline|CrowdSec]] bloom filter (FNV-1a 임베디드 BLOOM_B64) + Cloudflare Turnstile 캡차
|
||||
- 엣지 스크립트: `crowdsec-bouncer-middleware` (ID `64811`, ScriptType `2` Middleware)
|
||||
- 연결된 Pull Zone: **iron-kr (5555227)**, **iron-jp (5555247)** — 둘 다 `MiddlewareScriptId: 64811` 공유
|
||||
- 미장착 풀존: `iron-git` (git smart HTTP 보호 우회, 의도), `iron-kr-waf` (SafeLine 다운스트림), `i-gate` (idle)
|
||||
- bloom filter 동기화: jp1 `infra-tool` 컨테이너의 `/opt/crowdsec-bouncer/bouncer.py` (3분 delta + 매시 full sync)
|
||||
- 소스: [[crowdsec-safeline|CrowdSec]] bloom filter (FNV-1a 임베디드 `BLOOM_B64`) + Cloudflare Turnstile 캡차
|
||||
|
||||
> 옛 메모의 풀존 ID `5316471 (inouter)`, `5330178 (actions)`, `5554681 (waf-kr)` 는 현 계정에 더 이상 존재하지 않음. iron-kr / iron-jp / iron-kr-waf 로 통합·이전됨.
|
||||
`cfb-manager` (K8s `default/cfb-manager`) 는 **Cloudflare Worker bouncer 관리 API** 이며 BunnyCDN 미들웨어 64811 와 무관.
|
||||
|
||||
## 동작 순서
|
||||
|
||||
```
|
||||
요청 → BunnyCDN 엣지
|
||||
1. 국가 차단 (Cdn-RequestCountryCode 헤더)
|
||||
- 차단 시 403 반환
|
||||
1. 국가 차단 (Cdn-RequestCountryCode 헤더 기반)
|
||||
- 차단 국가 → 403 반환
|
||||
2. CrowdSec bloom filter (악성 IP 판별)
|
||||
- bloom filter hit → 캡차 또는 403
|
||||
- cfb-manager가 주기적으로 bloom filter 업데이트
|
||||
- hit → 캡차 또는 403
|
||||
- miss → 통과
|
||||
3. 캡차 (Cloudflare Turnstile)
|
||||
- bloom hit된 IP에게 캡차 제시
|
||||
- bloom hit IP 에게 캡차 제시
|
||||
- 통과 시 4시간 허용 (DB + 쿠키)
|
||||
4. 정상 → Origin으로 전달
|
||||
4. 정상 → Origin 으로 전달
|
||||
```
|
||||
|
||||
## 차단 국가
|
||||
|
||||
US, CA, GB, DE, FR, IT, ES, NL, BE, AT, CH, SE, NO, DK, FI, PL, CZ, PT, IE, RO, HU, BG, HR, SK, SI, LT, LV, EE, LU, MT, CY, GR, IS, UA, RU, BY
|
||||
북미·유럽·구소련 권역:
|
||||
|
||||
(북미 + 유럽 + 구소련)
|
||||
`US, CA, GB, DE, FR, IT, ES, NL, BE, AT, CH, SE, NO, DK, FI, PL, CZ, PT, IE, RO, HU, BG, HR, SK, SI, LT, LV, EE, LU, MT, CY, GR, IS, UA, RU, BY`
|
||||
|
||||
## 주의사항
|
||||
|
||||
- **BunnyCDN Traffic Manager 국가 차단은 사용하지 않음** — Let's Encrypt 검증 및 Origin Shield fetch를 막아서 Free SSL 발급 실패 + 500 에러 유발
|
||||
- 엣지 스크립트의 국가 차단은 `Cdn-RequestCountryCode` 헤더 기반 → CDN 내부 요청(Let's Encrypt, Origin Shield)에는 이 헤더가 없으므로 영향 없음
|
||||
- **BunnyCDN Traffic Manager 국가 차단은 사용하지 않음** — Let's Encrypt 검증 및 Origin Shield fetch 를 막아서 Free SSL 발급 실패 + 500 에러 유발
|
||||
- 엣지 스크립트의 국가 차단은 `Cdn-RequestCountryCode` 헤더 기반 → CDN 내부 요청 (Let's Encrypt, Origin Shield) 에는 이 헤더가 없으므로 영향 없음
|
||||
- Free SSL 자동 발급/갱신 정상 동작
|
||||
|
||||
## Pull Zone 전수 (2026-04-10)
|
||||
## Pull Zone
|
||||
|
||||
| ID | 이름 | OriginUrl | Middleware | Smart Cache | IgnoreQS | BlockNoRef | 비고 |
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| 5555227 | **iron-kr** | `https://220.120.65.245` | **64811** | ✅ | false | true | 메인 inouter.com 계열. 2026-04-10 `IgnoreQueryStrings` `true→false` (iron-jp 와 통일, privilege 교차 / 배포 cache-bust 버그 방지) |
|
||||
| 5555247 | **iron-jp** | `https://172.233.93.180` | **64811** | ✅ | **false** ⚠ | true | anvil.it.com 계열 |
|
||||
| 5555224 | iron-kr-waf | `https://220.120.65.245:9443` | null | ❌ | true | true | SafeLine WAF 다운스트림 보호 |
|
||||
| 5584382 | iron-git | `https://220.120.65.245` | null | ❌ | true | **false** ⚠ | git smart HTTP 보호 우회 (의도) |
|
||||
| 5557897 | i-gate | `https://172.233.93.180` | null | ❌ | true | true | idle 슬롯, 0 byte |
|
||||
| 5555227 | `iron-kr` | `https://220.120.65.245` | 64811 | ✅ | false | true | 메인 inouter.com 계열 |
|
||||
| 5555247 | `iron-jp` | `https://172.233.93.180` | 64811 | ✅ | false | true | anvil.it.com 계열 |
|
||||
| 5555224 | `iron-kr-waf` | `https://220.120.65.245:9443` | null | ❌ | true | true | SafeLine WAF 다운스트림 보호 |
|
||||
| 5584382 | `iron-git` | `https://220.120.65.245` | null | ❌ | true | false | git smart HTTP 보호 우회 (의도) |
|
||||
| 5557897 | `i-gate` | `https://172.233.93.180` | null | ❌ | true | true | idle 슬롯 |
|
||||
|
||||
공통: `EnableLogging: true`, `EnableWebSockets: true (max 500)`, `EnableGeoZone*: true (전 지역)`, `BlockedCountries: []`, `BlockedIps: []`, `EdgeRules: []` (Edge Rules 미사용 — 모든 분기는 미들웨어 코드 안), `OriginType: 0 (URL)`, `VerifyOriginSSL: false`, `EnableOriginShield: false`. `OptimizerEnabled`: iron-kr / iron-jp 만 true.
|
||||
공통 설정: `EnableLogging: true`, `EnableWebSockets: true (max 500)`, `EnableGeoZone*: true (전 지역)`, `BlockedCountries: []`, `BlockedIps: []`, `EdgeRules: []` (모든 분기는 미들웨어 코드 안에서), `OriginType: 0 (URL)`, `VerifyOriginSSL: false`, `EnableOriginShield: false`. `OptimizerEnabled` 는 `iron-kr` / `iron-jp` 만 `true`.
|
||||
|
||||
## 호스트네임 인벤토리 (17개)
|
||||
## 호스트네임 인벤토리
|
||||
|
||||
| Pull Zone | Hostname | 시스템? | TLS | ForceSSL |
|
||||
|---|---|---|---|---|
|
||||
| iron-kr | `iron-kr.b-cdn.net` | ✅ | ✅ | false |
|
||||
| iron-kr | `actions.it.com` | — | ✅ | false |
|
||||
| iron-kr | `n8n.inouter.com` | — | ✅ | false |
|
||||
| iron-kr | `jarvis.inouter.com` | — | ✅ | false |
|
||||
| iron-kr | `telegram-webhook.inouter.com` | — | ✅ | false |
|
||||
| iron-kr | `vault.inouter.com` | — | ✅ | false |
|
||||
| iron-kr | `outline.inouter.com` | — | ✅ | false |
|
||||
| iron-jp | `iron-jp.b-cdn.net` | ✅ | ✅ | false |
|
||||
| iron-jp | `anvil.it.com` | — | ✅ | false |
|
||||
| iron-jp | `n8n.anvil.it.com` | — | ✅ | false |
|
||||
| iron-jp | `tg.anvil.it.com` | — | ✅ | false |
|
||||
| iron-jp | `linode.actions.it.com` | — | ✅ | false |
|
||||
| iron-kr-waf | `iron-kr-waf.b-cdn.net` | ✅ | ✅ | false |
|
||||
| iron-kr-waf | `juiceshop.keepanker.cv` | — | ✅ | false |
|
||||
| iron-git | `iron-git.b-cdn.net` | ✅ | ✅ | false |
|
||||
| iron-git | `gitea.inouter.com` | — | ✅ | false |
|
||||
| i-gate | `i-gate.b-cdn.net` | ✅ | ✅ | false |
|
||||
| Pull Zone | Hostname | 시스템? |
|
||||
|---|---|---|
|
||||
| iron-kr | `iron-kr.b-cdn.net` | ✅ |
|
||||
| iron-kr | `actions.it.com` | |
|
||||
| iron-kr | `n8n.inouter.com` | |
|
||||
| iron-kr | `jarvis.inouter.com` | |
|
||||
| iron-kr | `telegram-webhook.inouter.com` | |
|
||||
| iron-kr | `vault.inouter.com` | |
|
||||
| iron-kr | `outline.inouter.com` | |
|
||||
| iron-jp | `iron-jp.b-cdn.net` | ✅ |
|
||||
| iron-jp | `anvil.it.com` | |
|
||||
| iron-jp | `n8n.anvil.it.com` | |
|
||||
| iron-jp | `tg.anvil.it.com` | |
|
||||
| iron-jp | `linode.actions.it.com` | |
|
||||
| iron-kr-waf | `iron-kr-waf.b-cdn.net` | ✅ |
|
||||
| iron-kr-waf | `juiceshop.keepanker.cv` | |
|
||||
| iron-git | `iron-git.b-cdn.net` | ✅ |
|
||||
| iron-git | `gitea.inouter.com` | |
|
||||
| i-gate | `i-gate.b-cdn.net` | ✅ |
|
||||
|
||||
**합계**: 사용자 호스트 12 + 시스템 호스트 5 = 17. 모두 `HasCertificate: true` (Let's Encrypt 자동 발급/갱신). Bunny API 의 list/get 응답에는 인증서 만료일이 노출되지 않음 → 만료 임박 모니터링은 능동 외부 cert 체크 또는 Bunny 대시보드 알림에 의존.
|
||||
총 17 (사용자 12 + 시스템 5). 전부 `HasCertificate: true` (Let's Encrypt 자동 발급/갱신). Bunny API 응답에는 인증서 만료일이 노출되지 않아 만료 모니터링은 외부 cert 체크 또는 Bunny 대시보드 알림에 의존.
|
||||
|
||||
## Edge Script / Middleware attach 매트릭스
|
||||
## Edge Script / Middleware attach
|
||||
|
||||
| Script ID | 이름 | Type | Attached pullzones | 비고 |
|
||||
|---|---|---|---|---|
|
||||
| **64811** | `crowdsec-bouncer-middleware` | 2 (Middleware) | iron-kr (5555227), iron-jp (5555247) | 두 풀존 동일 미들웨어 공유 |
|
||||
| (none) | — | — | iron-kr-waf, iron-git, i-gate | iron-git 의도적 우회 (git pack 바이너리 보호 불가), iron-kr-waf 는 다운스트림 SafeLine, i-gate idle |
|
||||
| Script ID | 이름 | Type | 부착 풀존 |
|
||||
|---|---|---|---|
|
||||
| 64811 | `crowdsec-bouncer-middleware` | 2 (Middleware) | iron-kr, iron-jp |
|
||||
|
||||
## CrowdSec Bouncer 동기화 구조
|
||||
기타 풀존 미장착 사유: `iron-git` 은 git smart HTTP 바이너리 보호 불가라 의도적 우회, `iron-kr-waf` 는 SafeLine 이 담당, `i-gate` 는 idle.
|
||||
|
||||
## CrowdSec bloom filter 동기화
|
||||
|
||||
```
|
||||
CrowdSec LAPI (jp1 Incus, 10.253.100.240:8080) → 악성 IP decision
|
||||
CrowdSec LAPI (jp1, 10.253.100.240:8080) → decision stream
|
||||
↓
|
||||
infra-tool 컨테이너 (jp1) /opt/crowdsec-bouncer/bouncer.py
|
||||
infra-tool 컨테이너 /opt/crowdsec-bouncer/bouncer.py
|
||||
├ 3분 delta sync
|
||||
└ 매시 full sync
|
||||
↓
|
||||
bloom filter (FNV-1a) base64 → BunnyCDN compute API
|
||||
→ Edge Script 64811 코드의 BLOOM_B64/BLOOM_VERSION 상수 정규식 교체
|
||||
→ Edge Script 64811 코드의 BLOOM_B64 / BLOOM_VERSION 상수 정규식 교체
|
||||
→ publish
|
||||
↓
|
||||
엣지 스크립트가 요청마다 client IP 를 bloom filter 로 체크
|
||||
→ hit → Turnstile 캡차 (verified 4h 쿠키)
|
||||
→ miss → origin 통과
|
||||
hit → Turnstile 캡차 (verified 4h 쿠키)
|
||||
miss → origin 통과
|
||||
```
|
||||
|
||||
> **주의**: `cfb-manager` (K8s `default/cfb-manager`) 는 **Cloudflare Worker bouncer 관리 API** 이며 BunnyCDN 미들웨어 64811 와는 무관. 옛 메모 혼동 정정.
|
||||
## Turnstile sitekey
|
||||
|
||||
## 미들웨어 64811 Turnstile sitekey 이력
|
||||
미들웨어 64811 의 `TURNSTILE_SITE_KEY` 와 `TURNSTILE_SECRET_KEY` 는 env 변수로 주입 (코드에 hardcoded 아님). 현재 값은 [[cloudflare#Turnstile 위젯]] 의 `inouter-bunny-middleware` (`0x4AAAAAAC3otPWhldI96Aks`). 이 위젯은 cs-cf-worker-bouncer 의 이름 패턴 (`crowdsec-cloudflare-worker-bouncer-widget`) 과 다르므로 bouncer rotation 대상 외 — 수동 관리.
|
||||
|
||||
| 시점 | sitekey | 이름 | 비고 |
|
||||
|---|---|---|---|
|
||||
| ~2026-04-09 | `0x4AAAAAAC2cntUlRC3KKMKG` | `crowdsec-cloudflare-worker-bouncer-widget` (inouter.com) | cs-cf-worker-bouncer 가 자동 발급/rotate. 미들웨어 64811 이 baked-in 사용 |
|
||||
| **2026-04-10** | **삭제됨** | — | cf-audit-cleanup-2 의 cfb-manager DELETE inouter.com 트리거 → bouncer restart 가 destructive cleanup. 미들웨어 stale, 잠재 버그 발생 |
|
||||
| **2026-04-10** | **`0x4AAAAAAC3otPWhldI96Aks`** | **`inouter-bunny-middleware`** | 복구. kappa 가 jp1 bouncer 호스트의 cs-cf-worker-bouncer 토큰을 일시 빌려 직접 API 로 생성. 이름이 bouncer 패턴과 다르므로 freeze. Vault `secret/cloud/cloudflare/turnstile-inouter-bunny` (sitekey/secret/name). Syn 이 미들웨어 64811 env 갱신 + publish (deployment `3816dbc5-…`) |
|
||||
위젯 교체 절차:
|
||||
1. 신규 위젯 생성 (이름에 `bouncer` 포함 금지)
|
||||
2. Vault `secret/cloud/cloudflare/turnstile-inouter-bunny` 에 `sitekey`, `secret`, `name` 저장
|
||||
3. 미들웨어 64811 의 `TURNSTILE_SITE_KEY` / `TURNSTILE_SECRET_KEY` env 두 변수 **동시** 갱신 + publish
|
||||
4. 옛 sitekey 가 미들웨어 env 에 남아있지 않은지 검증 (grep), 옛 위젯 삭제 가능
|
||||
|
||||
> 미들웨어 64811 의 `TURNSTILE_SITE_KEY` / `TURNSTILE_SECRET_KEY` env 변수를 갱신할 때는 반드시 두 변수 모두 동시에 갱신 + publish. 코드 자체에는 sitekey 가 hardcoded 되지 않음 (env 만 참조).
|
||||
## 특이사항
|
||||
|
||||
## 특이사항 (2026-04-10 감사)
|
||||
|
||||
- **i-gate (5557897)**: 시스템 호스트네임 1개만, 0 byte 트래픽. 빈 슬롯 — 제거 또는 명확한 용도 부여 필요.
|
||||
- ~~**iron-kr / iron-jp `IgnoreQueryStrings` 불일치**~~: 2026-04-10 둘 다 `false` 로 통일 완료. iron-kr 의 실측 cache hit rate 가 0.23% 로 사실상 0 이라 변경 영향 무시할 수준. 안전한 기본값 (query string 무시 안 함) 으로 맞춤.
|
||||
- **Turnstile sitekey gap**: 미들웨어 64811 의 `TURNSTILE_SITE_KEY` 는 `inouter-bunny-middleware` (inouter.com zone) 단일 키 → `actions.it.com`, `anvil.it.com`, `*.b-cdn.net` 호스트에서 ban 발동 시 캡챠 위젯 로드 실패 가능. zone별 dispatcher 또는 multi-domain 위젯 통합 TODO.
|
||||
- 옛 메모의 풀존 ID `5316471 (inouter)`, `5330178 (actions)`, `5554681 (waf-kr)` 는 현 계정에 더 이상 존재하지 않음. `*.actions.it.com` Cloudflare DNS 가 아직 `actions.b-cdn.net` 을 가리키는 dead reference 가 남아 있음 — [[cloudflare]] 정리 필요. (`nas.inouter.com` 은 2026-04-10 cf-audit-cleanup-1 에서 정리 완료)
|
||||
|
||||
## 참조
|
||||
|
||||
- 전수 감사 정본 (대화 로그): Outline `agent-qna` doc `51b963c3-b251-48b5-a57a-a2305959c470` (2026-04-10)
|
||||
- 워크스페이스 런북: `~/syn/bunnycdn/README.md`
|
||||
- API 레퍼런스: [[bunnycdn]]
|
||||
- **i-gate (5557897)**: 시스템 호스트 1개, 0 byte 트래픽. 빈 슬롯 — 용도 부여 또는 제거 필요
|
||||
- **Turnstile sitekey zone gap**: `TURNSTILE_SITE_KEY` 가 `inouter.com` zone 단일 키 → `actions.it.com`, `anvil.it.com`, `*.b-cdn.net` 호스트에서 ban 발동 시 캡차 위젯 로드 실패 가능. zone별 dispatcher 또는 multi-domain 위젯 통합 TODO
|
||||
|
||||
## 관련 문서
|
||||
|
||||
- [[bunnycdn]] — BunnyCDN API 레퍼런스
|
||||
- [[crowdsec-safeline]] — CrowdSec 및 SafeLine WAF 설정
|
||||
- [[cloudflare]] — Cloudflare DNS/CDN (Turnstile 캡차 키 관리)
|
||||
- [[cloudflare]] — Cloudflare DNS/CDN (Turnstile 위젯 정본)
|
||||
|
||||
Reference in New Issue
Block a user