Skip to content

[발전 방안 제안(Improvement Plan)]: SPI 기반 통합 감사·보안 로깅 시스템 #191

@ryudg

Description

@ryudg

아이디어명 Idea Name

SPI 기반 통합 감사·보안 로깅 시스템

아이디어 요약 Idea Summary

현재 전자정부 표준프레임워크 4.3.0의 로깅 모듈에 SPI(Service Provider Interface) 기반 감사 추적, 보안 이벤트 로깅, 개인정보 접근 기록 관리 기능을 확장 제공.

라이브러리 특성에 맞춰 표준 인터페이스와 기본 구현체를 제공하고, 각 기관에서 정책에 맞는 구현체를 XML 설정으로 연결하여 정부 감사 요구사항을 안전하고 유연하게 충족.

제안배경 Suggestion Background

[분석 - 코드 검증 결과]

  1. 로깅 모듈 기능 공백

    • 현재 org.egovframe.rte.fdl.logging 모듈은 기본 로깅만 제공
    • 정부 시스템 필수 요구사항인 감사·보안·개인정보 접근 로깅 기능 부재
    • 각 기관에서 동일 기능을 중복 개발하여 품질 편차 발생
  2. 품질 관리 체계 미흡

    • 다수 모듈에서 <skipTests>true</skipTests> 설정으로 테스트 비활성화
    • 품질 검증 없이 배포되는 코드의 안정성 우려
    • CI/CD 파이프라인에서 결함 탐지 불가능
  3. 정부 규제 대응 부족**(예측)**

    • 개인정보보호법 제29조(안전조치의무) 위반 가능성
    • 전자정부법 제56조(정보시스템 감사) 요구사항 미충족 가능성
    • 정보통신망법 접속기록 보관 의무 미준수 가능성

[라이브러리 특성 고려사항]

  1. 라이브러리 vs 애플리케이션 구분
    • 현재 프로젝트는 애플리케이션이 아닌 라이브러리/런타임 제공이 목적
    • XML 기반 설정과 Spring Framework 5.3.37 환경
    • 각 기관의 다양한 정책과 인프라에 대한 유연한 확장성 필요

기대효과 Expectations

표준 API 제공: 감사·보안·개인정보 접근 로깅을 위한 일관된 SPI/인터페이스 제시
확장 용이성: 기본 구현 제공 + 기관별 어댑터 교체 가능 구조
운영 안정성 지원: 비즈니스 로직과 로그 저장을 분리하고 실패 격리를 고려한 설계 방향
보안·규제 대응 지원: 민감정보 마스킹 SPI 제공, 접근 이력 기록을 위한 어노테이션 제공
도입 용이성: XML 설정 예시와 최소한의 변경으로 점진적 적용 가능

자유기술 Free Writing

1. 핵심 설계 철학

egovframe-rte-fdl-logging (확장)
  ├── 표준 인터페이스 (SPI)       ← 라이브러리가 제공
  ├── 기본 구현체 (NOP/SLF4J)    ← 즉시 사용 가능
  ├── 확장 포인트 (어댑터)        ← 각 기관에서 구현
  └── XML 설정 예제             ← 가이드 제공

SPI(Service Provider Interface) 원칙:

  • 라이브러리: 계약과 기본 구현만 제공 (애노테이션 최소화)
  • 애플리케이션: XML 설정으로 정책에 맞는 구체 구현 선택
  • 확장성: 기존 의존성만 사용하여 안정성 확보

2. 패키지 구조 (하위 호환성 고려)

