CI/CD pipelines are critical infrastructure that can become attack vectors if not properly secured. This guide covers essential security practices for your DevOps workflows.
Pipeline Security Threats
Common Attacks
- Dependency poisoning: Malicious packages
- Code injection: Malicious commits
- Secrets exposure: Leaked credentials
- Supply chain attacks: Compromised tools
- Privilege escalation: Excessive permissions
Securing Source Code
Branch Protection
1
2
3
4
5
6
7
| # GitHub branch protection rules
main:
required_reviews: 2
require_code_owner_reviews: true
dismiss_stale_reviews: true
require_status_checks: true
require_signed_commits: true
|
Commit Signing
1
2
3
4
5
6
| # Configure GPG signing
git config --global user.signingkey YOUR_KEY_ID
git config --global commit.gpgsign true
# Sign commits
git commit -S -m "Signed commit"
|
Secrets Management
Never Hardcode Secrets
1
2
3
4
5
| # ❌ Bad - secrets in code
DATABASE_URL: "postgresql://user:password@localhost/db"
# ✅ Good - use secret managers
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
GitHub Actions Secrets
1
2
3
4
5
6
7
8
9
10
11
12
| name: Deploy
on: push
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy
env:
API_KEY: ${{ secrets.API_KEY }}
run: ./deploy.sh
|
HashiCorp Vault Integration
1
2
3
4
5
6
7
8
| - name: Get secrets from Vault
uses: hashicorp/vault-action@v2
with:
url: https://vault.example.com
token: ${{ secrets.VAULT_TOKEN }}
secrets: |
secret/data/production db_password ;
secret/data/production api_key
|
Dependency Security
Dependency Scanning
1
2
3
4
5
6
7
8
9
10
| # GitHub Actions - Dependency Review
name: Dependency Review
on: [pull_request]
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/dependency-review-action@v3
|
npm Audit
1
2
3
4
5
6
7
8
| # Check for vulnerabilities
npm audit
# Fix automatically where possible
npm audit fix
# Force fix (may have breaking changes)
npm audit fix --force
|
Renovate Bot
1
2
3
4
5
6
7
8
9
10
| {
"extends": ["config:base"],
"vulnerabilityAlerts": {
"enabled": true
},
"automerge": true,
"major": {
"automerge": false
}
}
|
Container Security
Secure Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # Use specific versions, not 'latest'
FROM node:18.17-alpine
# Run as non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nodejs -u 1001
USER nodejs
# Copy only necessary files
COPY --chown=nodejs:nodejs package*.json ./
RUN npm ci --only=production
COPY --chown=nodejs:nodejs . .
# Use read-only filesystem where possible
CMD ["node", "server.js"]
|
Image Scanning
1
2
3
4
5
6
7
| - name: Scan image
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
|
SAST (Static Application Security Testing)
CodeQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| name: CodeQL
on:
push:
branches: [main]
pull_request:
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: github/codeql-action/init@v2
with:
languages: javascript, python
- uses: github/codeql-action/autobuild@v2
- uses: github/codeql-action/analyze@v2
|
SonarQube
1
2
3
4
5
| - name: SonarQube Scan
uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
|
Access Control
Least Privilege
1
2
3
4
5
6
7
8
9
10
11
| # GitHub Actions - minimal permissions
permissions:
contents: read
pull-requests: write
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: npm test
|
OIDC Authentication
1
2
3
4
5
| - name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActions
aws-region: us-east-1
|
Pipeline as Code Security
Validate Pipeline Configs
1
2
3
4
5
6
7
8
9
| # Pre-commit hook for pipeline validation
repos:
- repo: local
hooks:
- id: validate-github-workflow
name: Validate GitHub Workflows
entry: actionlint
language: system
files: ^\.github/workflows/.*\.yml$
|
Audit Pipeline Changes
1
2
3
4
5
| - name: Pipeline Change Notification
if: contains(github.event.head_commit.modified, '.github/workflows')
run: |
echo "Pipeline modified - security review required"
# Send notification to security team
|
Monitoring and Logging
Audit Logs
1
2
3
4
5
6
| - name: Log deployment
run: |
echo "Deployment by ${{ github.actor }}"
echo "Commit: ${{ github.sha }}"
echo "Timestamp: $(date)"
# Send to centralized logging
|
Alerting
1
2
3
4
5
6
7
| - name: Notify on failure
if: failure()
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: 'Pipeline failed - investigate immediately'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
|
Compliance
Policy Enforcement
1
2
3
4
5
6
7
8
9
10
11
12
| # Open Policy Agent
package pipeline
deny[msg] {
input.image.tag == "latest"
msg = "Using 'latest' tag is not allowed"
}
deny[msg] {
not input.image.signed
msg = "Only signed images are allowed"
}
|
SBOM Generation
1
2
3
4
5
6
| - name: Generate SBOM
uses: anchore/sbom-action@v0
with:
image: myapp:${{ github.sha }}
format: spdx-json
output-file: sbom.json
|
Best Practices
- Minimal permissions: Grant only necessary access
- Secrets rotation: Regularly rotate credentials
- Immutable builds: Never modify published artifacts
- Audit everything: Comprehensive logging
- Automated scanning: Integrate security tools
- Signed artifacts: Verify authenticity
- Isolated environments: Separate dev/staging/prod
- Regular updates: Keep tools and dependencies current
Incident Response
Pipeline Compromise Plan
- Immediately revoke all secrets
- Audit recent pipeline runs
- Review code changes
- Scan for malicious artifacts
- Notify affected parties
- Post-mortem analysis
Conclusion
CI/CD pipeline security is crucial for protecting your software supply chain. Implement these practices to build secure, trustworthy deployment processes.