Setting Up Vault in Spring: A Comprehensive Guide
Spring vault balians-it.com

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
  2. Prerequisites
  3. Setting Up Vault
  4. Installing Vault
  5. Starting Vault Server
  6. Integrating Vault with Spring
  7. Adding Dependencies
  8. Configuring Vault in Spring
  9. Using Vault in a Spring Application
  10. Reading Secrets
  11. Writing Secrets
  12. Example Spring Boot Application
  13. Conclusion


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:

  • Java Development Kit (JDK) 8 or higher
  • Maven or Gradle
  • Spring Boot framework
  • HashiCorp Vault

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:

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



To view or add a comment, sign in

More articles by Shant Khayalian

Insights from the community

Others also viewed

Explore topics