--:--
notes/commonplace/secrets.mdx

NOTES / Commonplace ·

Managing secrets for a small deployment

A secret is anything that grants access: API keys, passwords, private keys, tokens.

Where secrets live

  • Never in the repository, public or private. Git history keeps everything forever; deleting the line later doesn't help.

  • In CI: GitHub Secrets (repository or per environment). Encrypted at rest, masked in logs, only readable by workflows.

  • On the server: a file outside git with tight permissions, loaded as environment variables.

    umask 077 && echo 'API_KEY=...' >> secrets.env   # file readable only by you
    

    With Docker Compose: env_file: [secrets.env] on the service, and secrets.env in .gitignore.

  • In the app: read from process.env at startup; never log them, never send them to the browser.

Getting them from CI to the server

Make it generic, so a new key needs no code change. One pattern:

  1. Name every app secret with a prefix: APP_TRANSLATOR_KEY, APP_SMTP_PASSWORD.
  2. In the deploy job, expose all secrets as JSON (toJSON(secrets)), select the APP_ ones with jq, strip the prefix.
  3. Send the resulting NAME=value lines over SSH stdin, not as command-line arguments (those show up in ps and logs).
  4. A deploy script on the server upserts each line into secrets.env (replace the line with the same name, keep the rest) and restarts the app.

Things that leak secrets

  • Pasting command output: many CLIs print keys (az ... keys list). Pipe straight into the file instead:

    echo "KEY=$(az ... keys list --query key2 -o tsv)" >> secrets.env
    
  • echo with secrets on a shared screen, shell history (HISTCONTROL=ignorespace and a leading space help), screenshots, chat messages.

  • Error messages that dump the environment.

When one leaks

  1. Rotate: regenerate the key at the provider (services usually give two keys so you can switch with no downtime) and update it where it is used.
  2. Check usage and billing for abuse.
  3. If rotating isn't worth it, decide consciously: what can someone do with it, and what would it cost? A free-tier key at worst burns the free quota; a cloud admin key can cost thousands.

Related: CI/CD with GitHub Actions and GHCR, SSH keys.