2년 고정운영 병목·취약점 감사 + 무중단 업데이트 구조
2026-07-10. JIT 중단 후, 현 시스템을 ~2년 무인 고정운영하기 위한 5차원 병렬감사 + 무중단 업데이트 구현.
방법: 5개 sonnet 에이전트 병렬감사(TLS·디스크·감독·보안·업데이트) + opus 종합. 라이브 무접촉 감사.
🔴 즉시 조치 완료: 정적서빙 RCE (인증없는 원격 명령실행)
- 취약: 게이트웨이SPA정적코어.한선
_존재하는가(test -f)·_파일읽기(cat)가 요청경로를 이스케이프 없이 체계()(system())에 연결. _경로정리는 ".."만 막고 셸메타($();|)는 통과. static: 도메인(bank/security/gateway.crowny.org, HTTPS공개)에 GET /$(touch$IFS/tmp/pwned)x`로 실증됨(증거파일 생성).
- 수정: 셸 제거 → 네이티브 opcode(_존재하는가=파일바이트크기 opcode297 stat, _파일읽기=버퍼파일읽기 opcode874) + _경로정리에 셸메타 거부(다중방어).
- 검증·배포: shadow에서 RCE차단+정적서빙 정상(200·CL 32348·본문일치)+회귀0 → 라이브 컷오버(백업 gwlive.bak-preRCE.toau). 라이브 증거파일 미생성 확인, 전도메인 200, HTTPS 200.
감사 발견 (심각도순)
치명 (즉시~수주)
- [보안] 정적서빙 RCE — ✅ 수정·배포 완료(위).
- [디스크] 스왑 98% 소진 (24GB중 507MB 여유). 원인=모니터판.toau RSS 3.67GB 누수(~2.6GB/일). 수일 내 OOM 위험.
- [디스크] 루트 96%(여유 17GB). /private/tmp/claude-501 세션스크래치 16GB(무재부팅+19세션 상시라 자연청소 안됨). 4~8주 내 소진.
- [인증서] 3버킷 300도메인 하드캡 무경보 초과. 현재 246, 54슬롯. gateway.yaml 월 수십 증가 → 수주~수개월 내 도달, 초과분 조용히 TLS 없음(cert-manager.sh:314 "4버킷 미지원 누락"만 로그).
- [인증서] 갱신 자동화 2개 월요일 3:30 동시충돌. cert-renew.sh 락없음+무조건 pkill(게다가 node 대상=라이브 한선씨와 불일치).
- [감독] 재부팅→전면정지. 전 ~270서비스가 LaunchAgent(세션전용), LaunchDaemon 0·자동로그인 미설정 → 정전/OS업데이트 재부팅 시 GUI로그인 전까지 게이트웨이 포함 완전정지.
높음
- [보안] 9100 admin·9401 auth·대다수 백엔드 0.0.0.0 바인드(외부노출). admin API 무인증(누구나 인증서갱신 트리거→LE한도소진 가능). CROWNY_TCP_LOOPBACK 가드 존재하나 미사용.
- [업데이트] 컷오버 5~7초 다운타임. kickstart-k가 전워커 동시kill. REUSEPORT 있으나 롤링 미활용 — 무중단 인프라(Q감독 maybe_recycle new-before-kill) 이미 존재,
rolling 트리거만 배선하면 됨.
- [감독] RunAtLoad=false 13종(cert-manager/renew·log-rotate·sweep 포함), 워치독 3종 KeepAlive 없음.
- [디스크] 로그 로테이션 사각: org.crowny.card dlopen 크래시루프 로그 120MB, stunnel 64MB, /tmp·~/Library/Logs 미로테이트. 고아 산출물 t521.out 208MB 등.
중간
- [보안] paywall 2026-09-30 실배선 — 402+pay 리다이렉트(전면차단 아님). 지갑조회 실패 fail-open/closed 미확인 → 드라이런 권고.
- [보안] CSP 헤더 부재, 인증데이터(profiles.json) 자동백업 부재.
- [업데이트] gateway.yaml 핫리로드 불가(설정로드 accept루프 진입전 1회만).
gw add "재기동 불필요" 주장은 허위 → 워커 롤링으로 우회.
구현 계획 (이번 세션)
- ✅ RCE 수정·배포.
- 무중단 롤링 업데이트(Q감독 rolling 명령), 안전 디스크 정리(P0 완화), 나머지는 우선순위 처방으로 추적(자동로그인·인증서자동화는 사용자 판단 필요).
✅ 구현 완료: 무중단 롤링 업데이트 (라이브 실증)
게이트웨이Q/Q감독.sh에
rolling 배선(기존 검증된 maybe_recycle new-before-kill 패턴 재사용):
recycle_one_slot(slot): 신워커 기동→wait_worker_listening(LISTEN 폴)→통과 후에만 구워커 kill(실패 시 구워커 유지=fail-safe).
rolling_all(): 락 획득→현재 워커 스냅샷→각 슬롯 순차 교체→해제. 항상 최소 N워커가 8080 청취(무중단), 8443 stunnel 무접촉.
- 메인루프가
$STATE_DIR/reload-request 플래그 감지→rolling_all. Q감독.sh rolling 명령이 플래그 생성.
- 실증: shadow(240요청 fail=0) + 라이브 프로덕션(240요청 fail=0, 워커 전부 교체). 로그: 신워커 LISTEN확인 후 구워커 kill 순서.
2년 무중단 업데이트 절차 (kickstart -k 불필요, 다운타임 0)
bashcd /Users/ef/crowny-gateway/한선게이트웨이
hanseonc_high 게이트웨이통합.한선 > /tmp/gwnew.toau # 새 소스 컴파일
mv -f /tmp/gwnew.toau /tmp/gwlive.toau # 바이너리 mv교체(cp금지)
GWQ_PORT=8080 bash ../게이트웨이Q/Q감독.sh rolling # 무중단 순차교체(최대 10s 내)
GWQ_PORT=8080 bash ../게이트웨이Q/Q감독.sh status # 확인
※ 백엔드 270서비스 개별 교체·바이너리 mv스왑은 이미 무중단. gateway.yaml 라우트 변경은 rolling으로 반영(핫리로드 대체).
잔여 처방 (사용자 판단/후속 필요)
- 재부팅 생존(치명 #6): 핵심 서비스(gateway/gwhealth/supervisor)를 LaunchDaemon화 또는 autoLoginUser 설정 — 자동로그인은 보안 트레이드오프라 사용자 판단 필요. sudo 요.
- 인증서 300캡(#4)+갱신충돌(#5): cert-manager 4버킷 확장 + cert-renew.sh 락추가·node→한선씨 대상수정. 경합 자동화라 신중 배포.
- 디스크 P0(#2#3): 모니터판.toau 누수 재기동(2.6GB/일) + /private/tmp/claude-501 세션스크래치 N일 자동정리 + log-rotate 대상확장(/tmp·~/Library/Logs). 다중세션이라 조율 필요.
- 포트노출(#7): 9100 admin·9401 auth를 CROWNY_TCP_LOOPBACK=1로 loopback 전환(admin API 접근경로 확인 후).
- paywall 드라이런(#11): 2026-09-30 전 지갑조회 실패 fail-open/closed 검증.
✅ 순서대로 처리 (#1→#2→#3)
#1 재부팅 생존 — 준비완료(사장님 실행 대기)
- ★결정적: FileVault ON → 재부팅 무인생존은 근본 불가(부팅시 암호 수동입력). 사장님 결정 = FileVault 해제 + autologin.
- 도구
~/.claude/scripts/재부팅생존-확인.sh 제공(준비상태 점검). 순서: sudo fdesetup disable(복호화 1~3h) → 시스템설정 자동로그인 ef → 스크립트로 검증.
- (감사 오탐 정정: cert-manager 등 RunAtLoad=false는 StartCalendarInterval이라 정상, recovery=once, watchdog=StartInterval300 — KeepAlive 불요. 진짜 병목은 FileVault뿐.)
#2 인증서 2년안정 — 완료
- cert-renew.sh: standalone+
pkill node+rogue재시작(라이브 한선씨와 불일치·월3:30충돌·락없음) → cert-manager auto 위임(자기락, webroot 무중단)으로 재작성. 백업 .bak-prefix-20260710.
- cert-manager: 300캡 무경보 드롭 → 280 조기경보(마커 /tmp/crowny-cert-cap-경보.txt + 알림 + [Ta]로그). 4버킷(400캡)은 stunnel_conf_gen ext3 SNI 동반 필요 = 다음 작업.
#3 디스크 P0 — 완료(누수차단+구조적정리)
- 모니터판.toau 스왑누수+CPU폭주 차단: RSS 3719MB/CPU98.3% → 재기동(org.crowny.monitor KeepAlive) → 6MB/0.0%. 2.6GB/일 증가 트래젝토리 정지. (근본=busy-spin/누수 코드버그, 별도 수정필요.)
- 고아 산출물(무결성상세.psv 181M등 3일+) 정리.
- 세션 스크래치 16GB = 전부 활성세션 데이터(내부 최신파일 오늘) — 상위 mtime만 보면 오삭제 위험, 내부최신+lsof핸들로 판정. 지금 삭제 불가.
- 구조적 fix:
~/.claude/scripts/스크래치정리.sh(내부무활동 N일+핸들0=죽은세션만) + org.crowny.scratch-cleanup(매일 4:17, 7일 임계) 배선 → 세션 종료시 자동회수.
잔여 후속(우선순위)
- FileVault 해제(사장님 sudo) → autologin → 재부팅 검증.
- 인증서 4버킷(400캡): cert-manager set_d(crownybus.com-ext3) + stunnel_conf_gen ext3 SNI 라우팅.
- 모니터판 busy-spin/누수 근본수정(모니터판.한선).
- org.crowny.card dlopen 크래시루프(120MB 로그) 근본수정 + log-rotate 대상확장(/tmp·~/Library/Logs).
- 9100 admin·9401 auth loopback 전환(CROWNY_TCP_LOOPBACK=1).
- paywall 2026-09-30 fail-open/closed 드라이런.
후속 진행 (②⑥ 완료)
② 인증서 4버킷(400캡) — 완료
cert-manager: set_d(crownybus.com-ext3) + D발급블록 + 커버리지체크4곳 + retry_d + 캡경보 380/400. stunnel_conf_gen.py: ext3를 LINEAGE/PRIORITY/groups/슬레이브루프 4곳.
출력중립 증명: san(ext3)=빈set, match(도메인,빈set)=False → >300 전까지 dormant(현재 무영향). 라이브 stunnel 정본생성기=stunnel_conf_gen.py 확인. (stunnel 재생성 자동화는 모든 도메인추가 공통 기존 이슈.)
⑥ paywall fail-open — 완료·배포
드라이런 확정: 종전 fail-CLOSED(지갑 판독불가→크라우니달러0→402, 정상 유료회원도 지갑서비스 히컵에 락아웃). 수정: 토큰검증이 지갑 부재를 -1 센티넬로 구분(진짜 crowny:0과 별개), 유료게이트검사가 -1→fail-open(허용). 검증: -1→허용·0→차단·150→허용·에폭전→허용. 무중단 롤링으로 배포 시도.
★무중단 롤링 함정(실측)
롤링 중 스왑 고갈(528MB free)로 신워커가 10s LISTEN 타임아웃→롤링이 워커수 감소로 degrade(fail-safe: 구워커 유지). 스왑 회복(모니터 재기동으로 23GB free) 후 kickstart로 클린 2워커 복원.
교훈: 무중단 롤링은 메모리 여유가 전제. GWQ 워커 기동 타임아웃(wait_worker_listening 10s)이 압박 시 부족. 배포 전 스왑/메모리 확인 권장.
잔여(③④⑤)
③ 모니터판 busy-spin/누수 근본수정(재기동으로 임시완화됨), ④ org.crowny.card dlopen 크래시루프+log-rotate 대상확장, ⑤ 9100/9401 loopback 전환.
③ 모니터판 누수 — 완화(근본 별도)
근본버그 2종 식별: (a) TCP대기(9614) 바인드 실패시 서버<0 → TCP수락(-1) 즉시반환 busy-spin(98%CPU) —
동안(서버>=0)+종료메시지로 수정. (b) 루프가 메모리복원(배열)만 하고 문자열되감기 없음 → 보드HTML 문자열 누수.
(b) 수정 시도(문자열보호+문자열마크/되감기, 상태=파일기반이라 안전) 했으나 실측 여전히 6분에 3.4GB 누수·CPU 99% — 문자열되감기가 보드HTML 문자열을 회수 못함(VM 문자열풀 서브틀티, 게이트웨이선 동일패턴 작동하나 여기선 미작동). 근본원인 별도조사 필요. 실용 2년대응:
org.crowny.monitor-recycle(6시간 kickstart)로 누수 상한(~650MB). 폭주 3.7GB→7MB 클린 복원.
④ card 크래시루프 + log-rotate — 완료
card: better-sqlite3가 Node v26.3.1 ABI 불일치(ERR_DLOPEN_FAILED)로 100% 크래시(121MB 로그). 근본=Python3.14 pyexpat 깨져 node-gyp 실패 → system python(/usr/bin/python3)으로 재빌드 성공 → 9450 정상·exit0·크래시루프 정지. 121MB 로그 절단. log-rotate.sh: 단일디렉토리→글로브배열(/tmp/crowny-·stunnel-
·gwq-·
-stderr, ~/.crownyos/logs, ~/Library/Logs/crowny) copytruncate. 즉시 stunnel 67M·game 17M 회수.
⑤ 9100/9401 loopback — 완료
9100 admin(crownyc gwadmin.toau, start.sh:48에 CROWNY_TCP_LOOPBACK=1)·9401 auth(auth-server.js:803 listen에 '127.0.0.1') 둘 다 0.0.0.0→127.0.0.1 전용. 외부 직접도달(무인증 cert갱신 트리거·세션토큰 평문) 차단. 게이트웨이/stunnel/cert-manager는 localhost 접근이라 무영향(검증: 게이트 401·auth 로컬200·admin 로컬200).
최종 종합
①만 사장님 sudo(FileVault) 대기, ②③④⑤ 완료. 이번 2년운영 하드닝으로 RCE·무중단업데이트·인증서안정·paywall복원력·모니터/card/디스크·포트보안 처리.