크라우니 통합 인증 — 메일 정본 IdP 1차 완료 (2026-07-30)
개요
오너 확정: 통합 아이디
kps / kps1234, 정본 계정 =
메일(mail.crowny.org:9610), 회원정보·디지털자산은 블록체인 기록 방향.
스펙 SSOT =
/Users/ef/crowny-mail/docs/크라우니-통합인증-IdP스펙.md.
한 일
- 메일 IdP 승격 — 인메모리 불투명 세션 → 통합토큰
id.exp.ver.sig(클라우드 검증구현 채택). /api/auth/verify·/api/auth/jwks·/api/auth/logout-all 신규, login 응답에 idpToken 추가(기존 필드 유지=무중단). 시크릿=crowny-data/auth/.idp-secret(부팅1회 캐시), ver=세션버전.psv.
- 부트스트랩 교착 해소 — 비번변경이 admin 세션을 요구하는데 kps 현재 비번 미상 →
/api/auth/bootstrap-reset(127.0.0.1 + .bootstrap-key 일치, 사용 후 삭제). 원장(append-only 해시체인) 직접편집 없이 정상 USER_PW 경로 유지.
- 소비자 연동 4종 — 클라우드(:9611/:9662)·텔레(:9619)·DEX(:9402)·넥서스(:9805). 전부 자체토큰 우선 → 실패 시 IdP 폴백(하위호환 무중단). IdP id는 각 서비스 기존 계정에 매핑만(신규 자동생성 금지).
- kps 계정 활성화 — 메일(admin)·클라우드·DEX·넥서스·SSO:9401(비번 통일)·텔레(기존 레코드 매핑).
수리한 결함 3건 (작업 중 발견)
- 메일 세션 2.7년 무만료:
세션생성 만료가 현재시간()+86400000인데 현재시간()은 초(date +%s) — 24h 의도가 실제 약 2.7년. 86400으로 교정. 탈취 세션이 수년간 유효했던 상태.
- 넥서스 RBAC 완전 우회:
규칙권한허용()(불리언 반환)을 == 0으로 비교 — 3진논리에서 거짓=-1이라 항상 거짓 → 403 분기 사망, 무토큰 요청도 규칙표 저장 통과. != 참으로 교정(저장/롤백 2곳). 수리 후 무토큰·편집자 모두 403, 데이터 md5 불변 실측.
- 클라우드 교차소유자 우회(선행 턴): 유효 토큰 +
?owner=타인으로 타인 데이터 조회. 토큰 확정 소유자만 사용하도록 3모듈 수리.
실측 검증 (본세션 직접)
- 메일 kps 로그인 → idpToken 81자 →
/api/auth/verify {ok:1,id:kps,role:admin}
- 그 토큰으로: 클라우드 사이드카/게이트웨이 200 · 텔레
/api/auth/me {ok:true,id:kps,role:user} · 넥서스 /api/rules 200 · DEX 보호라우트 인증통과
- 위조 sig: 전 서비스 401 · 무토큰 401 · DEX 타인사칭(userId=cloudtest) 403
- 회귀: cloudtest 자체 로그인 200, 넥서스 자체 로그인 정상, 메일 기존 웹 로그인 정상
- 서비스 생존: 9610·9619·9402·9805·9611·9662 전부 up
잔여
- 연동 미착수: 트레이딩/트레이더(:7740/7741, JS — sso-middleware를 메일 verify로 전환) · 집사회(:9772) · 메신저(:9939, 인증 전무) · ERP
- ERP 정본 미정 — aimed-erp:9910 · erp:9938 · erp-unified:9981 · 일일업무:9918 전부 라이브, enterprise:9700 다운. 오너 결정 필요. 견적 서비스 도메인도 확인 필요.
- 넥서스 프록시(:9802) 경유 시 Authorization 헤더 보존 여부 미검증(직결만 확인).
- 스펙 §5 블록체인 앵커(계정·자산 이벤트를 체인에 앵커링) 미착수.
- 텔레 launchd 서비스가 장기구동 누적 OOM으로 crash-loop였음(기존 알려진 이슈, 이번 변경과 무관) — 재부트스트랩으로 정상화.
ERP·견적 정본 확정 (다른 세션 회신, 2026-07-30)
- 데이터 정본 = crowny-erp (erp.crowny.org:9938) — 넥서스 감사게이트.한선이
/Users/ef/crowny-erp/data/cells/*.psv를 직접 읽음(실코드). 실행체=crownyc-pinned run /Users/ef/crowny-erp/portal/서버.toau.
- UI 정본 = 넥서스 /app/erp/ (nexus.crowny.org, :9802 감사게이트 서빙). 오늘 QT 견적도구 카드 + SD(영업) 진입 배선됨.
- 나머지는 별도 트랙: aimed-erp:9910=에임드 경영AI 전용 · erp-unified:9981=집계형(erp-a 셀 2,105) · 일일업무:9918=space 연동 · enterprise:9700=다운.
- 최종 정본 선언은 사장님 확인 대기(다른 세션도 확정하지 않음).
- 견적 = quote.crowny.org :9626 — crowny-services 공유 서비스서버. 데이터 계약
crowny-quote/v1, 스펙 SSOT = quote.crowny.org/rules/ (라이브). 연동 계획(quotes.save·pricebook.search·share.create MCP)도 그 문서가 SSOT.
견적 IdP 연동 완료 (실측)
견적은 공유
서비스서버.toau를 쓰므로 IdP 폴백을 이미 상속하나,
프로세스가 부팅 시점 바이트코드를 들고 있어 재기동 전에는 401이었다.
→ :9626 단독 재기동(다른 28서비스 무영향) 후: IdP 토큰
/api/files 200, 무토큰
401, 루트 200 실측.
★교훈: 공유 .toau 갱신은
서비스별 재기동 시점에만 반영된다. 연동 후 각 서비스 단독 재기동이 필요.
IdP 2차 연동 완료 (ERP·트레이딩·집사회·메신저)
- ERP :9938 —
libs/크라우니인증.한선의 크라우니검증에 오프라인 IdP 폴백 추가(기존 9401 위임 우선). ★발견: 서버.한선에 보호 라우트가 하나도 없음(전 라우트 공개, 인증 임포트는 dead code) — 라우트 게이트 신설은 별도 승인 필요로 남김.
- 트레이딩/트레이더 :7740/7741 — 공유
sso-middleware.js 1개 수정으로 양쪽 적용. 메일 verify 폴백 + 60초 캐시. 동반 .한선 오프라인 검증 작성.
- 집사회 :9772 — X-Deacon-Key(서비스간) 유지 + Bearer 신원 식별 추가. 미션
발행자에 실제 id 기록(스키마 무변경), claim/report는 사이드 감사로그 IdP감사.psv. ★티켓.psv에 사람-id 컬럼 추가는 라이브 장부라 보류·보고.
- 메신저 :9939 — 인증 강제 없음(라이브 서비스 보호). Bearer 오면
[인증됨:id] 마킹만 부가, WAL 6필드 스키마 무변경. 무토큰 200 유지 실측.
수용력 실측 (2026-07-30, 로드 8 환경)
- 구조적 상한: 한선씨 서버 = 단일스레드 순차 accept → 서비스 1개 처리량 = 1000 / 요청당ms. 12코어 중 1코어만 사용.
- 라우트별: /api/health 1.25ms(800 req/s) · /api/files(견적) 2.6ms(386) · /api/chain 7.0ms(143) · /api/services 19.4ms(52)
- 동시성 곡선: 동시4=132 req/s · 동시16=241(정점) · 동시40=79(역전). 동시20에서 개별지연 6ms→72ms.
- 5초 폴링 기준 수용인원: 가벼운 라우트 ~2,500명 / 보통 ~700명 / 무거운 ~260명. 안전계수·피크 반영 실사용 권장 300~500명(가벼우면 1,000명).
- 대역폭·메모리는 병목 아님: 응답 150B~수KB, 500명×5초폴링=0.8Mbps(1Gbps의 0.08%), 프로세스 RSS 5~10MB.
- ★진짜 병목 = 소프트웨어: 문자열핸들 누수(480,000 상한, ~8,000요청에 exit43. warp·넥서스분기서버 이미 90%) > 무거운 라우트 > Connection:close.
측정 도구 (신규, 재사용)
crowny-services/도구/부하판정.한선 — 4상 판정 코어(티/옴/타). 처리량·이론상한·수용인원 산출. 타=실패발생·핸들90%·p95≥p50×10, 옴=핸들70%·p95≥p50×3. brain 학습 완료.
crowny-services/도구/부하시험.sh <URL> [요청수] [동시수] [토큰] — p50/p95/핸들% 수집 후 판정코어 호출. 첫 실행 실측: /api/chain 동시8에서 타(p95 665ms vs p50 21ms = 큐 폭주).
수용력 고도화 1차 (2026-07-30, 본세션 실측 재검증)
완료
문자열 누수 방어 배선 4종: 메일 IdP(:9610)·넥서스 감사API(:9805)·텔레(:9619)·클라우드관리(:9662) 전부 문자열보호() 부팅1회 + 200요청마다 문자열GC() 이중 방어. 전 서비스 생존·회귀 200 확인.
메일은 문자열보호()를 원장 리플레이 이후에 배치(부팅 시 로드한 유저·메일 문자열까지 보호범위 포함).
★전역 스칼라 함수내 bare 재대입 무한재귀 함정 회피 = 카운터를 top-level 루프 또는 맵으로 구현.
메일 IdP 부수효과(실측): /api/auth/verify 500req·동시20 — 처리량 84.5→154.8 req/s, p50 197→114ms, p95 419→164ms.
/api/services 캐싱: 응답 JSON 전체 캐시(40요청 주기 재계산 + 쓰기 시 즉시 무효화). p50 19.38ms → 3.08ms (6.3배), 동시8 처리량 44.1→129.5 req/s. 수용인원 ~320명(5초폴링·안전50%).
★진짜 원인은 registry 파싱이 아니라 매 요청 체계("date +%s") 서브프로세스 spawn(~5ms) 이었음. 주석의 "60초 캐시"는 lsof에만 걸려 있었고 캐시 유효성 체크 자체가 spawn 뒤에 있었다. → 다른 서비스도 같은 패턴 전수 점검 필요(잔여).keep-alive 조사 결론 (조사만, 코드 무변경)
- VM 제약 없음: TCP읽기(op493)는 같은 fd로 반복 호출 가능, accept 시 SO_RCVTIMEO(기본 5s) 자동 설정 → keep-alive 루프는 기존 opcode로 구현 가능.
- 현재 실측: 직결·게이트웨이·클라이언트 3경로 전부
Connection: close. keep-alive를 쓰는 구간이 하나도 없음.
- ★게이트웨이↔백엔드 keep-alive는 구조적 불가: 프록시가 응답 끝을 EOF로 판정(Content-Length 파싱 아님)해서 백엔드가 연결을 안 닫으면 무한 블록. 프록시.한선:101 주석이 명시. 고치려면 Content-Length/청크 프레이밍으로 재작성 = 게이트웨이 대수술.
- 권장 1단계(저위험): 게이트웨이의 클라이언트측 accept 루프만 keep-alive화, upstream은 close 유지. 백엔드 한선씨 서버 무접촉으로 원거리 RTT 개선 가능. 단 순차 accept라 연결당 요청수 상한 + 유휴 타임아웃 필수(없으면 한 클라이언트가 나머지를 막음).
- 위험: head-of-line blocking은 keep-alive로 해소되지 않음(핸드셰이크 비용만 감소, 처리량 상한은 그대로).
미결 — 오너 승인 필요
/Users/ef/crowny-services/서비스서버.한선(29개 서비스 공유, cloud:9611·quote:9626 포함)의 문자열 방어 배선이 안전 게이트에 차단됨(공유 인프라 변경은 명시적 지목 필요). GC=0·보호=0 상태로 exit43 최대 노출 지점으로 잔존.
크라우니클라우드 미작동 화면 보수 (2026-07-30, 본세션 실측 재검증)
보수목록 SSOT =
crowny-services/docs/클라우드-미작동-보수목록.md (프론트 호출 API 전수 ↔ 백엔드 실응답 대조로 도출)
★최중요 수리 — 승인해도 적용이 안 되던 결함
클라우드_가드.한선 가드approve가
서비스적용(kind, what, payload) /
게이트적용(kind, what, payload) 3인자로 호출했으나 두 함수 모두
2인자 정의. payload 자리에 사람이 읽는
what 문자열이 들어가 파싱 실패 →
승인해도 실제 반영 0, 그런데 ok:1로 조용히 통과. 변경보호(제품의 존재 이유)가 무력화된 상태였다.
- 수리: 호출을 정의에 맞춰 2인자로. 종단 실측 — create 큐등록→승인→
사용자서비스.psv에 실제 행 생성 확인(수리 전엔 0행). 거절 경로도 확인(반영 0 = 정상).
- ★교훈: 한선씨는 인자 수 불일치를 컴파일 에러로 잡지 않는다. 크로스모듈 호출은 정의부 시그니처를 grep으로 대조하고, 게이트류는 "승인 후 실제 파일이 변했는가"까지 봐야 한다(200/ok:1은 증거가 아님).
큐/데이터 결함 3건 (C절)
- C-1 ID 충돌: 같은 초 3건이 동일 ID 발급 → 단조 시퀀스 부여. 실측
_8/_9/_10 상이, 각각 approve 시 의도한 항목만 처리.
- C-2 원시 HTTP 헤더가 큐에 기록: 본문 파싱 실패 시 400·큐 미기록으로 수정 + 읽기 시
^(pend_|gate_) 접두 필터. 오염 grep 0건.
- C-3 게이트 ts=0 → 실제 epoch.
신규 API 3종 (B절) + 프론트 배선 (A절)
POST /api/services/update(큐 경유) · GET /api/services/stats?id= · GET /api/services/logs?id=&lines=(tail, id 화이트리스트, 40줄 상한)
- 프론트: [저장] 버튼의 "지원되지 않습니다" 토스트 → 실제 호출. 상세 통계·실시간 로그를 실API 배선(하드코딩
12,408/14d 06:12/0.02%/가짜 로그 제거).
- ★정직 원칙 관철:
requests/errorRate는 서비스별 카운터가 없어 null + note로 반환, 프론트는 "—". 그럴듯한 숫자로 채우지 않음.
- 라우트 add/edit는 이미 정상 배선이었음(정적 추출에서만 누락 — 변수 조립 경로).
검증 (본세션 직접)
GET 9종 200 · 승인/거절 종단 · 신규 3종 실응답 · 큐 오염 0 · 디자인 diff
티(100, 신규색 0) · 콘솔에러 0 · 라이브 8종 생존 + 공개 HTTPS 200 · 테스트 흔적 전량 정리(백업 후).
잔여
- 서비스별 요청 수·오류율 계측기(각 서비스에 카운터 필요) — 미착수, 현재는 정직한 null
서비스서버.한선(29공유) 문자열 방어 배선 — 오너 승인 대기(exit43 최대 노출)
서비스서버.한선 문자열 방어 배선 (2026-07-31, 오너 승인 후)
29개 서비스 공유 파일의 마지막 미방어 지점 해소. exit43 최대 노출 제거.
- 배선: 시크릿 로드 직후
문자열보호() 1회(부팅 문자열=시크릿·IdP시크릿·registry·경로를 GC 경계 아래로) + 서버 루프에서 200요청마다 문자열GC(). ★카운터는 top-level 루프에 둠(함수 내 전역 스칼라 bare 재대입 = 컴파일러 무한재귀 함정 회피).
- 그림자 선검증(라이브 무접촉):
/tmp/서비스서버_방어.toau를 SERVICE=cloud PORT=18099로 기동 → 250요청 소크 250/250 성공, GC 주기 통과 후 생존, STR 경고 0. 인증(IdP 200/무토큰 401)·정적(90KB)·자체로그인 200 전부 회귀 통과.
- 배포:
.toau 교체(.bak-문자열방어-20260731 보존) 후 cloud:9611·quote:9626만 단독 재기동(manage.sh restart 금지 — 29개 동시 재시작). 나머지 27개는 각자 재기동 시 자연 반영.
- 라이브 실측: cloud/quote 로그에
STR_PROTECT 각 1건 · IdP 200 / 무토큰 401 · 자체계정 로그인 200 · 공개 HTTPS cloud·quote 200 · 서비스 8종 생존(crownyc 140프로세스).
- 이로써 문자열 방어 배선 완료: 서비스서버(29공유)·메일IdP·넥서스·텔레·클라우드관리 = 5/5.
warp·넥서스분기 방어 + 2만 소크 (2026-07-31) — ★진단 정정
배선
crowny-warp/워프서버.한선: 최상위 루프 → top-level 카운터. 문자열보호() + 200요청마다 문자열GC().
crowny-butler/libs/넥서스분기서버.한선: 루프가 주() 안 → 지역 변수 카운터(전역 스칼라 함수내 재대입 함정 회피). 문자열보호()는 모델로드() 이후(모델 문자열까지 보호).
- 그림자 검증(18602/18798) 후 배포, 9602·9798 재기동. 라이브 로그에
STR_PROTECT 각 1건, 응답 200, 공개 warp.crowny.org 200, 서비스 10종 생존.
- 함정: 그림자 사본을 /tmp에 두면
가져오기가 엔트리 디렉토리 기준이라 라이브러리 미해결 → 원본 디렉토리에 임시 사본을 둘 것.
★소크 결과가 이전 진단을 뒤집음
"warp·넥서스분기가 90% 경고 중이라 가장 급하다"는
오독이었다. 경고 시각을 대조하니:
- warp: 경고가 부팅 1분 내 1회, 이후 10.5시간 재발 0. 미방어 대조군으로 2만 요청 소크 → 경고 0건, 생존. 무거운 라우트 1,700요청 추가에도 0건. 요청경로 누수 없음(부팅 시 대용량 생존셋이 임계를 한 번 스친 것).
- 넥서스분기서버: 경고 2건, 두 번째가 부팅 2시간 20분 뒤 → 진짜 누적. 방어가 실제로 필요한 쪽.
- 부수 관측: 미방어 9MB vs 방어 5MB(GC 효과는 메모리에 나타남).
- 교훈(메모리 등재): STR 경고는
.err mtime과 프로세스 시작시각을 대조해 부팅1회/누적을 먼저 구분. "방어 후 경고 없음"은 증거가 아니며 미방어 대조군이 있어야 증명. 부팅1회형은 GC로 해결 안 됨(생존셋 축소 또는 STR_ID_MAX 상향이 처방).
요청·오류 계측기 (2026-07-31) — 클라우드 화면 null 해소
- 계측 지점: 공유
서비스서버.한선(:9611)과 사이드카 클라우드관리.한선(:9662) 양쪽. ★설계 정정: /cloudapi/*는 게이트웨이가 9662로 보내므로 stats API 트래픽은 9662가 받는다 → 스냅샷 파일 분리(cloud.psv=9662, cloud-web.psv=9611)로 쓰기 경합 회피.
- 방식: 인메모리 카운터 + 100요청마다 1회만
data/metrics/<서비스>.psv 덮어쓰기(요청마다 파일 I/O 금지 — 핫패스 0.73ms보다 비쌈). 카운터는 top-level 루프(전역 스칼라 함수내 재대입 함정 회피).
- 미재기동 서비스는 파일이 없어 계속 null + note(허위 수치 방지) —
id=bible 실측 확인.
- 성능 회귀 없음:
/api/health p50 0.73→0.76ms(9662), 배선 후 재측정 1.23ms(부하 변동 범위).
★정직성 교정 — 오류율은 근사치로 라벨링
본세션 검증에서
요청 수는 정확(200요청 투입 → 정확히 200 증가)하나
오류 수는 과소집계 확인:
- 100건 무토큰 401 투입 → 77건 집계 / 200건 투입 → 197건 집계(98.5%). 회차마다 편차.
- 원인: 하위 핸들러 7종이 상태코드를 상위로 반환하지 않고 처리여부(1/0)만 반환 → 상위 게이트가 처리한 401/400만 확실히 집계.
- 조치: 숫자를 정확한 척 표시하지 않도록 note를 교정 — "요청수=서버 시작 이후 실측. 오류율은 근사치(하위 핸들러 상태코드 미전파로 과소집계)". 정확한 오류율을 원하면 7모듈이 상태코드를 반환하도록 시그니처 변경 필요(별도 작업).
- 회귀: GET 9종 200·무토큰 401·공개 HTTPS cloud/quote 200·서비스 10종 생존.