Zero Trust IAM 플랫폼 — Zanzibar 스타일 ReBAC 인가 엔진 · Passwordless 인증(Passkey + DPoP) · Kafka Streams 실시간 위험분석 · CAEP/SSF 연속 접근 평가
Java 21 · Spring Boot 4.1 · PostgreSQL 16 · Redis 7 · Kafka 3.9 · Next.js
관계 기반 인가(ReBAC)로 "누가 · 무엇에 · 왜 접근 가능한가" 를 관계 그래프로 답하고, 모든 인증 활동을 실시간으로 위험 평가해 표준 프로토콜(CAEP/SSF)로 세션을 연속 통제하는 IAM 플랫폼.
권한 그래프 탐색기 — 한 주체가 접근 가능한 리소스를 관계 그래프로(ListObjects), 노드 클릭 시 왜 접근 가능한지(explain 유도 경로) + 누가 접근 가능한지(Zanzibar Expand userset 트리)
실시간 보안 대시보드 — 공격 시뮬 → Kafka Streams 윈도우 탐지 → CAEP 경보 (2초 폴링)
Passkey 로그인 — Spring Security 7 WebAuthn passwordless
관측 대시보드 — 프로비저닝된 Grafana: Check 처리량(hit/miss)·p95/p99·캐시 히트율, 인증 이벤트 → brute-force 경보 → CAEP SET 발행까지 커스텀 메트릭으로
- 권한을 역할(RBAC)로만 모델링하면 "이 폴더의 뷰어는 그 안 문서도 볼 수 있다" 같은 관계·상속을 표현하기 어렵다.
- Bearer 토큰은 탈취되면 그대로 사용된다. 로그인 이후 위험이 바뀌어도 세션은 만료까지 살아있다.
flowchart LR
U([User]) -->|Passkey / DPoP| IDP[OAuth2·OIDC IdP<br/>PKCE · JWKS]
IDP -->|DPoP-bound token| RP[Resource / API]
RP -->|Check obj#relation@subj| REBAC[ReBAC engine · Zanzibar]
REBAC --> PG[(PostgreSQL<br/>relation_tuple)]
REBAC -.cache + zookie.-> REDIS[(Redis)]
IDP ==>|auth events| KAFKA[(Kafka<br/>auth-events)]
KAFKA --> STREAMS[Kafka Streams<br/>brute-force window]
STREAMS ==>|risk-alerts| CAEP[CAEP responder]
CAEP -->|session-revoked SET| SSF[(caep-events · SSF)]
CAEP -.lock + step-up.-> REDIS
- ReBAC: Google Zanzibar 모델(관계튜플 + userset rewrite)을 직접 구현 — Check / Expand / ListObjects 3대 API + explain(유도 경로), RBAC/ABAC와의 트레이드오프
- 인증: OAuth2/OIDC IdP + WebAuthn Passkey(passwordless) + DPoP sender-constrained 토큰
- 실시간: Kafka Streams stateful 처리(윈도우·상태스토어·exactly-once)로 이상 로그인 탐지
- 연속평가: OpenID CAEP/SSF(2025.9 final) 표준으로 분산 세션 무효화 + step-up
말이 아니라 실행으로 — 통합테스트 + 라이브 부하로 증명한다.
P1 정확성 (Testcontainers, 11개 통과): 직접 부여 · editor⊆viewer(computed_userset) · 소유자 상속 · 그룹 멤버십(userset) · 폴더 상속(tuple_to_userset) · 깊은 중첩(그룹 중첩 + 폴더 체인) · Expand 트리(전체 rewrite 트리 + 사이클 종료) · 캐시 hit/무효화 · zookie revision.
P2 성능 (k6, 30 VU · 30s, 깊이 15 중첩 그룹 Check):
| 처리량 | p95 | p90 | avg | 실패 | |
|---|---|---|---|---|---|
| 캐시 없음 (매 요청 그래프순회 + 전이폐쇄 CTE) | 3,286/s | 20.96ms | 14.66ms | 8.71ms | 0% |
| zookie 캐시 (hit 99.99%) | 9,625/s | 4.8ms | 3.62ms | 2.89ms | 0% |
→ zookie revision 캐시로 처리량 2.9배 · p95 4.4배. 캐시 없이도(전이폐쇄 CTE 단일 쿼리) 깊이 15에서 p95 21ms.
P3 인증 (라이브 검증): OAuth2/OIDC IdP(discovery · JWKS · PKCE S256) · Passkey/WebAuthn passwordless UI · DPoP(sender-constrained, discovery 노출) · 토큰 라이프사이클(client_credentials 발급 → introspect active → revoke → introspect inactive).
P4 실시간 위험분석 (라이브 검증): Spring Security 인증 이벤트 → Kafka(auth-events) → Kafka Streams 1분 텀블링 윈도우 brute-force 카운트 → 임계치 초과 시 risk-alerts에 경보(attacker 6회 실패 → {"type":"BRUTE_FORCE","count":6}).
P5 연속 접근 평가 (라이브 검증): risk-alerts(BRUTE_FORCE) 소비 → ① principal Redis lock(step-up 강제) ② 서명된 CAEP session-revoked SET(RFC 8417 / OpenID CAEP) → caep-events. 전체 연쇄: brute-force → auth-events → Streams → risk-alerts → CAEP SET + lock.
| 영역 | 기술 |
|---|---|
| 언어/프레임워크 | Java 21 · Spring Boot 4.1 · Spring Security 7 |
| 인가 | Zanzibar-style ReBAC (PostgreSQL + JSONB namespace config) |
| 인증 | OAuth2/OIDC Authorization Server · WebAuthn · DPoP |
| 실시간 | Apache Kafka 3.9 · Kafka Streams |
| 저장소 | PostgreSQL 16 (Flyway) · Redis 7 |
| 관측 | Micrometer · Prometheus · Grafana |
| 프론트 | Next.js |
# 1) 인프라 (Postgres 5436, Redis 6382)
docker compose up -d
# 2) 앱 (포트 8102)
./gradlew bootRun
# 3) 헬스체크
curl http://localhost:8102/actuator/health- P0 — 스캐폴딩 & 기동
- P1 — ReBAC 인가 엔진 코어 (관계튜플, userset rewrite, Check/ListObjects) — 통합테스트 6/6 ✅
- P2 — ReBAC 성능 & 일관성 (zookie·캐시·전이폐쇄 CTE·k6) — 캐시로 처리량 2.9배·p95 4.4배 ✅
- P3 — 인증 (OAuth2/OIDC IdP + PKCE · Passkey/WebAuthn · DPoP · introspection/revocation) ✅
- P4 — Kafka Streams 실시간 위험분석 (인증이벤트→Kafka, 윈도우 brute-force 탐지) ✅
- P5 — CAEP/SSF 연속 접근 평가 (risk→세션무효화 SET + step-up lock) ✅
- P6 — 프론트 데모 3종(권한그래프·실시간대시보드·Passkey) + 관측(Prometheus/Grafana) + 문서 ✅
- P7 — 고도화: Zanzibar Expand API(userset 트리 + 프론트 감사 뷰) · 커스텀 메트릭(Check 타이머 히스토그램, 인증/경보/CAEP 카운터) · Grafana 대시보드 프로비저닝 ✅
docs/adr/— 진행하며 기록