지난 블로그에서 주요 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 생성확인
Spring Boot의 auto-configuration은 추가한 jar 파일에 맞게 application.yaml에 설정값만 입력해 주면 자동적으로 설정을 해준다.
예를들면 application.yaml 파일에 JDBC 설정을 해주면 자동으로 DataSource를 만들어주는 것이 좋은 예이다.
현재 어떤 Auto-configuration이 적용되어있는지 알고 싶다면 Log를 debug로 실행시키면 확인할 수 있다.
로그에서 "CONDITIONS EVALUATION REPORT"의 아랫부분을 보면 DataSourceAutoConfiguration의 Auto-configuration을 진행하는 것을 알 수 있다.(빨간색 박스)
이 부분을 Exclude 하는 설정을 1.2에서 진행한다.
우리는 그동안 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:" 부분이 제거된 것을 확인할 수 있다.
지난 블로그에도 있는 내용이지만 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()
}
새로운 "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;
}
}
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);
}
}
상기 "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;
}
}
Springboot를 기동하면 아래와 같이 DataSource가 생성되는 것을 확인할 수 있다.
The End~~~!!!