본문 바로가기!

Vault/Spring

[Vault] (Spring Cloud Config - 1 ) Server + Vault 연동하기

728x90
반응형

Spring Cloud Config Server는 분산 시스템에서 중앙 집중식 설정 관리를 가능하게 해주는 도구로, 

애플리케이션 설정을 Git, Vault 등의 외부 저장소에서 관리하여, 이를 Spring Boot 기반의 클라이언트 애플리케이션이 가져와서 사용할 수 있도록 구성할 수 있습니다.

 

이번 글에서는 Spring Cloud Config Server와 HashiCorp Vault(HCP Vault)를 연동하여, 보안이 필요한 설정 값을 안전하게 관리하는 방법을 설명합니다.

또한, Spring Cloud Config Client가 설정 값을 어떻게 가져와서 애플리케이션에서 활용할 수 있는지도 함께 다뤄보겠습니다.

 

 

1.   Vault 구성

Vault는 비밀번호, API 키, 인증 정보 등의 보안 데이터를 저장하고 관리하는 강력한 도구입니다.

Vault는 설치형(On-Premise)으로 사용할 수도 있고, HCP(HashiCorp Cloud Platform) Vault(SaaS)를 사용하여 관리형 서비스로 운영할 수도 있습니다.

 

필자의 경우 HCP Vault(SaaS)를 사용하여 설정 값을 저장하고 관리하는 방식을 선택했습니다. 

 

1-1)  KV(Key-Value) 엔진 구성

  • 1) KV V2 시크릿 엔진 활성화를 진행합니다.
vault login <your-root-token>  # Vault 로그인 (토큰 사용)
export VAULT_NAMESPACE=admin  # 네임스페이스 설정

vault secrets enable -path=spring-config-kv -version=2 kv
  • vault secrets enable : 새로운 시크릿 엔진을 활성화하는 명령어
    • -version=2 : Key-Value Version 2(KV V2) 엔진을 활성화합니다.
    • kv : 사용하려는 시크릿 엔진 유형이 Key-Value(kv)임을 명시합니다.
    • -path=spring-config-kv : 시크릿 엔진을 spring-config-kv라는 경로(path)에 마운트합니다.

 

  • 환경별 시크릿 저장합니다. (dev, local, prod)
# dev 환경
vault kv put spring-config-kv/spring/dev \
    db_url="jdbc:mysql://dev-db-url" \
    username="dev-username" \
    password="dev-password"
    
# local 환경
vault kv put spring-config-kv/spring/local \
    db_url="jdbc:mysql://local-db-url" \
    username="local-username" \
    password="local-password"
    
# prod 환경  
vault kv put spring-config-kv/spring/prod \
    db_url="jdbc:mysql://prod-db-url" \
    username="prod-username" \
    password="prod-password"
  • vault kv put <경로> <키>=<값> : Vault KV V2 시크릿 엔진에 데이터를 저장하는 명령어
    • spring-config-kv/spring/dev  spring-config-kv 경로 아래 spring/dev 위치에 시크릿 저장합니다.
    • db_url="<DB URL 기입>" :  db_url 값을 저장합니다.
    • password="<DB 패스워드 기입>"password 값을 저장합니다.
    • username="<DB User 이름 기입>"username 값 저장합니다.

 

  • 저장된 시크릿 조회 예시) (dev)
$ vault kv get spring-config-kv/spring/dev

========== Secret Path ==========
spring-config-kv/data/spring/dev

======= Metadata =======
Key                Value
---                -----
created_time       2025-03-08T09:38:55.872151421Z
custom_metadata    <nil>
deletion_time      n/a
destroyed          false
version            1

====== Data ======
Key         Value
---         -----
db_url      jdbc:mysql://dev-db-url
password    dev-password
username    dev-username

 

 

 

 

2.   Spring Cloud Config Server 구성

Spring Cloud Config Server는 HashiCorp Vault와 연결되어 클라이언트 애플리케이션에 필요한 설정 값을 제공하는 역할을 합니다.

 

2-1) Gradle 의존성 (dependencies 설정)

Gradle 기반의 Spring Boot 프로젝트를 생성하고, build.gradle.kts에 아래와 같이 의존성을 추가합니다.

dependencies {
    // Spring Cloud Config Server
    implementation("org.springframework.cloud:spring-cloud-config-server")

    // Spring Cloud Vault
    implementation("org.springframework.cloud:spring-cloud-starter-vault-config")

    // Kotlin 필수 설정
    implementation("org.jetbrains.kotlin:kotlin-reflect")
}
  • implementation("org.springframework.cloud:spring-cloud-config-server")
    • Spring Cloud Config Server를 활성화하는 라이브러리
  • implementation("org.springframework.cloud:spring-cloud-starter-vault-config")
    • HashiCorp Vault와 Spring Cloud Config Server 간 연동을 위한 라이브러리

 

 

2-2)  Config Server 애플리케이션 코드 작성 (KotlinGradleVaultApplication.kt)

package com.example.kotlin_gradle_vault

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.cloud.config.server.EnableConfigServer

@SpringBootApplication
@EnableConfigServer
class KotlinGradleVaultApplication

