Menu

Topic 4 of 8

Secrets In CI CD

Learn Secrets In CI CD for free with explanations, exercises, and a quick test (for Platform Engineer).

Published: January 23, 2026 | Updated: January 23, 2026

Why this matters

As a Platform Engineer, you wire up CI/CD that touches code, infra, and production environments. Secrets (tokens, keys, passwords, certificates) are the keys to your kingdom. A leak can halt deployments, expose data, or enable supply-chain attacks. Securing secrets in CI/CD lets teams ship fast without risking everything.

  • Real tasks you will face: choosing a secrets store; wiring pipelines to fetch short-lived credentials; preventing secrets from landing in logs or artifacts; rotating and revoking credentials; auditing access in compliance reviews.
  • Your success metric: no hard-coded secrets, no plain-text exposure in logs/artifacts, scoped least-privilege access, and quick, low-drama rotation.

Concept explained simply

Secrets in CI/CD are sensitive values used by pipelines to authenticate to services (cloud providers, registries, databases). Instead of hard-coding, you store secrets safely and inject them only when needed, keep them short-lived and scoped, and never print them.

Mental model

Think of your pipeline as a clean room. Secrets are access badges issued at the door, checked by guards (policies), and shredded when you leave. The less time a badge exists and the fewer doors it opens, the safer the building.

Key principles to remember
  • Least privilege: every token can do only what the job needs.
  • Ephemeral: prefer short-lived, auto-expiring credentials over long-lived keys.
  • Just-in-time: fetch secrets only in the steps that need them.
  • No exposure: never echo secrets; avoid storing them in logs, artifacts, or images.
  • Traceability: audit who/what accessed which secret and when.

Core patterns you will use

  • Use a managed secrets store (e.g., cloud KMS + secrets manager, Vault). Avoid storing secrets in repo or pipeline YAML.
  • OIDC/workload identity: pipelines authenticate to cloud providers without static keys.
  • Masking: configure CI to mask secret values and disable command echoing when needed.
  • Context scoping: restrict secrets to repos, branches, protected environments, and runners.
  • Rotation: automate regular rotation; ensure zero-downtime switchover.
  • Scanning: pre-commit and CI scans to catch accidental commits of secrets.
  • Kubernetes: inject secrets via sealed secrets or external secrets operators; mount at runtime.

Worked examples

Example 1: GitHub Actions with OIDC to AWS (no long-lived keys)

Goal: Deploy to S3 without storing AWS access keys in GitHub.

name: deploy
on: [push]
permissions:
  id-token: write
  contents: read
jobs:
  s3-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Configure AWS via OIDC
        run: |
          export AWS_REGION=us-east-1
          # aws CLI uses OIDC + role configured to trust GitHub
          aws sts get-caller-identity
      - name: Upload
        run: |
          set +x  # avoid echoing commands with variables
          aws s3 sync dist/ s3://my-bucket/ --delete
  • No static AWS keys stored in CI.
  • permissions.id-token enables OIDC; AWS role trust policy allows GitHub to assume it.
  • set +x reduces risk of data echo.
Example 2: GitLab CI pulling a secret at job time
stages:
  - build

build:
  image: alpine:3.19
  stage: build
  variables:
    # Masked variable in GitLab CI settings: DOCKER_PASSWORD
    DOCKER_USERNAME: ci-bot
  script:
    - set +x
    - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
    - docker build -t registry.example.com/app:$CI_COMMIT_SHORT_SHA .
    - docker push registry.example.com/app:$CI_COMMIT_SHORT_SHA
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
  • Password is masked in logs; not stored in repo.
  • Scoped to main branch via rules.
Example 3: Kubernetes sealed secret decrypted only in the cluster
# Developer holds only the public key; CI applies sealed secret manifest.
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
  name: app-secret
  namespace: prod
spec:
  encryptedData:
    DB_PASSWORD: AgB... # produced by kubeseal using the cluster's public key
  • Even if the sealed secret is in your repo, only the cluster controller can decrypt it.
  • CI never sees the plaintext; it just applies the manifest to the cluster.

How to design your secret flow (step-by-step)

  1. Inventory: list every place the pipeline needs credentials (registry, cloud, DB, chat webhook).
  2. Choose issuance: OIDC for cloud roles; secrets store for app creds; dynamic secrets where possible.
  3. Scope: bind secrets to environments and branches (e.g., only protected branches can access prod).
  4. Inject: load only in the step that needs it; avoid exporting to the whole job.
  5. Protect logs: enable masking, avoid verbose flags, use set +x before sensitive commands.
  6. Rotate: script rotation and update references; test rollback.
  7. Audit: enable access logs; review monthly.

