In the traditional approach of configuration management, each application stores its own configurations. As the number of services grow managing application configurations can be a highly challenging task and prone to errors. A better way to manage configurations is through a centralized configuration server. Centralized configuration helps maintain all configurations at one single place, to fetch the configurations all other microservices communicate with the centralized configuration server.

In this article, we will learn how to set up a centralized configuration management server using Spring Cloud and HashiCorp Vault.

Image

Setup HashiCorp vault

HashiCorp Vault is a secure way to store sensitive information, it comes with role based controlled access, encryption, dynamic secrets etc. You can find more details here

As a quick start we can download the vault binary and run vault server -dev to start the vault server.
For production server follow this guide .

Once the vault server has started there will be a vault root token and unseal keys on the console. Make sure to back up those.

Now the server is up and running. It can be accessed on http://localhost:8200/. On the vault UI goto secret and create a new secret, add config-client as path and add config kv pair for password, url, username. Image

Setup Spring configuration server

  • Create a new spring cloud project config-server
  • Add spring-cloud-config-server dependency
  • On the application class add @EnableConfigServer annotation.
  • Update the following application properties, replace XXXX-XXXX-XXXX with the vault root token
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
spring.cloud.config.server:
  vault:
    port: 8200
    host: 127.0.0.1
    scheme: http
    authentication: TOKEN
    token: XXXX-XXXX-XXXX
    kv-version: 2
spring:
  profiles:
    active: vault
  application:
    name: config-server
server:
  port: 8888

This is it for setting up a configuration server, now run the config-server, we can also add more security like basic authentication to the config-server using spring security.

Setup Spring configuration client

A config client would consume configuration from a config-server. This will be any microservice that communicates with the server and fetch the latest configs.

  • Setup a spring cloud project config-client
  • Add spring-cloud-starter-config and spring-boot-starter-actuator
  • Add a DemoController to test our configuration
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.example.demo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RefreshScope
public class DemoController{

    @Value("${url}")
    String url;

    @Value("${username: n/a}")
    String username;

    @Value("${password}")
    String password;


    @GetMapping("/print-config")
    public String latestConfig(){
        System.out.println("Values :" + url+", "+username+", "+password);
        return "Values :" + url+", "+username+", "+password;
    }
}

  • Update the application properties
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19

spring:
  application:
    name: config-client
  profiles:
    active: default
  config:
    import: optional:configserver:http://localhost:8888
  cloud:
    config:
      label: config-client


management:
  endpoints:
    web:
      exposure:
        include:
          - refresh

To take care of config changes, we have enabled the refresh actuator, whenever a configuration value is changed in vault, invoke the refresh endpoint by POST http://localhost:8080/actuator/refresh, this will notify the config-client to fetch the latest updated values without the need to restart the application!!

Testing the application

Run the client. For now to print the config values at runtime, we have exposed GET endpoint http://localhost:8080/print-config. A GET to endpoint /print-config in postman, will print the config values in the application console.

If we update the value in the vault, in this example, update password from password123456 to password123 and trigger refresh endpoint POST http://localhost:8080/actuator/refresh.

The application will now use the latest value password123. To verify this we can print the values once again by doing a GET on /print-config.

Image