Skip to content

Feature: RDBMS 관리 기능 구현#180

Merged
KwonSunJae merged 21 commits intodevelopfrom
feature/179
Dec 31, 2025
Merged

Feature: RDBMS 관리 기능 구현#180
KwonSunJae merged 21 commits intodevelopfrom
feature/179

Conversation

@hyobin-yang
Copy link

@hyobin-yang hyobin-yang commented Dec 18, 2025

[Phase 1] RDBMS 포트 및 모델 정의 구현

📋 개요

AWS RDS 자원 관리 기능 구현의 Phase 1로, 헥사고날 아키텍처를 준수하여 CSP(Cloud Service Provider) 비종속적인 포트 인터페이스와 도메인 모델을 정의했습니다.

🎯 구현 목표

  • CSP 비종속성: AWS, Azure, GCP 등 다양한 클라우드 프로바이더를 동일한 인터페이스로 지원
  • 헥사고날 아키텍처 준수: 포트와 어댑터를 명확히 분리하여 도메인 로직과 인프라 의존성 분리
  • 확장성: providerSpecificConfig를 통한 CSP별 특화 설정 지원

📦 구현 내용

1. Command 모델 정의 (port/model/rdbms/)

1.1 RdbmsCreateCommand

RDBMS 인스턴스 생성을 위한 도메인 커맨드입니다. CSP 중립적인 필드를 사용하여 모든 클라우드 프로바이더를 동일한 인터페이스로 지원합니다.

주요 추상화 전략:

CSP 중립적 필드 AWS Azure GCP
instanceName dbInstanceIdentifier serverName instanceId
instanceSize db.t3.micro GP_Gen5_2 db-custom-2-7680
networkSecurityId securityGroupId firewallRule authorizedNetworks
zone availabilityZone zone zone
highAvailability multiAz highAvailability highAvailability

핵심 필드:

  • engine: 데이터베이스 엔진 타입 (mysql, postgresql, mariadb, oracle, sqlserver)
  • allocatedStorage: 스토리지 크기 (GB) - 모든 CSP 공통 단위
  • providerSpecificConfig: CSP별 특화 설정을 위한 확장 포인트
    • AWS: subnetGroupName, parameterGroupName
    • Azure: resourceGroupName, sku
    • GCP: databaseFlags, backupConfiguration

설계 고려사항:

  • CSP 공통 개념은 중립적 필드로 추상화
  • CSP 특화 기능은 providerSpecificConfig로 확장 가능
  • JIT 세션 관리 패턴을 위한 CloudSessionCredential 포함

1.2 RdbmsUpdateCommand

RDBMS 인스턴스 수정을 위한 도메인 커맨드입니다. 인스턴스 크기, 스토리지, 패스워드 등 변경 가능한 속성만 포함합니다.

주요 필드:

  • instanceSize: 인스턴스 크기 변경 (CSP 중립적)
  • allocatedStorage: 스토리지 크기 변경 (GB)
  • adminPassword: 관리자 패스워드 변경 (선택적)
  • applyImmediately: 즉시 적용 여부 (일부 CSP만 지원)
  • providerSpecificConfig: CSP별 특화 수정 옵션

설계 고려사항:

  • 수정 가능한 속성만 포함하여 불필요한 필드 제거
  • CSP별 지원 여부 차이는 providerSpecificConfig로 처리

1.3 RdbmsDeleteCommand

RDBMS 인스턴스 삭제를 위한 도메인 커맨드입니다. 스냅샷, 백업 등 삭제 관련 옵션을 포함합니다.

주요 필드:

  • skipSnapshot: 최종 스냅샷 건너뛰기 (AWS 특화, 다른 CSP는 providerSpecificConfig로)
  • snapshotName: 최종 스냅샷 이름 (선택적)
  • deleteAutomatedBackups: 자동 백업 삭제 여부
  • providerSpecificConfig: CSP별 특화 삭제 옵션

설계 고려사항:

  • AWS 특화 기능(skipSnapshot)도 포함하되, 주석으로 다른 CSP 처리 방법 명시
  • CSP별 차이는 providerSpecificConfig로 확장 가능

1.4 RdbmsQuery

