The full picture
- Injection mechanics:
spring.config.import=vault://secret/app(Spring Cloud Vault), K8s Secrets as env or mounted files (spring.config.import=configtree:/run/secrets/), cloud-native config imports for ASM/GSM. Env vars are acceptable but visible in/procand crash dumps — mounted files edge them out. - Rotation reality: HikariCP won't re-read a changed password — you need context refresh, pool eviction hooks, or dynamic credentials with TTL shorter than rotation cadence. If you can't answer 'what happens when the DB password rotates', it isn't managed.
- Defense in depth: actuator
/env,/configprops,/heapdumpredact-or-deny (Boot 3 shows******by default — keepshow-values: neverin prod); bantoString()on config records holding secrets; CI secret scanning (gitleaks) + pre-commit hooks. - The bootstrap problem: 'the secret to fetch the secrets' — solve with workload identity (IRSA, GKE WI, K8s auth to Vault), not a long-lived token in an env var — that's just moving the same secret.
# K8s: mount secret as files
volumeMounts: [{ name: db-creds, mountPath: /run/secrets/db }]
# application.yml
spring:
config:
import: "configtree:/run/secrets/"
# -> file /run/secrets/db/password becomes property db.password
# No env exposure; rotation = file update + refresh strategy.