Using Vault as a backing store Config Server

Using Vault as a Config Server Backend

The Spring Cloud Services tile provides platform users the ability to provision their own Config Server for use in a Spring Boot Application. The most common use case for the backing store of these config servers is a git repository. On occasion, it is necessary to encrypt these configuration values when at rest and in transport, and a more secure back-end than git is required.

Config Server instances can also be backed by Vault, a secure secret store. This recipe will discuss the configuration changes required for code in order to work with a Vault back-end.

Create the service instance

Just as with regular config server instances, create the vault-back-end service as follows:

cf create-service p-config-server standard my-config-server -c ./configServerConfig.json

the parameter passed to the -c flag indicates the location of the configuration file, in JSON. An example is below:

{
  "vault" :
  {
    "host":"vault.pcfbeta.io",
    "port":80,
    "backend":"secret",
    "defaultKey":"cook"
  }
}

This JSON should be self-explanatory. The configuration for the vault node is the location of the vault server and the backend/Key to use when accessing secrets.

The next step is to modify the application to be aware of the configuration values. First, add a section like the following to your bootstrap.yml:

spring:
  application:
    name: cook
  profiles:
    active: default
  cloud:
    config:
      token: <valid-token>

The spring.application.name needs to match the defaultKey portion of the config server instance. Also, the active profiles needs to include default as that is the default vault configuration. Lastly, the cloud.config.token will be provided to you by your vault administrator. This is what allows the application to access the vault secret store.

The service instance created above will need to be bound to the application. This can be accomplished through either an entry in the manifest.yml file or via the command line.

In order for the auto-reconfiguration to take place and wire the config server for the application, the following must exist in the maven pom.xml:

  <dependency>
    <groupId>io.pivotal.spring.cloud</groupId>
    <artifactId>spring-cloud-services-starter-config-client</artifactId>
  </dependency>

This imports the necessary spring libraries to perform the auto-reconfiguration if the config server instance exists in VCAP_SERVICES.

It is important to note the connection to the configuration server is over https. If the certificate for the api for the foundation is self-signed, or if certificate authorities are not available, then we will have to import this certificate to a local JVM trust store. This can be easily accomplished through the Java BuildPack by simply setting the TRUST_CERTS environment variable to the api endpoint:

cf set-env <app name> TRUST_CERTS api.run.haas-156.pez.pivotal.io

and restage the application.

Secrets can be input into vault in using a simple command line interface, or HTTP REST calls. For example, to add a secret the following command can be executed:

curl -H "X-Vault-Token: fab6876c-536c-e7c2-1f8c-b008859a8056" -H "Content-Type: application/json" -X POST -d '{"chicken":"Rips"}' http://vault.cfapps.haas-156.pez.pivotal.io/v1/secret/cook

The X-Vault-Token value will again be provided by your vault administrator. The JSON value of the -d parameter is the name/value pair being written to the secret/cook location, as matched in our bootstrap.yml and create-service commands.

Accessing a config value from the application is also straightforward. The following example illustrates how to retrieve the "chicken" value as described above with a default value of "Jim Dandy" if the config server wiring is incomplete:

@RestController
@SpringBootApplication
public class Application {

    @Value("${chicken:Jim Dandy}")
    private String chicken;

    @RequestMapping("/chicken")
    String getChicken() {
        return this.chicken;
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}

Troubleshooting

Adding the actuator endpoint to you application can be of use. After application start, go the the /health endpoint of the app and you should see something like the following:

"configServer":{"status":"UP","propertySources":["vault:cook"]}

if there is a status of "DOWN", then the configuration server is not properly configured.

In the application logs, there should be something like

Fetching config from server at: https://config-b29121b6-375a-4a82-bd47-e43e96d3915e.cfapps.haas-156.pez.pivotal.io

where the url is the url of the config server. This piece of data confirms that the spring auto-reconfiguration is wiring the service instance to the application correctly.

Lastly, a cf env <app name> on the application can verify that the service is correctly bound to the application and that the application environment variables (such as TRUST_CERTS) are properly set.

Questions?