contexa-iam

엔드투엔드 동적 인가 워크플로

데이터베이스 기반 정책 흐름으로 대부분의 URL 및 메서드 인가 규칙을 중앙화할 수 있는 완전한 정책 기반 인가 시스템을 구축합니다. 자동 리소스 탐색부터 런타임 집행까지, Contexa는 Spring Security 설정에 유지해야 하는 정적 인가 코드의 양을 줄여 줍니다.

왜 이 방식이 중요한가

기존 Spring Security는 인가 규칙을 Java 설정에 직접 하드코딩하도록 만드는 경우가 많습니다. 새 엔드포인트가 추가되거나, 역할이 바뀌거나, 권한 정책이 조정될 때마다 코드 수정, 재빌드, 재배포가 필요해집니다. Contexa는 그 운영 부담을 런타임에서 관리되는 정책으로 이동시키면서도, 정말 필요한 정적 매처는 그대로 유지할 수 있게 합니다.

전통적 방식과 Contexa 방식 비교

기존 Spring Security

Java
http.authorizeHttpRequests(auth -> auth
    .requestMatchers("/api/admin/**")
        .hasRole("ADMIN")
    .requestMatchers("/api/users/**")
        .hasAuthority("READ_USERS")
    .requestMatchers("/api/reports/**")
        .hasAnyRole("ADMIN", "ANALYST")
    .requestMatchers("/api/orders/**")
        .hasAuthority("MANAGE_ORDERS")
    .requestMatchers("/api/settings/**")
        .hasRole("SUPER_ADMIN")
    .requestMatchers("/api/audit/**")
        .hasAuthority("VIEW_AUDIT_LOG")
    // ... 20+ more lines
    .anyRequest().authenticated()
);

변경이 생길 때마다 코드 수정, 재빌드, 재배포가 필요합니다. 소스 코드를 읽지 않고서는 누가 무엇에 접근할 수 있는지 한눈에 파악하기 어렵습니다.

VS

Contexa 동적 인가

Java
http.authorizeHttpRequests(auth -> auth
    .requestMatchers("/css/**", "/js/**")
        .permitAll()
    .anyRequest()
        .access(customDynamicAuthorizationManager)
);

동적 인가 매니저는 대부분의 애플리케이션 전용 URL 규칙을 하나의 런타임 인가 진입점으로 대체할 수 있습니다. 정책은 관리자 화면에서 관리되고 데이터베이스에 저장되며, 애플리케이션을 다시 컴파일하지 않고 런타임에 집행됩니다.

핵심 장점

항목 기존 방식 Contexa
정책 변경 코드 수정 + 재빌드 + 재배포 관리자 화면 수정 후 즉시 반영
새 엔드포인트 보호 requestMatchers를 수동 추가 ResourceScanner가 자동 탐색
정책 작성 개발자가 Java 코드 작성 Policy Center의 빠른/수동/AI 작성 흐름
감사 추적 Git 이력 중심 CentralAuditFacade 기반 정책 서비스 이벤트 및 거부된 URL 인가 결과 기록
AI 통합 지원 없음 AI 위험 평가, 조건 추천
세밀도 URL 패턴 + 역할 URL, 메서드, 소유권, 시간, IP, AI 조건
가시성 소스 코드를 읽어야 파악 가능 여러 이해관계자가 함께 볼 수 있는 중앙 대시보드

전체 워크플로 개요

동적 인가 시스템은 다섯 단계의 파이프라인으로 동작합니다. 각 단계는 스캐너 등록, 정책 저장, 요청 시점 집행까지 실제 런타임 구성요소에 대응합니다.

ResourceScanner
시작 시 모든 엔드포인트와 @Protectable 메서드를 자동 탐색
registers
ManagedResource Registry
탐색된 리소스를 라이프사이클 상태와 함께 ManagedResourceRepository에 동기화
curates
Policy Center
현재 OSS 기준 리소스 검토, 빠른/수동 작성, AI 초안, 정책 목록 관리를 담당하는 UI
persists
DB Policy Storage
정책, 조건, 타깃을 데이터베이스에 저장
loads
Dynamic Authorization Manager
CustomDynamicAuthorizationManager가 일치하는 URL 정책을 런타임에 평가