fun main(args: Array<String>) {
    runApplication<KotlinGradleVaultApplication>(*args)
}
  • @EnableConfigServer
    • Spring Cloud Config Server를 활성화하는 어노테이션
    • 이 설정을 통해 Spring Cloud Config Server가 활성화되며, Vault에서 설정 값을 가져올 수 있도록 동작하게 됩니다.

 

2-3)  application.yml 설정

Vault와 연동하여 설정 값을 가져오기 위해 Spring Cloud Config Server의 설정 파일을 구성합니다.

server:
  port: 8888

spring:
  application:
    name: spring-config-server
  profiles:
    active: vault
  cloud:
    config:
      server:
        vault:
          fail-fast: true                  # Vault 연결 실패 시 서버 시작 차단
          host: {vault hostname 기입}
          port: 8200
          namespace: {vault namespace 기입}
          authentication: token
          token: {vault token 기입}         # Vault 접근 토큰
          kv-version: 2
          backend: spring-config-kv        # Vault의 KV 엔진 경로
          profile-separator: '/'
          scheme: https
  • server.port: 8888
    • Spring Cloud Config Server가 포트 8888에서 실행됩니다.
  • spring.profiles.active: vault
    • Vault를 설정 저장소로 사용하도록 프로파일 활성화합니다.
  • spring.cloud.config.server.vault.fail-fast: true
    • Vault 연결 실패 시 서버 시작을 차단 합니다.
    • (설정 값을 필수로 가져와야 할 경우 유용합니다.)
  • spring.cloud.config.server.vault.host: {vault hostname}
  • spring.cloud.config.server.vault.port: 8200
  • spring.cloud.config.server.vault.namespace: {vault namespace 기입}
  • spring.cloud.config.server.vault.authentication: token
  • spring.cloud.config.server.vault.token: {vault token 기입}
    • Vault 서버 정보를 정의합니다.
      • 호스트네임 또는 IP,  포트 번호, 네임스페이스(HCP Vault 사용 시 필수) 등을 기입합니다.
  • spring.cloud.config.server.vault.kv-version: 2
    • Vault에서 사용되는 Key-Value (KV) 엔진의 버전을 기입합니다. (V2 사용)
  • spring.cloud.config.server.vault.backend: spring-config-kv
    • Vault에서 설정 값을 저장하는 KV 엔진의 마운트 경로입니다
  • spring.cloud.config.server.vault.profile-separator: '/'
    • Vault에서 프로파일별 설정을 구분하는 구분자 (spring/prod 형식으로 저장됨) 를 설정합니다.
  • spring.cloud.config.server.vault.scheme: https
    • Vault와의 통신 방식을 정의합니다. (HTTPS 사용)

 

 

2-4)  Spring Cloud Config Server 실행

  • ./gredlew clean bootRun 명령어를 통해 Config Server를 실행합니다.

 

  • Vault에서 Config Server가 설정을 가져오는 과정을 확인합니다.

  • propertySourcesvault:spring/dev에서 가져온 설정이 포함되어 확인 가능합니다.
  • db_url, username, password 등의 정보가 정상적으로 Vault에서 가져와졌음을 확인 가능합니다.

 

 

 

개인 정리

최종 테스트에서는 KV mount를 spring-config-kv로 설정하고, spring/dev 밑에 KV를 저장하는 방식을 사용하여 Config Server에서 spring/dev 경로로 값을 가져오도록 진행했으나, KV mount를 spring-test로 하고, ops 밑에 직접 KV를 저장했을 때는 ops/default 경로에서 값을 정상적으로 가져올 수 있었음.. ( localhost:8888/ops/default -- 이런 호출 방식으로 진행 )

 

정리하자면....

Spring Cloud Config Server의 프로퍼티 매핑 방식은 다음과 같다고 한다... (URL 참고)

  • Config Server는 설정 값을 {application}/{profile}/{label} 형태로 매핑하여 제공
    • {application} : spring.application.name (애플리케이션 이름)
    • {profile}spring.profiles.active (현재 활성화된 프로필)
    • {label} : 기본적으로 master (Git 레이블이나 브랜치)

즉, 내가 application.yml에 backend를 spring-config-kv로 설정해놨기에,

http://localhost:8888/spring/prod 로 호출을 하면 spring-config-kv/spring/prod에서 데이터를 가져옴!

 

 

Vault KV Mount 및 Profile Path의 차이점 (테스트 결과)

1. KV Mount를 spring-config-kv로 설정하고, spring/prod 경로로 KV 저장한 경우

  • Vault 경로 : spring-config-kv/spring/prod
  • Config Server 요청 : http://localhost:8888/spring/prod
  • 정상적으로 값을 가져올 수 있음

2. KV Mount를 spring-test로 설정하고, ops에 직접 KV 저장한 경우

  • Vault 경로: spring-test/ops
  • Config Server 요청: http://localhost:8888/ops/default
  • ops/default에서 값을 가져와야 정상적으로 동작

 

Config Server는 spring/{profile} 형태로 경로를 찾지만, Vault는 KV Mount마다 다른 접근 방식을 요구할 수 있음!!

KV Mount 이름과 Config Server의 Profile 구조가 정확히 일치해야 예상한 대로 설정이 로딩되며, 필요에 따라 profile-separator, default-context 설정을 조정할 필요가 있음

 

 

728x90
반응형