Running in production Required
Keep secrets in a secrets store
Keep passwords, keys and tokens in a secrets manager or the platform's encrypted store. Give them to the app when it starts, and rotate them on a schedule.
How to do it
Use a store such as HashiCorp Vault, AWS Secrets Manager or your host's encrypted settings. On a single server, a root-only file or systemd credentials will do. Give each secret an owner and a rotation date at most 90 days ahead, and rotate at once after a leak. Automate it where the store can, as rotate secrets automatically says. See secrets out of code for keeping them out of the repository. See also let CI sign in with OIDC and keep secrets out of state.
Example
# systemd: the secret reaches the service as a file, never in its environment listing
[Service]
LoadCredential=db-password:/etc/shop/db-password
// Node.js: systemd puts each credential in a private folder
import { readFileSync } from 'node:fs';
import path from 'node:path';
const dbPassword = readFileSync(path.join(process.env.CREDENTIALS_DIRECTORY, 'db-password'), 'utf8').trim();
from pathlib import Path
import os
db_password = (Path(os.environ["CREDENTIALS_DIRECTORY"]) / "db-password").read_text().strip()
How to check
A secret scanner finds no secret in the repository or the build output. Every secret in the store shows an owner and a rotation date that has not passed.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers engineering playbook: https://agentwranglers.se/playbook/engineering/running-in-production/secrets-store.