└── src └── main └── java └── hello
Accessing Vault
This guide walks you through the process of using Spring Vault to build an application that loads secrets from HashiCorp Vault, a secrets management tool.
What you’ll build
You will load secrets stored in Vault and use the transit encryption backend.
What you’ll need
-
About 15 minutes
-
A favorite text editor or IDE
-
Java 17 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-accessing-vault.git
-
cd into
gs-accessing-vault/initial
-
Jump ahead to Install and launch HashiCorp Vault.
When you finish, you can check your results against the code in gs-accessing-vault/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:
Create a Gradle build file
Below is the initial Gradle build file.
build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.0'
id 'io.spring.dependency-management' version '1.1.5'
}
group = 'gs-accessing-vault'
version = '0.1.0'
repositories {
mavenCentral()
maven {
url "https://repo.spring.io/milestone"
}
}
ext {
set('springCloudVersion', "2023.0.2")
}
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}"
}
}
tasks.named('test') {
useJUnitPlatform()
}
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-accessing-vault</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.0</version>
</parent>
<properties>
<spring-cloud.version>2023.0.2</spring-cloud.version>
</properties>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-libs-milestone</id>
<url>https://repo.spring.io/libs-milestone</url>
</repository>
</repositories>
</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.12.2/vault_1.12.2_darwin_amd64.zip $ unzip vault_1.12.2_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 secrets 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 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/github github.oauth2.key=foobar
Configure your application
Here you configure your application with application.properties
. Spring Cloud Vault is configured with the bootstrap context.
src/main/resources/application.properties
spring.cloud.vault.token=00000000-0000-0000-0000-000000000000
spring.cloud.vault.scheme=http
Create an Application class
Here you create an Application class with all the components.
src/main/java/hello/Application.java
package hello;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.vault.core.VaultKeyValueOperationsSupport.KeyValueBackend;
import org.springframework.vault.core.VaultSysOperations;
import org.springframework.vault.core.VaultTemplate;
import org.springframework.vault.core.VaultTransitOperations;
import org.springframework.vault.support.VaultMount;
import org.springframework.vault.support.VaultResponse;
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
private VaultTemplate vaultTemplate;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... strings) throws Exception {
// You usually would not print a secret to stdout
VaultResponse response = vaultTemplate
.opsForKeyValue("secret", KeyValueBackend.KV_2).get("github");
System.out.println("Value of github.oauth2.key");
System.out.println("-------------------------------");
System.out.println(response.getData().get("github.oauth2.key"));
System.out.println("-------------------------------");
System.out.println();
// Let's encrypt some data using the Transit backend.
VaultTransitOperations transitOperations = vaultTemplate.opsForTransit();
// We need to setup transit first (assuming you didn't set up it yet).
VaultSysOperations sysOperations = vaultTemplate.opsForSys();
if (!sysOperations.getMounts().containsKey("transit/")) {
sysOperations.mount("transit", VaultMount.create("transit"));
transitOperations.createKey("foo-key");
}
// Encrypt a plain-text value
String ciphertext = transitOperations.encrypt("foo-key", "Secure message");
System.out.println("Encrypted value");
System.out.println("-------------------------------");
System.out.println(ciphertext);
System.out.println("-------------------------------");
System.out.println();
// Decrypt
String plaintext = transitOperations.decrypt("foo-key", ciphertext);
System.out.println("Decrypted value");
System.out.println("-------------------------------");
System.out.println(plaintext);
System.out.println("-------------------------------");
System.out.println();
}
}
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:
Value of github.oauth2.key ------------------------------- foobar ------------------------------- Encrypted value ------------------------------- vault:v1:2wgVE2PXiR9o55xbyur5KHJl8IwyGDkDU4l1SZScUq6BuqZYgTopwvc4 ------------------------------- Decrypted value ------------------------------- Secure message -------------------------------
Vault’s secret backend compares well to a document store that uses URIs to identify documents. Documents are JSON-based that allows convenient object mapping of Vault data. |
Summary
Congratulations! You set up a Vault server and wrote a simple application that uses Spring Vault to read secrets 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. |