← Back to libraryQuestion 229 of 273
🔧CI/CDIntermediate

Secrets & Environment Management

📌 Definition:

Secrets are sensitive values a pipeline needs — API keys, tokens, database passwords, signing credentials — stored encrypted in the CI system and injected into jobs as environment variables at run time, never committed to the repository.

📖 Detailed Explanation:

Hard-coding credentials in code or YAML is a serious, common security failure; anyone with repo read access (and anyone who ever cloned it) gets the secret, and it lives forever in git history. CI systems provide an encrypted secret store (repository/organization/environment scoped) that injects values as masked environment variables — masked meaning the platform redacts them from logs if accidentally printed. Environments (dev/staging/prod) let you scope different secret values and add protection rules like required approvals before a job can access production secrets. Good practice: least privilege (a token scoped to only what the job needs), rotation, environment scoping, and never echoing secrets. For test environments specifically, prefer dedicated test credentials and test data, never production secrets, so a leak or a rogue test can't touch real systems.

🔑 Key Points:
  • Store secrets in the CI's encrypted store; never commit them to the repo/history
  • Injected as masked env vars — the platform redacts them from logs
  • Scope by environment (dev/staging/prod) with protection rules on prod
  • Least privilege + rotation: tokens scoped narrowly and rotated regularly
  • Tests use dedicated test credentials/data, never production secrets
🌍 Real-World Example:

An API key was pasted directly into a workflow file. A security scan flags it; the team rotates the key immediately (since it's now in git history forever), moves the new key into the encrypted secrets store as ${{ secrets.API_KEY }}, and scopes it to the staging environment so it can never touch production.

📎 Code Example:
jobs:
  api-tests:
    runs-on: ubuntu-latest
    environment: staging          # scopes which secrets are available
    steps:
      - uses: actions/checkout@v4
      - run: npm ci
      - run: npm run test:api
        env:
          API_BASE_URL: https://staging.example.com
          API_TOKEN: ${{ secrets.STAGING_API_TOKEN }}   # injected, masked in logs
# NEVER: API_TOKEN: 'sk_live_9f8a...' hard-coded in YAML or source
🎯 Scenario-Based Interview Question:

Scenario: A code review turns up a database password committed in a test config file six months ago. The author says 'it's only the staging DB, and I'll just delete the line'. Why is deleting the line insufficient, and what's the correct remediation?