Seamlessly integrate HashiCorp Vault with Spring Boot SSL configuration using native
ssl.bundle
support.
Spring Boot's built-in SSL bundle support is powerful but has limitations when working with HashiCorp Vault:
Issue | Impact |
---|---|
No Vault Integration | Must manually fetch certificates from Vault using scripts or CLI |
File System Dependency | Requires storing PEM files locally in resources or filesystem |
Manual Certificate Rotation | No automation for certificate lifecycle management |
DevOps Overhead | Additional tooling and processes required |
# β Requires manual certificate management
spring:
ssl:
bundle:
pem:
mybundle:
keystore:
certificate: classpath:server.crt # Must be manually placed
private-key: classpath:server.key # Must be manually rotated
spring-vault-ssl-bundle bridges this gap by extending Spring Boot's SSL bundle system with native Vault support.
π Zero File Management - Certificates are fetched directly from Vault
π Automatic Rotation Ready - Built for dynamic certificate workflows
π― Native Integration - Works seamlessly with existing ssl.bundle
configuration
β‘ Zero Code Changes - Just update your YAML configuration
π Secure by Design - Leverages Vault's security model
β‘ Smart Caching - Eliminates duplicate Vault calls within the same bundle
π― Flexible Configuration - Simple for common cases, advanced when needed
Maven:
<dependency>
<groupId>com.gridatek</groupId>
<artifactId>spring-vault-ssl-bundle</artifactId>
<version>0.10.0</version>
</dependency>
Gradle:
implementation("com.gridatek:spring-vault-ssl-bundle:0.10.0")
# Store your SSL certificates in Vault
vault kv put secret/ssl-certs/my-service \
certificate=@server.crt \
private-key=@server.key \
ca-certificate=@ca.crt
Simple Configuration (Recommended):
server:
port: 8443
ssl:
enabled: true
bundle: my-service
spring:
cloud:
vault:
host: localhost
port: 8200
scheme: http
authentication: TOKEN
token: ${VAULT_TOKEN}
kv:
enabled: true
backend: secret
ssl:
bundle:
pem:
my-service:
keystore:
certificate: "vault:secret/data/ssl-certs/my-service"
truststore:
certificate: "vault:secret/data/ssl-certs/my-service"
That's it! Your application now loads SSL certificates directly from Vault.
Store certificates in Vault using this JSON structure:
{
"certificate": "-----BEGIN CERTIFICATE-----\nMIIC...\n-----END CERTIFICATE-----",
"private-key": "-----BEGIN PRIVATE KEY-----\nMIIE...\n-----END PRIVATE KEY-----",
"ca-certificate": "-----BEGIN CERTIFICATE-----\nMIIC...\n-----END CERTIFICATE-----"
}
Field Requirements by Use Case:
- Keystore-only Configuration (Server SSL):
certificate
is required,private-key
is filled automatically unless explicitly specified. - Truststore-only Configuration (Client SSL): Only
ca-certificate
is required - Keystore and Truststore Configuration (Full SSL Bundle):
certificate
andca-certificate
are required,private-key
is filled automatically unless explicitly specified.
Specify the Vault path once - the system automatically maps standard field names:
spring:
ssl:
bundle:
pem:
web-server:
keystore:
certificate: "vault:secret/data/ssl-certs/web-server"
truststore:
certificate: "vault:secret/data/ssl-certs/web-server"
Automatic Field Mapping:
certificate
β Server certificateprivate-key
β Private keyca-certificate
β CA certificate
When you need custom field names or separate paths:
spring:
ssl:
bundle:
pem:
api-gateway:
keystore:
certificate: "vault:secret/data/ssl-certs/api-gateway:server_cert"
private-key: "vault:secret/data/private-keys/api-gateway:server_key"
truststore:
certificate: "vault:secret/data/ca-certs/root:ca_bundle"
For client applications that only need to validate server certificates:
spring:
ssl:
bundle:
pem:
client-app:
truststore:
certificate: "vault:secret/data/ca-certs/trusted-cas"
Different services can have different certificate configurations:
spring:
ssl:
bundle:
pem:
# Internal service communication
internal:
keystore:
certificate: "vault:secret/data/ssl-certs/internal"
truststore:
certificate: "vault:secret/data/ssl-certs/internal"
# External client connections
external:
keystore:
certificate: "vault:secret/data/ssl-certs/external"
truststore:
certificate: "vault:secret/data/ca-certs/public-cas"
vault:<vault-path>
vault:<vault-path>:<field-name>
# Use default field names
certificate: "vault:secret/data/ssl-certs/my-app"
# Specify custom field name
certificate: "vault:secret/data/ssl-certs/my-app:server_certificate"
# Different paths for different components
certificate: "vault:pki/cert/my-app:certificate"
private-key: "vault:pki/private/my-app:private_key"
# Enable KV v2
vault secrets enable -path=secret kv-v2
# Store certificate
vault kv put secret/ssl-certs/my-service \
certificate=@server.crt \
private-key=@server.key
# Enable KV v1
vault secrets enable -path=secret kv
# Store certificate
vault kv put secret/ssl-certs/my-service \
certificate=@server.crt \
private-key=@server.key
The library automatically detects and handles both KV v1 and KV v2 formats.
Feature | Native Spring Boot | spring-vault-ssl-bundle |
---|---|---|
Vault Integration | β Manual scripts | β Native support |
File Management | β Required | β Eliminated |
Certificate Rotation | β Manual process | β Automation-ready |
Configuration | β Simple | |
Security | β Vault-secured | |
DevOps Friendly | β Extra tooling | β Built-in |
Performance | β File system | β Smart caching |
Flexibility | β Static files | β Dynamic configuration |
- Java: 17 or higher
- Spring Boot: 3.2 or higher and its corresponding Spring Cloud version
This library has minimal dependencies and integrates seamlessly with your existing Spring Boot application:
Maven:
<dependencies>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Spring Cloud Vault Config -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-vault-config</artifactId>
</dependency>
<!-- Spring Vault SSL Bundle (This Library) -->
<dependency>
<groupId>com.gridatek</groupId>
<artifactId>spring-vault-ssl-bundle</artifactId>
<version>0.10.0</version>
</dependency>
</dependencies>
Gradle:
dependencies {
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.springframework.cloud:spring-cloud-starter-vault-config")
implementation("com.gridatek:spring-vault-ssl-bundle:0.10.0")
}
The library itself uses these dependencies with provided
scope, meaning they must be present in your application:
<dependencies>
<!-- SLF4J API -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- Spring Boot Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<scope>provided</scope>
</dependency>
<!-- Spring Cloud Starter Vault Config -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-vault-config</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
Why Provided Scope?
- β No Version Conflicts - Uses your application's Spring Boot version
- β Smaller Library Size - Dependencies are expected to be in your classpath
- β Better Integration - Aligns with your application's Spring ecosystem
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
Made with β€οΈ for the Spring Boot community