RDBMS 인스턴스 목록 조회를 위한 쿼리 모델입니다. 페이징, 필터링 기능을 제공합니다.

주요 필드:

  • regions: 조회할 리전 목록 (null이면 모든 리전)
  • instanceName: 인스턴스 이름으로 필터링 (CSP 중립적)
  • engine: 엔진 타입으로 필터링
  • instanceSize: 인스턴스 크기로 필터링 (CSP 중립적)
  • status: 상태로 필터링 (CSP별 상태 값 다를 수 있음)
  • tagsEquals: 태그로 필터링
  • page, size: 페이징 정보

편의 메서드:

  • all(): 모든 인스턴스 조회
  • byInstanceName(): 특정 이름으로 조회
  • byEngine(): 특정 엔진 타입으로 조회
  • byStatus(): 특정 상태로 조회

설계 고려사항:

  • CSP별 상태 값 차이는 Adapter에서 처리
  • 페이징은 Spring Data의 Page 인터페이스와 호환

2. Port 인터페이스 정의 (port/outbound/rdbms/)

헥사고날 아키텍처의 핵심인 포트 인터페이스를 정의했습니다. 포트는 도메인과 외부 시스템 간의 **계약(Contract)**을 정의하며, CSP별 구현은 Adapter에서 담당합니다.

2.1 RdbmsManagementPort

역할: RDBMS 인스턴스의 CRUD 작업을 담당하는 포트입니다.

책임:

  • RDBMS 인스턴스 생성 (createRdbms)
  • RDBMS 인스턴스 수정 (updateRdbms)
  • RDBMS 인스턴스 삭제 (deleteRdbms)

특징:

  • 모든 메서드는 Command 객체를 받아 도메인 중심 설계
  • 반환 타입은 CloudResource로 통일하여 일관성 유지
  • 세션 자격증명은 Command 내부에 포함되어 JIT 패턴 준수

2.2 RdbmsDiscoveryPort

역할: RDBMS 인스턴스의 조회/탐색 기능을 담당하는 포트입니다.

책임:

  • RDBMS 인스턴스 목록 조회 (listRdbmsInstances)
  • 특정 RDBMS 인스턴스 조회 (getRdbmsInstance)
  • RDBMS 인스턴스 상태 조회 (getInstanceStatus)

특징:

  • 조회 작업은 읽기 전용이므로 @Transactional(readOnly = true) 적용 가능
  • 페이징을 위해 Spring Data의 Page<CloudResource> 반환
  • 단건 조회는 Optional<CloudResource>로 null 안전성 보장
  • 세션 자격증명을 명시적으로 전달하여 JIT 패턴 준수

2.3 RdbmsLifecyclePort

역할: RDBMS 인스턴스의 생명주기 관리(시작/중지/재시작)를 담당하는 포트입니다.

책임:

  • ResourceLifecyclePort를 확장하여 일반적인 리소스 생명주기 관리 기능 상속
    • 리소스 시작 (start(ResourceIdentity, CloudSessionCredential))
    • 리소스 중지 (stop(ResourceIdentity, CloudSessionCredential))
    • 리소스 종료 (terminate(ResourceIdentity, CloudSessionCredential))
  • RDBMS 특화 기능 추가
    • RDBMS 인스턴스 재시작 (rebootInstance(String, CloudSessionCredential))

특징:

  • ResourceLifecyclePort를 확장하여 인터페이스 계층 구조 명확화
  • 일반적인 리소스 생명주기 관리는 부모 인터페이스의 메서드 사용
  • RDBMS 특화 기능인 reboot만 추가로 제공
  • reboot는 OS 레벨 재부팅으로 stop + start보다 빠르고 안전
  • CSP별 지원 여부는 Capability 시스템에서 검증

🔄 Phase 2: AWS RDS 어댑터 구현

Phase 1에서 정의한 포트 인터페이스를 구현하는 AWS RDS 어댑터를 구현했습니다.

1. AWS RDS 어댑터 구현 (adapter/outbound/aws/rds/)

1.1 AwsRdsConfig

역할: AWS RDS 클라이언트를 생성하는 설정 클래스입니다.