아래 섹션에서는 이 파이프라인이 실제 시나리오에서 어떻게 작동하는지 네 가지 예로 설명합니다.

시나리오 1 — 새 API 엔드포인트 보호

새 REST 컨트롤러를 작성한 뒤, 보안 설정 코드를 직접 수정하지 않고도 동적으로 보호하고 싶은 경우를 가정합니다.

1
@RequestMapping으로 컨트롤러 작성

평소와 같은 방식으로 엔드포인트를 만듭니다. 별도 보안 애노테이션은 필요하지 않습니다.

Java
@RestController
@RequestMapping("/api/v1/invoices")
public class InvoiceController {

    @GetMapping
    public List<InvoiceDto> listInvoices() {
        return invoiceService.findAll();
    }

    @PostMapping
    public InvoiceDto createInvoice(@RequestBody CreateInvoiceRequest req) {
        return invoiceService.create(req);
    }

    @DeleteMapping("/{id}")
    public void deleteInvoice(@PathVariable Long id) {
        invoiceService.delete(id);
    }
}
2
시작 시 ResourceScanner가 자동 탐색

MvcResourceScanner는 애플리케이션 시작 시 자동으로 실행됩니다. 모든 컨트롤러의 @RequestMapping, @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping을 스캔합니다.

예제에서는 세 개의 새 리소스가 데이터베이스에 등록됩니다.

리소스 ID HTTP 메서드 URL 패턴 타입
GET:/api/v1/invoices GET /api/v1/invoices URL
POST:/api/v1/invoices POST /api/v1/invoices URL
DELETE:/api/v1/invoices/{id} DELETE /api/v1/invoices/{id} URL

수동 등록은 필요하지 않습니다. 스캐너가 자동으로 탐색합니다.

3
Policy Center에서 검토, 이름 지정, 권한 정의

관리자 콘솔에서 Policy Center를 엽니다. 현재 OSS 템플릿 트리에서는 발견된 리소스를 다루는 주요 클라이언트 화면이 Policy Center이며, 레거시 컨트롤러 경로는 서버 코드에만 남아 있습니다.

각 리소스에 대해 다음 작업을 수행할 수 있습니다.

  • AI가 생성한 표시 이름과 설명을 검토합니다. 예: "List Invoices", "Create Invoice", "Delete Invoice"
  • 역할/권한 정책으로 관리하려는 리소스를 Permission으로 정의합니다.
  • 공개로 유지할 리소스라면 인가 관리 대상에서 제외하거나, 이미 제외한 리소스를 복원합니다.
4
정책 생성 — 빠른 모드, 수동 모드, AI 지원

현재 OSS 정책 작성 흐름의 중심은 Policy Center입니다. 빠른 역할-권한 매핑, 수동 작성, AI 보조 초안 생성이 모두 여기서 이루어집니다.

옵션 A: 빠른 모드

가장 빠른 경로입니다. 역할과 권한을 선택하고 단순한 ALLOW 정책을 저장합니다.

  1. 리소스를 선택합니다. 예: GET:/api/v1/invoices
  2. 대상 역할 ADMIN, ACCOUNTANT를 선택합니다.
  3. 권한 INVOICES_READ를 할당합니다.
  4. 효과는 ALLOW로 설정합니다.
  5. Quick 모드의 Create Policy 버튼으로 저장하거나, 리소스 표면에서 먼저 Create Permission & Policy를 눌러 작성 흐름에 진입합니다.

이렇게 생성된 정책은 hasAnyRole('ADMIN', 'ACCOUNTANT')에 해당하는 간단한 규칙이지만, 코드가 아니라 데이터베이스에 저장됩니다.

옵션 B: 수동 / AI 지원 모드

복잡한 인가 로직, 추가 조건, 다중 타깃, AI 보조 초안이 필요한 경우 사용합니다.

Policy Definition (Conceptual)
Policy: "Invoice Deletion - Restricted"
  Target:   DELETE:/api/v1/invoices/{id}
  Effect:   ALLOW
  Roles:    ADMIN
  Conditions:
    - Time:  weekdays 09:00-18:00 only
    - IP:    internal network (10.0.0.0/8)
    - AI:    #ai.hasActionIn('ALLOW', 'CHALLENGE')

