Spring Cloud Vault: Secure Secrets Management for Microservices
Learn how to integrate Spring Cloud Vault for dynamic secrets, database credentials, and API keys.
20+ years shipping production Java in banking & fintech. Notes here come from systems that actually shipped.
- ✓Basic knowledge of Spring Boot and microservices
- ✓Familiarity with HashiCorp Vault concepts (tokens, policies, secrets engines)
- ✓Java 17+ and Spring Boot 3.x
- ✓A running Vault instance (dev or production)
- Use Spring Cloud Vault to externalize secrets from config files.
- Supports dynamic database credentials, PKI, and AWS secrets.
- Integrates seamlessly with Spring Boot via spring-cloud-starter-vault-config.
- Avoid storing secrets in Git; use Vault's encrypted backend.
- Enable secret rotation to minimize exposure.
Think of Vault as a high-security bank vault for your application's passwords and API keys. Instead of writing them on sticky notes (config files), your app asks the vault teller for them when needed. The teller gives temporary, time-limited keys, so if someone steals them, they expire quickly.
| Chrome | Firefox | Safari | Edge |
|---|---|---|---|
| ✓ | ✓ | ✓ | ✓ |
Let me guess: your database passwords are in a properties file committed to Git. Or worse, hardcoded. I've seen it at a fintech startup where a junior dev pushed credentials to a public repo. Within hours, someone had mined their AWS keys and spun up instances costing $50k. Don't be that team.
Spring Cloud Vault is the production-grade solution for managing secrets in microservices. It integrates HashiCorp Vault with Spring Boot, letting you externalize configuration like database passwords, API keys, and even dynamic credentials. The best part? Secrets can rotate without restarting your application.
In this article, I'll show you how to set up Spring Cloud Vault, use dynamic database credentials, avoid common pitfalls I've seen in production, and debug issues when they arise. By the end, you'll have a secrets management strategy that security auditors will love.
Setting Up Spring Cloud Vault
Let's get our hands dirty. First, add the dependency. If you're using Spring Boot 3.x, the latest Spring Cloud Vault version is 4.0. Ensure your BOM is aligned.
``xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-vault-config</artifactId> </dependency> ``
Next, configure bootstrap.yml (yes, bootstrap is still used for Vault). Here's a minimal config:
``yaml spring: application: name: myapp cloud: vault: host: vault.example.com port: 8200 scheme: https authentication: TOKEN token: ${VAULT_TOKEN} kv: enabled: true backend: secret default-context: myapp ``
Now, if you have a secret at secret/myapp/database, you can inject it via @Value("${database.password}"). Spring Cloud Vault automatically populates the Environment.
But here's the catch: never hardcode the token in your config file. Use environment variables or a CI/CD secret. I've seen teams commit tokens to Git and wonder why they got hacked.
Dynamic Database Credentials
Static secrets are better than hardcoding, but dynamic credentials are the real game-changer. Vault can generate database credentials on the fly with a limited TTL. When the lease expires, the credentials are revoked.
First, configure a database backend in Vault:
```bash vault secrets enable database vault write database/config/my-postgresql \ plugin_name=postgresql-database-plugin \ allowed_roles="my-role" \ connection_url="postgresql://{{username}}:{{password}}@localhost:5432/mydb" \ username="vault_admin" \ password="adminpass"
vault write database/roles/my-role \ db_name=my-postgresql \ creation_statements="CREATE USER \"{{name}}\" WITH PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \ default_ttl="1h" \ max_ttl="24h" ```
Now in Spring Boot, add the dependency for database backend:
``xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-vault-config-databases</artifactId> </dependency> ``
Configure bootstrap.yml:
``yaml spring: cloud: vault: database: enabled: true role: my-role backend: database ``
Spring Cloud Vault will automatically request credentials and configure the datasource. The credentials are rotated when the lease is about to expire.
What the docs won't tell you: the default lease refresh is too conservative. I've seen apps crash because the credentials expired before refresh. Set spring.cloud.vault.database.lease-endpoint to a reasonable value, and ensure your connection pool evicts idle connections.
maxLifetime less than the lease TTL to force new connections.What the Official Docs Won't Tell You
After years of debugging Vault in production, here are the gotchas that will save your weekend.
1. Bootstrap Context is Mandatory Spring Cloud Vault requires the bootstrap context to load before application context. If you're using Spring Boot 3.x, you need to enable bootstrap via spring.cloud.bootstrap.enabled=true or use the new spring.config.import approach. The docs show the old way; the new way is:
``yaml spring: config: import: vault://secret/myapp ``
But this doesn't support all features like database backend yet. Stick with bootstrap for now.
2. Token Renewal is Not Automatic Contrary to what you might think, Spring Cloud Vault does not automatically renew your authentication token. You must configure it:
``yaml spring: cloud: vault: token: renewal: enabled: true lease-endpoint: /v1/auth/token/renew-self ``
Otherwise, your token expires and your app dies. I learned this the hard way during a midnight incident.
3. Secret Paths Are Case-Sensitive Vault paths are case-sensitive. secret/MyApp is different from secret/myapp. Inconsistency between your Vault setup and application config leads to "secret not found" errors. Standardize on lowercase.
4. Dynamic Secrets Need Connection Pool Tuning When using dynamic database credentials, your connection pool must handle credential rotation. Set spring.datasource.hikari.maxLifetime to a value less than the lease TTL. Otherwise, connections with expired credentials remain in the pool.
5. Vault Agent is Better for Kubernetes If you're on Kubernetes, consider Vault Agent sidecar instead of the Spring integration. It injects secrets into a shared volume, avoiding token management in the app. Spring Cloud Vault works, but Vault Agent is more robust.
Integrating with Spring Cloud Config
Many microservices use Spring Cloud Config Server for external configuration. You can combine it with Vault for secrets. The Config Server can serve Vault-backed property sources, or you can use Vault directly.
I prefer direct Vault integration per service to avoid a single point of failure. But if you already have Config Server, add the Vault backend:
``yaml spring: cloud: config: server: vault: host: vault.example.com port: 8200 ``
Then your services only need Config Server. But this adds latency and complexity. For most teams, direct Vault integration is simpler.
What the docs don't tell you: when using Config Server with Vault, the Config Server itself needs a Vault token. If that token expires, all downstream services lose secrets. Implement token renewal on the Config Server as well.
Production Best Practices
Here's my checklist for production-ready Vault integration:
- Use Short-Lived Tokens with Renewal: Set token TTL to 24h and enable renewal. Use periodic tokens if possible.
- Enable Audit Logging: Vault audit logs are crucial for compliance and debugging. Enable file or syslog audit.
- Apply Least Privilege Policies: Each service should have its own policy with minimal permissions. Never use root tokens.
- Use Dynamic Secrets: Prefer dynamic database, AWS, and PKI secrets over static ones.
- Monitor Lease Expiry: Set up alerts for lease renewal failures. Use Spring Actuator health indicators.
- Test Rotation in Staging: Simulate token and credential expiration to ensure your app recovers gracefully.
- Secure Vault Itself: Vault should be deployed in a dedicated, hardened environment. Use TLS, seal/unseal procedures, and backup.
One more thing: never use @Value for secrets in singleton beans if you expect rotation. Use @RefreshScope or a custom bean that re-fetches secrets on change.
Debugging Vault in Production
When things go wrong, here's how to debug:
- Check Vault Server Health:
vault statusor/v1/sys/healthendpoint. Ensure it's sealed or unsealed. - Verify Token:
vault token lookup <token>shows TTL, policies, and renewable status. - Test Secret Retrieval:
vault kv get secret/myapp/databaseor curl with token. - Enable Debug Logging: In Spring Boot, set
logging.level.org.springframework.cloud.vault=DEBUGto see secret resolution. - Inspect Environment: Use
/actuator/envto see if Vault properties are loaded. - Check Lease Renewal Logs: Look for
VaultLeaserenewal attempts and failures.
403 Forbidden: Token lacks policy. Check Vault policies.404 Not Found: Wrong path. Verify path in Vault and config.500 Internal Server Error: Vault server issue. Check Vault logs.
I always keep a Vault CLI handy in production pods for quick debugging.
vault read to test connectivity. But ensure your pod has the Vault binary and token.The Stale Token Outage at Midnight
- Always use renewable tokens with appropriate TTLs.
- Implement lease renewal in your application.
- Monitor Vault token expiry with alerts.
- Test secret retrieval after token expiry in staging.
- Document Vault policies and token lifecycle.
vault token renew <token>Check TTL: vault token lookup <token>| File | Command / Code | Purpose |
|---|---|---|
| bootstrap.yml | spring: | Setting Up Spring Cloud Vault |
| application.yml | spring: | What the Official Docs Won't Tell You |
| VaultHealthIndicator.java | @Component | Production Best Practices |
| application.properties | logging.level.org.springframework.cloud.vault=DEBUG | Debugging Vault in Production |
Key takeaways
Interview Questions on This Topic
How does Spring Cloud Vault integrate with Spring Boot's property source?
VaultPropertySource to the Spring Environment. It reads secrets from configured Vault paths and makes them available as properties. The @Value annotation and Environment can then access these properties.Frequently Asked Questions
20+ years shipping production Java in banking & fintech. Notes here come from systems that actually shipped.
That's Spring Cloud. Mark it forged?
4 min read · try the examples if you haven't