Keep secrets out of code, and store them in a secrets manager in production.
Secrets must never be:
- committed to the repository
- baked into build artefacts, such as Docker images
- printed in logs
Git history keeps a leaked secret forever. So if someone commits a secret, you must rotate it (replace it with a new one). Deleting it from the code is not enough.
Environment variables are the baseline. They are injected at deploy time and kept out of code. They are easy to use. But they can leak through crash dumps, child processes and debug endpoints.
A secrets manager is better for production. Examples are HashiCorp Vault, AWS Secrets Manager or a cloud KMS (Key Management Service). It gives you:
- central storage
- encryption at rest
- fine-grained access policies
- audit logs
- automatic rotation, or short-lived dynamic credentials that expire on their own
Other good practice:
- Use separate secrets per service and per environment, each with least privilege (only the access it needs).
- Plan regular rotation.
- Run secret scanning in CI and in pre-commit hooks.
- Keep a runbook (a written step-by-step guide) for revoking a leaked secret quickly.
- Never put secrets in code, images or logs.
- A leaked secret must be rotated, not just deleted.
- Environment variables are a baseline, but they can leak.
- Secrets managers give access control, audit logs, rotation and dynamic credentials.
- Use least privilege per service and environment, and scan for secrets.
Read more