Skip to content
6 min read·Lesson 6 of 10

Secrets and Supply-Chain Security

Keep secrets out of pipelines, authenticate to clouds without long-lived keys, and harden the software supply chain end-to-end.

A pipeline has access to your code, your build tools, your registry, and your cloud accounts. A compromised pipeline is one of the worst things that can happen to a software company — see SolarWinds, Codecov, and 3CX. This lesson covers the controls that prevent it.

Where Secrets Live

LocationUse case
CI secret store (GitHub, GitLab, etc.)Build-time tokens, API keys
Cloud secret manager (AWS Secrets Manager, Azure Key Vault, GCP Secret Manager)Runtime app secrets
HashiCorp Vault / 1PasswordCentralised secrets across CI and runtime
Sealed Secrets / SOPSEncrypted secrets in Git

Secrets in environment variables are masked in logs by GitHub Actions automatically — but only if they were passed via secrets:. Anything you echo or cat on stdout is fair game for leakage. Be careful with debug output.

OIDC: The Modern Way to Auth to Clouds

The old way: store an AWS access key and secret in CI secrets, rotate occasionally, hope nothing leaks. The new way: federation.

GitHub Actions can issue an OpenID Connect (OIDC) token signed by GitHub. AWS, Azure, and GCP can verify that token and exchange it for a short-lived role.

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write          # required to mint the OIDC token
      contents: read
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-deploy
          aws-region: us-east-1
      - run: aws s3 cp ./dist s3://my-bucket --recursive

On the AWS side, the role's trust policy says "trust GitHub's OIDC issuer, but only for this repo, this branch":

{
  "Effect": "Allow",
  "Principal": { "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com" },
  "Action": "sts:AssumeRoleWithWebIdentity",
  "Condition": {
    "StringEquals": {
      "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",
      "token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:ref:refs/heads/main"
    }
  }
}

Benefits:

  • No static AWS keys to leak
  • Each job gets a fresh, short-lived (≤1 hour) credential
  • The trust policy can be scoped tightly — only main, only PRs, only specific environments
  • Same pattern works for Azure (azure/login) and GCP (google-github-actions/auth)

Pin Everything

Floating tags can be hijacked. Pin third-party actions, base images, and dependencies to immutable references.

# Bad — @v3 floats
- uses: someorg/action@v3

# Good — SHA is immutable
- uses: someorg/action@a1b2c3d4e5f6789...   # v3.1.4

Dependabot understands SHA-pinned actions and opens PRs to update them. Your security team gets to review every upgrade.

Container base images

# Pin to digest
FROM node:20.11.0-bookworm-slim@sha256:abcd1234...

Application dependencies

Use lockfiles (package-lock.json, poetry.lock, go.sum, Cargo.lock) and commit them. CI installs from the lockfile only — no surprise upgrades mid-build.

Dependency Scanning

  • Dependabot (GitHub) — opens PRs to upgrade vulnerable deps
  • Snyk, Mend, JFrog Xray — commercial SCA
  • Trivy, Grype — open-source CLI scanners
  • OSV-Scanner — Google's, fast, multi-ecosystem

Scan in the pipeline; fail builds on critical CVEs (with overrides for known false positives). Scan registry images on a schedule too — new CVEs are disclosed every day.

SBOMs (Software Bill of Materials)

An SBOM is a machine-readable list of every dependency in your build. Two common formats: SPDX and CycloneDX. Generate one per release:

syft myimage:1.0 -o cyclonedx-json > sbom.json
trivy sbom sbom.json                    # scan it later for new CVEs

Customers and regulators increasingly require SBOMs (US Executive Order 14028, EU Cyber Resilience Act).

Artefact Signing

Sign every artefact you ship; verify the signature before deploying. The standard tool is cosign from the Sigstore project.

# Sign (uses keyless OIDC by default)
cosign sign ghcr.io/org/app@sha256:abc...

# Verify
cosign verify --certificate-identity-regexp 'github.com/org/.*' \
              --certificate-oidc-issuer https://token.actions.githubusercontent.com \
              ghcr.io/org/app@sha256:abc...

Without signing, anyone with registry write access can swap a malicious image for a real one. With signing, you can prove an image was built by your CI.

SLSA — A Maturity Model

SLSA ("Supply-chain Levels for Software Artifacts") defines four levels of supply-chain integrity:

Level 1Build is scripted; provenance is recorded
Level 2Hosted build service produces signed provenance
Level 3Build is hardened; non-falsifiable provenance
Level 4Two-party review and hermetic, reproducible builds

GitHub Actions provides "build provenance" attestations that satisfy SLSA Level 3 with the right configuration:

- uses: actions/attest-build-provenance@v1
  with:
    subject-name: ghcr.io/org/app
    subject-digest: sha256:abc...
    push-to-registry: true

Hardening the Pipeline Itself

  • Restrict who can edit workflow files (CODEOWNERS + branch protection)
  • Disallow self-hosted runners on public repos (poison-PR risk)
  • Use minimal permissions: permissions: read-all at workflow level, then opt in
  • Forbid pull_request_target with checked-out PR code without review
  • Audit third-party actions before allowing them at org level
  • Enable artifact attestations and image signing

If a Secret Leaks

  1. Rotate the secret immediately at the source (cloud, registry, etc.)
  2. Search Git history (git log -S, GitHub secret scanning, trufflehog) for additional exposure
  3. Audit access logs for use during the leaked window
  4. Force-push to remove from history is rarely sufficient — assume the secret is permanently public
  5. Post-mortem and fix the leak path so it can't happen again

Fast rotation is more important than preventing every leak. Build the muscle.

Key Takeaways

  • Never commit secrets — use the CI tool secret store and inject at runtime.
  • OIDC federation lets pipelines assume short-lived cloud roles with no static keys.
  • Pin dependencies and third-party actions to SHAs; scan SBOMs for vulnerabilities.
  • Sign artefacts with cosign and verify them at deploy time.
  • SLSA provides a maturity model for supply-chain integrity.

Test your knowledge

Try exam-style practice questions to reinforce what you've learned.

Practice Questions →