DevSecOps · Guide · 2026

Building a Secure CI/CD Pipeline with GitHub Actions and Trivy

A practical, opinionated walkthrough for shifting security left — from source commit to production deploy — using GitHub Actions, Trivy, OIDC, and a handful of small, boring guardrails that actually work.

Why DevSecOps

Traditional pipelines treat security as a gate at the end. DevSecOps flips that: every commit is scanned, every dependency is checked, every image is verified before it reaches production. The goal is not to add friction — it is to catch the boring 90% of issues automatically so humans can focus on the interesting 10%.

Pipeline Stages

  1. Source — signed commits, branch protection, required reviews.
  2. Static analysis — CodeQL / Semgrep for SAST.
  3. Dependencies — Trivy or Dependabot for SCA + license checks.
  4. Build — reproducible container images, pinned base images.
  5. Image scan — Trivy scan on the built image, fail on HIGH/CRITICAL.
  6. SBOM — generate + attach a Software Bill of Materials.
  7. Deploy — OIDC to cloud, no long-lived keys, immutable tags.
  8. Runtime — monitoring, alerting, and periodic re-scans.

A Minimal Secure Workflow

The workflow below runs on every push. It installs dependencies, runs a filesystem scan with Trivy, builds a Docker image, scans the image, and uploads the SARIF report to GitHub's Security tab.

name: ci-secure

on:
  push:
    branches: [main]
  pull_request:

permissions:
  contents: read
  security-events: write
  id-token: write        # for OIDC to AWS/GCP

jobs:
  build-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Trivy filesystem scan
        uses: aquasecurity/trivy-action@0.24.0
        with:
          scan-type: fs
          scan-ref: .
          severity: HIGH,CRITICAL
          exit-code: '1'
          ignore-unfixed: true
          format: sarif
          output: trivy-fs.sarif

      - name: Upload SARIF
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: trivy-fs.sarif

      - name: Build image
        run: docker build -t app:${{ github.sha }} .

      - name: Trivy image scan
        uses: aquasecurity/trivy-action@0.24.0
        with:
          image-ref: app:${{ github.sha }}
          severity: HIGH,CRITICAL
          exit-code: '1'
          ignore-unfixed: true

Secrets Management

  • Never commit .env — use GitHub Encrypted Secrets or a cloud secret store.
  • Prefer OIDC over long-lived cloud keys (AWS configure-aws-credentials, GCP Workload Identity).
  • Rotate anything that ever appeared in a log. Assume it is compromised.
  • Run gitleaks in CI to catch accidental secret commits.

Container Hardening

  • Use minimal base images (distroless, alpine, or chainguard).
  • Pin by digest, not by tag: FROM node@sha256:....
  • Run as a non-root USER. Drop Linux capabilities.
  • Set readOnlyRootFilesystem: true in Kubernetes.

SBOM & Supply Chain

Generate an SBOM with trivy sbom or syft, attach it to the release, and sign artifacts with cosign. This gives you a queryable inventory the day a new CVE drops — instead of grepping repositories at 2am.

Failing Loudly

A scan that warns is a scan that gets ignored. Set exit-code: 1 on HIGH/CRITICAL and let the pipeline fail. Then triage — either fix, upgrade, or explicitly waive with a tracked .trivyignore entry and an expiry date.

Beyond the Pipeline

  • Re-scan running images on a schedule — CVEs are published continuously.
  • Ship logs and metrics (Prometheus + Grafana, or a hosted stack).
  • Practice restoring from backups. An untested backup is a hope.

Wrap-up

A secure pipeline is not a single tool — it is a chain of small, enforced defaults. Start with Trivy + branch protection + OIDC, add SBOMs and image signing next, and layer on runtime monitoring once the basics are boring. The best security work is invisible.

Also see the DevSecOps tools stack guide.

Written by Piyush Prasad — Cloud & DevOps Engineer. Back to portfolio.