BusinessPolicyServiceImpl는 이런 비즈니스 입력을 런타임에 평가 가능한 정책 타깃, 규칙, SpEL/XACML 호환 조건으로 변환해 저장합니다.

5
런타임 집행 — 자동이며 즉시 반영

정책은 데이터베이스에 저장됩니다. CustomDynamicAuthorizationManagerPolicyRetrievalPoint를 통해 정책을 로드하고(캐시 포함), 런타임 매처 목록을 구성합니다.

예를 들어 DELETE /api/v1/invoices/42 요청이 들어오면 다음 순서로 처리됩니다.

  1. Spring Security가 CustomDynamicAuthorizationManager에 인가 판단을 위임합니다.
  2. 매니저가 요청 URL을 "Invoice Deletion - Restricted" 정책과 매칭합니다.
  3. 역할, 시간, IP 대역, 현재 AI 액션 상태 등 모든 조건을 평가합니다.
  4. 모든 조건이 통과하면 AuthorizationDecision(true)를 반환합니다.
  5. URL 인가 결과가 거부일 경우 CentralAuditFacade가 요청/결과 맥락과 함께 비동기로 기록합니다.

결과: 엔드포인트가 동적으로 보호됩니다. 코드 변경도, 재배포도 필요 없습니다. 정책은 관리자 화면에서 언제든지 수정할 수 있습니다.

시나리오 2 — 비즈니스 메서드 보호

Contexa는 URL 수준 인가를 넘어 @Protectable 애노테이션을 사용한 메서드 수준 보호를 지원합니다. 이를 통해 소유권 개념이 포함된 세밀한 접근 제어를 서비스 메서드 단위로 적용할 수 있습니다.

1
@Protectable 지정
Java
@Service
public class DocumentService {

    @Protectable(ownerField = "createdBy")
    public Document getDocument(Long documentId) {
        return documentRepository.findById(documentId)
            .orElseThrow(() -> new NotFoundException("Document not found"));
    }

    @Protectable(ownerField = "createdBy")
    public void updateDocument(Long documentId, UpdateDocumentRequest req) {
        Document doc = documentRepository.findById(documentId)
            .orElseThrow(() -> new NotFoundException("Document not found"));
        doc.setTitle(req.getTitle());
        doc.setContent(req.getContent());
        documentRepository.save(doc);
    }
}

ownerField는 반환된 엔티티에서 소유자를 식별하는 필드 또는 getter 이름을 지정합니다. 이를 통해 리소스 소유자는 자신의 데이터에 언제나 접근할 수 있도록 소유권 기반 인가를 적용할 수 있습니다.

2
시작 시 MethodResourceScanner가 탐지

MethodResourceScanner는 모든 빈에서 @Protectable 애노테이션을 찾아 METHOD 타입 리소스로 등록합니다.

리소스 ID 클래스 메서드 타입
DocumentService.getDocument DocumentService getDocument METHOD
DocumentService.updateDocument DocumentService updateDocument METHOD
3
Policy Center에서 METHOD 리소스 검토

현재 OSS 관리자 경험에서는 METHOD 유형 리소스도 URL 리소스와 함께 Policy Center 리소스 영역에 표시됩니다. 라이프사이클도 동일합니다. 검토, 권한 정의, 정책 연결, 제외 흐름을 같은 방식으로 따릅니다.

4
소유권 + AI 조건을 포함한 Policy Center 작성 흐름

선택한 METHOD 리소스 맥락에서 정책 작성 흐름을 열고, 소유권 조건과 추가 조건을 함께 사용하는 정책을 만들 수 있습니다.

Policy Definition (Conceptual)
Policy: "Document Update - Owner or Admin"
  Target:   DocumentService.updateDocument
  Effect:   ALLOW
  Rules:
    Rule 1 (Owner Access):
      Condition: #ownership.isOwner(authentication, returnObject)
      Effect:    ALLOW
    Rule 2 (Admin Override):
      Condition: hasRole('ADMIN')
      Effect:    ALLOW
    Rule 3 (AI Risk Gate):
      Condition: #ai.isBlocked()
      Effect:    DENY (overrides all)