Common mistakes and how to self-check

  • Hard-coding secrets in YAML or Dockerfiles. Self-check: search for patterns like AKIA, xoxb-, -----BEGIN.
  • Leaking to logs via -x or set -x. Self-check: review logs; verify masked values are not visible.
  • Over-broad permissions. Self-check: list actions the token can perform; remove unused ones.
  • Forgetting rotation. Self-check: document expiry dates; add a calendar reminder or a CI job that warns before expiry.
  • Sharing one secret across multiple services. Self-check: map secret-to-service and break apart shared creds.
Quick self-audit checklist
  • No static cloud keys in repo or CI variables when OIDC is available.
  • All secrets masked; verbose logging disabled around secret use.
  • Secrets scoped to environment/branch; prod secrets only on protected runners.
  • Rotation process exists and is tested.
  • Secrets never land in artifacts or container layers.

Exercises

Do these hands-on. They mirror the graded exercises below.

Exercise 1: Spot and fix leaks

Review this CI snippet. Identify every risk and propose fixes.

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      DOCKER_PASS: mySuperSecret123
    steps:
      - run: |
          set -x
          echo "Logging in"
          docker login -u user -p $DOCKER_PASS
          echo "Password was $DOCKER_PASS"  # debug
      - run: |
          export AWS_ACCESS_KEY_ID=AKIA... # added for convenience
          export AWS_SECRET_ACCESS_KEY=abcd...
          aws s3 ls
  • List the issues and for each, write a safer alternative.

Exercise 2: Short-lived cloud access

Write a CI job that deploys to a cloud bucket using short-lived credentials (OIDC/workload identity). No static keys. Prove in logs that no key is printed.

  • Deliverable: CI YAML with id-token permission (or equivalent), a call showing the caller identity, and a deployment step with set +x around sensitive commands.
Readiness checklist before you submit
  • Zero plaintext secrets in YAML.
  • No secret value appears in any echo or log line.
  • Permissions are minimal (only the actions required).
  • Secrets are injected only into the steps that need them.
  • Rotation or expiry is documented.

Practical projects

  • Project 1: Migrate from static registry credentials to a scoped robot account + masked password, then rotate it and prove zero downtime.
  • Project 2: Replace static cloud keys with OIDC role assumption; remove old keys; add an automated check that fails if keys reappear.
  • Project 3: Implement sealed/external secrets for a Kubernetes deployment. Ensure CI applies manifests without ever holding plaintext.

Learning path

  • Start: Understand masking, scoping, and safe logging.
  • Next: Implement OIDC/workload identity for one cloud.
  • Then: Add scanning and rotation automation.
  • Advanced: Dynamic secrets (e.g., DB creds) and per-environment isolation.

Who this is for

  • Platform and DevOps engineers wiring CI/CD to cloud and Kubernetes.
  • Backend engineers who own deployment pipelines.
  • Security engineers improving supply-chain hardening.

Prerequisites

  • Basic CI/CD YAML skills (any major system).
  • Familiarity with cloud IAM concepts (roles, policies).
  • Comfort with shell scripting and environment variables.

Next steps

  • Do the exercises and projects above.
  • Run a secrets audit on a real pipeline and fix at least three issues.
  • When ready, take the Quick Test. Everyone can take it; only logged-in users get saved progress.

Mini challenge

Within one day, remove all static cloud keys from one pipeline using OIDC or equivalent, prove the job still works, and document the change so teammates can follow the pattern.

Practice Exercises

2 exercises to complete

Instructions

Review this CI snippet. Identify each risk and propose a safer alternative for every line that mishandles secrets.

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      DOCKER_PASS: mySuperSecret123
    steps:
      - run: |
          set -x
          echo "Logging in"
          docker login -u user -p $DOCKER_PASS
          echo "Password was $DOCKER_PASS"  # debug
      - run: |
          export AWS_ACCESS_KEY_ID=AKIA... # added for convenience
          export AWS_SECRET_ACCESS_KEY=abcd...
          aws s3 ls
  • List all issues.
  • Rewrite the snippet to avoid these problems.
Expected Output
- A list of at least five issues with explanations. - A revised CI snippet that uses masked variables or OIDC, avoids echoing secrets, and disables verbose logging around sensitive commands.

Secrets In CI CD — Quick Test

Test your knowledge with 8 questions. Pass with 70% or higher.

8 questions70% to pass

Have questions about Secrets In CI CD?

AI Assistant

Ask questions about this tool