Context
Problem Statement:
After externalizing secrets to environment variables (ADR-0001), we needed a production-grade secrets management solution:
Business Context:
Technical Context:
Decision
We will implement HashiCorp Vault as the centralized secrets management solution with Spring Cloud Vault integration.
Specific Implementation:
- Key-Value v2 secrets engine for application secrets
- Database secrets engine for dynamic PostgreSQL credentials
- PKI secrets engine for TLS certificate management
- Transit engine for encryption as a service
`
secret/hdim/
├── common/ # Shared across all services
│ ├── jwt
│ └── encryption
├── services/
│ ├── gateway-service/
│ ├── patient-service/
│ ├── care-gap-service/
│ └── ...
└── integrations/
├── fhir-server/
└── external-apis/
`
- Kubernetes auth for production (pod identity)
- AppRole for CI/CD pipelines
- Token auth for local development
Alternatives Considered
Alternative 1: AWS Secrets Manager
Description: AWS-managed secrets service
Pros:
Cons:
Why Not Chosen: Need cloud-agnostic solution; may deploy to multiple clouds
Alternative 2: Kubernetes Secrets with Sealed Secrets
Description: Encrypted Kubernetes secrets using Bitnami Sealed Secrets
Pros:
Cons:
Why Not Chosen: Need dynamic credential rotation and comprehensive audit trail
Alternative 3: CyberArk Conjur
Description: Enterprise secrets management
Pros:
Cons:
Why Not Chosen: Cost prohibitive; Vault provides similar features open-source
Consequences
Positive Consequences
Negative Consequences
Mitigation
Configuration
Vault Server (docker/vault/config/vault.hcl)
storage "file" {
path = "/vault/data"
}
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = 0
tls_cert_file = "/vault/certs/vault.crt"
tls_key_file = "/vault/certs/vault.key"
}
api_addr = "https://vault:8200"
cluster_addr = "https://vault:8201"
ui = trueSpring Cloud Vault Integration
spring:
cloud:
vault:
uri: ${VAULT_ADDR:http://localhost:8200}
authentication: TOKEN
token: ${VAULT_TOKEN:}
kv:
enabled: true
backend: secret
default-context: hdim/services/${spring.application.name}Secret Paths
| Secret Type | Path | Rotation |
|-------------|------|----------|
| JWT Secret | secret/hdim/common/jwt | Manual (quarterly) |
| Database Creds | database/creds/hdim-readonly | Dynamic (1 hour TTL) |
| API Keys | secret/hdim/integrations/* | Manual |
| TLS Certs | pki/issue/hdim | Automatic (30 days) |
Implementation Plan
Files Created
Infrastructure:
docker/vault/config/vault.hcldocker/vault/init-vault.shdocker-compose.secrets.ymlDocumentation:
docs/SECRETS_MANAGEMENT.mdDependencies:
spring-cloud-vault to gradle/libs.versions.tomlSuccess Metrics
| Metric | Target | Measurement |
|--------|--------|-------------|
| Secret rotation frequency | Monthly | Vault audit logs |
| Mean time to rotate | <5 minutes | Automation metrics |
| Hardcoded credentials | 0 | Static analysis |
| Vault availability | 99.9% | Monitoring |