이 정책은 문서 소유자 또는 ADMIN에게 update 권한을 허용하지만, Zero Trust 액션이 BLOCK으로 해석되면 작업을 거부합니다.

5
동적 메서드 수준 인가 활성화

정책은 이제 메서드 수준에서 적용됩니다. updateDocument()가 호출되면 Contexa의 AOP 인터셉터가 메서드 실행 전에 정책을 평가합니다. 소유권은 authentication.getName()과 엔티티의 createdBy 필드를 비교해 판단합니다.

시나리오 3 — AI 보조 정책 작성

Contexa는 기존 역할, 권한, 조건 템플릿, 선택적 커스텀 SpEL을 조합해 정책 작성을 보조할 수 있습니다. OSS 코드 기준으로는 별도의 위협 점수 언어를 추가하는 것이 아니라, 보조 초안 생성과 승인 상태 처리로 이해하는 편이 정확합니다.

AI 기반 위험 분석

민감한 리소스에 대한 정책을 만들 때 AI 엔진은 다음 요소를 참고합니다.

  • 사용 가능한 역할과 권한 — Policy Center가 노출하는 기존 접근 엔터티
  • 타깃 리소스 메타데이터 — URL 또는 METHOD 타깃과 호환 가능한 조건 유형
  • 저장된 조건 템플릿 — 조건 카탈로그가 반환하는 재사용 가능한 SpEL 템플릿
  • 커스텀 조건 입력 — 관리자가 직접 작성한 customConditionSpel

조건 자동 추천

분석 결과를 바탕으로 AI는 정책에 적합한 조건을 추천합니다.

AI-Generated Recommendations
Resource: DELETE:/api/v1/customers/{id}
Draft summary: sensitive destructive endpoint

Recommended Conditions:
  1. Role restriction:     ADMIN only
  2. Time restriction:     Business hours (M-F 09:00-18:00)
  3. IP restriction:       Internal network only
  4. MFA requirement:      Step-up authentication required
  5. AI action gate:       #ai.hasActionIn('ALLOW', 'CHALLENGE')
  6. Rate limit:           Max 10 deletions per hour per user

Selected flow: assisted policy draft
Rationale: combine role, time, IP, and AI action checks for a high-risk target.
           maximum protection with multiple condition layers.

승인 워크플로

정책은 승인 상태를 가질 수 있습니다. 런타임 로더는 PENDINGREJECTED 정책을 건너뛰고, 승인된 정책 또는 승인 불필요 정책만 로드합니다.

AI 초안 / 보조 초안
source = AI_GENERATED or AI_EVOLVED
submit
승인 대기
approvalStatus = PENDING
approve
활성 정책
approvalStatus = APPROVED or NOT_REQUIRED

CustomDynamicAuthorizationManager는 승인 상태가 PENDING 또는 REJECTED인 정책을 평가에서 제외합니다. APPROVED 또는 NOT_REQUIRED 상태의 정책만 런타임 평가에 참여할 수 있습니다.

정책에서의 AI 표현식

승인된 이후 AI 조건은 런타임에서 다음과 같은 SpEL 표현식으로 평가됩니다.

Java (SpEL)
// Allow if AI determines the request is safe
#ai.isAllowed()

// Require step-up authentication if AI detects anomalies
#ai.needsChallenge()

// Action-based gating for threshold-like decisions
#ai.hasActionIn('ALLOW', 'CHALLENGE')

// Combined with traditional conditions
hasRole('ADMIN') and !#ai.isBlocked()

시나리오 4 — 정적 인가에서 동적 인가로 전환

이 시나리오는 20줄 이상의 하드코딩된 requestMatchers 구성을 Contexa의 동적 인가로 바꾸는 과정을 설명합니다.

이전: 정적 보안 구성

