Springboot 구동시 AWS Secret을 조회하여 Datasource 생성

David Jeon·2024년 1월 2일
1
post-thumbnail

지난 블로그에서 주요 DB Connection 정보, Key 정보 등을 AWS의 Secret Manager 서비스를 이용하는 것을 살펴봤다.

Secret Manager 연동 블로그 : https://velog.io/@hyjeon316/Java%EB%A1%9C-AWSSDK%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-AWS-Secret-%EC%A1%B0%ED%9A%8C

이번 블로그에서는 Springboot 구동시 AWS Secret을 조회하여 Datasource 생성되도록 구현하는 방법을 설명하고자 한다.
이전 블로그의 작업이 완료된 상태에서 설명을 이어서 진행한다.

<개발 환경>
개발 OS : Windows
Java : 17
IDE : 인텔리제이
Cloud : AWS

<사전작업 - 지난 블로그 참조>
1) Secret 생성
2) Access token 생성하여 Local PC에 AWS Configure 등록
3) Springboot 프로젝트 생성

<작업 순서>
1) DataSourceAutoConfiguration 중지 설정
2) Springboot Project gradle 설정
3) SecretManagerConfig Class 구현
4) DBConnectionInfo Class 구현
5) MyDataSourceConfiguration Class 구현
6) Springboot Project를 시작하여 DataSource 생성확인

1. DataSourceAutoConfiguration 중지 설정

1.1 DataSourceAutoConfiguration 기본 설정

Spring Boot의 auto-configuration은 추가한 jar 파일에 맞게 application.yaml에 설정값만 입력해 주면 자동적으로 설정을 해준다.
예를들면 application.yaml 파일에 JDBC 설정을 해주면 자동으로 DataSource를 만들어주는 것이 좋은 예이다.

현재 어떤 Auto-configuration이 적용되어있는지 알고 싶다면 Log를 debug로 실행시키면 확인할 수 있다.
로그에서 "CONDITIONS EVALUATION REPORT"의 아랫부분을 보면 DataSourceAutoConfiguration의 Auto-configuration을 진행하는 것을 알 수 있다.(빨간색 박스)

이 부분을 Exclude 하는 설정을 1.2에서 진행한다.

1.2 DataSourceAutoConfiguration 중지 설정

우리는 그동안 JDBC 설정값을 추가했지만 본 블로그에서는 AWS의 Secret에서 조회한 정보를 이용하여 DataSource를 생성할 것이기 때문에 Auto-configuration을 진행을 제외하는 설정을 application.yaml에 추가하기만 하면 된다.

application.yaml

logging:
  level:
    root: debug

spring:
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
  • 실행 화면


이전 로그에서 "DataSourceAutoConfigration matched:" 부분이 제거된 것을 확인할 수 있다.

2. Springboot Project gradle 설정

지난 블로그에도 있는 내용이지만 Springboot 프로젝트를 생성후 아래와 같이 Gradle 설정을 해주면 AWSSDK를 사용할 수 있다.

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.0'
    id 'io.spring.dependency-management' version '1.1.4'
}

group = 'com.sample.aws'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.0'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation platform('software.amazon.awssdk:bom:2.21.44')
    implementation 'software.amazon.awssdk:secretsmanager'
    implementation 'software.amazon.awssdk:regions'
    implementation 'org.apache.commons:commons-lang3:3.14.0'
    compileOnly 'org.projectlombok:lombok'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    runtimeOnly 'org.postgresql:postgresql'
}

tasks.named('test') {
    useJUnitPlatform()
}

3. SecretManagerConfig Class 구현

새로운 "dev.secret.database" Secret을 만들고 소스에 적용한다.
Secret 생성 방법 : https://velog.io/@hyjeon316/Java%EB%A1%9C-AWSSDK%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%98%EC%97%AC-AWS-Secret-%EC%A1%B0%ED%9A%8C

package com.sample.aws.secretmanager.config.aws;

import lombok.extern.slf4j.Slf4j;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.secretsmanager.SecretsManagerClient;
import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueRequest;
import software.amazon.awssdk.services.secretsmanager.model.GetSecretValueResponse;
import software.amazon.awssdk.services.secretsmanager.model.SecretsManagerException;

@Slf4j
public class SecretManagerConfig {
    private String databaseSecretName = "dev.secret.database";

    public String getDBConnectionInfo() {
        String secret = "";
        Region region = Region.AP_NORTHEAST_2;
        SecretsManagerClient secretsClient = SecretsManagerClient.builder()
                .region(region)
                .build();

        try {
            log.info("Secret Name = [{}]", databaseSecretName);
            GetSecretValueRequest valueRequest = GetSecretValueRequest.builder()
                    .secretId(databaseSecretName)
                    .build();

            GetSecretValueResponse valueResponse = secretsClient.getSecretValue(valueRequest);
            secret = valueResponse.secretString();
            // log.info(secret);

        } catch (SecretsManagerException e) {
            log.warn(e.awsErrorDetails().errorMessage());
        } catch (Exception e) {
            log.warn(e.getMessage());
        }

        return secret;
    }
}

4. DBConnectionInfo Class 구현

DB Connection 정보를 Object로 변환하기 위해 Object Class를 구현한다.

package com.sample.aws.secretmanager.config.domain;

import lombok.Getter;
import lombok.Setter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

@Setter
@Getter
public class DBConnectionInfo {

    private String username;
    private String password;
    private String engine;
    private String host;
    private int port;
    private String dbname;

    public String toStringJson() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
    }
}

5. MyDataSourceConfiguration Class 구현

상기 "1.2" 설정을 통해 Springboot가 기동되면서 Property 파일 설정에 의해 자동으로 생성되는 부분을 막았고 AWS Secret에서 조회한 DB 정보를 이용하여 DataSource 생성하는 소스를 구현한다.

package com.sample.aws.secretmanager.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sample.aws.secretmanager.config.aws.SecretManagerConfig;
import com.sample.aws.secretmanager.config.domain.DBConnectionInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

@Slf4j
@Configuration(proxyBeanMethods = false)
public class MyDataSourceConfiguration {

    @Bean
    @Primary
    public DataSourceProperties dataSourceProperties() throws Exception{
        log.info("Start generating a Datasource Using AWS Secret Manager.");
        DataSourceProperties dataSourceProperties = new DataSourceProperties();
        SecretManagerConfig secretManagerConfig = new SecretManagerConfig();
        String secretDBConnectionInfo = secretManagerConfig.getDBConnectionInfo();

        ObjectMapper objectMapper = new ObjectMapper();
        DBConnectionInfo dbConnectionInfo = objectMapper.readValue(secretDBConnectionInfo, DBConnectionInfo.class);
        log.info(dbConnectionInfo.toStringJson());
        dataSourceProperties.setUrl("jdbc:postgresql://"+ dbConnectionInfo.getHost()+":"+dbConnectionInfo.getPort()+"/"+dbConnectionInfo.getDbname());
        dataSourceProperties.setUsername(dbConnectionInfo.getUsername());
        dataSourceProperties.setPassword(dbConnectionInfo.getPassword());
        log.info("Datasource is generated.");
        return dataSourceProperties;
    }
}

6. Springboot 기동

Springboot를 기동하면 아래와 같이 DataSource가 생성되는 것을 확인할 수 있다.

The End~~~!!!

profile
코딩이 즐거운 아저씨

0개의 댓글