358 lines
11 KiB
YAML
358 lines
11 KiB
YAML
# Security-Enhanced CI/CD Pipeline Template
|
|
#
|
|
# This template demonstrates security best practices for CI/CD pipelines.
|
|
# Adapt this template to your specific security tool and workflow needs.
|
|
#
|
|
# Key Security Features:
|
|
# - SAST (Static Application Security Testing)
|
|
# - Dependency vulnerability scanning
|
|
# - Secrets detection
|
|
# - Infrastructure-as-Code security scanning
|
|
# - Container image scanning
|
|
# - Security artifact uploading for compliance
|
|
|
|
name: Security Scan Pipeline
|
|
|
|
on:
|
|
push:
|
|
branches: [main, develop]
|
|
pull_request:
|
|
branches: [main, develop]
|
|
schedule:
|
|
# Run weekly security scans on Sunday at 2 AM UTC
|
|
- cron: '0 2 * * 0'
|
|
workflow_dispatch: # Allow manual trigger
|
|
|
|
# Security: Restrict permissions to minimum required
|
|
permissions:
|
|
contents: read
|
|
security-events: write # For uploading SARIF results
|
|
pull-requests: write # For commenting on PRs
|
|
|
|
env:
|
|
# Configuration
|
|
SECURITY_SCAN_FAIL_ON: 'critical,high' # Fail build on these severities
|
|
REPORT_DIR: 'security-reports'
|
|
|
|
jobs:
|
|
# Job 1: Static Application Security Testing (SAST)
|
|
sast-scan:
|
|
name: SAST Security Scan
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0 # Full history for better analysis
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.11'
|
|
|
|
- name: Run SAST Scanner
|
|
run: |
|
|
# Example: Using Semgrep for SAST
|
|
pip install semgrep
|
|
semgrep --config=auto \
|
|
--json \
|
|
--output ${{ env.REPORT_DIR }}/sast-results.json \
|
|
. || true
|
|
|
|
# Alternative: Bandit for Python projects
|
|
# pip install bandit
|
|
# bandit -r . -f json -o ${{ env.REPORT_DIR }}/bandit-results.json
|
|
|
|
- name: Process SAST Results
|
|
run: |
|
|
# Parse results and fail on critical/high severity
|
|
python3 -c "
|
|
import json
|
|
import sys
|
|
|
|
with open('${{ env.REPORT_DIR }}/sast-results.json') as f:
|
|
results = json.load(f)
|
|
|
|
critical = len([r for r in results.get('results', []) if r.get('extra', {}).get('severity') == 'ERROR'])
|
|
high = len([r for r in results.get('results', []) if r.get('extra', {}).get('severity') == 'WARNING'])
|
|
|
|
print(f'Critical findings: {critical}')
|
|
print(f'High findings: {high}')
|
|
|
|
if critical > 0:
|
|
print('❌ Build failed: Critical security issues found')
|
|
sys.exit(1)
|
|
elif high > 0:
|
|
print('⚠️ Warning: High severity issues found')
|
|
# Optionally fail on high severity
|
|
# sys.exit(1)
|
|
else:
|
|
print('✅ No critical security issues found')
|
|
"
|
|
|
|
- name: Upload SAST Results
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: sast-results
|
|
path: ${{ env.REPORT_DIR }}/sast-results.json
|
|
retention-days: 30
|
|
|
|
# Job 2: Dependency Vulnerability Scanning
|
|
dependency-scan:
|
|
name: Dependency Vulnerability Scan
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: '3.11'
|
|
|
|
- name: Scan Python Dependencies
|
|
if: hashFiles('requirements.txt') != ''
|
|
run: |
|
|
pip install safety
|
|
safety check \
|
|
--json \
|
|
--output ${{ env.REPORT_DIR }}/safety-results.json \
|
|
|| true
|
|
|
|
- name: Scan Node Dependencies
|
|
if: hashFiles('package.json') != ''
|
|
run: |
|
|
npm audit --json > ${{ env.REPORT_DIR }}/npm-audit.json || true
|
|
|
|
- name: Process Dependency Results
|
|
run: |
|
|
# Check for critical vulnerabilities
|
|
if [ -f "${{ env.REPORT_DIR }}/safety-results.json" ]; then
|
|
critical_count=$(python3 -c "import json; data=json.load(open('${{ env.REPORT_DIR }}/safety-results.json')); print(len([v for v in data.get('vulnerabilities', []) if v.get('severity', '').lower() == 'critical']))")
|
|
echo "Critical vulnerabilities: $critical_count"
|
|
if [ "$critical_count" -gt "0" ]; then
|
|
echo "❌ Build failed: Critical vulnerabilities in dependencies"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
- name: Upload Dependency Scan Results
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: dependency-scan-results
|
|
path: ${{ env.REPORT_DIR }}/
|
|
retention-days: 30
|
|
|
|
# Job 3: Secrets Detection
|
|
secrets-scan:
|
|
name: Secrets Detection
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0 # Full history to scan all commits
|
|
|
|
- name: Run Gitleaks
|
|
uses: gitleaks/gitleaks-action@v2
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
GITLEAKS_ENABLE_SUMMARY: true
|
|
|
|
- name: Alternative - TruffleHog Scan
|
|
if: false # Set to true to enable
|
|
run: |
|
|
pip install truffleHog
|
|
trufflehog --json --regex --entropy=True . \
|
|
> ${{ env.REPORT_DIR }}/trufflehog-results.json || true
|
|
|
|
- name: Upload Secrets Scan Results
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: secrets-scan-results
|
|
path: ${{ env.REPORT_DIR }}/
|
|
retention-days: 30
|
|
|
|
# Job 4: Container Image Scanning
|
|
container-scan:
|
|
name: Container Image Security Scan
|
|
runs-on: ubuntu-latest
|
|
if: hashFiles('Dockerfile') != ''
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Build Docker Image
|
|
run: |
|
|
docker build -t app:${{ github.sha }} .
|
|
|
|
- name: Run Trivy Scanner
|
|
uses: aquasecurity/trivy-action@master
|
|
with:
|
|
image-ref: app:${{ github.sha }}
|
|
format: 'sarif'
|
|
output: '${{ env.REPORT_DIR }}/trivy-results.sarif'
|
|
severity: 'CRITICAL,HIGH'
|
|
|
|
- name: Upload Trivy Results to GitHub Security
|
|
if: always()
|
|
uses: github/codeql-action/upload-sarif@v3
|
|
with:
|
|
sarif_file: '${{ env.REPORT_DIR }}/trivy-results.sarif'
|
|
|
|
- name: Upload Container Scan Results
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: container-scan-results
|
|
path: ${{ env.REPORT_DIR }}/
|
|
retention-days: 30
|
|
|
|
# Job 5: Infrastructure-as-Code Security Scanning
|
|
iac-scan:
|
|
name: IaC Security Scan
|
|
runs-on: ubuntu-latest
|
|
if: hashFiles('**/*.tf', '**/*.yaml', '**/*.yml') != ''
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Run Checkov
|
|
run: |
|
|
pip install checkov
|
|
checkov -d . \
|
|
--output json \
|
|
--output-file ${{ env.REPORT_DIR }}/checkov-results.json \
|
|
--quiet \
|
|
|| true
|
|
|
|
- name: Run tfsec (for Terraform)
|
|
if: hashFiles('**/*.tf') != ''
|
|
run: |
|
|
curl -s https://raw.githubusercontent.com/aquasecurity/tfsec/master/scripts/install_linux.sh | bash
|
|
tfsec . \
|
|
--format json \
|
|
--out ${{ env.REPORT_DIR }}/tfsec-results.json \
|
|
|| true
|
|
|
|
- name: Process IaC Results
|
|
run: |
|
|
# Fail on critical findings
|
|
if [ -f "${{ env.REPORT_DIR }}/checkov-results.json" ]; then
|
|
critical_count=$(python3 -c "import json; data=json.load(open('${{ env.REPORT_DIR }}/checkov-results.json')); print(data.get('summary', {}).get('failed', 0))")
|
|
echo "Failed checks: $critical_count"
|
|
if [ "$critical_count" -gt "0" ]; then
|
|
echo "⚠️ Warning: IaC security issues found"
|
|
# Optionally fail the build
|
|
# exit 1
|
|
fi
|
|
fi
|
|
|
|
- name: Upload IaC Scan Results
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: iac-scan-results
|
|
path: ${{ env.REPORT_DIR }}/
|
|
retention-days: 30
|
|
|
|
# Job 6: Security Report Generation and Notification
|
|
security-report:
|
|
name: Generate Security Report
|
|
runs-on: ubuntu-latest
|
|
needs: [sast-scan, dependency-scan, secrets-scan]
|
|
if: always()
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Download All Scan Results
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: all-results/
|
|
|
|
- name: Generate Consolidated Report
|
|
run: |
|
|
# Consolidate all security scan results
|
|
mkdir -p consolidated-report
|
|
|
|
cat > consolidated-report/security-summary.md << 'EOF'
|
|
# Security Scan Summary
|
|
|
|
**Scan Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
|
**Commit**: ${{ github.sha }}
|
|
**Branch**: ${{ github.ref_name }}
|
|
|
|
## Scan Results
|
|
|
|
### SAST Scan
|
|
See artifacts: `sast-results`
|
|
|
|
### Dependency Scan
|
|
See artifacts: `dependency-scan-results`
|
|
|
|
### Secrets Scan
|
|
See artifacts: `secrets-scan-results`
|
|
|
|
### Container Scan
|
|
See artifacts: `container-scan-results`
|
|
|
|
### IaC Scan
|
|
See artifacts: `iac-scan-results`
|
|
|
|
---
|
|
|
|
For detailed results, download scan artifacts from this workflow run.
|
|
EOF
|
|
|
|
- name: Comment on PR (if applicable)
|
|
if: github.event_name == 'pull_request'
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const fs = require('fs');
|
|
const report = fs.readFileSync('consolidated-report/security-summary.md', 'utf8');
|
|
|
|
github.rest.issues.createComment({
|
|
issue_number: context.issue.number,
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
body: report
|
|
});
|
|
|
|
- name: Upload Consolidated Report
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: consolidated-security-report
|
|
path: consolidated-report/
|
|
retention-days: 90
|
|
|
|
# Security Best Practices Demonstrated:
|
|
#
|
|
# 1. ✅ Minimal permissions (principle of least privilege)
|
|
# 2. ✅ Multiple security scan types (defense in depth)
|
|
# 3. ✅ Fail-fast on critical findings
|
|
# 4. ✅ Secrets detection across full git history
|
|
# 5. ✅ Container image scanning before deployment
|
|
# 6. ✅ IaC scanning for misconfigurations
|
|
# 7. ✅ Artifact retention for compliance audit trail
|
|
# 8. ✅ SARIF format for GitHub Security integration
|
|
# 9. ✅ Scheduled scans for continuous monitoring
|
|
# 10. ✅ PR comments for developer feedback
|
|
#
|
|
# Compliance Mappings:
|
|
# - SOC 2: CC6.1, CC6.6, CC7.2 (Security monitoring and logging)
|
|
# - PCI-DSS: 6.2, 6.5 (Secure development practices)
|
|
# - NIST: SA-11 (Developer Security Testing)
|
|
# - OWASP: Integrated security testing throughout SDLC
|