AI 기반 Zero Trust 파이프라인
Spring Security는 누구인지를 결정합니다. Contexa의 AI는 다음에 무엇을 할 수 있는지를 결정합니다 — 행동 컨텍스트를 기반으로, 지속적으로. 규칙을 작성할 필요가 없습니다. 행동이 베이스라인에서 벗어나면 Contexa가 찾아냅니다.
인증 후 사각지대(Post-Authentication Blind Spot)
기존 보안은 입구에서 멈춥니다. 방화벽, WAF, 로그인 폼은 신원을 확인합니다 — 하지만 세션이 수립되면 내부는 대부분 방어되지 않습니다. 탈취된 자격 증명, 침해된 세션, 밀리초 내에 인증을 통과하는 AI 에이전트 모두가 이 인증 후 사각지대를 악용합니다.
Contexa는 Spring Security와 Spring AI를 결합하여 인증 이후의 액션을 모니터링하고 제어하는 통합 제로 트러스트 레이어를 구축합니다 — 로그인 자체만이 아닌.
AISessionSecurityContextRepository.loadDeferredContext(...), AbstractZeroTrustSecurityService.applyZeroTrustToContext(...), ZeroTrustAccessControlFilter.doFilterInternal(...), ZeroTrustChallengeFilter.doFilterInternal(...)로 이어집니다. 비동기 경로는 ZeroTrustEventPublisher.publishMethodAuthorization(...), ZeroTrustEventListener.handleZeroTrustEvent(...), SecurityPlaneAgent, SecurityEventProcessor.process(...), SecurityDecisionEnforcementHandler.handle(...)로 이어집니다.
한번 들어오면 완전 접근.
세션 탈취 = 게임 오버.
기존 인증
입구만 지킵니다.
- 로그인 시 패스워드 / SSO / MFA
- 세션 쿠키 = 영원히 신뢰됨
- 인증 후 모니터링 없음
- 세션 탈취 = 완전 접근
규칙 기반 WAF
알려진 패턴을 잡습니다.
- 시그니처 기반 탐지
- 정적 IP / 속도 제한 규칙
- 행동 이상 탐지 불가
- AI 에이전트가 쉽게 우회
Contexa AI Zero Trust
행동 컨텍스트를 이해합니다.
- LLM이 인증 후 모든 액션을 분석
- 사용자별 HCAD 행동 베이스라인
- 시그니처가 아닌 편차를 탐지
- Spring Security와 5가지 적용 액션
- 크로스 인스턴스 실시간 차단
"규칙은 묻습니다: 정책을 위반했는가? — 일치하는 규칙이 없으면 통과합니다.
Contexa는 묻습니다: 이 사람에게 정상적인 행동인가? — 행동이 벗어나면 잡아냅니다."
두 개의 흐름, 하나의 방어
Contexa는 두 가지 상호 보완적 흐름으로 연속적인 제로 트러스트 방어막을 형성합니다. Flow A는 백그라운드에서 실행되어 AI로 이벤트를 분석합니다. Flow B는 HTTP 요청 시점에 실행되어 Spring Security의 권한 시스템을 통해 저장된 결정을 적용합니다. 액션 저장소가 둘을 연결하며, distributed 모드에서는 Redis 기반 저장소와 Redisson 전파가 인스턴스 간 공유 상태를 담당합니다.
ZeroTrustEventPublisher.publishMethodAuthorization(...)가 ZeroTrustSpringEvent를 발행하면서 시작되고, ZeroTrustEventListener.handleZeroTrustEvent(...)가 이를 비동기 처리 경로로 넘깁니다. Flow B는 AISessionSecurityContextRepository.loadDeferredContext(...)가 요청 보안 컨텍스트를 읽을 때 시작되며, AbstractZeroTrustSecurityService.applyZeroTrustToContext(...)가 저장된 액션을 Spring Security 권한으로 반영합니다.
@Protectable 메서드 또는 보호된 URL에 접근SecurityDecision를 만들고, 그 최종 적용 액션이 ZeroTrustActionRepository에 기록됩니다. BLOCK은 크로스 인스턴스 전파를 트리거할 수 있고, ALLOW는 베이스라인 학습으로 이어집니다.Action
Repository
SecurityContextRepository를 대체합니다. ZeroTrustActionRepository를 통해 현재 ZeroTrustAction을 조회하며, distributed 모드에서는 이 공유 상태가 Redis 기반으로 유지됩니다.GrantedAuthority를 동적으로 교체: BLOCK→ROLE_BLOCKED, CHALLENGE→ROLE_MFA_REQUIRED 등.ROLE_MFA_REQUIRED가 감지되면 분산 락과 함께 적응형 MFA 챌린지를 초기화실제 시나리오: 정상 사용자 vs. 계정 탈취
두 사용자 모두 유효한 자격 증명으로 인증합니다. 둘 다 MFA를 통과합니다. 기존 보안은 이들을 구별할 수 없습니다. Contexa의 AI는 로그인 이후 무슨 일이 일어나는지를 감시합니다.
시간: 오전 10:00 (평소 근무 시간)
디바이스: Windows / Chrome (등록됨)
인증: PASS
요청 빈도: 정상 속도
내비게이션: 6개월 베이스라인과 일치
패턴: 정상
액션: ALLOW
새 세션 데이터로 베이스라인 업데이트.
시간: 오후 2:00 (근무 시간 내)
디바이스: Windows / Chrome (모방됨)
인증: PASS
요청 빈도: 5,000건 대량 내보내기
내비게이션: 이전에 이 경로에 접근한 적 없음
패턴: 이상 탐지
액션: BLOCK
모든 인스턴스 통보. SSE를 통해 관리자 알림.
AI는 이 행동이 이 사람의 것이 아님을 인식했습니다 —
자격 증명이 완벽하게 유효했음에도 불구하고.
브리지 — AISecurityContextRepository
이것이 AI와 Spring Security가 만나는 단일 통합 지점입니다. Spring Security의 기본 HttpSessionSecurityContextRepository를 AISessionSecurityContextRepository로 교체함으로써, Contexa는 모든 인증 객체에 후속 요청에 적용될 AI 결정을 주입합니다 — 애플리케이션 코드 한 줄의 변경 없이.
loadDeferredContext(...)를 호출하고, 저장소는 요청 컨텍스트를 지연 로드한 뒤 AbstractZeroTrustSecurityService.applyZeroTrustToContext(...)를 통해 현재 액션을 불러옵니다. 이어서 adjustAuthoritiesByAction(...)가 이를 권한으로 변환하고, 필요할 때 saveContext(...)가 갱신된 보안 컨텍스트를 저장합니다. Standalone에서는 같은 계약을 인메모리 구현이 담당하고, distributed에서는 Redis 기반 저장소와 broadcaster가 이를 담당합니다.
동작 원리
loadDeferredContext()를 호출권한 변환
매 요청마다, adjustAuthoritiesByAction()은 ZeroTrustActionRepository에서 읽은 현재 액션에 따라 사용자의 Spring Security 권한을 동적으로 교체합니다:
| AI 결정 | 부여 권한(Granted Authority) | 적용 결과 | ||
|---|---|---|---|---|
| ALLOW | → | 원래 권한 유지 | → | 정상 접근, 베이스라인 학습 |
| BLOCK | → | ROLE_BLOCKED 만 |
→ | 403 Forbidden, 세션 무효화 |
| CHALLENGE | → | ROLE_MFA_REQUIRED 만 |
→ | MFA 챌린지, 최대 2회 시도 |
| ESCALATE | → | ROLE_REVIEW_REQUIRED 만 |
→ | 423 Locked, 300초 후 자동 BLOCK |
| PENDING | → | 원래 권한 + ROLE_PENDING_ANALYSIS |
→ | 응답 래핑, 실시간 인터럽트 |
SecurityContextRepository 내부에서 발생하므로, 기존의 모든 @PreAuthorize, hasRole(), isAuthenticated() 표현식이 자동으로 AI 제로 트러스트 상태를 반영합니다. @Protectable 메서드, URL 기반 정책, SpEL 표현식 모두가 투명하게 혜택을 받습니다.
ZeroTrustAction — 5가지 결정
SecurityDecision을 출력하며, 그 안에는 제안 액션과 실제 집행에 사용되는 액션이 함께 담깁니다. riskScore와 confidence 같은 필드는 SecurityDecision에 감사 로깅 및 학습 목적으로 유지됩니다.
| 액션 | HTTP | TTL | Authority | 의미 & 후속 처리 |
|---|---|---|---|---|
| ALLOW | 200 | 1500s | — | 요청이 신뢰됨. 정상 진행. SecurityLearningService를 통해 베이스라인 학습 트리거. |
| BLOCK | 403 | 영구 | ROLE_BLOCKED |
위협 확인됨. 세션 무효화, Redisson RTopic을 통한 크로스 인스턴스 전파. 사용자는 /zero-trust/blocked로 리다이렉트. |
| CHALLENGE | 401 | 1800s | ROLE_MFA_REQUIRED |
의심스러운 활동. ChallengeMfaInitializer를 통해 MFA 챌린지 시작. 최대 2회 시도; 실패 시 BLOCK으로 에스컬레이션. |
| ESCALATE | 423 | 300s | ROLE_REVIEW_REQUIRED |
인간 검토 필요. 300초 후 자동 BLOCK으로 승격. SoarApprovalNotifier를 통한 SOAR 통합. |
| PENDING_ANALYSIS | 503 | 0s | ROLE_PENDING_ANALYSIS |
AI 분석 진행 중. BlockableResponseWrapper로 응답이 래핑되어 실시간 중간 스트림 인터럽트 가능. |
ZeroTrustAction은 유틸리티 메서드도 제공합니다: isBlocking()은 BLOCK과 ESCALATE에 대해 true를 반환하고; isAccessRestricted()는 BLOCK, CHALLENGE, ESCALATE에 대해 true를 반환합니다.
Flow A — 이벤트 기반 AI 분석 파이프라인
사용자가 @Protectable 리소스에 접근하면, 보안 이벤트는 각각 특정 순서와 책임을 가진 3단계 핸들러 체인을 통과합니다. 전체 파이프라인은 백그라운드에서 비동기로 실행되어 분석을 사용자 요청의 직접 경로 밖에 둡니다.
핸들러 체인
ColdPathEventProcessor에 위임합니다. ProcessingResult를 파이프라인 컨텍스트에 저장합니다.ZeroTrustActionRepository에 기록합니다. BLOCK: blockedFlag 설정 + BlockingSignalBroadcaster를 통한 브로드캐스트. ALLOW: 베이스라인 학습이 예약되며 최종적으로 SecurityLearningService.learnBaselineOnly(...)로 이어집니다.CentralAuditFacade를 통해 완전한 감사 로그를 기록합니다. 결정, 리스크 점수, 신뢰도, 판단 근거, 처리 시간을 포함합니다.AI 분석 — Layer 1 & Layer 2
ColdPathEventProcessor는 계층형 AI 전략을 오케스트레이션합니다. Layer 1은 빠른 Tier 1 LLM으로 ~98%의 요청을 처리합니다. 신뢰도가 불충분할 경우 Layer 2로 에스컬레이션하여 심층 포렌식 분석을 수행합니다. 두 레이어 모두 구조화된 프롬프트 엔지니어링을 위해 SecurityPromptTemplate을 사용합니다.
SecurityDecision이며, ZeroTrustAction(ALLOW, BLOCK, CHALLENGE, ESCALATE)을 직접 포함합니다. riskScore와 confidence 필드는 감사 및 베이스라인 학습을 위해 기록됩니다 — 액션 결정을 주도하지 않습니다.
Layer 1 — 컨텍스트 분석
SessionContext를 구축합니다SecurityPromptTemplate으로 프롬프트를 구성하고 UnifiedLLMOrchestrator로 전송합니다. 결과는 제안 액션과 최종 적용 액션을 담은 SecurityDecision입니다.Layer 2 — 전문가 조사
Layer 1의 신뢰도가 설정된 임계값 이하일 때 트리거됩니다. 완전한 포렌식 분석을 위해 Tier 2 LLM을 사용합니다.
ApprovalService가 SoarApprovalNotifier를 통해 인간 승인을 요청합니다Flow B — 동적 권한 적용
매 HTTP 요청마다, Spring Security의 필터 체인이 ZeroTrustActionRepository를 통해 현재 액션을 읽어 적용합니다. 핵심 메커니즘은 권한 교체입니다 — 사용자의 GrantedAuthority 집합이 현재 ZeroTrustAction에 따라 동적으로 재작성됩니다.
필터 체인 순서
loadDeferredContext() 시 ZeroTrustDeferredSecurityContext로 래핑합니다. 첫 접근 시: ZeroTrustActionRepository에서 현재 액션을 조회하고 adjustAuthoritiesByAction()를 거쳐 ZeroTrustAuthenticationToken을 생성합니다./zero-trust/blocked로 리다이렉트 또는 Block-MFA 시작 (ChallengeMfaInitializer를 통해 최대 2회 시도).ESCALATE:
/zero-trust/analysis-pending으로 423 반환. TTL 5분; 자동으로 BLOCK으로 승격.PENDING_ANALYSIS: 실시간 중간 스트림 인터럽트를 위해
BlockableResponseWrapper로 응답 래핑.
ROLE_MFA_REQUIRED를 감지합니다. 분산 락(30초)을 획득합니다. ChallengeMfaInitializer를 통해 MFA 상태 머신을 초기화합니다. MFA 챌린지 페이지로 리다이렉트합니다. 실패 → 자동으로 BLOCK으로 에스컬레이션.@PreAuthorize, hasRole(), URL 기반 인가가 이제 AI 조정된 권한으로 투명하게 동작합니다.적용 인프라
AI가 결정을 내립니다. Spring Security의 필터 체인과 분산 인프라가 이를 적용합니다 — 밀리초 내에, 모든 인스턴스에 걸쳐, 심지어 응답 중에도.
BLOCK 적용
크로스 인스턴스 전파와 함께 즉각적인 거부.
ZeroTrustActionRepository를 통해 BLOCK을 기록하고 blockedFlag를 설정합니다. distributed 모드에서는 이 상태가 Redis 기반으로 유지됩니다.BLOCK:{userId}를 발행합니다. 모든 인스턴스가 실시간으로 신호를 수신합니다.ConcurrentHashMap을 업데이트합니다.BlockableServletOutputStream이 모든 write()에서 차단 상태를 확인합니다. 전송 중인 응답도 즉시 종료됩니다.IBlockedUserRecorder가 DB에 영속화합니다.CHALLENGE 적용
추가 인증을 요구합니다. 분산 락으로 레이스 컨디션을 방지합니다.
ROLE_MFA_REQUIRED를 감지합니다. 분산 락(30초)을 획득합니다.BlockMfaStateStore가 시도를 추적합니다 (1시간 내 최대 2회). 성공 시 챌린지를 해제합니다.ESCALATE 적용
인간 검토를 요구합니다. 시간 제한이 있으며 자동으로 BLOCK으로 승격됩니다.
ROLE_REVIEW_REQUIRED를 부여합니다. TTL: 300초.ApprovalService.requestApproval() → SoarApprovalNotifier가 보안 팀에 알림을 전송합니다.AdminOverrideService.approve()가 해결합니다. TTL 만료 시 (300초) → 자동으로 BLOCK으로 승격.크로스 인스턴스 전파 & 차단 해제
차단 결정이 모든 인스턴스에 실시간으로 전파됩니다. 차단된 사용자는 MFA 검증을 통해 차단 해제를 요청할 수 있습니다.
contexa:security:block-signal. 신호: BLOCK:{userId}, UNBLOCK:{userId}.BLOCKED → UNBLOCK_REQUESTED → RESOLVED.ZeroTrustUnblockController: Block-MFA (최대 2회 시도) → MFA 검증 → requestUnblockWithMfa().관리자가
BlockedUserService.resolveBlockById()를 통해 승인 → Redis 키 삭제 → UNBLOCK 신호 브로드캐스트.
모니터링, 학습 & SSE
모든 AI 결정은 실시간으로 대시보드에 스트리밍되고, 미래 결정을 개선하기 위해 학습 루프에 피드백됩니다.
실시간 스트림
실시간 모니터링을 위한 Server-Sent Events.
ZeroTrustSsePublisher가 결정을 브로드캐스트- SSE 엔드포인트:
/api/aiam/sse/zero-trust/subscribe - 실시간 액션 피드: ALLOW/BLOCK/CHALLENGE/ESCALATE
- 분석 완료, 차단 해제 알림
관리자 대시보드
보안 운영자를 위한 시각적 제어 센터.
/zero-trust/blocked— 차단된 사용자 페이지/zero-trust/challenge-required— MFA 챌린지/zero-trust/analysis-pending— 검토 진행 중- 결정 오버라이드를 위한
AdminOverrideService
학습 루프
모든 ALLOW 결정이 베이스라인을 개선합니다.
SecurityLearningService→BaselineLearningService- EMA (지수 이동 평균) 베이스라인 업데이트
SecurityDecisionPostProcessor벡터 저장- IP/경로 빈도 맵을 위한 LFU 퇴거
SpEL 통합 & 설정
SpEL 표현식에서의 Zero Trust
Spring Security의 @PreAuthorize 및 @PostAuthorize 어노테이션은 AbstractAISecurityExpressionRoot의 커스텀 표현식 메서드를 통해 Zero Trust 상태를 참조할 수 있습니다.
| 표현식 | 반환 타입 | 설명 |
|---|---|---|
isZeroTrustAllowed() | boolean | 현재 사용자의 ZeroTrustAction이 ALLOW |
isZeroTrustBlocked() | boolean | 현재 사용자의 액션이 BLOCK |
isZeroTrustChallenged() | boolean | 현재 사용자의 액션이 CHALLENGE |
getZeroTrustAction() | ZeroTrustAction | 현재 ZeroTrustAction enum 값을 반환 |
설정 레퍼런스
| 프로퍼티 | 기본값 | 설명 |
|---|---|---|
security.zerotrust.enabled | true | Zero Trust 파이프라인 활성화/비활성화 |
security.zerotrust.mode | ENFORCE | SHADOW (로그만) 또는 ENFORCE (완전 적용) |
security.zerotrust.sampling.rate | 1.0 | 분석할 요청 비율 (0.0-1.0) |
security.zerotrust.hotpath.enabled | true | Layer 1 hot-path 분석 활성화 |
security.zerotrust.redis.updateIntervalSeconds | 30 | Redis 액션 업데이트 간격 |
contexa.infrastructure.mode | STANDALONE | STANDALONE (인메모리) 또는 DISTRIBUTED (Redis+Kafka) |