Secrets Management: Stop Shipping Keys in Your .env
A .env file committed once lives in git history forever. Real secrets management is about rotation, scoping, and never letting a credential touch disk in plaintext.
The .env file is fine for a side project and a liability everywhere else. The problems aren't hypothetical: it gets committed by accident, copied into Slack, baked into a Docker image layer, and printed by a crash dump. Proper secrets management is less about a vault product and more about four habits.
1. Secrets never live in the repo or the image
A secret committed once is in git history forever — rewriting history doesn't help once it's pushed; you must rotate. And a secret passed as a Docker ARG or copied in an early layer is readable with docker history. Inject secrets at runtime, from the environment or a mounted file, never at build time.
# leaks into the image layer — readable forever
ARG API_KEY
# correct: provided at runtime by the orchestrator
ENV API_KEY_FILE=/run/secrets/api_key
2. Use a secrets manager as the source of truth
Vault, AWS Secrets Manager, GCP Secret Manager, or a Kubernetes secrets store CSI driver. The app fetches the secret at startup (or reads a mounted file the platform refreshes). Benefits you can't get from a file: centralised access control, audit logs of who read what, and automatic versioning.
3. Rotation has to be routine, not heroic
If rotating a credential requires a coordinated redeploy and a prayer, it never happens — so a leaked key stays valid for years. Design for rotation: support two valid credentials at once so you can roll the new one out, switch, then revoke the old without downtime. Short-lived, auto-renewed credentials (dynamic database creds, IAM role assumption) are the end state — a leaked 15-minute token is nearly worthless.
4. Scope every credential to least privilege
The reporting service's database user does not need DROP TABLE. The image-upload role needs write to one S3 prefix, not s3:*. Scope by action and by resource so that a single leaked credential is a contained incident, not a full breach.
5. Detect leaks before attackers do
Run a pre-commit secret scanner (gitleaks, trufflehog) and the same in CI so a key never reaches the remote. Turn on your cloud's automatic credential-exposure alerts. Assume something will leak eventually and make sure you find out first.
Rules of thumb
- Inject secrets at runtime. Nothing sensitive in the repo or the image.
- A leaked secret is rotated, not "removed from history." Build rotation in from day one.
- Prefer short-lived dynamic credentials over long-lived static keys.
- Scope to least privilege so one leak doesn't become a breach.
- Scan for secrets in pre-commit and CI — catch them before the push.