What is secrets management and why tokens do not belong in code

BasicsSecurityDevOpsCI/CD

Secrets management diagram: code moves through CI/CD while tokens and keys are stored separately in a protected vault

Hook

Secrets management is the discipline that keeps tokens, passwords, and keys from becoming a hidden mine inside your repository. Code can be shared with teammates, reviewers, and CI/CD. Secrets cannot be treated the same way.

If an API key reaches git, the problem is not solved by deleting one line. The value may already be in commit history, forks, caches, build logs, or somebody’s local clone. That is why the practical rule is simple: secrets do not belong in code.

Problem / Context

Small projects often start innocently. One token goes into .env, another is sent in chat, the database password lands in a note, and a deployment key is added to GitHub Actions. While the team is tiny, this can feel manageable.

Then the project gains staging, production, several developers, a contractor, CI/CD, Docker, monitoring, and external integrations. Suddenly nobody is fully sure which token is used where, who can read it, when it was last changed, or what will break after rotation. At that point secrets are no longer just configuration. They are part of the product’s security model.

Secrets management exists for this moment. It answers practical questions:

  • where secrets are stored;
  • who can read them;
  • how they reach the application;
  • how their permissions are limited;
  • how quickly they can be revoked;
  • how the team notices accidental exposure.

A good setup does not ask a developer to copy a production password into a local file. It gives separate secrets for separate environments, narrow permissions for each token, and a clear replacement procedure.

Why it matters

A leaked secret may look like a small mistake, but the consequences can be expensive. One token can expose a private repository, delete data, create costly cloud resources, send spam, break a deploy pipeline, or open production access.

The uncomfortable part is that secrets are often used by machines, not people. A person may notice a suspicious login. A token can quietly work for weeks if its permissions are too broad and there is no audit log. That is why token scope, secret scanning, and regular rotation matter.

Secrets management also reduces operational stress. When values live in random places, every incident becomes a search: where is this key, who created it, can we disable it, will production fall over? When there is a vault or at least a disciplined platform secrets store, the answer is faster and calmer.

The mental model

Think of the repository as the house manual and secrets as the keys to the doors. The manual can be shared with builders. The apartment keys should not be glued into every copy of the manual.

A practical model looks like this:

  • code contains variable names and expected configuration;
  • local development uses test values from a local .env that never reaches git;
  • CI/CD reads secrets from platform settings;
  • production receives secrets from a vault or secrets manager;
  • each environment has separate values;
  • each token has minimal token scope;
  • secret scanning catches accidental leaks before merge or immediately after push.

This does not need to be a complex enterprise vault on day one. For a small project, a healthy start is .gitignore, an .env.example file, GitHub Actions secrets, separate production variables in hosting, and enabled secret scanning. The important part is having a system, not a pile of informal habits.

How to do it

1. Inventory the secrets

Start by listing everything that counts as a secret. Usually that includes:

  • database URL;
  • external service API key;
  • OAuth client secret;
  • webhook secret;
  • SSH key or deploy token;
  • JWT signing key;
  • encryption key;
  • admin password;
  • cloud access token.

Do not stop at .env. Check README files, documentation, Dockerfile, docker compose, CI/CD logs, issues, old snippets, and git history. Secrets often live exactly where somebody once left them “temporarily”.

2. Separate environments

Development, staging, and production should not share the same token. If a local laptop has production access, any local malware or accidental commit becomes a production risk.

A minimal healthy model:

  • development uses test keys or a sandbox;
  • staging has separate integrations and test data;
  • production has the narrowest permissions and strictest access;
  • break-glass access exists, but is not used every day.

3. Move secrets out of code

Code should keep only variable names: DATABASE_URL, STRIPE_SECRET_KEY, GITHUB_TOKEN. Values should arrive from the runtime environment.

For local work:

  • add .env to .gitignore;
  • create .env.example without real values;
  • document where to get test keys;
  • do not ask people to copy production secrets.

For CI/CD:

  • use the platform secrets store;
  • do not print secrets in logs;
  • avoid passing secrets through build args if they may remain in an image layer;
  • separate secrets for pull request, staging, and production workflows.

4. Limit permissions

A token that can do everything is convenient only until the first leak. Prefer several narrow tokens:

  • read-only token for API reads;
  • deploy token only for one environment;
  • separate webhook secret for signature checks;
  • service account without access to unrelated projects.

The principle of least privilege sounds formal, but in real life it means one simple thing: if a token only needs to read data, it should not be able to delete data.

5. Enable detection and rotation

Secret scanning should work before a leak turns into an incident. In GitHub, this can be enabled at repository or organization level. For self-hosted Git, add checks to CI/CD or pre-commit.

If a secret has already reached git, deleting it from the file is not enough. The safer order is:

  1. revoke the old secret;
  2. create a new one with minimal permissions;
  3. update the secrets store;
  4. verify deploy and runtime;
  5. clean history if that reduces future risk;
  6. record the incident and root cause.

Rotation should not be a heroic midnight ritual. It should be a normal procedure. If the team is afraid to change a token, secrets management is not finished yet.

Common mistakes

  • committing .env and assuming a private repository is enough protection;
  • using one production token in development, staging, and CI/CD;
  • storing secrets in README files, notes, chats, or issues;
  • giving admin permissions when read-only access would work;
  • printing secrets in logs for “just a minute” debugging;
  • passing secrets into a Docker image so they remain in layer history;
  • deleting an exposed key from a file but not revoking it;
  • having no clear owner for rotation;
  • never scanning old commits for leaked values.

Conclusion / Action Plan

Secrets management is not paranoia and it is not an enterprise luxury. It is basic hygiene for any project that has tokens, a database, CI/CD, or production.

Start small:

  1. find all secrets in the project;
  2. remove real values from code;
  3. add .env.example;
  4. move CI/CD and production secrets into a secrets store;
  5. separate development, staging, and production;
  6. limit token scope;
  7. enable secret scanning;
  8. write a short rotation plan.

When secrets live separately from code, deploys become calmer, reviews become safer, and incidents do not start with “I think we committed a key”.

Official sources:

Quick checklist

  • Check that secrets are not stored in code, README files, issues, chats, or Docker images.
  • Separate secrets for development, staging, and production.
  • Enable secret scanning and check repository history.
  • Limit token scope to the smallest required permission set.
  • Prepare a rotation plan for every secret that may have been exposed.

Prompt Pack: check secrets management

Help me check whether my project handles secrets safely. Input data: - where tokens, API keys, database passwords, and deployment keys currently live; - which environments exist: development, staging, production; - which CI/CD or GitHub Actions workflows are used; - who has access to the repository, hosting, and secrets; - whether secret scanning, audit logs, and rotation procedures exist; - what would happen if one token accidentally reached git. Return: 1. a short verdict: healthy, risky, or critical; 2. secrets that must be moved out of code; 3. a safer storage model for local, staging, and production; 4. minimum token scope for each access path; 5. a rotation plan for already exposed secrets; 6. a checklist that can be added to pull request review. Response format: verdict, risks, target model, rotation plan, checklist.