This demo shows how to store PEM certificates in HashiCorp Vault and use them with Spring Boot SSL bundles for secure communication between two servers.
┌─────────────┐ HTTPS/SSL ┌─────────────┐
│ Server A │ ───────────────► │ Server B │
│ Port 8443 │ │ Port 8444 │
└─────────────┘ └─────────────┘
│ │
│ Vault Token Auth │
└─────────────┬─────────────────┘
│
┌─────────────┐
│ Vault │
│ Port 8200 │
│ (Dev Mode) │
└─────────────┘
spring-vault-ssl-bundle-demo/
├── pom.xml # Root POM
├── common/ # Shared DTOs and services
│ ├── src/main/java/
│ │ └── com/demo/common/
│ │ └──dto/ # MessageRequest, MessageResponse
│ └── pom.xml
├── server-a/ # Server A (Client + Server)
│ ├── src/main/java/
│ │ └── com/demo/servera/
│ ├── src/main/resources/
│ │ └── application.yml
│ └── pom.xml
├── server-b/ # Server B (Server only)
│ ├── src/main/java/
│ │ └── com/demo/serverb/
│ ├── src/main/resources/
│ │ └── application.yml
│ └── pom.xml
├── docker-compose.yml # Vault setup
├── generate-certs.sh # Certificate generation
└── certificates/ # Generated certificates
- Java 17+
- Maven 3.6+
- Docker & Docker Compose
- OpenSSL (for certificate generation)
chmod +x generate-certs.sh
./generate-certs.sh
This creates:
certificates/ca-cert.pem
- Certificate Authoritycertificates/server-a-cert.pem
&certificates/server-a-key.pem
- Server A SSLcertificates/server-b-cert.pem
&certificates/server-b-key.pem
- Server B SSL
# Start Vault
docker compose up -d
# Make sure the init script is executable
chmod +x vault-init.sh
# Run script and initialize with certificates
./vault-init.sh
This will:
- Start Vault in dev mode (port 8200)
- Initialize KV secrets engine
- Store all PEM certificates in Vault at paths:
secret/ssl-certs/server-a
secret/ssl-certs/server-b
./mvnw clean install
Terminal 1 - Server B:
./mvnw spring-boot:run -pl server-b
Terminal 2 - Server A:
./mvnw spring-boot:run -pl server-a
# Server A health (with SSL)
curl -k https://localhost:8443/api/v1/health
# Server B health (with SSL)
curl -k https://localhost:8444/api/v1/health
# Test Server A → Server B communication
curl -k -X POST "https://localhost:8443/api/v1/test/send-to-server-b?message=Hello%20World"
# Simple ping test
curl -k https://localhost:8443/api/v1/test/ping-server-b
# Send message directly to Server A
curl -k -X POST https://localhost:8443/api/v1/message \
-H "Content-Type: application/json" \
-d '{"message":"Direct message","timestamp":"2024-01-01T10:00:00"}'
# Send message directly to Server B
curl -k -X POST https://localhost:8444/api/v1/message \
-H "Content-Type: application/json" \
-d '{"message":"Direct message","timestamp":"2024-01-01T10:00:00"}'
secret/
└── ssl-certs/
├── server-a/
│ ├── certificate # PEM certificate
│ ├── private-key # PEM private key
│ └── ca-certificate # CA certificate
└── server-b/
├── certificate # PEM certificate
├── private-key # PEM private key
└── ca-certificate # CA certificate
Spring Boot automatically retrieves certificates from Vault using the vault:
prefix:
spring:
ssl:
bundle:
pem:
server-a-ssl:
keystore:
certificate: "vault:secret/data/ssl-certs/server-a:certificate"
private-key: "vault:secret/data/ssl-certs/server-a:private-key"
truststore:
certificate: "vault:secret/data/ssl-certs/server-a:ca-certificate"
The demo uses token authentication for simplicity:
spring:
cloud:
vault:
authentication: TOKEN
token: demo-root-token
- PEM Certificate Storage: Certificates stored as text in Vault KV store
- SSL Bundle Integration: Spring Boot 3.1+ SSL bundles with Vault backend
- Mutual TLS: Both servers use certificates for client authentication
- Multi-Module Maven: Shared common module for DTOs and services
- Inter-Service Communication: HTTPS communication with client certificates
- Dynamic Certificate Loading: Certificates loaded from Vault at runtime
-
Certificate Verification Failed
- Ensure certificates are properly generated with correct SAN entries
- Check Vault connectivity and token validity
-
SSL Handshake Failures
- Verify both keystore and truststore are configured
- Check certificate validity periods
-
Vault Connection Issues
- Ensure Vault is running:
docker compose ps
- Check Vault logs:
docker compose logs vault
- Ensure Vault is running:
Enable verbose SSL logging:
logging:
level:
javax.net.ssl: DEBUG
org.springframework.vault: DEBUG
# Access Vault CLI
docker exec -it vault-demo vault status
# List secrets
docker exec -it vault-demo vault kv list secret/ssl-certs
# Read certificate
docker exec -it vault-demo vault kv get secret/ssl-certs/server-a
- Use proper Vault authentication (AppRole, Kubernetes, etc.)
- Configure certificate rotation policies
- Use proper CA certificates (not self-signed)
- Implement certificate monitoring and alerts
- Use Vault namespaces for multi-tenancy
- Configure proper RBAC policies
# Stop services
docker compose down
# Remove certificates
rm -rf certificates/
# Clean Maven build
./mvnw clean
This demo provides a complete working example of using Vault-stored PEM certificates with Spring Boot SSL bundles in a multi-module Maven project.