Problem Statement
Explain security best practices for CI/CD pipelines. Include secrets management, artifact security, vulnerability scanning, and supply chain security.
Explanation
Secrets management is critical for CI/CD security. Never commit secrets to repositories. Use platform secret managers:
GitLab CI/CD variables (masked and protected):
```yaml
variables:
PUBLIC_VAR: "visible"
# SECRET_VAR configured in GitLab UI (Settings > CI/CD > Variables)
# Mark as "Masked" to hide in logs
# Mark as "Protected" to limit to protected branches
deploy:
script:
- deploy --api-key=$SECRET_VAR
```
GitHub Actions secrets:
```yaml
steps:
- name: Deploy
run: ./deploy.sh
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
```
External secret management integration (HashiCorp Vault):
```yaml
# GitLab
vault_secrets:
image: vault:latest
script:
- export VAULT_TOKEN=$(vault login -method=jwt role=my-role jwt=$CI_JOB_JWT -field=token)
- export SECRET=$(vault kv get -field=value secret/api-key)
- deploy --api-key=$SECRET
```
```yaml
# GitHub Actions with Vault
- name: Import Secrets
uses: hashicorp/vault-action@v2
with:
url: https://vault.example.com
method: jwt
role: github-actions
secrets: |
secret/data/api key | API_KEY
secret/data/db password | DB_PASS
```
Rotate secrets regularly, use short-lived tokens when possible, limit secret scope (per-project, per-environment), audit secret access.
Artifact security ensures build outputs are safe. Sign artifacts for verification:
```yaml
# Sign container images
- name: Sign Image
run: |
cosign sign --key cosign.key myapp:${{ github.sha }}
```
Verify artifact integrity:
```yaml
- name: Verify Signature
run: |
cosign verify --key cosign.pub myapp:${{ github.sha }}
```
Vulnerability scanning detects security issues:
Container scanning:
```yaml
# GitLab (built-in)
container_scanning:
stage: test
variables:
DOCKER_IMAGE: myapp:latest
allow_failure: true
# GitHub Actions with Trivy
- name: Scan Image
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
```
Dependency scanning:
```yaml
# GitLab (built-in)
dependency_scanning:
stage: test
artifacts:
reports:
dependency_scanning: gl-dependency-scanning-report.json
# GitHub Actions with Snyk
- name: Snyk Test
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
with:
args: --severity-threshold=high
```
Static Application Security Testing (SAST):
```yaml
# GitLab
sast:
stage: test
artifacts:
reports:
sast: gl-sast-report.json
# GitHub Actions with Semgrep
- name: Semgrep
uses: returntocorp/semgrep-action@v1
with:
config: auto
```
Dynamic Application Security Testing (DAST):
```yaml
dast:
stage: security
image: owasp/zap2docker-stable
script:
- zap-baseline.py -t https://staging.example.com
```
Supply chain security protects against compromised dependencies:
Dependency pinning (lock files):
```yaml
- name: Verify Lock File
run: |
if ! git diff --exit-code package-lock.json; then
echo "Lock file changed, failing build"
exit 1
fi
```
Software Bill of Materials (SBOM):
```yaml
- name: Generate SBOM
uses: anchore/sbom-action@v0
with:
image: myapp:${{ github.sha }}
format: cyclonedx
output-file: sbom.json
- name: Upload SBOM
uses: actions/upload-artifact@v3
with:
name: sbom
path: sbom.json
```
Code signing with Sigstore:
```yaml
- name: Sign Artifacts
uses: sigstore/cosign-installer@main
- run: |
cosign sign-blob --key cosign.key artifact.tar.gz > artifact.tar.gz.sig
```
Access control for pipelines:
- Protected branches (only certain users can merge/push)
- Required reviews before pipeline runs
- Branch protection rules
- Environment-specific permissions
GitHub:
```yaml
environment:
name: production
required-reviewers: ['security-team', 'ops-lead']
```
GitLab protected environments (Settings > CI/CD > Protected Environments).
Audit logging:
```yaml
- name: Log Deployment
run: |
echo "Deployed by ${{ github.actor }} at $(date)" >> audit.log
curl -X POST https://audit.example.com/log \
-d '{"user":"${{ github.actor }}","action":"deploy"}'
```
Network security:
- Private runners/agents behind firewall
- Egress filtering (allow only necessary external access)
- Secrets for webhook authentication
- HTTPS for all communications
Compliance as Code:
```yaml
compliance_check:
stage: validate
script:
- run-compliance-tests
- check-license-compliance
- verify-security-policies
```
Best practices: never commit secrets, use platform secret managers, integrate with Vault/AWS Secrets Manager for production, scan all dependencies, scan containers before deployment, implement SAST/DAST, generate and track SBOMs, sign artifacts, limit pipeline permissions, enable audit logging, regularly update dependencies, use automated security scanning in every pipeline. Understanding security practices prevents breaches and ensures compliance in CI/CD workflows.