transitioning pipelines to a devsecops pipeline design
Traditional DevOps focuses on speed and reliability but often treats security as an afterthought — vulnerabilities are caught too late in production.
DevSecOps integrates security at every stage of the pipeline. Here are the critical additions:
The "Shift Left" Principle
Instead of finding security issues after deployment, DevSecOps catches them early:
- Pre-commit: Scan for secrets before code is pushed
- Build time: SAST analysis, dependency checks, container scanning
- Pre-deploy: Verify signatures, compliance gates, IaC security
- Runtime: Intrusion detection, vulnerability monitoring
- Post-deploy: DAST testing, regression checks
# DevSecOps vs DevOps Pipelines in GitHub Actions
## Core Differences
### Traditional DevOps Pipeline
- **Focus**: Speed and reliability
- **Security**: Added at the end (security testing after deployment)
- **Approach**: "Shift right" - security concerns are addressed late
### DevSecOps Pipeline
- **Focus**: Speed, reliability, AND security throughout
- **Security**: Integrated at every stage (build, test, deploy, run)
- **Approach**: "Shift left" - catch security issues early and often
---
## Key Security Stages in DevSecOps
| Stage | Traditional DevOps | DevSecOps |
|-------|-------------------|----------|
| **Code Commit** | Basic linting | SAST scan, secrets detection, code review |
| **Build** | Compile, test | Compile, test, dependency scan, build artifact scan |
| **Deploy** | Push to registry | Image signing, compliance check, SBOM generation |
| **Runtime** | Monitoring only | Monitoring + vulnerability detection + intrusion detection |
---
## GitHub Actions Workflow Examples
### Example 1: Traditional DevOps (No Security)
```yaml
name: Traditional DevOps Pipeline
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm ci
- run: npm test
- run: npm run build
- uses: docker/build-push-action@v4
with:
push: true
tags: myrepo:latest
```
**Problems:**
- ❌ No dependency vulnerability checks
- ❌ No secrets scanning
- ❌ No container image scanning
- ❌ No compliance validation
- ❌ Security issues found only in production
---
### Example 2: DevSecOps Pipeline (Security-First)
```yaml
name: DevSecOps Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
# STAGE 1: SECURE CODE SCANNING
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Secrets detection
- name: Scan for secrets
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
# Static Application Security Testing (SAST)
- name: SonarQube SAST scan
uses: SonarSource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
# Alternative: Semgrep for SAST
- name: Semgrep scan
uses: returntocorp/semgrep-action@v1
with:
config: >-
p/owasp-top-ten
p/security-audit
p/ci/gh-actions
# STAGE 2: DEPENDENCY SECURITY
dependency-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Dependency vulnerability scanning
- name: Run Snyk security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
# Alternative: GitHub native dependency scanning
- name: Enable dependency graph
run: echo "Dependencies monitored by GitHub Dependabot"
# SBOM generation (Software Bill of Materials)
- name: Generate SBOM
uses: CycloneDX/cyclonedx-npm@v1
with:
output-file: sbom.json
# STAGE 3: BUILD & CONTAINER SECURITY
build-secure:
needs: [security-scan, dependency-check]
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Run unit tests
run: npm test
- name: Build application
run: npm run build
# Container image scanning BEFORE push
- name: Build and scan Docker image with Trivy
uses: aquasecurity/trivy-action@master
with:
scan-type: 'image'
scan-ref: 'dockerfile:./Dockerfile'
format: 'sarif'
output: 'trivy-results.sarif'
# Upload scan results
- name: Upload Trivy scan to GitHub Security
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
# Fail if critical vulnerabilities found
- name: Trivy scan (fail on critical)
uses: aquasecurity/trivy-action@master
with:
scan-type: 'image'
scan-ref: 'dockerfile:./Dockerfile'
severity: 'CRITICAL'
exit-code: '1'
# Hadolint: Dockerfile best practices
- name: Lint Dockerfile
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: Dockerfile
- name: Build Docker image
run: docker build -t myrepo:${{ github.sha }} .
# Container image signing
- name: Sign Docker image
run: |
docker sign myrepo:${{ github.sha }}
# Push to registry
- name: Push to registry
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login -u "${{ secrets.REGISTRY_USER }}" --password-stdin
docker push myrepo:${{ github.sha }}
# STAGE 4: INFRASTRUCTURE AS CODE SECURITY
iac-security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Scan Kubernetes manifests
- name: Scan Kubernetes manifests with Kubesec
uses: controlplaneio/kubesec-action@master
with:
path: 'k8s/'
# Scan Terraform/CloudFormation
- name: Scan IaC with Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: infrastructure/
framework: terraform,cloudformation
output_format: sarif
output_file_path: reports/checkov.sarif
- name: Upload IaC scan results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: reports/checkov.sarif
# STAGE 5: COMPLIANCE & POLICY CHECK
compliance:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# License compliance
- name: Check license compliance
uses: licensefinder/license_finder_action@v2
# OWASP compliance check
- name: OWASP dependency check
uses: dependency-check/Dependency-Check_Action@main
with:
path: '.'
format: 'All'
args: >
--enableExperimental
# Policy-as-Code (example with OPA/Rego)
- name: Run policy checks
run: |
# Example: Check for required labels, no root containers, etc
echo "Running compliance policies..."
# STAGE 6: PRE-DEPLOYMENT SECURITY
pre-deploy-security:
needs: [build-secure, iac-security, compliance]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Verify signatures
- name: Verify artifact signatures
run: |
echo "Verifying digital signatures of build artifacts"
# Check security gates
- name: Validate security requirements
run: |
# Check that all security scans passed
# Verify vulnerabilities are below threshold
# Check compliance requirements met
echo "All security gates must pass before deployment"
- name: Generate security report
run: |
echo "Generating pre-deployment security report..."
# Aggregate all scan results
# STAGE 7: DEPLOYMENT (with runtime security)
deploy:
needs: pre-deploy-security
runs-on: ubuntu-latest
environment:
name: production
url: https://myapp.example.com
steps:
- uses: actions/checkout@v4
- name: Deploy with security context
run: |
# Deploy with:
# - Read-only root filesystem
# - Non-root user
# - Resource limits
# - Network policies
echo "Deploying with security hardening..."
# Runtime security monitoring
- name: Enable runtime monitoring
run: |
# Deploy runtime security tools
# - Falco for intrusion detection
# - Wazuh for log monitoring
# - Prometheus for metrics
echo "Runtime security monitoring enabled"
# STAGE 8: POST-DEPLOYMENT VERIFICATION
post-deploy-security:
needs: deploy
runs-on: ubuntu-latest
if: always()
steps:
- name: DAST scan (Dynamic Application Security Testing)
uses: zaproxy/action-full-scan@v0.7.0
with:
target: 'https://myapp.example.com'
rules_file_name: '.zap/rules.tsv'
cmd_options: '-a'
- name: Runtime vulnerability scan
run: |
# Check running containers for new vulnerabilities
# Compare against vulnerability databases updated since build
echo "Scanning runtime environment..."
- name: Security regression test
run: |
# Run security-specific tests
npm run test:security
- name: Notify security team
if: failure()
run: |
curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
-d '{"text":"Security check failed in production deployment"}'
```
---
## Quick Comparison Table
```
Feature | DevOps | DevSecOps
----------------------------------|--------|----------
Secrets scanning | ❌ | ✅
SAST/Code analysis | ❌ | ✅
Dependency scanning | ❌ | ✅
Container image scanning | ❌ | ✅
IaC security scanning | ❌ | ✅
DAST/Runtime scanning | ❌ | ✅
Compliance checking | ❌ | ✅
Artifact signing | ❌ | ✅
Security gates/approvals | ❌ | ✅
Security reporting | ❌ | ✅
Post-deployment security | ❌ | ✅
```
---
## Key DevSecOps Tools for GitHub Actions
**Scanning:**
- Trivy (container images)
- Snyk (dependencies)
- SonarQube/Semgrep (SAST)
- Checkov (IaC)
- Kubesec (Kubernetes)
- Trufflehog (secrets)
**Compliance:**
- OWASP Dependency Check
- License Finder
- Checkov
**Testing:**
- OWASP ZAP (DAST)
- Sonarqube (code quality)
**Signing & Verification:**
- Cosign (container image signing)
- Sigstore (supply chain security)
---
## Security Best Practices in Pipelines
1. **Fail on Security Findings**: Set exit codes to fail builds on critical vulnerabilities
2. **Automate Everything**: Don't rely on manual security reviews
3. **Scan Early and Often**: Check code before and after merge
4. **Generate SBOM**: Track all dependencies for compliance
5. **Sign Artifacts**: Ensure integrity of deployed code
6. **Monitor Runtime**: Security doesn't end at deployment
7. **Report Results**: Feed findings into incident tracking
8. **Update Tools**: Keep security scanners current
9. **Threshold-Based Gates**: Define acceptable risk levels
10. **Audit Logs**: Record all security decisions
Comments