- 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 섹션의 날짜 주석 제거
12 KiB
date, topic, areas, tags
| date | topic | areas | tags | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 2026-04-10 | Edge layer cleanup (BunnyCDN+Cloudflare 전수 감사·정리·인시던트·복구) |
|
|
하루 동안 여러 건의 엣지 레이어 정리 작업이 연쇄적으로 일어남. 감사 → 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.comCNAME →actions.b-cdn.net— dead 풀존 참조ironclad.jp.inouter.comA10.19.228.193,k8s.jp.inouter.comA10.253.103.124— 사설 IP 공개 DNS 노출*.actions.it.comCNAME →actions.b-cdn.net— dead 풀존 참조inouter.com/anvil.it.comCF Worker bouncer 라우트가 DNSproxied: 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: truevs iron-jpfalse— 같은 미들웨어인데 캐시 키 정책 불일치 - BunnyCDN 미들웨어
TURNSTILE_SITE_KEY는inouter.comzone 단일 키 → actions / anvil /*.b-cdn.net에서 ban 발동 시 캡차 로드 실패 가능
2. CF DNS 정리 1차 (cf-audit-cleanup-1)
조치
Syn 가 CF API 로 아래 레코드 삭제:
nas.inouter.comCNAME →actions.b-cdn.netironclad.jp.inouter.comA10.19.228.193k8s.jp.inouter.comA10.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) + 수동 EndpointSlice192.168.9.100:5000 - Traefik IngressRoute
nas(web) +nas-tls(websecure), Middlewareredirect-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-bunny 에 sitekey / 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분):
- CF API 에서 account 의 zone 목록 fetch
- yaml 에 없는 zone 발견 → 12-space indent 로 자동 추가 (script bug, YAML 파괴)
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 가설 증명 (이름 패턴 분리).
교훈
- DONE 회신 전에 ground truth 직접 검증. API 응답·in-memory 상태가 아닌 disk + systemd + 외부 API 직접 조회.
- destructive cron 은 recovery 윈도우의 적. 복구 작업 전 모든 자동화 (cron, systemd timer, scheduled job) 를 먼저 멈추고 수동 mode 로 진입.
- 같은 시각 두 다른 크기의 백업 파일은 scheduled writer 의 흔적. 이걸 일찍 감지했으면 근본 원인 파악이 빨랐음.
- 에이전트의 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-proxiesns 신설,nas.inouter.comreverse proxy 동작 cf-zone-synccron 영구 제거, yaml writer =cfb-manager단일- 미해결 별건:
cfb-managerDELETE destructive 동작 문서화, Worker 라우트 null orphan (vultr/linode.actions.it.com) 정리, Turnstileinouterlegacy 위젯 결정
관련 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
639c9b5edge: 2026-04-10 BunnyCDN+CF 전수 감사 결과 정본 반영f5264bbedge: CF inouter.com zone 정리 1차 (cf-audit-cleanup-1)9d71167infra: nas.inouter.com Traefik 리버스 프록시 (LAN-only) 복원218c323edge: cf-audit-cleanup-2 + recovery 정본 반영7a8230dedge: cf-audit-cleanup-2 3차 인시던트 (cron-induced crashloop) + kappa 직접 복구 반영8fc6a34edge: cf-zone-sync cron 영구 제거 (cleanup-2 인시던트 근본 원인)d16090aedge: iron-kr IgnoreQueryStrings true→false (iron-jp 와 통일)