Files
obsidian/history/2026-04-10-edge-cleanup.md
kappa 72750cfc9d 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 섹션의 날짜 주석 제거
2026-04-10 11:38:36 +09:00

12 KiB

date, topic, areas, tags
date topic areas tags
2026-04-10 Edge layer cleanup (BunnyCDN+Cloudflare 전수 감사·정리·인시던트·복구)
infra/cloudflare.md
infra/crowdsec-safeline.md
infra/nas-storage.md
services/bunnycdn-security.md
history
edge
bunnycdn
cloudflare
crowdsec
incident

하루 동안 여러 건의 엣지 레이어 정리 작업이 연쇄적으로 일어남. 감사 → 1차 정리 → nas 복원 → cleanup-2 시도 → 3-incident chain → 복구 → cron 영구 제거 → iron-kr IgnoreQS 통일 순서.

1. BunnyCDN+CF 도메인 전수 감사

배경

Obsidian 정본의 CF/BunnyCDN 정보가 오래되어 현재 상태와 불일치. 전체 도메인 인벤토리 재구축 필요.

조치

Syn 가 BunnyCDN MCP + CF MCP 로 실측 조회.

결과: BunnyCDN 풀존 5개 / 호스트 17개 (사용자 12 + 시스템 5). CF zone 6개 / DNS 60건 / Turnstile 8개 / Workers 9개. 상세는 Outline doc 51b963c3-b251-48b5-a57a-a2305959c470.

Obsidian 정본 (infra/cloudflare.md, services/bunnycdn-security.md) 을 현재 상태로 전면 재작성.

