Secrets, Properly

The Secret Leak Ladder (Worst → Best)

#PatternWho can read it
1COPY .env into the imageanyone who can pull the image, forever
2ENV DB_PASSWORD=… in the Dockerfilesame - it's baked into image metadata
3-e DB_PASSWORD=… at run timeanyone with docker inspect rights; often leaks into logs & crash dumps
4File mounted read-only + *_FILE envonly processes inside the container
5Secret manager (Vault, cloud SM) fetched at startupnarrowest: short-lived, audited, rotatable

Level 4 is the pattern every orchestrator standardized on (Swarm secrets, Kubernetes secret volumes):

$ echo "$DB_PASS" > /srv/secrets/db_password && chmod 600 /srv/secrets/db_password
$ docker run -d \
    -v /srv/secrets/db_password:/run/secrets/db_password:ro \
    -e DB_PASSWORD_FILE=/run/secrets/db_password \
    crm-api:v3

The _FILE convention (supported by the official postgres, mysql, redis images and easy to add to your own apps): if X_FILE is set, read the value from that path instead of X*.

Scenario: Real incident shape: a crash reporter uploads the process environment with every stack trace. Env-var secrets ship themselves to a third-party SaaS on every crash. File-based secrets don't. That's the Secrets Off the Env lab.
Tip: Also rotate what you can't hide: even with perfect hygiene, treat any secret that ever touched an env var, a log line or an image layer as burned.