org.egovframe.rte.fdl.logging
  ├── audit/                           # 신규: 감사 로깅 SPI
  │   ├── AuditEvent.java              # 표준 감사 이벤트 인터페이스
  │   ├── DefaultAuditEvent.java       # 기본 이벤트 구현체
  │   ├── AuditSink.java               # SPI: 감사 저장 인터페이스
  │   ├── CompositeAuditSink.java      # 복수 저장소 지원
  │   ├── Slf4jAuditSink.java          # 기본: SLF4J 출력
  │   ├── annotation/
  │   │   └── EgovAuditable.java       # 선언적 감사 어노테이션
  │   └── advisor/
  │       └── AuditAdvisor.java        # AOP 어드바이저
  ├── security/                        # 신규: 보안 이벤트
  │   ├── SecurityEvent.java           # 보안 이벤트 DTO
  │   ├── SecurityEventSink.java       # SPI: 보안 이벤트 저장
  │   └── annotation/
  │       └── EgovSecurityAuditable.java
  ├── privacy/                         # 신규: 개인정보 접근
  │   ├── PrivacyAccessEvent.java      # 개인정보 접근 이벤트
  │   ├── PrivacyAccessSink.java       # SPI: 개인정보 로그 저장
  │   └── annotation/
  │       └── EgovPrivacyAccess.java
  ├── context/                         # 신규: 요청 컨텍스트
  │   ├── RequestContextAccessor.java  # SPI: 사용자/세션 정보 접근
  │   └── ServletRequestContextAccessor.java # 서블릿 구현체
  └── util/                            # 신규: 유틸리티
      ├── SensitiveDataMasker.java     # SPI: 민감정보 마스킹
      └── DefaultSensitiveDataMasker.java # 기본 마스킹 구현

3. 핵심 SPI 인터페이스

3.1 감사 이벤트 계약

// 최소 인터페이스만 제시 (필드는 기관별로 확장 가능)
public interface AuditEvent {
  String getAction();
  DataSensitivity getSensitivity();
  boolean isSuccess();
}

public interface AuditSink {
  void accept(AuditEvent event);
}

public enum DataSensitivity { PUBLIC, INTERNAL, PERSONAL, SENSITIVE }

※ 상세 구현체와 빌더는 샘플로 별도 제공.

3.2 요청 컨텍스트 SPI

// 환경 추상화 인터페이스만 제시 (구현은 선택)
public interface RequestContextAccessor {
  String getCurrentUserId();
  String getClientIp();
  String getSessionId();
}

※ 서블릿/보안 연동 구현은 선택 사항이며 샘플로 별도 제공.

4. 어노테이션 기반 선언적 감사

4.1 감사 어노테이션

// 최소 속성만 선언 (나머지는 구현에서 선택)
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EgovAuditable {
  String action();
  DataSensitivity sensitivity() default DataSensitivity.PUBLIC;
}

※ 개인정보 접근 기록용 @EgovPrivacyAccess는 목적·대상 식별 중심으로 간단 선언(코드 생략).

4.2 AOP 어드바이저 구현

/**
 * 감사 로깅 AOP 어드바이저
 * Spring AOP를 통한 투명한 감사 이벤트 생성
 */
public class AuditAdvisor {
  public Object auditableMethod(ProceedingJoinPoint pjp) throws Throwable { /* ... */ }
}

5. 기본 구현 방향

  • 기본 저장소 예시: SLF4J 로거 사용(구현은 기관별로 대체 가능)
  • 민감정보 마스킹: 정규식 기반의 단순 마스킹 전략 제공(교체 가능 SPI)
  • 복수 저장소: 컴포지트 패턴으로 병렬 전송 가능(에러 격리 권장)

6. XML 기반 설정

<!-- META-INF/spring/context-audit.xml (요약 예시) -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/aop   http://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

  <context:property-placeholder location="classpath*:egovframe-audit.properties"/>

  <bean id="servletRequestContextAccessor"
        class="org.egovframe.rte.fdl.logging.context.ServletRequestContextAccessor"/>

  <bean id="defaultSensitiveDataMasker"
        class="org.egovframe.rte.fdl.logging.util.DefaultSensitiveDataMasker"/>

  <bean id="slf4jAuditSink"
        class="org.egovframe.rte.fdl.logging.audit.Slf4jAuditSink"/>

  <bean id="auditAdvisor"
        class="org.egovframe.rte.fdl.logging.audit.advisor.AuditAdvisor">
    <constructor-arg ref="slf4jAuditSink"/>
    <constructor-arg ref="servletRequestContextAccessor"/>
    <constructor-arg ref="defaultSensitiveDataMasker"/>
  </bean>

  <aop:config>
    <aop:aspect ref="auditAdvisor">
      <aop:around pointcut="@annotation(org.egovframe.rte.fdl.logging.audit.annotation.EgovAuditable)"
                  method="auditableMethod"/>
    </aop:aspect>
  </aop:config>

