이러한 기능중에서 유연성, 안정성, 보안성 향상을 위하여 설정의 집중화를 구현하는 Spring Cloud Config는 애플리케이션의 설정을 외부화하고 중앙에서 관리할 수 있게 한다. 이를 통해 설정 변경을 용이하게하고 여러 환경 간에 설정을 공유할 수 있다.
Config Server 구성하기
◼︎ 환경
- Model : MacBook Pro (14-inch, 2021)
- CPU : Apple M1 Pro
- MENORY : 16GB
- DISK : 512 GB SSD
- OS : macOS 13.2.4 (22F66)
- TOOLS : Visual Studio Code, Java 11, Gradle, Docker
- Version Control : GitHub
- Programming Language : Java
- Framework : Spring Boot 2.7.12, Spring Security 5.7.7
- DBMS : MySql 8.0.33
- Cloud : Oracle Cloud Free Tier
① Gradle
brew 을 이용하여 gradle 을 설치한다.
# brew update
# brew install gradle
# gradle init --type java-application
Select build script DSL:
1: Kotlin
2: Groovy
Enter selection (default: Kotlin) [1..2] 2
Select test framework:
1: JUnit 4
2: TestNG
3: Spock
4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4] 4
Project name (default: studio-config):
Enter target version of Java (min. 7) (default: 21): 11
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] yes
> Task :init
To learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.6/samples/sample_building_java_applications.html
BUILD SUCCESSFUL in 2m 17s
1 actionable task: 1 executed
다음으로 build.gradle 파일에 org.springframework.cloud:spring-cloud-config-server 의존성을 추가한다.
build.gradle
dependencies {
implementation 'org.springframework.cloud:spring-cloud-config-server'
// lombok
implementation 'org.projectlombok:lombok'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
// test
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
springCloudVersion 속성은 gradle.properties 에 정의했다.
springBootVersion=2.7.18
springDependencyManagementVersion=1.1.4
springCloudVersion=2021.0.8
sourceCompatibility=11
가장 어려웠던 부분이 spring cloud version 을 확인하는것 과정이었다.
마지막으로 @EnableConfigServer 을 구현하는 서버 소스를 추가한다. (소스는 ② 생성되는 코드들을 참고했다)package architecture.studio.config;
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication@EnableConfigServerpublic class ConfigServer {
public static void main(String[] args) { SpringApplication.run(ConfigServer.class, args); }
}
② Spring Initializer
package architecture.studio.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
public static void main(String[] args) {
SpringApplication.run(ConfigServer.class, args);
}
}
config server 의존성을 선택하여 새로운 config server 프로젝트를 생성한다. (2.x 버전은 지원하지 않고 있다.)
Config Server 프로젝트 생성
이미 프로젝트가 존재했고 해당 프로젝트에서 config 을 분리하는 것으로 목표로 했기 때문에 ① 방식을 참고하여 서브 프로젝트를 추가하고 생성된 프로젝트에 설정을 추가하는 방식으로 구현했다.
존재하는 spring boot 프로젝트에 config-server 를 추가하는 경우는 "Supported Versions" 참고하여 호환되는 Spring Cloud 버전을 확인 하려 하였으나 https://spring.io/projects/spring-cloud 문서가 더 도움이 되었다. 문서에 따르면 2.6.x, 2.7.x 버전은 2021.0.x aka Jubilee 버전이 지원하고 있다.
2021.0 정보는 https://github.com/spring-cloud/spring-cloud-release/wiki/Spring-Cloud-2021.0-Release-Notes 확인 가능한데 2024년 2월 기준으로 '2021.0.8' 이 가장 최신이다. 이제 해당 버전으로 의존성를 추가한다.
설정정보 저장소
대부분의 자료들이 github 을 저장소로 사용하여 config server 을 구성하고 있는데 로컬 파일을 사용하는 방식으로 구성했다. 로컬 파일들은 jar 파일에 포함되어 배포 될수 있도록 src/main/resources/config 경로에 [application]-[profile].yml 규칙으로 생성하였다. 주의 할것은 이 파일들은 "--" 문자를 포함하면 오류가 발생한다.
config server 에 대한 설정은 application.yml 에 아래와 같이 설정하였다.
application.yml
---
logging:
level:
root: debug
---
server:
port: 8888
spring:
application:
name: studio-config
profiles:
active: native
cloud:
config:
server:
native:
searchLocations: classpath:/config, classpath:/config/{application},
classpath:/config/{application}/{profile}
웹 브라우져에서 http://localhost:8888/[application]/[profile] 형식으로 호출하여 프로파일에 따른 설정을 확인할 수 있다.
암호화
비밀번호와 같은 중요 정보들을 암호화하여 설정 파일을 구성하기 위한 목적으로 Config Server 가 제공하는 암호화 기능을 사용하였다
Config Server 는 암호화 구현을 위하여 대칭(공유) 키 또는 비대칭 키(RSA 키 쌍)를 사용하여 할 수 있다. 비대칭 키가 보안 측면에서 더 우수하지만, 대칭 키 방식은 application.yml(application.properties) 파일에 에 대칭 키 문자 하나만 설정하면 되기 떄문에 더 편리하다고 할 수 있다.
대칭 키를 설정은 encrypt.key 에 개인 키 암호를 설정해야 한다. (또는 ENCRYPT_KEY 환경 변수를 사용하여 값을 지정하는 방법도 있다.)
비대칭 키 방식은 keystore (JDK 에 포함된
keytool
유틸리티로 생성) 을 사용하는 이유에서 아래 설정들이 필요하다.- encrypt.keyStore.location : keyStore 파일 위치
- encrypt.keyStore.password : KeyStore 파일에 접근을 위한 비빌번호
- encrypt.keyStore.alias : KeyStore 내의 엔트리를 식별하는 고유한 이름. KeyStore는 공개 키, 개인 키 쌍 및 이에 대한 인증서를 저장하는 데 사용되는데, 이러한 엔트리는 각각 고유한 이름인 alias로 식별됨
※KeyStore에 저장되는 개별 항목을 "엔트리(entry)"라고 한다. 이 엔트리는 주로 공개 키와 개인 키 쌍과 그에 대응하는 인증서를 포함한다.
KeyStore 를 생성하고 비대칭키를 설정하는 것은 "Spring Cloud Config - Creating a Key Store for Testing" 참고했다.
참고로 긴 기간동안 키가 유효하도록 아래와 같이 10년동안 유효하게 키 스토어를 생성했다.
참고로 긴 기간동안 키가 유효하도록 아래와 같이 10년동안 유효하게 키 스토어를 생성했다.
keytool -genkeypair -alias testalias -keyalg RSA -keysize 2048 \
-dname "CN=ConfigServer, OU=none, O=none, L=none, ST=none, C=KR" \
-keystore server.jks -keypass testkeypass \
-storepass teststorepass -validity 3650
생성된 키는 src/main/resources/key 경로에 복사하고 아래와 같이 application.yml 파일에 설정을 추가했다.
application.yml
keyStore:
location: classpath:/key/server.jks
password: *****
alias: studiokey
secret: *****
application.yml
spring:
datasource:
url: "{cipher}AQCnTtoaV9juWvUutYNWNVyx9Bd+E9zUf+Mf1"
username: "{cipher}AQCHbvX1Sa9VyjTfaFLP2uSesfTCe0Wn"
password: "{cipher}AQBUIaBt+nzhl+mbyOlSb5MStLWkvZ1wjW2iwByefg34aLs="
암호화
암호화를 위한 키 설정을 하고 나면 ConfigServer 가 제공하는 암호화와 복호화를 RESTful API 을 호출하여 데이터를 암호화 하고 값을 {cipher} 을 접두사로 하여 application.yml 파일에 값을 수정한다.
curl -X POST \
-H "Content-Type: application/json" \
-d 'jdbc:mysql://xxx.xxx.xxx:3306/xxxdb?serverTimezone=Asia/Seoul' \
http://localhost:8888/encrypt
복호화 역시 동일한 방법으로 /decrypt 를 호출하면 된다.
Config Server 에서 설정 불러오기
Spring boot 프로그램에서 앞에서 생성한 Config Server 에서 설정을 읽어드리도록 하려면 ❶ Config Server 의 경우와 같이 org.springframework.cloud:spring-cloud-config-server 의존성을 추가하고 ❷
Config Server 에서 설정을 읽어드리도록 application.yml 설정을 추가한다.
/application.yml
추가로 dev , prod 프로파일을 application.yml 이 아닌 테스트를 위하여 프로그램을 실행 할 떄 prod 인자를 사용하여 개발 과 운영 모드로 동작할 수 있도록 아래와 같은 설정을 build.gradle 에 추가하였다. 이를 통하여 개발과 운영을 동일한 코드로 구현하고 테스트를 위하여 프로그램을 실행할 떄 프로파일을 인자로 넘겨서 처리하도록 할 수 있었다.
build.gradle
logging:
level:
root: INFO
spring:
application:
name: studio
config:
import: optional:configserver:http://localhost:8888
추가로 dev , prod 프로파일을 application.yml 이 아닌 테스트를 위하여 프로그램을 실행 할 떄 prod 인자를 사용하여 개발 과 운영 모드로 동작할 수 있도록 아래와 같은 설정을 build.gradle 에 추가하였다. 이를 통하여 개발과 운영을 동일한 코드로 구현하고 테스트를 위하여 프로그램을 실행할 떄 프로파일을 인자로 넘겨서 처리하도록 할 수 있었다.
build.gradle
tasks.named("bootRun") {
if (project.hasProperty('profile')) {
jvmArgs = ["-Dspring.profiles.active=${project.getProperty('profile')}"]
}
}
./gradlew bootRun -Pprofile=dev
locathost:8888/studio/dev 에 해당하는 /config/studio-dev.yml 을 읽어드림.
./gradlew bootRun -Pprofile=prod
./gradlew bootRun -Pprofile=prod
댓글 없음:
댓글 쓰기