주요 기능:

  • 세션 자격증명 기반 RDS 클라이언트 생성
  • JIT 패턴 준수: 요청별로 클라이언트 생성 및 종료
  • 리전 처리: 명시적 리전 전달 또는 세션 리전 사용
  • 세션 검증: AWS 세션 자격증명 유효성 검증

설계 특징:

  • @ConditionalOnProperty로 AWS 활성화 여부에 따라 빈 생성 제어
  • 세션 만료 검증 및 타입 검증 포함
  • 리전 기본값 처리 (null이면 us-east-1)

1.1.1 AwsS3Config 리팩토링

역할: AWS S3 설정 클래스를 JIT 세션 관리 패턴으로 리팩토링했습니다.

리팩토링 배경:

  • AwsRdsConfig와 일관된 패턴 유지
  • JIT 세션 관리 패턴 적용으로 멀티 테넌트 환경 지원 강화

1.2 AwsRdsMapper

역할: AWS SDK의 DBInstance 객체를 도메인 모델인 CloudResource로 변환하는 매퍼입니다.

1.3 AwsRdsManagementAdapter

역할: RDBMS 인스턴스의 생성, 수정, 삭제 기능을 제공하는 어댑터입니다.

구현된 기능:

1. createRdbms (인스턴스 생성)

  • RdbmsCreateCommandCreateDbInstanceRequest 변환
  • CSP 중립 필드 → AWS 특화 필드 매핑:
    • instanceNamedbInstanceIdentifier
    • instanceSizedbInstanceClass
    • networkSecurityIdvpcSecurityGroupIds
    • zoneavailabilityZone
    • highAvailabilitymultiAZ
  • 인스턴스 생성 후 available 상태까지 대기 (최대 30분)
  • 생성된 인스턴스를 AwsRdsMapper를 통해 CloudResource로 변환하여 반환

2. updateRdbms (인스턴스 수정)

  • RdbmsUpdateCommandModifyDbInstanceRequest 변환
  • 수정 가능한 필드만 변환: instanceSize, allocatedStorage, adminPassword, applyImmediately
  • 수정 후 available 상태까지 대기
  • 수정된 인스턴스를 CloudResource로 변환하여 반환

3. deleteRdbms (인스턴스 삭제)

  • RdbmsDeleteCommandDeleteDbInstanceRequest 변환
  • 삭제 옵션 처리: skipSnapshot, snapshotName, deleteAutomatedBackups
  • 삭제는 비동기로 진행되므로 대기하지 않음

주요 특징:

  • 모든 작업은 세션 자격증명을 사용하여 요청별로 RDS 클라이언트 생성
  • 작업 완료 후 클라이언트 자동 종료 (try-finally)
  • 에러 발생 시 CloudErrorTranslator를 통한 통일된 예외 처리
  • waitForInstanceAvailable 메서드로 인스턴스 상태 대기 (폴링 간격: 30초)

1.4 AwsRdsDiscoveryAdapter

역할: RDBMS 인스턴스의 조회/탐색 기능을 제공하는 어댑터입니다.

구현된 기능:

1. listRdbmsInstances (인스턴스 목록 조회)

  • RdbmsQueryDescribeDbInstancesRequest 변환
  • 쿼리 조건에 따른 필터링:
    • instanceName: dbInstanceIdentifier로 필터링
    • engine: 엔진 타입으로 필터링
    • instanceSize: dbInstanceClass로 필터링
    • status: dbInstanceStatus로 필터링
  • 페이징 처리: Spring Data Page 인터페이스 반환
  • 조회된 인스턴스들을 AwsRdsMapper를 통해 CloudResource로 변환

2. getRdbmsInstance (특정 인스턴스 조회)

  • 인스턴스 ID로 단건 조회
  • Optional<CloudResource> 반환으로 null 안전성 보장
  • Availability Zone에서 리전 추출

3. getInstanceStatus (인스턴스 상태 조회)

  • 인스턴스 ID로 상태만 조회
  • AWS 상태 문자열 그대로 반환

주요 특징:

  • executeWithRdsClient 헬퍼 메서드로 클라이언트 생성/종료 자동화
  • 리전 처리: 쿼리의 첫 번째 리전 사용 또는 null 처리
  • 에러 발생 시 CloudErrorTranslator를 통한 통일된 예외 처리

