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’ll build
You’ll start up Vault, store configuration properties inside Vault, build a Spring application and connect it with Vault.
What you’ll need
-
About 15 minutes
-
A favorite text editor or IDE
-
JDK 1.8 or later
-
You can also import the code straight into your IDE:
How to complete this guide
Like most Spring Getting Started guides, you can start from scratch and complete each step or you can bypass basic setup steps that are already familiar to you. Either way, you end up with working code.
To start from scratch, move on to Build with Gradle.
To skip the basics, do the following:
-
Download and unzip the source repository for this guide, or clone it using Git:
git clone https://github.com/spring-guides/gs-vault-config.git
-
cd into
gs-vault-config/initial
-
Jump ahead to Install and launch HashiCorp Vault.
When you finish, you can check your results against the code in gs-vault-config/complete
.
Build with Gradle
Build with Gradle
First you set up a basic build script. You can use any build system you like when building apps with Spring, but the code you need to work with Gradle and Maven is included here. If you’re not familiar with either, refer to Building Java Projects with Gradle or Building Java Projects with Maven.
Create the directory structure
In a project directory of your choosing, create the following subdirectory structure; for example, with mkdir -p src/main/java/hello
on *nix systems:
└── src └── main └── java └── hello
Create a Gradle build file
Below is the initial Gradle build file.
build.gradle
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.7.0")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
jar {
archiveBaseName = 'gs-vault-config'
archiveVersion = '0.1.0'
}
repositories {
mavenCentral()
}
test {
useJUnitPlatform()
}
ext {
springCloudVersion = '2021.0.3'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-vault-config'
testImplementation "org.springframework.boot:spring-boot-starter-test"
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
The Spring Boot gradle plugin provides many convenient features:
-
It collects all the jars on the classpath and builds a single, runnable "über-jar", which makes it more convenient to execute and transport your service.
-
It searches for the
public static void main()
method to flag as a runnable class. -
It provides a built-in dependency resolver that sets the version number to match Spring Boot dependencies. You can override any version you wish, but it will default to Boot’s chosen set of versions.
Build with Maven
Build with Maven
First you set up a basic build script. You can use any build system you like when building apps with Spring, but the code you need to work with Maven is included here. If you’re not familiar with Maven, refer to Building Java Projects with Maven.
Create the directory structure
In a project directory of your choosing, create the following subdirectory structure; for example, with mkdir -p src/main/java/hello
on *nix systems:
└── src └── main └── java └── hello
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-vault-config</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
</parent>
<dependencies>
<!-- Vault Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>2021.0.3</spring-cloud.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
The Spring Boot Maven plugin provides many convenient features:
-
It collects all the jars on the classpath and builds a single, runnable "über-jar", which makes it more convenient to execute and transport your service.
-
It searches for the
public static void main()
method to flag as a runnable class. -
It provides a built-in dependency resolver that sets the version number to match Spring Boot dependencies. You can override any version you wish, but it will default to Boot’s chosen set of versions.
Build with your IDE
Build with your IDE
-
Read how to import this guide straight into Spring Tool Suite.
-
Read how to work with this guide in IntelliJ IDEA.
Install and launch HashiCorp Vault
With your project set up, you can install and launch HashiCorp Vault.
If you are using a Mac with homebrew, this is as simple as:
$ brew install vault
Alternatively, download Vault for your operating system from https://www.vaultproject.io/downloads.html:
$ https://releases.hashicorp.com/vault/1.2.1/vault_1.2.1_darwin_amd64.zip $ unzip vault_1.2.1_darwin_amd64.zip
For other systems with package management, such as Redhat, Ubuntu, Debian, CentOS, and Windows, see instructions at https://www.vaultproject.io/docs/install/index.html.
After you install Vault, launch it in a console window. This command also starts up a server process.
$ vault server --dev --dev-root-token-id="00000000-0000-0000-0000-000000000000"
You should see the following as one of the last output lines:
[INFO ] core: post-unseal setup complete
The command above starts Vault in development mode using in-memory storage without transport encryption. This is fine for evaluating Vault locally. Make sure to use proper SSL certificates and a reliable storage backend for production use. Consult Vault’s Production Hardening guide for further details. |
Store configuration in Vault
Vault is a secrets management system allowing you to store sensitive data which is encrypted at rest. It’s ideal to store sensitive configuration details such as passwords, encryption keys, API keys.
Launch another console window to store application configuration in Vault using the Vault command line.
First, you need to set two environment variables to point the Vault CLI to the Vault endpoint and provide an authentication token.
$ export export VAULT_TOKEN="00000000-0000-0000-0000-000000000000" $ export VAULT_ADDR="http://127.0.0.1:8200"
Now you can store a configuration key-value pairs inside Vault:
$ 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
.
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
.
Build an executable JAR
You can run the application from the command line with Gradle or Maven. You can also build a single executable JAR file that contains all the necessary dependencies, classes, and resources and run that. Building an executable jar makes it easy to ship, version, and deploy the service as an application throughout the development lifecycle, across different environments, and so forth.
If you use Gradle, you can run the application by using ./gradlew bootRun
. Alternatively, you can build the JAR file by using ./gradlew build
and then run the JAR file, as follows:
If you use Maven, you can run the application by using ./mvnw spring-boot:run
. Alternatively, you can build the JAR file with ./mvnw clean package
and then run the JAR file, as follows:
The steps described here create a runnable JAR. You can also build a classic WAR file. |
As our Application
implements CommandLineRunner
, the run
method is invoked automatically when boot starts. You should see something like this:
---------------------------------------- Configuration properties example.username is demouser example.password is demopassword ----------------------------------------
Now start your application with the cloud
profile activated. You should see something like this:
---------------------------------------- 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
.
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. |