Keep App Config Behind Security on PROD
The 3-Line Engineering Rule
Never commit plaintext secrets or config files to Git; inject production configs dynamically through secure secret stores with strict role-based access.
Exposed API keys, database credentials, and production toggle endpoints in source code lead to total infrastructure compromise and data breaches.
Use HashiCorp Vault, AWS Secrets Manager, or Kubernetes Secrets with envelope encryption. Gate production runtime config updates behind strict multi-factor auth and audit logs.
Architectural Blueprint & Sequence
Hover over nodes to inspect state transitionsGit Repository
Code ONLY (Zero Secrets)
CI/CD Pipeline
Builds immutable container image
HashiCorp Vault / KMS
Encrypted secrets & dynamic creds
Production Pod
Injects into in-memory ENV at boot
Actuator / Config Endpoints
Protected behind VPN / Internal Auth
Key Engineering Takeaways
- Zero secrets in Git repositories (enforce via pre-commit GitGuardian / gitleaks).
- Inject secrets via environment variables or ephemeral memory mounts at runtime.
- Dynamic configuration endpoints (e.g. Spring Boot `/actuator/env`) must never be exposed publicly.
- Rotate production database passwords automatically using short-lived dynamic credentials.
The Problem & Production Reality
Security breaches frequently stem from simple operational mistakes: a developer commits a `.env` file containing AWS keys, or an unprotected `/actuator/env` endpoint allows an attacker to dump database passwords in plaintext. Production configuration must be treated with zero-trust isolation.
Anti-Pattern: Hardcoded Secrets and Public Config Endpoints
Hardcoding database credentials in application.yml or leaving Spring Actuator endpoints publicly reachable on the web.
// ❌ ANTI-PATTERN: application.yml committed to Git
spring:
datasource:
url: jdbc:postgresql://prod-db.internal:5432/orders
username: admin
password: SuperSecretPassword123! # ❌ COMMITTED TO GIT!
management:
endpoints:
web:
exposure:
include: "*" # ❌ Exposes /actuator/env and /actuator/heapdump to the public internet!Production Pattern: Cloud Secret Injection & Actuator Lockdown
Reference environment variables populated dynamically from AWS Secrets Manager or Kubernetes Secrets, and lock Actuator behind internal port authentication.
// ✅ PRODUCTION PATTERN: Dynamic Config & Security Isolation
// application.yml
spring:
datasource:
url: ${DB_URL}
username: ${DB_USER}
password: ${DB_PASSWORD} # Injected at runtime from Vault / K8s secret
management:
server:
port: 9090 # Run management endpoints on a separate private internal port!
endpoints:
web:
exposure:
include: health,info,prometheus # Only expose safe metrics; never env/heapdump
base-path: /internal/management
endpoint:
health:
show-details: when_authorized
// SecurityConfig.java
@Configuration
public class ManagementSecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.securityMatcher("/internal/management/**")
.authorizeHttpRequests(auth -> auth
.requestMatchers("/internal/management/health").permitAll()
.anyRequest().hasRole("OPS_ADMIN") // Strict RBAC for operational toggles
)
.httpBasic(Customizer.withDefaults())
.build();
}
}Trade-off Analysis & Staff Recommendations
| Aspect | Pros / Strengths | Cons / Hazards | Staff Recommendation |
|---|---|---|---|
| Static Environment Variables vs Dynamic Vault Secrets | Dynamic Vault leases generate temporary 1-hour credentials that automatically expire. | Requires Vault sidecar agent integration in Kubernetes. | Use standard K8s Secret injection for early stages; upgrade to dynamic Vault leases for PCI-DSS/SOC2 compliance. |
| Runtime Hot Reloading | Update configurations without restarting pods. | Can lead to inconsistent states if pods reload config at different times. | Prefer immutable pod rollouts over dynamic hot reloading for critical configuration changes. |