1.5 AwsRdsLifecycleAdapter

역할: RDBMS 인스턴스의 생명주기 관리(시작/중지/재시작) 기능을 제공하는 어댑터입니다.

구현된 기능:

1. start (인스턴스 시작) - ResourceLifecyclePort 구현

  • ⚠️ 제한사항: AWS RDS는 EC2와 달리 인스턴스를 시작/중지할 수 없습니다
  • UnsupportedOperationException 발생
  • RDS 인스턴스는 항상 실행 중이거나 중지된 상태로만 존재
  • ResourceIdentity를 통해 리소스 정보 전달

2. stop (인스턴스 중지) - ResourceLifecyclePort 구현

  • StopDbInstanceRequest 생성 및 실행
  • RDS 인스턴스 중지 지원 (일부 엔진만 지원)
  • ResourceIdentity를 통해 리소스 정보 전달

3. terminate (인스턴스 종료) - ResourceLifecyclePort 구현

  • RDS의 경우 terminate는 RdbmsManagementPort.deleteRdbms()를 통해 처리해야 함
  • UnsupportedOperationException 발생하여 명시적으로 처리 방법 안내

4. rebootInstance (인스턴스 재시작) - RdbmsLifecyclePort 추가 기능

  • RebootDbInstanceRequest 생성 및 실행
  • RDS 인스턴스 재시작 지원
  • OS 레벨 재부팅으로 stop + start보다 빠르고 안전한 재시작 제공

주요 특징:

  • RdbmsLifecyclePort를 구현하여 ResourceLifecyclePort의 모든 기능 상속
  • 모든 작업은 세션 자격증명을 사용하여 요청별로 RDS 클라이언트 생성
  • 작업 완료 후 클라이언트 자동 종료
  • 에러 발생 시 CloudErrorTranslator를 통한 통일된 예외 처리

아키텍처 개선:

  • RdbmsLifecyclePortResourceLifecyclePort를 확장하여 일반적인 리소스 생명주기 관리 기능 상속
  • RDBMS 특화 기능인 reboot만 추가로 제공하여 인터페이스 계층 구조 명확화

2. DTO 클래스 구현 (dto/)

Controller 계층에서 사용하는 요청/응답 DTO 클래스들을 구현했습니다.

2.1 RdbmsCreateRequest

역할: RDBMS 인스턴스 생성을 위한 요청 DTO입니다.

2.2 RdbmsUpdateRequest

역할: RDBMS 인스턴스 수정을 위한 요청 DTO입니다.

2.3 RdbmsDeleteRequest

역할: RDBMS 인스턴스 삭제를 위한 요청 DTO입니다.

2.4 RdbmsQueryRequest

역할: RDBMS 인스턴스 목록 조회를 위한 요청 DTO입니다.

2.5 RdbmsResponse

역할: RDBMS 인스턴스 정보를 반환하는 응답 DTO입니다.

3. 의존성 추가 (pom.xml)

AWS RDS SDK 의존성을 추가했습니다.

<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>rds</artifactId>
</dependency>

✅ 체크리스트

Phase 1

  • Command 모델 정의 (Create, Update, Delete, Query)
  • Port 인터페이스 정의 (Management, Discovery, Lifecycle)
  • CSP 비종속적 필드 추상화
  • providerSpecificConfig 확장 포인트 제공
  • JIT 세션 관리 패턴 준수
  • 헥사고날 아키텍처 원칙 준수

Phase 2

  • AwsRdsConfig 구현 (RDS 클라이언트 생성)
  • AwsRdsMapper 구현 (AWS SDK ↔ CloudResource 변환)
  • AwsRdsManagementAdapter 구현 (CRUD 작업)
  • AwsRdsDiscoveryAdapter 구현 (조회 작업)
  • AwsRdsLifecycleAdapter 구현 (생명주기 관리)
  • DTO 클래스 구현 (Request/Response)
  • pom.xml에 AWS RDS SDK 의존성 추가
  • AwsS3Config 리팩토링 (JIT 세션 관리 패턴 적용)
  • RdbmsLifecyclePort 구조 개선 (ResourceLifecyclePort 확장)
  • RdbmsController에 감사 로깅 추가
  • ObjectStorageController 감사 로깅 리소스 타입 통일 (CLOUD_PROVIDER 사용)

