Interview Prep Zoneby CuriouserLabs

Question 4 of 5 · architect level

How do you handle secrets in a Spring Boot application — from local dev to production?

🎤 Say this first

Never in git, never in the image, never in plain application.yml. Production: platform-injected — cloud secret managers (AWS/GCP/Azure) or Vault, surfaced to Boot via spring.config.import=vault:/CSI-mounted files/env vars, with IAM/workload identity replacing bootstrap credentials where possible. Rotation must be designed, not hoped for: short-lived dynamic credentials (Vault DB engine) or rolling restarts on rotation. Local dev gets harmless defaults or a dev vault — a leaked dev secret should be worthless. And assume leakage will be attempted: scanners in CI, /env and heapdump actuators locked down, secrets excluded from logs and error reports.

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 /proc and 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, /heapdump redact-or-deny (Boot 3 shows ****** by default — keep show-values: never in prod); ban toString() 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.
Config-tree import: files, not env
# 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.

🔄 Likely follow-up questions

  • What breaks in connection pools when credentials rotate, and your mitigation?
  • Env vars vs mounted files vs fetch-at-startup — threat-model the differences.
  • How do you keep secrets out of heap dumps and Actuator endpoints?