Initial commit
This commit is contained in:
862
references/devsecops.md
Normal file
862
references/devsecops.md
Normal file
@@ -0,0 +1,862 @@
|
||||
# DevSecOps in CI/CD
|
||||
|
||||
Comprehensive guide to integrating security into CI/CD pipelines with SAST, DAST, SCA, and security gates.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Shift-Left Security](#shift-left-security)
|
||||
- [SAST (Static Application Security Testing)](#sast-static-application-security-testing)
|
||||
- [DAST (Dynamic Application Security Testing)](#dast-dynamic-application-security-testing)
|
||||
- [SCA (Software Composition Analysis)](#sca-software-composition-analysis)
|
||||
- [Container Security](#container-security)
|
||||
- [Secret Scanning](#secret-scanning)
|
||||
- [Security Gates & Quality Gates](#security-gates--quality-gates)
|
||||
- [Compliance & License Scanning](#compliance--license-scanning)
|
||||
|
||||
---
|
||||
|
||||
## Shift-Left Security
|
||||
|
||||
**Core principle:** Integrate security testing early in the development lifecycle, not just before production.
|
||||
|
||||
**Security testing stages in CI/CD:**
|
||||
|
||||
```
|
||||
Commit → SAST → Unit Tests → SCA → Build → Container Scan → Deploy to Test → DAST → Production
|
||||
↓ ↓ ↓ ↓ ↓
|
||||
Secret Code Dependency Docker Dynamic Security
|
||||
Scan Analysis Vuln Check Image Scan App Testing Gates
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Find vulnerabilities early (cheaper to fix)
|
||||
- Faster feedback to developers
|
||||
- Reduce security debt
|
||||
- Prevent vulnerable code from reaching production
|
||||
|
||||
---
|
||||
|
||||
## SAST (Static Application Security Testing)
|
||||
|
||||
Analyzes source code, bytecode, or binaries for security vulnerabilities without executing the application.
|
||||
|
||||
### Tools by Language
|
||||
|
||||
| Language | Tools | GitHub Actions | GitLab CI |
|
||||
|----------|-------|----------------|-----------|
|
||||
| **Multi-language** | CodeQL, Semgrep, SonarQube | ✅ | ✅ |
|
||||
| **JavaScript/TypeScript** | ESLint (security plugins), NodeJsScan | ✅ | ✅ |
|
||||
| **Python** | Bandit, Pylint, Safety | ✅ | ✅ |
|
||||
| **Go** | Gosec, GoSec Scanner | ✅ | ✅ |
|
||||
| **Java** | SpotBugs, FindSecBugs, PMD | ✅ | ✅ |
|
||||
| **C#/.NET** | Security Code Scan, Roslyn Analyzers | ✅ | ✅ |
|
||||
|
||||
### CodeQL (GitHub)
|
||||
|
||||
**GitHub Actions:**
|
||||
```yaml
|
||||
name: CodeQL Analysis
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
schedule:
|
||||
- cron: '0 2 * * 1' # Weekly scan
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze Code
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: ['javascript', 'python']
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: security-extended
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
```
|
||||
|
||||
**Key features:**
|
||||
- Supports 10+ languages
|
||||
- Deep semantic analysis
|
||||
- Low false positive rate
|
||||
- Integrates with GitHub Security tab
|
||||
- Custom query support
|
||||
|
||||
### Semgrep
|
||||
|
||||
**GitHub Actions:**
|
||||
```yaml
|
||||
- name: Run Semgrep
|
||||
uses: returntocorp/semgrep-action@v1
|
||||
with:
|
||||
config: >-
|
||||
p/security-audit
|
||||
p/owasp-top-ten
|
||||
p/cwe-top-25
|
||||
```
|
||||
|
||||
**GitLab CI:**
|
||||
```yaml
|
||||
semgrep:
|
||||
stage: test
|
||||
image: returntocorp/semgrep
|
||||
script:
|
||||
- semgrep --config=auto --sarif --output=semgrep.sarif .
|
||||
artifacts:
|
||||
reports:
|
||||
sast: semgrep.sarif
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
- Fast (runs in seconds)
|
||||
- Highly customizable rules
|
||||
- Multi-language support
|
||||
- CI-native design
|
||||
|
||||
### Language-Specific SAST
|
||||
|
||||
**Python - Bandit:**
|
||||
```yaml
|
||||
# GitHub Actions
|
||||
- name: Run Bandit
|
||||
run: |
|
||||
pip install bandit
|
||||
bandit -r src/ -f json -o bandit-report.json
|
||||
bandit -r src/ --exit-zero -ll # Only high severity fails build
|
||||
|
||||
# GitLab CI
|
||||
bandit:
|
||||
stage: test
|
||||
image: python:3.11
|
||||
script:
|
||||
- pip install bandit
|
||||
- bandit -r src/ -ll -f gitlab > bandit-report.json
|
||||
artifacts:
|
||||
reports:
|
||||
sast: bandit-report.json
|
||||
```
|
||||
|
||||
**JavaScript - ESLint Security Plugin:**
|
||||
```yaml
|
||||
# GitHub Actions
|
||||
- name: Run ESLint Security
|
||||
run: |
|
||||
npm install eslint-plugin-security
|
||||
npx eslint . --plugin=security --format=json --output-file=eslint-security.json
|
||||
```
|
||||
|
||||
**Go - Gosec:**
|
||||
```yaml
|
||||
# GitHub Actions
|
||||
- name: Run Gosec
|
||||
uses: securego/gosec@master
|
||||
with:
|
||||
args: '-fmt sarif -out gosec.sarif ./...'
|
||||
|
||||
# GitLab CI
|
||||
gosec:
|
||||
stage: test
|
||||
image: securego/gosec:latest
|
||||
script:
|
||||
- gosec -fmt json -out gosec-report.json ./...
|
||||
artifacts:
|
||||
reports:
|
||||
sast: gosec-report.json
|
||||
```
|
||||
|
||||
### SonarQube/SonarCloud
|
||||
|
||||
**GitHub Actions:**
|
||||
```yaml
|
||||
- name: SonarCloud Scan
|
||||
uses: SonarSource/sonarcloud-github-action@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
with:
|
||||
args: >
|
||||
-Dsonar.projectKey=my-project
|
||||
-Dsonar.organization=my-org
|
||||
-Dsonar.sources=src
|
||||
-Dsonar.tests=tests
|
||||
-Dsonar.python.coverage.reportPaths=coverage.xml
|
||||
```
|
||||
|
||||
**GitLab CI:**
|
||||
```yaml
|
||||
sonarqube:
|
||||
stage: test
|
||||
image: sonarsource/sonar-scanner-cli:latest
|
||||
script:
|
||||
- sonar-scanner
|
||||
-Dsonar.projectKey=$CI_PROJECT_NAME
|
||||
-Dsonar.sources=src
|
||||
-Dsonar.host.url=$SONAR_HOST_URL
|
||||
-Dsonar.login=$SONAR_TOKEN
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DAST (Dynamic Application Security Testing)
|
||||
|
||||
Tests running applications for vulnerabilities by simulating attacks.
|
||||
|
||||
### OWASP ZAP
|
||||
|
||||
**Full scan workflow (GitHub Actions):**
|
||||
```yaml
|
||||
name: DAST Scan
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 3 * * 1' # Weekly scan
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
dast:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
services:
|
||||
app:
|
||||
image: myapp:latest
|
||||
ports:
|
||||
- 8080:8080
|
||||
|
||||
steps:
|
||||
- name: Wait for app to start
|
||||
run: |
|
||||
timeout 60 bash -c 'until curl -f http://localhost:8080/health; do sleep 2; done'
|
||||
|
||||
- name: ZAP Baseline Scan
|
||||
uses: zaproxy/action-baseline@v0.10.0
|
||||
with:
|
||||
target: 'http://localhost:8080'
|
||||
rules_file_name: '.zap/rules.tsv'
|
||||
fail_action: true
|
||||
|
||||
- name: Upload ZAP report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: zap-report
|
||||
path: report_html.html
|
||||
```
|
||||
|
||||
**GitLab CI:**
|
||||
```yaml
|
||||
dast:
|
||||
stage: test
|
||||
image: owasp/zap2docker-stable
|
||||
services:
|
||||
- name: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
alias: testapp
|
||||
script:
|
||||
# Baseline scan
|
||||
- zap-baseline.py -t http://testapp:8080 -r zap-report.html -J zap-report.json
|
||||
artifacts:
|
||||
when: always
|
||||
paths:
|
||||
- zap-report.html
|
||||
- zap-report.json
|
||||
reports:
|
||||
dast: zap-report.json
|
||||
only:
|
||||
- schedules
|
||||
- main
|
||||
```
|
||||
|
||||
**ZAP scan types:**
|
||||
|
||||
1. **Baseline Scan** (Fast, ~1-2 min)
|
||||
```bash
|
||||
zap-baseline.py -t https://staging.example.com -r report.html
|
||||
```
|
||||
- Passive scanning only
|
||||
- No active attacks
|
||||
- Good for PR checks
|
||||
|
||||
2. **Full Scan** (Comprehensive, 10-60 min)
|
||||
```bash
|
||||
zap-full-scan.py -t https://staging.example.com -r report.html
|
||||
```
|
||||
- Active + Passive scanning
|
||||
- Attempts exploits
|
||||
- Use on staging only
|
||||
|
||||
3. **API Scan**
|
||||
```bash
|
||||
zap-api-scan.py -t https://api.example.com/openapi.json -f openapi -r report.html
|
||||
```
|
||||
- For REST APIs
|
||||
- OpenAPI/Swagger support
|
||||
|
||||
### Other DAST Tools
|
||||
|
||||
**Nuclei:**
|
||||
```yaml
|
||||
- name: Run Nuclei
|
||||
uses: projectdiscovery/nuclei-action@main
|
||||
with:
|
||||
target: https://staging.example.com
|
||||
templates: cves,vulnerabilities,exposures
|
||||
```
|
||||
|
||||
**Nikto (Web server scanner):**
|
||||
```yaml
|
||||
nikto:
|
||||
stage: dast
|
||||
image: sullo/nikto
|
||||
script:
|
||||
- nikto -h http://testapp:8080 -Format json -output nikto-report.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SCA (Software Composition Analysis)
|
||||
|
||||
Identifies vulnerabilities in third-party dependencies and libraries.
|
||||
|
||||
### Dependency Scanning
|
||||
|
||||
**GitHub Dependabot (Built-in):**
|
||||
```yaml
|
||||
# .github/dependabot.yml
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 10
|
||||
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
```
|
||||
|
||||
**GitHub Actions - Dependency Review:**
|
||||
```yaml
|
||||
- name: Dependency Review
|
||||
uses: actions/dependency-review-action@v4
|
||||
with:
|
||||
fail-on-severity: high
|
||||
```
|
||||
|
||||
**npm audit:**
|
||||
```yaml
|
||||
- name: npm audit
|
||||
run: |
|
||||
npm audit --audit-level=high
|
||||
# Or with audit-ci for better control
|
||||
npx audit-ci --high
|
||||
```
|
||||
|
||||
**pip-audit (Python):**
|
||||
```yaml
|
||||
- name: Python Security Check
|
||||
run: |
|
||||
pip install pip-audit
|
||||
pip-audit --requirement requirements.txt --format json --output pip-audit.json
|
||||
```
|
||||
|
||||
**Snyk:**
|
||||
```yaml
|
||||
# GitHub Actions
|
||||
- name: Run Snyk
|
||||
uses: snyk/actions/node@master
|
||||
env:
|
||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
with:
|
||||
args: --severity-threshold=high --fail-on=all
|
||||
|
||||
# GitLab CI
|
||||
snyk:
|
||||
stage: test
|
||||
image: snyk/snyk:node
|
||||
script:
|
||||
- snyk test --severity-threshold=high --json-file-output=snyk-report.json
|
||||
artifacts:
|
||||
reports:
|
||||
dependency_scanning: snyk-report.json
|
||||
```
|
||||
|
||||
**OWASP Dependency-Check:**
|
||||
```yaml
|
||||
- name: OWASP Dependency Check
|
||||
run: |
|
||||
wget https://github.com/jeremylong/DependencyCheck/releases/download/v8.4.0/dependency-check-8.4.0-release.zip
|
||||
unzip dependency-check-8.4.0-release.zip
|
||||
./dependency-check/bin/dependency-check.sh \
|
||||
--scan . \
|
||||
--format JSON \
|
||||
--out dependency-check-report.json \
|
||||
--failOnCVSS 7
|
||||
```
|
||||
|
||||
### GitLab Dependency Scanning (Built-in)
|
||||
|
||||
```yaml
|
||||
include:
|
||||
- template: Security/Dependency-Scanning.gitlab-ci.yml
|
||||
|
||||
dependency_scanning:
|
||||
variables:
|
||||
DS_EXCLUDED_PATHS: "test/,tests/,spec/,vendor/"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Container Security
|
||||
|
||||
### Image Scanning
|
||||
|
||||
**Trivy (Comprehensive):**
|
||||
```yaml
|
||||
# GitHub Actions
|
||||
- name: Run Trivy
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
image-ref: myapp:${{ github.sha }}
|
||||
format: 'sarif'
|
||||
output: 'trivy-results.sarif'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
exit-code: '1'
|
||||
|
||||
- name: Upload to Security tab
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
if: always()
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
|
||||
# GitLab CI
|
||||
trivy:
|
||||
stage: test
|
||||
image: aquasec/trivy:latest
|
||||
script:
|
||||
- trivy image --severity HIGH,CRITICAL --format json --output trivy-report.json $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
- trivy image --severity HIGH,CRITICAL --exit-code 1 $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
|
||||
artifacts:
|
||||
reports:
|
||||
container_scanning: trivy-report.json
|
||||
```
|
||||
|
||||
**Grype:**
|
||||
```yaml
|
||||
- name: Scan with Grype
|
||||
uses: anchore/scan-action@v3
|
||||
with:
|
||||
image: myapp:latest
|
||||
fail-build: true
|
||||
severity-cutoff: high
|
||||
output-format: sarif
|
||||
|
||||
- name: Upload Grype results
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: ${{ steps.scan.outputs.sarif }}
|
||||
```
|
||||
|
||||
**Clair:**
|
||||
```yaml
|
||||
clair:
|
||||
stage: scan
|
||||
image: arminc/clair-scanner:latest
|
||||
script:
|
||||
- clair-scanner --ip $(hostname -i) myapp:latest
|
||||
```
|
||||
|
||||
### SBOM (Software Bill of Materials)
|
||||
|
||||
**Syft:**
|
||||
```yaml
|
||||
- name: Generate SBOM
|
||||
uses: anchore/sbom-action@v0
|
||||
with:
|
||||
image: myapp:${{ github.sha }}
|
||||
format: spdx-json
|
||||
output-file: sbom.spdx.json
|
||||
|
||||
- name: Upload SBOM
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sbom
|
||||
path: sbom.spdx.json
|
||||
```
|
||||
|
||||
**CycloneDX:**
|
||||
```yaml
|
||||
- name: Generate CycloneDX SBOM
|
||||
run: |
|
||||
npm install -g @cyclonedx/cyclonedx-npm
|
||||
cyclonedx-npm --output-file sbom.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Secret Scanning
|
||||
|
||||
### Pre-commit Prevention
|
||||
|
||||
**TruffleHog:**
|
||||
```yaml
|
||||
# GitHub Actions
|
||||
- name: TruffleHog Scan
|
||||
uses: trufflesecurity/trufflehog@main
|
||||
with:
|
||||
path: ./
|
||||
base: ${{ github.event.repository.default_branch }}
|
||||
head: HEAD
|
||||
|
||||
# GitLab CI
|
||||
trufflehog:
|
||||
stage: test
|
||||
image: trufflesecurity/trufflehog:latest
|
||||
script:
|
||||
- trufflehog filesystem . --json --fail > trufflehog-report.json
|
||||
```
|
||||
|
||||
**Gitleaks:**
|
||||
```yaml
|
||||
# GitHub Actions
|
||||
- name: Gitleaks
|
||||
uses: gitleaks/gitleaks-action@v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# GitLab CI
|
||||
gitleaks:
|
||||
stage: test
|
||||
image: zricethezav/gitleaks:latest
|
||||
script:
|
||||
- gitleaks detect --source . --report-format json --report-path gitleaks-report.json
|
||||
```
|
||||
|
||||
**GitGuardian:**
|
||||
```yaml
|
||||
- name: GitGuardian scan
|
||||
uses: GitGuardian/ggshield-action@master
|
||||
env:
|
||||
GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }}
|
||||
```
|
||||
|
||||
### GitHub Secret Scanning (Native)
|
||||
|
||||
Enable in: **Settings → Code security and analysis → Secret scanning**
|
||||
|
||||
- Automatic detection
|
||||
- Partner patterns (AWS, Azure, GCP, etc.)
|
||||
- Push protection (prevents commits with secrets)
|
||||
|
||||
---
|
||||
|
||||
## Security Gates & Quality Gates
|
||||
|
||||
### Fail Pipeline on Security Issues
|
||||
|
||||
**Threshold-based gates:**
|
||||
```yaml
|
||||
security-gate:
|
||||
stage: gate
|
||||
script:
|
||||
# Check vulnerability count
|
||||
- |
|
||||
CRITICAL=$(jq '.vulnerabilities | map(select(.severity=="CRITICAL")) | length' trivy-report.json)
|
||||
HIGH=$(jq '.vulnerabilities | map(select(.severity=="HIGH")) | length' trivy-report.json)
|
||||
|
||||
echo "Critical: $CRITICAL, High: $HIGH"
|
||||
|
||||
if [ "$CRITICAL" -gt 0 ]; then
|
||||
echo "❌ CRITICAL vulnerabilities found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$HIGH" -gt 5 ]; then
|
||||
echo "❌ Too many HIGH vulnerabilities: $HIGH"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
**SonarQube Quality Gate:**
|
||||
```yaml
|
||||
- name: Check Quality Gate
|
||||
run: |
|
||||
STATUS=$(curl -u $SONAR_TOKEN: "$SONAR_HOST/api/qualitygates/project_status?projectKey=$PROJECT_KEY" | jq -r '.projectStatus.status')
|
||||
if [ "$STATUS" != "OK" ]; then
|
||||
echo "Quality gate failed: $STATUS"
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
### Manual Approval for Production
|
||||
|
||||
**GitHub Actions:**
|
||||
```yaml
|
||||
deploy-production:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [sast, dast, container-scan]
|
||||
environment:
|
||||
name: production
|
||||
# Requires manual approval in Settings → Environments
|
||||
steps:
|
||||
- run: echo "Deploying to production"
|
||||
```
|
||||
|
||||
**GitLab CI:**
|
||||
```yaml
|
||||
deploy:production:
|
||||
stage: deploy
|
||||
needs: [sast, dast, container_scanning]
|
||||
script:
|
||||
- ./deploy.sh production
|
||||
when: manual
|
||||
only:
|
||||
- main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Compliance & License Scanning
|
||||
|
||||
### License Compliance
|
||||
|
||||
**FOSSology:**
|
||||
```yaml
|
||||
license-scan:
|
||||
stage: compliance
|
||||
image: fossology/fossology:latest
|
||||
script:
|
||||
- fossology --scan ./src
|
||||
```
|
||||
|
||||
**License Finder:**
|
||||
```yaml
|
||||
- name: Check Licenses
|
||||
run: |
|
||||
gem install license_finder
|
||||
license_finder --decisions-file .license_finder.yml
|
||||
```
|
||||
|
||||
**npm license checker:**
|
||||
```yaml
|
||||
- name: License Check
|
||||
run: |
|
||||
npx license-checker --production --onlyAllow "MIT;Apache-2.0;BSD-3-Clause;ISC"
|
||||
```
|
||||
|
||||
### Policy as Code
|
||||
|
||||
**Open Policy Agent (OPA):**
|
||||
```yaml
|
||||
policy-check:
|
||||
stage: gate
|
||||
image: openpolicyagent/opa:latest
|
||||
script:
|
||||
- opa test policies/
|
||||
- opa eval --data policies/ --input violations.json "data.security.allow"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete DevSecOps Pipeline
|
||||
|
||||
**Comprehensive example (GitHub Actions):**
|
||||
```yaml
|
||||
name: DevSecOps Pipeline
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
# Stage 1: Secret Scanning
|
||||
secret-scan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: trufflesecurity/trufflehog@main
|
||||
|
||||
# Stage 2: SAST
|
||||
sast:
|
||||
runs-on: ubuntu-latest
|
||||
needs: secret-scan
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: github/codeql-action/init@v3
|
||||
- uses: github/codeql-action/autobuild@v3
|
||||
- uses: github/codeql-action/analyze@v3
|
||||
|
||||
# Stage 3: SCA
|
||||
sca:
|
||||
runs-on: ubuntu-latest
|
||||
needs: secret-scan
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: npm audit --audit-level=high
|
||||
- uses: snyk/actions/node@master
|
||||
env:
|
||||
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
||||
|
||||
# Stage 4: Build & Container Scan
|
||||
build-scan:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [sast, sca]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: docker build -t myapp:${{ github.sha }} .
|
||||
- uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
image-ref: myapp:${{ github.sha }}
|
||||
exit-code: '1'
|
||||
|
||||
# Stage 5: DAST
|
||||
dast:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-scan
|
||||
if: github.ref == 'refs/heads/main'
|
||||
steps:
|
||||
- uses: zaproxy/action-baseline@v0.10.0
|
||||
with:
|
||||
target: 'https://staging.example.com'
|
||||
|
||||
# Stage 6: Security Gate
|
||||
security-gate:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [sast, sca, build-scan, dast]
|
||||
steps:
|
||||
- run: echo "All security checks passed!"
|
||||
- run: echo "Ready for deployment"
|
||||
|
||||
# Stage 7: Deploy
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
needs: security-gate
|
||||
environment: production
|
||||
steps:
|
||||
- run: echo "Deploying to production"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Fail Fast
|
||||
- Run secret scanning first
|
||||
- Run SAST early in pipeline
|
||||
- Block PRs with critical vulnerabilities
|
||||
|
||||
### 2. Balance Speed vs Security
|
||||
- SAST/SCA on every PR (fast)
|
||||
- Container scanning after build
|
||||
- DAST on schedules or staging only (slow)
|
||||
|
||||
### 3. Prioritize Findings
|
||||
**Focus on:**
|
||||
- Critical/High severity
|
||||
- Exploitable vulnerabilities
|
||||
- Direct dependencies (not transitive)
|
||||
- Public-facing components
|
||||
|
||||
### 4. Developer Experience
|
||||
- Clear error messages
|
||||
- Link to remediation guidance
|
||||
- Don't overwhelm with noise
|
||||
- Use quality gates, not just fail/pass
|
||||
|
||||
### 5. Continuous Improvement
|
||||
- Track security debt over time
|
||||
- Set SLAs for vulnerability remediation
|
||||
- Regular tool evaluation
|
||||
- Security training for developers
|
||||
|
||||
### 6. Reporting & Metrics
|
||||
|
||||
**Track:**
|
||||
- Mean Time to Remediate (MTTR)
|
||||
- Vulnerability backlog
|
||||
- False positive rate
|
||||
- Coverage (% of code scanned)
|
||||
|
||||
```yaml
|
||||
- name: Generate Security Report
|
||||
run: |
|
||||
echo "## Security Scan Summary" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- SAST: ✅ Passed" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- SCA: ⚠️ 3 vulnerabilities" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- Container: ✅ Passed" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- DAST: 🔄 Scheduled" >> $GITHUB_STEP_SUMMARY
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tool Comparison
|
||||
|
||||
| Category | Tool | Speed | Accuracy | Cost | Best For |
|
||||
|----------|------|-------|----------|------|----------|
|
||||
| **SAST** | CodeQL | Medium | High | Free (GH) | Deep analysis |
|
||||
| | Semgrep | Fast | Medium | Free/Paid | Custom rules |
|
||||
| | SonarQube | Medium | High | Free/Paid | Quality + Security |
|
||||
| **DAST** | OWASP ZAP | Medium | High | Free | Web apps |
|
||||
| | Burp Suite | Slow | High | Paid | Professional |
|
||||
| **SCA** | Snyk | Fast | High | Free/Paid | Easy integration |
|
||||
| | Dependabot | Fast | Medium | Free (GH) | Auto PRs |
|
||||
| **Container** | Trivy | Fast | High | Free | Fast scans |
|
||||
| | Grype | Fast | High | Free | SBOM support |
|
||||
| **Secrets** | TruffleHog | Fast | High | Free/Paid | Git history |
|
||||
| | GitGuardian | Fast | High | Paid | Real-time |
|
||||
|
||||
---
|
||||
|
||||
## Security Scanning Schedule
|
||||
|
||||
**Recommended frequency:**
|
||||
|
||||
| Scan Type | PR | Main Branch | Schedule | Notes |
|
||||
|-----------|----|-----------|-----------| ------|
|
||||
| Secret Scanning | ✅ Every | ✅ Every | - | Fast, critical |
|
||||
| SAST | ✅ Every | ✅ Every | - | Fast, essential |
|
||||
| SCA | ✅ Every | ✅ Every | Weekly | Check dependencies |
|
||||
| Linting | ✅ Every | ✅ Every | - | Very fast |
|
||||
| Container Scan | ❌ No | ✅ Every | - | After build |
|
||||
| DAST Baseline | ❌ No | ✅ Every | - | Medium speed |
|
||||
| DAST Full | ❌ No | ❌ No | Weekly | Very slow |
|
||||
| Penetration Test | ❌ No | ❌ No | Quarterly | Manual |
|
||||
|
||||
---
|
||||
|
||||
## Security Checklist
|
||||
|
||||
- [ ] Secret scanning enabled and running
|
||||
- [ ] SAST configured for all languages used
|
||||
- [ ] Dependency scanning (SCA) enabled
|
||||
- [ ] Container images scanned before deployment
|
||||
- [ ] DAST running on staging environment
|
||||
- [ ] Security findings triaged in issue tracker
|
||||
- [ ] Quality gates prevent vulnerable deployments
|
||||
- [ ] SBOM generated for releases
|
||||
- [ ] Security scan results tracked over time
|
||||
- [ ] Vulnerability remediation SLAs defined
|
||||
- [ ] Security training for developers
|
||||
- [ ] Incident response plan documented
|
||||
Reference in New Issue
Block a user