🔒 감사 로깅 적용

배경

RDBMS 인스턴스 관리 작업에 대한 보안 감사 및 컴플라이언스를 위해 감사 로깅을 추가했습니다. ObjectStorageController와 동일한 패턴을 적용하여 일관된 감사 로깅 정책을 유지합니다.

변경 사항

1. AuditResourceType 통일

변경 전:

  • OBJECT_STORAGE_CONTAINER: Object Storage Container 전용 리소스 타입
  • RDBMS_INSTANCE: RDBMS 인스턴스 전용 리소스 타입 (신규 추가 예정)
  • S3_BUCKET: S3 버킷 전용 리소스 타입

변경 후:

  • 모든 클라우드 리소스는 CLOUD_PROVIDER 리소스 타입 사용
  • 리소스별 타입 제거 (OBJECT_STORAGE_CONTAINER, RDBMS_INSTANCE, S3_BUCKET)

변경 이유:

  • 클라우드 리소스가 늘어날수록 AuditResourceType enum에 필드가 과도하게 증가하는 문제 방지
  • 클라우드 리소스는 모두 동일한 감사 정책을 적용하므로 통합된 리소스 타입 사용이 적절
  • action 필드로 구체적인 작업을 구분할 수 있어 리소스 타입 분리가 불필요

영향받는 파일:

  • AuditResourceType.java: OBJECT_STORAGE_CONTAINER, RDBMS_INSTANCE, S3_BUCKET 제거
  • ObjectStorageController.java: 모든 @AuditRequiredresourceTypeCLOUD_PROVIDER로 변경
  • RdbmsController.java: 모든 @AuditRequiredresourceTypeCLOUD_PROVIDER로 변경

2. RdbmsController 감사 로깅 추가

추가된 감사 로깅:

메서드 Action Severity Request Data Response Data 설명
listRdbmsInstances LIST_RDBMS_INSTANCES LOW RDBMS 인스턴스 목록 조회
getRdbmsInstance GET_RDBMS_INSTANCE LOW RDBMS 인스턴스 상세 조회
createRdbms CREATE_RDBMS_INSTANCE HIGH RDBMS 인스턴스 생성
updateRdbms UPDATE_RDBMS_INSTANCE HIGH RDBMS 인스턴스 수정
deleteRdbms DELETE_RDBMS_INSTANCE CRITICAL RDBMS 인스턴스 삭제
startInstance START_RDBMS_INSTANCE MEDIUM RDBMS 인스턴스 시작
stopInstance STOP_RDBMS_INSTANCE MEDIUM RDBMS 인스턴스 중지
rebootInstance REBOOT_RDBMS_INSTANCE MEDIUM RDBMS 인스턴스 재시작
getInstanceStatus GET_RDBMS_INSTANCE_STATUS LOW RDBMS 인스턴스 상태 확인

데이터 포함 정책:

  • 생성/수정: 요청 데이터와 응답 데이터 모두 포함 (변경 내용 추적)
  • 삭제: 요청 데이터만 포함 (응답은 없음)
  • 조회/상태 확인: 요청 데이터만 포함 (응답 데이터는 대용량일 수 있음)

3. 보안 및 안전성 보장

원본 데이터 보호:

  • 감사 로깅은 원본 요청/응답 데이터를 변경하지 않음
  • MaskingService.toMaskedJson()은 깊은 복사본을 생성하여 마스킹 처리
  • 비즈니스 로직에 영향을 주지 않음

민감 정보 자동 마스킹:

  • password, pwd, pass***
  • token, jwt, auth, key***
  • secretkey, secret_key → 마스킹
  • accountscope, account_scope → 마스킹
  • email, phone, ssn 등 → 부분 마스킹

비동기 처리:

  • DB 저장은 @Async로 비동기 처리되어 성능 영향 최소화
  • 로깅 실패가 비즈니스 로직에 영향을 주지 않음

