❯ Secrets management without a PhD: stop putting API keys in .env files
by Tess Walker — the help desk, Side Quest Studios September 25, 2026
Your .env file is in git. You know it's in git. You've known for six months. Every time you push, a little voice says "I'll fix that later," and later never comes because the deploy is green and nobody's screaming.
Then someone forks your repo, or a contractor clones it, or GitHub's secret scanner pings you at 2am, and suddenly you're rotating eleven credentials across four environments while your phone buzzes. I've done this dance. It's not fun. Let's fix it today, not next sprint.
Here's the thing nobody selling you a "secrets platform" wants you to hear: you don't need a PhD, a six-figure contract, or a Kubernetes operator with seventeen CRDs. You need three habits and about forty minutes. Everything else is ceremony.
The only two questions that matter
Secrets management reduces to this: where does the secret live, and who can read it? That's it. Every product, every blog post, every conference talk is an elaboration on those two questions.
If your answer to "where does it live" is "a file on the box next to the code," you've already lost. If your answer to "who can read it" is "anyone with shell access and cat," you've lost twice.
So the goal is to move the secret out of the code path, and to make reading it an auditable, permissioned act. Not because you're paranoid — because you're going to rotate it someday at 3am and you want that to be one command, not a scavenger hunt.
Start with the boring answer: environment variables from a real secret store
The single highest-leverage move is to stop committing secrets and start injecting them at runtime from something that isn't your repo. You have options. They're all fine. Pick one and move on.
If you're on a cloud, use its native secret manager — AWS Secrets Manager, GCP Secret Manager, whatever your host gives you. Not because it's magic, but because it handles encryption at rest, IAM, and rotation hooks for you. The CLI is one call:
Wrap that in your entrypoint. Don't bake it into the image. Don't echo it into the build log. If you're piping secrets into Docker builds, stop — build args leak into image history, and docker history will show the world your credentials.
If you're self-hosting and allergic to cloud lock-in — which, fair — use SOPS with age keys. It encrypts values in a YAML file you can commit, because the ciphertext is useless without the key. The key lives on the box, in your CI runner's secret store, or on a YubiKey. One command to decrypt:
That's it. That's the whole trick. Encrypted-at-rest in git, decrypted at runtime, key held separately. You get rotation, audit via git history, and no vendor invoice.
I've run both. SOPS plus age has been the one that survives contact with a team of five and a fleet of thirty boxes without anyone needing a wiki page to remember how it works.
The part everyone skips: rotation
Here's what actually bites you. Not storage. Rotation. You store the secret beautifully, then the day comes when you need to change it, and you discover it's hardcoded in three places, referenced by a cron job nobody remembers writing, and cached in a Redis key from 2024.
The fix is to make rotation a script, not an event. Write it down. Make it rotate.sh. It should:
- Generate a new secret (use
openssl rand -base64 32— notuuidgen, not your birthday). - Write it to the store.
- Restart or signal the consumers.
- Verify the new secret works before you delete the old one.
That last step is where people die. Never delete the old credential until the new one is confirmed live. Keep both valid for a window. Then kill the old one. I've watched a team take down production for forty minutes because they rotated first and verified never.
If your provider supports dual-credential rotation — most databases do — use it. Postgres roles, AWS IAM keys, Stripe restricted keys. They all let you have two live at once. That's your safety net.
What about the "just use Vault" crowd
Vault is a good tool. It's also a second job. I've stood up HashiCorp Vault for a team of four and watched it become a snowflake nobody wanted to touch, because unsealing it after a reboot required a quorum of humans who all went on holiday the same week.
If you have a platform team and a genuine multi-tenant need, sure. If you're a founder with three engineers and a product to ship, Vault is a distraction dressed as a solution. SOPS plus your cloud's native store will carry you to Series A and probably beyond.
Same logic for the managed "secrets as a service" pitch decks. They solve a real problem — the one you don't have yet. Don't buy the solution to somebody else's scale.
The 2am checklist
When it's dark and the pager is screaming, you want this to be muscle memory:
- Never put secrets in
.env,.bashrc,Dockerfile, or a CI variable that prints. If it's in the repo, it's public. Treat it that way. - Always inject at runtime, from a store, with the smallest permission set that works. One secret per service. No shared god-tokens.
- Rotate on a schedule and after every offboarding. Offboarding is the one people forget. The contractor who left in March still has the key you gave them in January.
- Audit who read what. Cloud secret managers log this for free. SOPS doesn't, so log your decrypt calls yourself — one line to syslog is enough.
- Test your rotation script in staging before you need it in anger. A rotation script that's never been run is a script that doesn't work.
That's the whole discipline. Four habits, forty minutes, no PhD.
The meta-lesson
Every time a new AI product launches — and they're launching daily, Meta's Muse is apparently out-downloading ChatGPT's early mobile numbers as I write this — the first thing it wants is your API key. And the second thing it wants is for you to paste that key into a web form with no rotation story and no audit trail.
Don't. The model is a commodity. Your credentials are not. Treat the key like the thing that pays your rent, because it is.
I've watched founders spend a weekend evaluating "secrets platforms" with comparison matrices and demo calls while their keys sat in a public repo. The evaluation was the procrastination. The fix was twenty minutes of git rm --cached .env and a SOPS commit.
Stop dithering. Go rotate something today.
References
- Secrets Management Cheat Sheet, OWASP Cheat Sheet Series (2024)
- Build secrets: pass secrets to builds without baking them into image layers, Docker Documentation (2025)
- What is AWS Secrets Manager?, Amazon Web Services Documentation (2025)
AI-assisted, curated for Side Quest Studios.