Vault Configuration

This guide walks you through the process of using Spring Cloud Vault to build an application that retrieves its configuration properties from HashiCorp Vault.

What You Will Build

You’ll start up Vault, store configuration properties inside Vault, build a Spring application and connect it with Vault.

What You Need

  • About 15 minutes

  • A favorite text editor or IDE

  • Java 17 or later

How to Complete This Guide

Like most Spring Getting Started guides you can start from scratch and complete each step, or you can jump straight to the solution, by viewing the code in this repository.

To see the end result in your local environment, you can do one of the following:

Starting with Spring Initializr

You can use this pre-initialized project and click Generate to download a ZIP file. This project is configured to fit the examples in this tutorial.

To manually initialize the project:

  1. Navigate to https://start.spring.io. This service pulls in all the dependencies you need for an application and does most of the setup for you.

  2. Choose either Gradle or Maven and the language you want to use. This guide assumes that you chose Java.

  3. Click Dependencies and select Vault Configuration

  4. Click Generate.

  5. Download the resulting ZIP file, which is an archive of an application that is configured with your choices.

If your IDE has the Spring Initializr integration, you can complete this process from your IDE.

Run HashiCorp Vault

An instance of HashiCorp Vault is required to complete this guide. This guide uses Docker Compose to run a containerized version of HashiCorp Vault. A compose.yaml file has been provided:

services:
  vault:
    container_name: "guide-vault"
    image: hashicorp/vault:latest
    environment:
      VAULT_DEV_ROOT_TOKEN_ID: "00000000-0000-0000-0000-000000000000"
    ports:
      - "8200:8200"

Run the HashiCorp Vault container with the docker compose up command.

Store Configuration in Vault

Vault is a secrets management system allowing you to store sensitive data which is encrypted at rest.

You need to access the Vault container to store the data. Connect to the running Docker container with the command:

docker exec -it guide-vault sh

You are now running commands inside of the HashiCorp Vault container.

First, you need to set two environment variables to point the Vault CLI to the Vault endpoint and provide an authentication token.

export VAULT_TOKEN="00000000-0000-0000-0000-000000000000"
export VAULT_ADDR="http://127.0.0.1:8200"

Now you can store configuration key-value pairs inside Vault. For this guide, you store two key-value pairs:

vault kv put secret/gs-vault-config example.username=demouser example.password=demopassword
vault kv put secret/gs-vault-config/cloud example.username=clouduser example.password=cloudpassword

Now you have written two entries in Vault secret/gs-vault-config and secret/gs-vault-config/cloud.

With the Vault container running and the data loaded, you are now ready to turn your attention to the Spring application.

Define your configuration class

Create a simple configuration for your Spring application:

src/main/java/hello/MyConfiguration.java

package hello;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @author Mark Paluch
 */
@ConfigurationProperties("example")
public class MyConfiguration {

  private String username;

  private String password;

  public String getUsername() {
    return username;
  }

  public void setUsername(String username) {
    this.username = username;
  }

  public String getPassword() {
    return password;
  }

  public void setPassword(String password) {
    this.password = password;
  }
}

Configure your application

Here you configure your application with application.properties. The code below uses Spring Boot’s Config Data API which allows importing configuration from Vault.

src/main/resources/application.properties

spring.application.name=gs-vault-config
spring.cloud.vault.token=00000000-0000-0000-0000-000000000000
spring.cloud.vault.scheme=http
spring.cloud.vault.kv.enabled=true
spring.config.import:  vault://

Create an Application class

Here you create an Application class with all the components.

src/main/java/hello/Application.java

package hello;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

@SpringBootApplication
@EnableConfigurationProperties(MyConfiguration.class)
public class Application implements CommandLineRunner {

  private final MyConfiguration configuration;

  public Application(MyConfiguration configuration) {
    this.configuration = configuration;
  }

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

  @Override
  public void run(String... args) {

    Logger logger = LoggerFactory.getLogger(Application.class);

    logger.info("----------------------------------------");
    logger.info("Configuration properties");
    logger.info("   example.username is {}", configuration.getUsername());
    logger.info("   example.password is {}", configuration.getPassword());
    logger.info("----------------------------------------");
  }
}

Spring Cloud Vault uses VaultOperations to interact with Vault. Properties from Vault get mapped to MyConfiguration for type-safe access. @EnableConfigurationProperties(MyConfiguration.class) enables configuration property mapping and registers a MyConfiguration bean.

Application includes a main() method that autowires an instance of MyConfiguration.

Run the Application

You can run the main method through your IDE. Alternatively, the ./gradlew bootRun and ./mvnw spring-boot:run commands launch the application.

As our Application implements CommandLineRunner, the run method is invoked automatically when boot starts. You should see the output:

----------------------------------------
Configuration properties
        example.username is demouser
        example.password is demopassword
----------------------------------------

Now start the application using the cloud profile. You can do so in Gradle with the ./gradlew bootRun --args='--spring.profiles.active=cloud' command or in Maven with the ./mvnw spring-boot:run -Dspring-boot.run.arguments="--spring.profiles.active=cloud" command. When you run the application with the cloud profile, you see:

----------------------------------------
Configuration properties
        example.username is clouduser
        example.password is cloudpassword
----------------------------------------

Configuration properties are bound according to the activated profiles. Spring Cloud Vault constructs a Vault context path from spring.application.name which is gs-vault and appends the profile name (cloud) so enabling the cloud profile will fetch additionally configuration properties from secret/gs-vault-config/cloud.

Building the Application

This section describes different ways to run this guide:

Regardless of how you choose to run the application, the output should be the same.

To run the application, you can package the application as an executable jar. The ./mvnw clean package command compiles the application to an executable jar. You can then run the jar with the java -jar target/gs-vault-config-0.0.1-SNAPSHOT.jar command.

Alternatively, if you have a Docker environment available, you could create a Docker image directly from your Maven or Gradle plugin, using buildpacks. With Cloud Native Buildpacks, you can create Docker compatible images that you can run anywhere. Spring Boot includes buildpack support directly for both Maven and Gradle. This means you can type a single command and quickly get a sensible image into a locally running Docker daemon. To create a Docker image using Cloud Native Buildpacks, run the ./mvnw spring-boot:build-image command. With a Docker environment enabled, you can run the application with the docker run --network container:guide-vault docker.io/library/gs-vault-config:0.0.1-SNAPSHOT command.

The --network flag tells Docker to attach our guide container to the existing network that our external container is using. You can find more information in the Docker documentation.

Native Image Support

Spring Boot also supports compilation to a native image, provided you have a GraalVM distribution on your machine.

You can then run the ./mvnw -Pnative native:compile command to generate a native image. When the build completes, you will be able to run the code with a near-instantaneous start up time by executing the target/gs-vault-config command.

To create native image container using Maven you should ensure that your pom.xml file uses the spring-boot-starter-parent and the org.graalvm.buildtools:native-maven-plugin. This plugin should be located in the <build> <plugins> section:

<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
</plugin>

You can also create a Native Image using Buildpacks. You can generate a native image by running the ./mvnw -Pnative spring-boot:build-image command. Once the build completes, you can start your application with the docker run --network container:guide-vault docker.io/library/gs-vault-config:0.0.1-SNAPSHOT command.

Summary

Congratulations! You set up a Vault server and wrote a simple application that uses Spring Vault to read secrets into configuration properties and encrypt data with a strong cipher — all without the headache of implementing key management, a cipher mode, and padding.

Want to write a new guide or contribute to an existing one? Check out our contribution guidelines.

All guides are released with an ASLv2 license for the code, and an Attribution, NoDerivatives creative commons license for the writing.

Get the Code