
이러한 기능중에서 유연성, 안정성, 보안성 향상을 위하여 설정의 집중화를 구현하는 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
참고 설정 및 소스
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#/src/main/resources/applicaiton.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} | |
encrypt: | |
keyStore: | |
location: classpath:/key/server.jks | |
password: ***** | |
alias: studiokey | |
secret: ***** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
description = "studio-config server" | |
bootJar { enabled = true } | |
println " build ${description} using spring boot ${springBootVersion} (${buildApplicationVersion})" | |
println " Spring Cloud Version : ${springCloudVersion} , sourceCompatibility : ${sourceCompatibility}" | |
println " ----------------------------------------------------" | |
jar { | |
enabled = true | |
manifest { | |
attributes('Implementation-Title': 'STUDIO CONFIG', 'Implementation-Version': '1.0.0' ) | |
} | |
} | |
configurations { | |
compileOnly { | |
extendsFrom annotationProcessor | |
} | |
} | |
repositories { | |
mavenCentral() | |
} | |
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}" | |
} | |
} | |
tasks.named('test') { | |
useJUnitPlatform() | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// /src/main/java/architecture/studio/config/ConfigServer.java | |
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
springBootVersion=2.7.18 | |
springDependencyManagementVersion=1.1.4 | |
springCloudVersion=2021.0.8 | |
sourceCompatibility=11 | |
junitJupiterVersion=5.10.1 |
댓글 없음:
댓글 쓰기