Java
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(auth -> auth
        .requestMatchers("/css/**", "/js/**", "/images/**").permitAll()
        .requestMatchers("/api/public/**").permitAll()
        .requestMatchers("/api/admin/users/**").hasRole("ADMIN")
        .requestMatchers("/api/admin/settings/**").hasRole("SUPER_ADMIN")
        .requestMatchers("/api/admin/audit/**").hasAuthority("VIEW_AUDIT")
        .requestMatchers("/api/reports/financial/**").hasAnyRole("ADMIN", "FINANCE")
        .requestMatchers("/api/reports/analytics/**").hasAnyRole("ADMIN", "ANALYST")
        .requestMatchers("/api/orders/**").hasAuthority("MANAGE_ORDERS")
        .requestMatchers("/api/customers/**").hasAuthority("MANAGE_CUSTOMERS")
        .requestMatchers("/api/products/**").hasAuthority("MANAGE_PRODUCTS")
        .requestMatchers("/api/inventory/**").hasAnyRole("ADMIN", "WAREHOUSE")
        .requestMatchers(HttpMethod.DELETE, "/api/**").hasRole("ADMIN")
        .requestMatchers(HttpMethod.PUT, "/api/users/*/role").hasRole("SUPER_ADMIN")
        // ... more rules
        .anyRequest().authenticated()
    );
    return http.build();
}
1
ResourceScanner 활성화 (자동 구성)

Contexa IAM 의존성을 추가하면 MvcResourceScanner가 자동 구성되어 시작 시 실행됩니다. 기존 엔드포인트가 자동으로 발견되고 리소스로 등록됩니다.

Java
// With the starter on the classpath, MVC and method resource scanners
// are auto-configured and populate managed resources at startup.
2
Policy Center에서 발견된 리소스 검토

관리자 콘솔의 Policy Center를 열고, 발견된 리소스를 검토합니다. 표시 이름을 확인하고, 필요한 리소스는 권한으로 정의하고, 공개로 남길 엔드포인트는 제외합니다. 이렇게 애플리케이션 전체 보호 표면을 인벤토리로 만들 수 있습니다.

3
권한 정의 및 정책 생성

각 리소스(또는 리소스 그룹)에 대해 Policy Center에서 동등한 동적 정책을 생성합니다. 기존 정적 규칙은 다음과 같이 매핑할 수 있습니다.

정적 규칙 동적 정책
.hasRole("ADMIN") Policy: roles=[ADMIN], effect=ALLOW
.hasAuthority("VIEW_AUDIT") Policy: permissions=[VIEW_AUDIT], effect=ALLOW
.hasAnyRole("ADMIN","FINANCE") Policy: roles=[ADMIN,FINANCE], effect=ALLOW

전환이 끝나면 시간 조건, IP 제한, AI 위험 판단과 같은 정적 구성으로는 어려운 조건을 즉시 추가할 수 있습니다.

4
정적 구성 교체

정적 보안 구성을 다음 한 줄 중심의 동적 구성으로 바꿉니다.

Java
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http,
        CustomDynamicAuthorizationManager customDynamicAuthorizationManager)
        throws Exception {
    http.authorizeHttpRequests(auth -> auth
        .requestMatchers("/css/**", "/js/**", "/images/**").permitAll()
        .requestMatchers("/api/public/**").permitAll()
        .anyRequest().access(customDynamicAuthorizationManager)
    );
    return http.build();
}

정적 matcher는 공개 리소스(정적 자산, 공개 API)처럼 정말로 공개여야 하는 영역에만 남기고, 나머지는 동적 인가 매니저에 위임합니다.

5
기본 정책 구성

명시적인 정책이 없는 리소스에 대한 기본 동작을 정합니다. 자세한 내용은 아래 기본 정책 관리 섹션을 참고하십시오.

기본 정책 관리

URL 요청이 어떤 정책과도 매칭되지 않으면 CustomDynamicAuthorizationManager.check(...)new AuthorizationDecision(true)를 반환합니다. 이것이 현재 OSS 코드 기준의 기본 동작입니다.

현재 기본 동작

Java
if (matchedDecisions.isEmpty()) {
    return new AuthorizationDecision(true);
}

Default Deny로 가는 방법

현재 OSS 코드에는 매칭되지 않는 URL 요청에 대한 전용 YAML 속성이 없습니다. Default Deny 방향으로 가려면 보호 대상 URL 공간에 대해 명시적인 catch-all DENY 정책을 만들거나, 코드를 통해 인가 매니저를 커스터마이즈해야 합니다.

아키텍처 심화

이 섹션은 HTTP 요청이 동적 인가 시스템을 통과하는 전체 라이프사이클을 설명합니다.

