Doppler service tokens in CI pipelines

A CI pipeline needs secrets to run integration tests and deploys, but it should never hold long-lived credentials or see more than its own environment. A scoped Doppler service token solves both. This page wires it into CI, extending Doppler for Multi-Cloud Secrets.

Problem 1: production secrets in the CI config

# ANTI-PATTERN: a broad token (or raw secrets) pasted into CI variables
env:
  DOPPLER_TOKEN: dp.st.prod.broadAccessToken   # grants prod to every CI job

A production-scoped token in CI hands every pipeline run access to production secrets.

Problem 2: echoing fetched secrets

# ANTI-PATTERN: secrets printed into the build log
doppler secrets download --no-file --format env   # then echoed by a later step

Downloading then printing leaks the values into the build log.

Secure implementation

# .github/workflows/test.yml
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: curl -Ls https://cli.doppler.com/install.sh | sh
      - run: doppler run --config ci -- pytest    # injects CI-scoped secrets only
        env:
          DOPPLER_TOKEN: $   # masked, read-only, ci config
# tests/conftest.py — read injected values, never print them
import os
from pydantic import SecretStr
API_KEY = SecretStr(os.environ["API_KEY"])   # masked in repr; unwrap only where needed

The DOPPLER_CI_TOKEN is a read-only token scoped to the ci config, stored as a masked CI secret. doppler run injects the values into the test process; nothing is downloaded to a file or printed.

Gotchas & version-specific behaviour

  • Scope the service token to the ci config and make it read-only.
  • Store DOPPLER_TOKEN as a masked CI secret; never inline it.
  • Prefer doppler run over doppler secrets download so values stay in the process, not a file.
  • Rotate the CI token on a schedule, independent of the secrets it exposes.

Production parity checklist

  • The CI token is read-only and scoped to the CI config.
  • The token is a masked CI secret.
  • Secrets are injected via doppler run, not written to a file or echoed.
  • Fetched values are SecretStr-wrapped in test code.
  • The token is rotated independently of the secrets.

Conclusion

A read-only, config-scoped Doppler service token gives CI exactly the secrets it needs and nothing more, with no long-lived credential in the pipeline. For the local-development equivalent, see Syncing Doppler Secrets to Local Docker Containers.