DevSecOps Pipeline
A DevSecOps pipeline integrates automated security testing into every phase of the CI/CD process: SAST on commit, SCA for dependencies, container scanning during the build, DAST against staging environments, and IaC scanning before deployment. Security gates ensure that critical findings halt the pipeline.
A DevSecOps pipeline automates security checks throughout all phases of the software development lifecycle. The goal: to identify vulnerabilities early on (when they are cheaper to fix) and to ensure that no insecure code is deployed to production.
Pipeline Architecture
Stage 1 - Pre-Commit (Developer Workstation):
- Semgrep/Bandit: SAST in the IDE or pre-commit hook
- gitleaks: Secrets scan (no API keys in commits!)
#!/bin/bash
semgrep --config=p/security --error .
gitleaks detect --source . --exit-code 1
Stage 2 - Build (CI, e.g., GitLab CI):
sast-scan:
image: returntocorp/semgrep
script:
- semgrep --config=p/owasp-top-ten --json > semgrep.json
artifacts:
reports:
sast: semgrep.json
sca-scan:
image: node:20
script:
- npm audit --json > npm-audit.json
- npx snyk test --json > snyk.json
allow_failure: false # If Critical: Stop pipeline!
container-scan:
image: aquasec/trivy
script:
- trivy image --exit-code 1 --severity CRITICAL $IMAGE
Stage 3 - Test (Staging):
dast-scan:
script:
- docker run owasp/zap2docker-stable zap-baseline.py
-t https://staging.example.com
-r zap-report.html
--exit-code 1 # If HIGH: Stop the pipeline!
Stage 4 - Deploy (Production):
iac-scan:
image: bridgecrew/checkov
script:
- checkov -d ./terraform --framework terraform
--hard-fail-on HIGH,CRITICAL
Security Gate Logic:
| Severity | Action |
|---|---|
| CRITICAL | Stop pipeline immediately, no merge allowed |
| HIGH | Stop pipeline (configurable) |
| MEDIUM | Warning, create ticket, merge allowed |
| LOW/INFO | Log, track trend |
Specific Tool Configurations
Semgrep (SAST) - GitHub Actions:
name: SAST Scan
on: [push, pull_request]
jobs:
semgrep:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: returntocorp/semgrep-action@v1
with:
config: >-
p/owasp-top-ten
p/django
p/nodejs
p/java
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
Trivy (Container + IaC Scanning):
# Dockerfile scan:
trivy config ./Dockerfile
# Image scan before push:
trivy image --severity HIGH,CRITICAL --exit-code 1 myapp:latest
# Kubernetes YAML:
trivy config ./k8s/
# GitHub Actions:
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.IMAGE }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1'
gitleaks (Secrets Detection) - .gitleaks.toml configuration:
[allowlist]
regexes = [
'''fake-api-key-.*''', # Ignore test keys
'''example\.com''', # Ignore example domains
]
# .pre-commit-config.yaml:
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.18.0
hooks:
- id: gitleaks
OWASP Dependency Check (SCA for Java/.NET):
mvn org.owasp:dependency-check-maven:check \
-DfailBuildOnCVSS=7 # Fail if CVSS >= 7
DAST with Nuclei (fast, template-based):
nuclei -u https://staging.example.com \
-t cves/ \
-severity critical,high \
-o nuclei-results.txt \
-exit-code # Exit 1 on findings