발견된 조치 필요 항목

  • servidor.it.com — CF zone 이지만 DNS 0건 (orphan zone). cert-manager wildcard + CrowdSec bouncer + Turnstile 위젯 설정은 살아있음. 죽은 도메인이 아니라 "배포 준비만 된 상태" 로 판단, 유지 결정.
  • nas.inouter.com CNAME → actions.b-cdn.net — dead 풀존 참조
  • ironclad.jp.inouter.com A 10.19.228.193, k8s.jp.inouter.com A 10.253.103.124 — 사설 IP 공개 DNS 노출
  • *.actions.it.com CNAME → actions.b-cdn.net — dead 풀존 참조
  • inouter.com / anvil.it.com CF Worker bouncer 라우트가 DNS proxied: false 라서 실제 enforcement 안 됨 — BunnyCDN 미들웨어 64811 단독 방어
  • vultr.actions.it.com/*, linode.actions.it.com/* Worker 라우트 script: null (orphan)
  • Turnstile inouter (0x4AAAAAACbmaudAjITah7y7, 2026-02-13) — 이름·도메인 불일치 (이름은 inouter 인데 도메인은 anvil.it.com). legacy 후보
  • iron-kr IgnoreQueryStrings: true vs iron-jp false — 같은 미들웨어인데 캐시 키 정책 불일치
  • BunnyCDN 미들웨어 TURNSTILE_SITE_KEYinouter.com zone 단일 키 → actions / anvil / *.b-cdn.net 에서 ban 발동 시 캡차 로드 실패 가능

2. CF DNS 정리 1차 (cf-audit-cleanup-1)

조치

Syn 가 CF API 로 아래 레코드 삭제:

  • nas.inouter.com CNAME → actions.b-cdn.net
  • ironclad.jp.inouter.com A 10.19.228.193
  • k8s.jp.inouter.com A 10.253.103.124

검증: dig @1.1.1.1 로 3건 모두 삭제 확인.

참고

nas.inouter.com*.inouter.com 와일드카드 (→ k3s.inouter.com → 192.168.9.53) 로 폴백되지만 LAN 전용 MetalLB VIP 라서 외부 접근 불가 — 실질적으로 의도한 결과.

3. nas.inouter.com Traefik 리버스 프록시 복원

배경

kappa 가 nas.inouter.com 을 Synology NAS (192.168.9.100) 의 DSM 접근 경로로 쓰고 싶어함.

조치

Heimdall 이 K3s 에 resources 생성:

  • Namespace lan-proxies (LAN 장비 reverse proxy 전용)
  • Selector-less Service nas (ClusterIP 5000/TCP) + 수동 EndpointSlice 192.168.9.100:5000
  • Traefik IngressRoute nas (web) + nas-tls (websecure), Middleware redirect-https
  • TLS: 기존 wildcard-inouter-tls 재사용

기술 노트

ExternalName Service 는 IP 를 받지 않고 DNS name 만 받음. LAN IP reverse proxy 에는 selector-less Service + 수동 EndpointSlice 패턴이 정석.

검증

curl -sk --resolve nas.inouter.com:443:192.168.9.53 https://nas.inouter.com/ → 200, <title>NAS - Synology DiskStation</title>. HTTP 301 redirect 정상.

4. CF cleanup-2 3-incident chain

배경

감사에서 발견한 "inouter/anvil 의 CF Worker bouncer 라우트가 dead" 항목 정리. BunnyCDN 미들웨어가 단독 방어하고 있으니 CF 측 라우트와 위젯을 제거해 관리 면적 축소 목적.

인시던트 #1 — destructive widget cleanup

Syn 가 cfb-manager API DELETE /domains/inouter.com 호출. cfb-manager 는 bouncer 호스트의 yaml 을 편집하고 systemctl restart 호출. 재기동된 bouncer 가 destructive cleanup 으로 모든 zone 의 Turnstile 위젯을 새로 rotate 하면서 기존 위젯을 삭제. 이 과정에서 BunnyCDN 미들웨어 64811 이 baked-in 으로 사용 중이던 inouter.com zone 위젯 0x4AAAAAAC2cntUlRC3KKMKG 가 함께 삭제. 잠재 버그 (현재 ban 없으면 미발현).

잘못된 가정: "zone 을 bouncer config 에서 빼면 위젯은 freeze 된 채 남는다" — 실제로는 bouncer restart 가 force-rotation 사이클.

인시던트 #2 — 복구 중 토큰 권한 공백

복구 시도. 새 Turnstile 위젯 생성 필요. Obsidian 에 "현 CF API 토큰은 Turnstile read-only" 기록 → kappa 가 CF 대시보드에서 수동 생성 경로로 먼저 제안. 이후 "API 가 있는데 왜 대시보드?" 피드백 → jp1 cs-cf-worker-bouncer 의 CF 토큰 (seUKZID4...) 을 SSH 경유로 확인, 이 토큰이 Turnstile read+write 권한 보유 확인. 해당 토큰을 일시 차용해 API 로 새 위젯 생성:

  • sitekey: 0x4AAAAAAC3otPWhldI96Aks
  • secret: 0x4AAAAAAC3otP9NIYkJUVYdMjNLZsbWgpM
  • name: inouter-bunny-middleware (bouncer auto 이름 패턴 crowdsec-cloudflare-worker-bouncer-widget 과 다름 → bouncer rotation 에서 freeze 보장)
  • domains: [inouter.com], mode: managed

Vault secret/cloud/cloudflare/turnstile-inouter-bunnysitekey / secret / name 저장. Syn 가 kappa 게이트웨이 ASK 프로토콜로 값을 받아 BunnyCDN 미들웨어 64811 env 변수 TURNSTILE_SITE_KEY / TURNSTILE_SECRET_KEY 갱신 후 publish (deployment 3816dbc5-..., HTTP 204).

인시던트 #3 — cron-induced crashloop

Syn 가 DONE: cf-audit-cleanup-2-recovery 회신. kappa 검증 결과:

  • bouncer-managed 위젯 4개 (keepanker / actions / ironclad / servidor) 사라짐 → CF Worker enforcement 4개 zone 다운
  • bouncer service 48회 crashloop (yaml: line 57: mapping values are not allowed)
  • 4개 zone 의 CF Worker 라우트 부재
  • cfb-manager /status 도 YAML 파싱 에러로 500

Syn 의 narrative ("cfb-manager /status 200, bouncer_running") 는 false positive — cfb-manager 의 in-memory 상태나 일시적 normal window 만 보고 disk + systemd status 직접 검증 생략.

근본 원인 발견

/etc/cron.d/cf-zone-sync/usr/local/bin/auto-add-cf-zones.sh (매 10분):

  1. CF API 에서 account 의 zone 목록 fetch
  2. yaml 에 없는 zone 발견 → 12-space indent 로 자동 추가 (script bug, YAML 파괴)
  3. systemctl restart crowdsec-cloudflare-worker-bouncer

inouter / anvil 을 yaml 에서 뺐더니 10분 뒤 cron 이 다시 넣으면서 indent bug 로 YAML 깨뜨림 → bouncer 재기동 실패 → crashloop. 매 10분 루프.

Syn 가 yaml 을 수동 fix 해 disk 에 push 했다고 한 것도 ~10분 후 cron 이 다시 깨뜨려 무효화. Syn 는 push 직후 validation 에 cfb-manager /status 만 쓰고 disk 내용을 재확인하지 않아 detect 못 함.

복구 (kappa 직접, Syn 우회)

단계 조치 결과
1 journalctl 로 crashloop 확인, cron 발견 auto-add-cf-zones.sh root cause 식별
2 mv /etc/cron.d/cf-zone-sync /etc/cron.d/cf-zone-sync.disabled.kappa-incident-20260410 cron 비활성화
3 cp yaml.bak.20260410004004 yaml 79 lines clean 복원
4 crowdsec-cloudflare-worker-bouncer -c yaml -t config is valid
5 systemctl reset-failed && systemctl start active (running), PID 371770
6 15 초 대기 후 CF API 검증 위젯 7개 (4개 bouncer-managed 자동 재생성 + inouter-bunny-middleware 생존 + crowdsec-captcha + inouter legacy), 라우트 4개 zone 재생성, inouter/anvil 은 0 routes

재생성된 bouncer-managed 위젯:

  • servidor: 0x4AAAAAAC3rgjWkt-40fI7d
  • actions: 0x4AAAAAAC3rg3VTXEllaMhY
  • keepanker: 0x4AAAAAAC3rhJWcBgQ5aPym
  • ironclad: 0x4AAAAAAC3rhaCWqBq5Qgza

inouter-bunny-middleware 가 rotation 에서 건드려지지 않음을 확인 — freeze 가설 증명 (이름 패턴 분리).

교훈

  1. DONE 회신 전에 ground truth 직접 검증. API 응답·in-memory 상태가 아닌 disk + systemd + 외부 API 직접 조회.
  2. destructive cron 은 recovery 윈도우의 적. 복구 작업 전 모든 자동화 (cron, systemd timer, scheduled job) 를 먼저 멈추고 수동 mode 로 진입.
  3. 같은 시각 두 다른 크기의 백업 파일은 scheduled writer 의 흔적. 이걸 일찍 감지했으면 근본 원인 파악이 빨랐음.
  4. 에이전트의 false-positive 보고는 신뢰 철회 신호. 복구를 다시 같은 에이전트에 맡기지 않고 kappa 가 직접 수행한 결정은 옳음.

참조

  • Outline incident report: 8f5c43f8-0b46-4032-b3f6-08106aa1e5e2
  • OpenMemory: cf-audit-cleanup-2 3-incident chain
  • Vault: secret/cloud/cloudflare/turnstile-inouter-bunny

5. cf-zone-sync cron 영구 제거

배경

인시던트 #3 의 근본 원인이자 3 writer 구조 (cfb-manager, bouncer read, cron) 중 조정 없이 동작하는 writer. 재발 방지.

조치

  • /etc/cron.d/cf-zone-sync.disabled.kappa-incident-20260410 완전 삭제
  • /usr/local/bin/auto-add-cf-zones.sh.disabled.20260410-incident 로 rename, chmod 600 (실행 불가, post-mortem 용 보존)
  • /usr/local/bin/sync-cf-zones.sh (older detect-only 버전, cron 미참조, yaml 편집 없음) — 건드리지 않고 dormant 유지
  • /var/log/cf-zone-sync.log (274 KB) — history 로 유지

결정 근거

Exclusion list 지원 재작성보다 자동 쓰기 자체를 제거 가 옳음. yaml 에 쓰는 주체가 하나일 때만 coordination 문제 해소. 신규 zone 추가 시 cfb-manager POST /domains 또는 수동 yaml edit + systemctl restart.

영향

cfb-manager protected_domains 4, bouncer active (PID 371770, 유지). 추가 자동화 없음.

6. iron-kr IgnoreQueryStrings true → false

배경

iron-kr 과 iron-jp 의 설정 불일치. iron-kr true (query string 을 캐시 키에서 무시) 는 privilege 교차 / 배포 cache-bust 버그의 time bomb. 안전한 기본값은 false.

실측

BunnyCDN statistics 조회: iron-kr 의 월 전체 평균 cache hit rate 0.22973383260803562 (≈ 0.23%). 실질적으로 캐시 미사용 상태라 변경 영향 무시 수준.

조치

bunny_update_pullzone pullzone_id 5555227{"IgnoreQueryStrings": false}. API 응답에서 "IgnoreQueryStrings": false 확인.

결과

iron-kr / iron-jp 둘 다 false 로 통일. 안전한 기본값 확보.

종합 — 오늘의 end state

  • BunnyCDN 풀존 5개 (iron-kr / iron-jp / iron-kr-waf / iron-git / i-gate), 호스트 17개 (유지)
  • BunnyCDN 미들웨어 64811 — TURNSTILE_SITE_KEY = 0x4AAAAAAC3otPWhldI96Aks (inouter-bunny-middleware, freeze)
  • iron-kr IgnoreQueryStrings: false (iron-jp 와 통일)
  • CF zone 6개, DNS 레코드 57건 (60 - 3 삭제)
  • CF Worker bouncer 보호 zone 4개 (keepanker / actions / ironclad / servidor)
  • K3s lan-proxies ns 신설, nas.inouter.com reverse proxy 동작
  • cf-zone-sync cron 영구 제거, yaml writer = cfb-manager 단일
  • 미해결 별건: cfb-manager DELETE destructive 동작 문서화, Worker 라우트 null orphan (vultr/linode.actions.it.com) 정리, Turnstile inouter legacy 위젯 결정

관련 OpenMemory 엔트리

  • 2026-04-10 BunnyCDN+Cloudflare 도메인 전수 감사
  • 2026-04-10 CF DNS 정리 1차 (cf-audit-cleanup-1)
  • 2026-04-10 nas.inouter.com LAN-only Traefik 리버스 프록시 복원
  • 2026-04-10 cf-audit-cleanup-2 3-incident chain
  • 2026-04-10 cf-zone-sync cron 영구 제거
  • 2026-04-10 iron-kr IgnoreQueryStrings true→false

관련 git commits

  • 639c9b5 edge: 2026-04-10 BunnyCDN+CF 전수 감사 결과 정본 반영
  • f5264bb edge: CF inouter.com zone 정리 1차 (cf-audit-cleanup-1)
  • 9d71167 infra: nas.inouter.com Traefik 리버스 프록시 (LAN-only) 복원
  • 218c323 edge: cf-audit-cleanup-2 + recovery 정본 반영
  • 7a8230d edge: cf-audit-cleanup-2 3차 인시던트 (cron-induced crashloop) + kappa 직접 복구 반영
  • 8fc6a34 edge: cf-zone-sync cron 영구 제거 (cleanup-2 인시던트 근본 원인)
  • d16090a edge: iron-kr IgnoreQueryStrings true→false (iron-jp 와 통일)