Setting Up Vault in Spring: A Comprehensive Guide
Spring Framework, with its robust ecosystem, provides powerful tools for developing enterprise-level applications. One of the critical aspects of these applications is securely managing secrets such as API keys, passwords, and other sensitive information. HashiCorp Vault is a popular solution for this, offering secure storage and fine-grained access control mechanisms. This guide walks you through setting up Vault in a Spring application, complete with examples.
Table of Contents
1. Introduction to Vault
Vault is a tool for securely accessing secrets. It provides a unified interface to any secret, tightly controlling access to secrets and auditing a detailed log of all access. Secrets can be anything from database credentials, API keys, passwords, certificates, etc.
2. Prerequisites
Before diving into the setup, ensure you have the following prerequisites:
3. Setting Up Vault
Installing Vault
First, download and install Vault. You can download Vault from the official website. Follow the installation instructions specific to your operating system.
For example, on a macOS system, you can use Homebrew:
brew install vault
Starting Vault Server
After installing Vault, start the Vault server in development mode:
vault server -dev
This command starts the Vault server in development mode, which is not recommended for production use but is perfect for local development and testing.
You should see output similar to this, indicating that Vault is running:
==> Vault server configuration:
Api Address: http://127.0.0.1:8200
Cgo: disabled
Cluster Address: https://127.0.0.1:8201
Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201")
Log Level: info
Mlock: supported: true, enabled: true
Redirect Addr: nil
Storage: inmem
Version: Vault v1.7.3
WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory and starts unsealed with a single unseal key. The root token is already authenticated to the CLI, so you can immediately begin using Vault.
Note the root token provided in the output; you will need it to authenticate.
4. Integrating Vault with Spring
Adding Dependencies
To integrate Vault with a Spring Boot application, add the following dependencies to your pom.xml (for Maven) or build.gradle (for Gradle) file.
For Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-vault-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.vault</groupId>
<artifactId>spring-vault-core</artifactId>
</dependency>
For Gradle:
implementation 'org.springframework.boot:spring-boot-starter-vault-config'
implementation 'org.springframework.vault:spring-vault-core'
Configuring Vault in Spring
In the application.properties or application.yml file, configure the Vault properties. For example:
application.properties:
spring.cloud.vault.uri=http://127.0.0.1:8200
spring.cloud.vault.token=<your-root-token>
spring.cloud.vault.scheme=http
spring.cloud.vault.kv.enabled=true
spring.cloud.vault.kv.backend=secret
spring.cloud.vault.kv.default-context=application
application.yml:
Recommended by LinkedIn
spring:
cloud:
vault:
uri: http://127.0.0.1:8200
token: <your-root-token>
scheme: http
kv:
enabled: true
backend: secret
default-context: application
Replace <your-root-token> with the actual root token from the Vault server.
5. Using Vault in a Spring Application
Reading Secrets
To read secrets from Vault, first, store some secrets in Vault. Use the Vault CLI to write a secret:
vault kv put secret/application db.username=admin db.password=secretpassword
In your Spring application, you can now access these secrets using the @Value annotation:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class DatabaseCredentials {
@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
// Getters and setters
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;
}
}
Writing Secrets
To write secrets to Vault programmatically, you can use the VaultTemplate provided by Spring Vault:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.vault.core.VaultTemplate;
import org.springframework.vault.support.VaultResponse;
import org.springframework.vault.core.VaultKeyValueOperations;
import org.springframework.vault.core.VaultKeyValueOperationsSupport;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
public class VaultService {
@Autowired
private VaultTemplate vaultTemplate;
public void writeSecret(String path, Map<String, String> secrets) {
VaultKeyValueOperations operations = vaultTemplate.opsForKeyValue("secret", VaultKeyValueOperationsSupport.KeyValueBackend.KV_2);
operations.put(path, secrets);
}
public Map<String, Object> readSecret(String path) {
VaultResponse response = vaultTemplate.opsForKeyValue("secret", VaultKeyValueOperationsSupport.KeyValueBackend.KV_2).get(path);
return response.getData();
}
}
In your application, you can use this service to read and write secrets:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class VaultCommandLineRunner implements CommandLineRunner {
@Autowired
private VaultService vaultService;
@Override
public void run(String... args) throws Exception {
Map<String, String> secrets = new HashMap<>();
secrets.put("apiKey", "12345");
secrets.put("apiSecret", "67890");
vaultService.writeSecret("api/credentials", secrets);
Map<String, Object> readSecrets = vaultService.readSecret("api/credentials");
System.out.println("Read Secrets: " + readSecrets);
}
}
6. Example Spring Boot Application
Here's a complete example of a Spring Boot application that integrates with Vault. This example includes the dependencies, configuration, and usage of Vault to store and retrieve secrets.
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-vault-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.vault</groupId>
<artifactId>spring-vault-core</artifactId>
</dependency>
application.yml:
spring:
application:
name: demo
cloud:
vault:
uri: http://127.0.0.1:8200
token: <your-root-token>
scheme: http
kv:
enabled: true
backend: secret
default-context: application
DatabaseCredentials.java:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class DatabaseCredentials {
@Value("${db.username}")
private String username;
@Value("${db.password}")
private String password;
// Getters and setters
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;
}
}
VaultService.java:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.vault.core.VaultKeyValueOperations;
import org.springframework.vault.core.VaultKeyValueOperationsSupport;
import org.springframework.vault.core.VaultTemplate;
import org.springframework.vault.support.VaultResponse;
import java.util.Map;
@Service
public class VaultService {
@Autowired
private VaultTemplate vaultTemplate;
public void writeSecret(String path, Map<String, String> secrets) {
VaultKeyValueOperations operations = vaultTemplate.opsForKeyValue("secret", VaultKeyValueOperationsSupport.KeyValueBackend.KV_2);
operations.put(path, secrets);
}
public Map<String, Object> readSecret(String path) {
VaultResponse response = vaultTemplate.opsForKeyValue("secret", VaultKeyValueOperationsSupport.KeyValueBackend.KV_2).get(path);
return response.getData();
}
}
VaultCommandLineRunner.java:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
@Component
public class VaultCommandLineRunner implements CommandLineRunner {
@Autowired
private VaultService vaultService;
@Override
public void run(String... args) throws Exception {
Map<String, String> secrets = new HashMap<>();
secrets.put("apiKey", "12345");
secrets.put("apiSecret", "67890");
vaultService.writeSecret("api/credentials", secrets);
Map<String, Object> readSecrets = vaultService.readSecret("api/credentials");
System.out.println("Read Secrets: " + readSecrets);
}
}
7. Conclusion
Integrating HashiCorp Vault with Spring Boot applications enhances security by managing secrets efficiently and securely. This guide has provided a comprehensive setup, from installing Vault to configuring it in a Spring application, and using it to read and write secrets. Following these steps will ensure that your application's sensitive information is well-protected.
Find us
linkedin Shant Khayalian
Facebook Balian’s
X-platform Balian’s
web Balian’s
#SpringBoot #HashiCorpVault #Java #SpringFramework #SecretManagement #DevSecOps #SecureCoding #CloudSecurity #SpringSecurity #ApplicationSecurity #SpringIntegration #SecureAppDevelopment #VaultSetup #SecureSecrets #SpringBootTutorial