HTTP 요청
클라이언트에서 들어오는 요청
filter chain
PlatformSecurityConfig
정적 자산과 공개 API 같은 공개 리소스만 정적 matcher로 처리하고, 나머지 요청은 동적 인가 흐름으로 넘깁니다.
.anyRequest().access()
CustomDynamicAuthorizationManager
핵심 엔진입니다. 요청에 매칭되는 정책을 찾고 평가를 조율합니다.
find policies
PolicyRetrievalPoint (PRP)
DB에서 정책을 읽고 캐싱하며, 변경 시 hot-reload를 지원합니다.
evaluate conditions
표현식 평가 (SpEL + AI)
PolicyExpressionConverter가 저장된 규칙 표현식을 읽고, ExpressionAuthorizationManagerResolver가 이를 평가합니다. #ai.* 표현식은 현재 요청의 Zero Trust 액션 상태를 참조합니다.
decision
AuthorizationDecision
ALLOW 또는 DENY와 함께 상세한 판단 맥락을 포함합니다.
async
CentralAuditFacade
정책 서비스 이벤트와 거부된 URL 인가 결과를 요청, 결과, 위험 맥락과 함께 비동기로 기록합니다.

핵심 구성 요소

CustomDynamicAuthorizationManager

AuthorizationManager<RequestAuthorizationContext>를 구현합니다. 초기화 시 PolicyRetrievalPoint를 통해 활성 정책을 읽고, URL 패턴과 HTTP 메서드를 ExpressionAuthorizationManager에 매핑한 RequestMatcherEntry 목록을 구성합니다.

PolicyRetrievalPoint (PRP)

정책 데이터 접근 계층입니다. DB에서 정책을 읽고 캐시하며, Policy Center 또는 관련 관리자 서비스가 authorizationManager.reload()와 PRP 캐시 초기화를 호출할 때 다시 로드됩니다. 현재 OSS 문서 범위에서는 PRP가 별도의 이벤트 구독자로 정책 변경을 수신한다고 단정하지 않습니다.

PolicyExpressionConverter

저장된 정책 조건을 Spring Security가 사용하는 정규화된 SpEL 문자열로 변환합니다. Policy Center/관리자 흐름에서 관리되는 정책 정의와 런타임 표현식 평가 엔진 사이를 연결합니다.

CentralAuditFacade

CentralAuditFacade는 IAM 정책 서비스와 거부된 인가 처리 경로에서 함께 사용됩니다. URL 인가 경로에서는 거부 결과가 요청 경로와 매칭된 정책 맥락과 함께 기록되어 운영자가 적용 결과를 추적할 수 있습니다.

장점 요약

인가 관리 관점에서 기존 정적 구성과 Contexa 동적 인가를 비교한 표입니다.

항목 기존 Spring Security Contexa 동적 인가
정책 변경 코드 변경, 빌드, 재배포 관리자 화면에서 수정, 즉시 반영
배포 필요 여부 규칙 변경마다 필요 불필요 — DB 기반, 무중단
감사 추적 Git 커밋 이력 중심 CentralAuditFacade 기반 정책 서비스 이벤트 및 거부된 URL 감사 기록
AI 통합 불가 AI 위험 판단, 조건 추천, 정책 초안 생성
세분성 URL 패턴 + 역할/권한 검사 URL + 메서드 + 소유권 + 시간 + IP + AI + 커스텀 조건
관리 UI 없음 Policy Center(리소스 검토 + 빠른 생성/수동/AI 작성) + policydetails.html 상세 편집
리소스 발견 수동 인벤토리 시작 시 ResourceScanner가 자동 수집
메서드 수준 보안 @PreAuthorize에 하드코딩된 표현식 @Protectable + DB 기반 동적 정책
정책 관리 주체 개발자 중심 보안 관리자, 컴플라이언스 담당자, 개발자
새 엔드포인트 보호 시간 코드 + 리뷰 + 머지 + 배포(수시간~수일) 자동 발견 후 Admin UI에서 정책 생성(수분)
승인 워크플로 코드 리뷰(PR) 기반 DRAFT — PENDING — APPROVED 흐름 지원
롤백 Git revert + 재배포 관리자 화면에서 비활성화, 즉시 반영