</beans>

7. Properties 설정 지원

# egovframe-audit.properties
# 감사 로깅 기본 설정 (현재 환경 호환)

# 감사 로깅 활성화
egovframe.audit.enabled=true

# 민감정보 마스킹 설정
egovframe.audit.masking.enabled=true

# 로그 출력 설정
egovframe.audit.slf4j.audit-logger=egov.audit
egovframe.audit.slf4j.security-logger=egov.security

# 성능 모니터링 (밀리초)
egovframe.audit.performance.slow-query-threshold-ms=1000
egovframe.audit.performance.log-execution-time=true

# 보관 정책 (일 단위)
egovframe.audit.retention.days=180
egovframe.audit.retention.archive-enabled=true

8. 사용 예시

8.1 비즈니스 서비스에 적용

// 서비스 메서드에 어노테이션으로 감사 로그 생성
@EgovAuditable(action = "USER_SEARCH", sensitivity = DataSensitivity.PERSONAL)
public List<User> searchUsers(String keyword) { /* ... */ }

// 개인정보 접근 기록용 어노테이션
@EgovPrivacyAccess(dataType = "사용자 상세정보", purpose = "업무 처리")
public UserDetail getUserDetail(String userId) { /* ... */ }

8.2 각 기관별 확장 구현 예시

// 기관별 구현 예시: SPI 구현체로 DB 저장
public class DatabaseAuditSink implements AuditSink {
  public void accept(AuditEvent event) { /* 기관 스키마에 맞게 저장 */ }
}
<!-- 기관 확장 예시 -->
<bean id="databaseAuditSink" class="com.agency.logging.DatabaseAuditSink"/>
<bean id="auditAdvisor">
  <constructor-arg ref="databaseAuditSink"/>
  <!-- 나머지 인자 생략 -->
</bean>

9. 테스트 아이디어

  • 어노테이션 적용 메서드 호출 시 AuditSink.accept가 한 번 호출되는지 검증
  • 민감정보 마스킹 실행 시 주민번호/전화/카드번호가 마스킹되는지 검증

10. 마이그레이션 가이드

10.1 단계적 적용 방안 (최소 위험)

<!-- 1단계: 기본 설정만 추가 -->
<import resource="classpath:META-INF/spring/context-audit.xml"/>

<!-- 2단계: 기존 서비스에 어노테이션 적용 -->
<!-- 코드 변경 없이 어노테이션만 추가 -->

<!-- 3단계: 기관별 구현체 개발 및 적용 -->
<!-- DatabaseAuditSink, ElasticsearchAuditSink 등 -->

<!-- 4단계: 모니터링 및 대시보드 구축 -->
<!-- 별도 관리 애플리케이션에서 구현 -->

10.2 기존 시스템과의 호환성

  • 기존 로깅: 유지
  • 성능 영향: 어노테이션 없는 메서드는 영향 없음
  • 설정 충돌: 독립적인 XML 네임스페이스 사용
  • 의존성 추가: 현재 프로젝트 라이브러리만 사용

참고문헌 Reference

  1. Spring Framework 5.3 AOP Documentation
  2. AspectJ 1.9 Documentation
  3. SLF4J Manual
  4. Spring Framework 5.3: Externalized Properties
  5. Spring Framework 5.3: TestContext Framework
  6. Mockito Documentation
  7. JUnit 4 Documentation
  8. OWASP Logging Cheat Sheet

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions