ML
Security

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.

May 26, 20269 min readSecuritySystem Design

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.
SharePostLinkedIn

Reader Discussion

2 replies// weighed in

TopNewestAuthor
Add to the thread
Disagree, agree harder, or share your own experience…
Email instead →markdown okbe kind
  1. Rachel Gold· Staff SREAgrees

    the on-call framing throughout this piece is what makes it land. too many infra articles assume you never get paged. those are written by people who never got paged.

    May 29, 2026·3 days later
  2. Omar Khalil· Senior SWEKind words

    this is the third article from this blog I've sent to my team this month. you're cooking. don't switch to crypto.

    May 31, 2026·5 days later

Worked on something similar? Email ducminhldm@gmail.com — I read every one. The good ones become future posts.

Comments seeded · live discussion via email