Adios
BlogSecurity

Security

Keep secrets out of source

Environment names can live in a manifest. Credentials should not. Secret references preserve that boundary from local work through production.

Adios team7 min read

A secret committed once can survive in clones, caches, logs, and old commits long after the visible line is deleted.

Commit the reference, not the value

Application code needs stable environment variable names. It does not need the production credential behind each name. In an Adios manifest, a secret reference records the dependency without placing the value in the repository.

That keeps the deploy contract reviewable. A teammate can see that the application expects DATABASE_URL or STRIPE_SECRET_KEY while access to the underlying value remains controlled separately.

env:
  DATABASE_URL: secret://DATABASE_URL
  API_SIGNING_KEY: secret://API_SIGNING_KEY

Treat build and runtime as different audiences

Some credentials are needed only while dependencies are installed or private source is fetched. Others are needed by the running process. Giving every secret to both phases creates a larger exposure surface than the application requires.

Scope each value to the path that uses it, and do not print resolved values in build output, runtime logs, or error messages. A secret store cannot protect a credential that the application writes back into a public log.

  • Build-only: private package tokens and Git deploy keys.
  • Runtime-only: database passwords, signing keys, and provider API credentials.
  • Both phases only when the same value is genuinely required by both.

Rotation should be ordinary

A credential will eventually need to change. Use names and application behavior that let a value be replaced without editing source. For high-impact credentials, plan for an overlap period where old and new values can both be accepted while workloads restart.

If a secret reaches Git, rotate it first and clean the repository second. Removing the line is useful housekeeping, but it does not make the exposed value safe again.

  • Create the replacement credential without disabling the old one.
  • Update the stored value and roll workloads onto the replacement.
  • Verify logs and provider activity use the new credential.
  • Revoke the old credential and record the rotation time.

Respond to a committed credential

Suppose a developer commits a database URL, removes it in the next commit, and force-pushes the branch. Treat the password as exposed anyway: a clone, CI fetch, editor index, or pull-request cache may already contain it.

Disable or rotate the credential, inspect its provider audit trail, search logs for accidental echoes, and only then clean repository history. History rewriting reduces future discovery; rotation removes the present access path.

  All articles