예외 처리:

  • 감사 로깅 중 예외 발생 시에도 원본 메서드 실행은 정상 진행
  • 로깅 실패는 로그로만 기록되고 사용자 요청은 실패하지 않음

참고 사항

  1. 기존 감사 로깅 시스템 활용

    • 기존에 구축된 @AuditRequired 어노테이션 기반 감사 로깅 시스템을 그대로 활용
    • 추가 설정이나 인프라 변경 없이 어노테이션만 추가하여 적용
  2. ObjectStorageController와의 일관성

    • ObjectStorageController와 동일한 패턴으로 구현
    • 리소스 타입도 CLOUD_PROVIDER로 통일하여 일관성 유지
  3. 확장성

    • 향후 다른 클라우드 리소스 컨트롤러에도 동일한 패턴으로 감사 로깅 추가 가능
    • CLOUD_PROVIDER 리소스 타입을 사용하여 enum 확장 없이 적용 가능

🔐 adminPassword 암호화 보안 구현

배경

RDBMS 인스턴스 생성 및 수정 시 전달되는 adminPassword는 민감한 정보이므로, 로그 파일 유출 및 메모리 덤프 공격으로부터 보호하기 위해 암호화 처리를 적용했습니다.

구현 내용

1. Service 계층에서 암호화

RdbmsUseCaseService에서 EncryptionService를 사용하여 adminPassword를 암호화합니다.

특징:

  • RdbmsCreateCommandRdbmsUpdateCommand에는 암호화된 값이 전달됨
  • 평문 패스워드는 Service 계층에서만 존재하고, Command에는 암호화된 값만 전달
  • 암호화 실패 시 CloudErrorCode.ENCRYPTION_FAILED 예외 발생

2. Adapter 계층에서 복호화

AwsRdsManagementAdapter에서 AWS SDK로 전달하기 직전에 복호화합니다.

특징:

  • AWS SDK로 전달하기 직전에만 복호화하여 평문 노출 시간 최소화
  • 복호화 실패 시 CloudErrorCode.DECRYPTION_FAILED 예외 발생
  • 복호화된 패스워드는 AWS SDK 요청에만 사용되고 즉시 GC 대상이 됨

3. 로깅 시 마스킹 처리

원본 데이터 보호:

  • 로깅 시 LogMaskingUtils.maskSensitiveData()를 사용하여 민감 정보 마스킹
  • 원본 요청 객체는 변경하지 않고, 마스킹된 문자열만 로그에 출력

마스킹 규칙:

  • password, pwd, pass***
  • token, jwt, auth, key***
  • secretkey, secret_key → 마스킹

보안상 이점

1. 로그 파일 보호 (가장 큰 이점)

  • ✅ 로그 파일에 평문 패스워드가 저장되지 않음
  • ✅ 감사 로그, 애플리케이션 로그, 에러 로그에서 평문 노출 방지
  • ✅ 로그 파일 유출 시에도 패스워드 노출 없음

2. 메모리 덤프 시 부분적 보호

  • ✅ Command 객체에 암호화된 값이 저장됨
  • ✅ 메모리 덤프 시 평문보다는 암호문이 노출됨
  • ⚠️ 한계: 복호화 키가 있으면 복호화 가능 (키 관리 중요)

3. 레이어 간 전달 보호

  • ✅ Service → Command → Adapter 전달 과정에서 암호화된 값 전달
  • ✅ 같은 JVM 내부이지만 레이어 간 전달 시 암호화된 형태로 전달

- RdbmsManagementPort 인터페이스 구현
- createRdbms: 인스턴스 생성 및 available 상태 대기
- updateRdbms: 인스턴스 수정 (크기, 스토리지, 패스워드)
- deleteRdbms: 인스턴스 삭제 (스냅샷 옵션 지원)
- Command → AWS SDK Request 변환 로직
- CSP 중립 필드를 AWS 특화 필드로 매핑"
@hyobin-yang hyobin-yang self-assigned this Dec 18, 2025
@KwonSunJae KwonSunJae merged commit 6e282c5 into develop Dec 31, 2025
3 checks passed
@KwonSunJae KwonSunJae deleted the feature/179 branch December 31, 2025 14:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants