반응형

Spring 연동 예제

build.gradle

extra["springCloudVersion"] = "2022.0.0"

dependencies {
	...
    implementation("org.springframework.cloud:spring-cloud-starter-vault-config")
}

dependencyManagement {
    imports {
        mavenBom("org.springframework.cloud:spring-cloud-dependencies:${property("springCloudVersion")}")
    }
}

application.yml

공통 설정

spring.cloud.vault:
  uri: http://192.168.56.11:8200 # vault 서버 주소
  token: hvs.EwyXMoRXoseiVXke0TdXiDYe # root_token
  connection-timeout: 5000
  read-timeout: 15000

option 1

  • vault://{engine_name}/{application_name}, vault://{engine_name}/{application_name}/{profile} 경로의 kv 값을 로딩
  • engine_name의 default 값은 secret
  • application_name의 default 값은 application
  • 아래처럼 설정 후 spring.profiles.active=local로 실행하면 가져오는 대상은 아래와 같음
    • vault://secret/application
    • vault://secret/application/local
    • vault://secret/demo
    • vault://secret/demo/local
spring.config.import: vault://
spring.application.name: demo

option 2

  • 아래처럼 설정 후 spring.profiles.active=local로 실행하면 가져오는 대상은 아래와 같음
    • vault://example/common
    • vault://example/common/local
    • vault://example/demo
    • vault://example/demo/local
spring.config.import: vault://
spring.cloud.vault:
  kv:
    enabled: true
    backend: example # engine_name
    default-context: common
    application-name: demo
    # profiles: local, dev
    # profile-separator: '/'

DemoController

@RestController
public class DemoController {
    @Value("${password}")
    private String password;

    @GetMapping("/api/password")
    public String getPassword() {
        return password;
    }
}

Spring 실행 후 확인

spring.profiles.active=local로 설정 & 실행 후 확인

Scheduler로 갱신하기 예제

설명

  • @Scheduled와 ContextRefresher를 활용하여 서버가 실행된 상태에서 재실행 없이 vault의 설정값을 갱신하는 예제.

DemoController

@RefreshScope // vault 설정값을 사용하는 클래스에 어노테이션 추가
@RestController
public class DemoController {
    @Value("${password}")
    private String password;

    @GetMapping("/api/password")
    public String getPassword() {
        return password;
    }
}

VaultRefreshScheduler

@Slf4j
@RequiredArgsConstructor
@EnableScheduling
@Component
public class VaultRefreshScheduler {
    // !!주의!! : ContextRefresher 객체를 주입받는 클래스에는 @RefreshScope를 붙이면 refresh() 실행시 hang이 걸림. 이유는 모름..
    private final ContextRefresher contextRefresher;

    @Scheduled(cron = "0/10 * * * * *") // 0초부터 10초마다 실행
    public void refresh() {
        log.info("refresh - start");
        log.info("refresh - changed : {}", contextRefresher.refresh());
        log.info("refresh - end");
    }
}

Vault 설정값 변경 & refresh 이후 설정값 변경 확인

password를 local-123456 -> local-123456-v2로 변경

Redis Pub/Sub으로 갱신하기 예제

설명

  • 스프링 서버가 실행될 때 Redis의 특정 topic을 구독하고, 해당 topic에 publish가 발생했을 때 서버의 설정값을 갱신하는 예제

gradle.build

dependencies {
    ...
    implementation("org.springframework.boot:spring-boot-starter-data-redis")
}

application.yml

spring.redis.host: localhost
spring.redis.port: 6379

RedisConfig

@Configuration
public class RedisConfig {
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer(
        RedisConnectionFactory connectionFactory,
        VaultRefreshListener vaultRefreshListener,
        ChannelTopic vaultRefreshTopic
    ) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.addMessageListener(vaultRefreshListener, vaultRefreshTopic);
        return container;
    }

    @Bean
    public ChannelTopic vaultRefreshTopic() {
        return new ChannelTopic("VAULT_REFRESH_TOPIC");
    }
}

VaultRefreshListener

@Slf4j
@RequiredArgsConstructor
@Component
public class VaultRefreshListener implements MessageListener {
    // 주의 : ContextRefresher 객체를 주입받는 클래스에는 @RefreshScope를 붙이면 refresh() 실행시 hang이 걸림. 이유는 모름..
    private final ContextRefresher contextRefresher;

    @Override
    public void onMessage(Message message, byte[] pattern) {
        String topic = new String(message.getChannel());
        String body = new String(message.getBody());
        log.info("refresh - start - topic : {}, body : {}", topic, body);
        log.info("refresh - changed : {}", contextRefresher.refresh());
        log.info("refresh - end");
    }
}

VaultRefreshController

@RequiredArgsConstructor
@RestController
public class VaultRefreshController {
    private final StringRedisTemplate redisTemplate;
    private final ChannelTopic vaultRefreshTopic;

    @GetMapping("/api/vault/refresh")
    public String refresh() {
        redisTemplate.convertAndSend(vaultRefreshTopic.getTopic(), "refresh");
        return "OK";
    }
}

실행 후 확인

  • 서버 실행시 VAULT_REFRESH_TOPIC을 구독
  • Vault Web UI에서 설정값 변경
  • /api/vault/refresh 호출시 VAULT_REFRESH_TOPIC에 발행
  • VAULT_REFRESH_TOPIC 발행이 일어났으므로 onMessage()에서 Vault 설정값 갱신 처리 수행
  • 갱신된 Vault 설정값을 활용

참고

 

반응형

'Development > Vault' 카테고리의 다른 글

[Vault] Secret Key 추가  (0) 2023.01.14
[Vault] Vault 설치  (0) 2023.01.14

+ Recent posts