CI/CD Infrastructure Security
Introduction
Continuous Integration and Continuous Deployment (CI/CD) pipelines have revolutionized software delivery by automating the build, test, and deployment processes. However, these same pipelines can become a significant security risk if not properly secured. CI/CD infrastructure security focuses on protecting your automation pipelines from being compromised and preventing them from becoming attack vectors into your production systems.
In this guide, we'll explore the essential security considerations for CI/CD infrastructure, common vulnerabilities, and best practices to secure your delivery pipelines - all explained in beginner-friendly terms.
Why CI/CD Infrastructure Security Matters
CI/CD pipelines typically have access to:
- Source code repositories
- Container registries
- Deployment credentials
- Production environments
- Sensitive configuration data
This makes them high-value targets for attackers. A compromised CI/CD pipeline could lead to:
- Unauthorized code being injected into your applications
- Theft of secrets and credentials
- Supply chain attacks affecting your users
- Unauthorized access to production environments
Common CI/CD Security Vulnerabilities
1. Insecure Secrets Management
One of the most common vulnerabilities is hardcoding secrets directly in pipeline configurations.
❌ Insecure Example:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to production
run: |
aws s3 cp ./build s3://my-website/ --recursive
env:
AWS_ACCESS_KEY_ID: AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
2. Insufficient Access Controls
Giving CI/CD systems excessive permissions is another major risk.
3. Insecure Pipeline Configurations
Misconfigured pipelines can introduce security risks.
4. Vulnerable Dependencies
CI/CD pipelines often pull in external dependencies that might contain vulnerabilities.
5. Insufficient Validation of Build Artifacts
Not validating what gets deployed can lead to malicious code reaching production.
Securing Your CI/CD Infrastructure: Best Practices
1. Secure Secrets Management
Use dedicated secrets management solutions instead of hardcoding credentials.
✅ Secure Example (GitHub Actions with Secrets):
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to production
run: |
aws s3 cp ./build s3://my-website/ --recursive
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
Most CI/CD platforms provide built-in secrets management:
- GitHub Actions Secrets
- GitLab CI/CD Variables
- Jenkins Credentials
- Azure DevOps Variable Groups
For more advanced needs, consider dedicated solutions like:
- HashiCorp Vault
- AWS Secrets Manager
- Azure Key Vault
2. Implement Least Privilege Access
Follow the principle of least privilege by granting only the permissions necessary for each job.
✅ Secure Example (AWS IAM role with limited permissions):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-website",
"arn:aws:s3:::my-website/*"
]
}
]
}
3. Secure Pipeline Configurations
Protect your pipeline definitions with these practices:
Use Pipeline Validation
Validate pipeline configurations with tools like:
# Example for GitHub Actions
actionlint .github/workflows/pipeline.yml
# Output: No errors detected
Enable Branch Protection
Configure your repository to require pull requests and approvals before merging to protected branches.
4. Secure Dependencies and Supply Chain
Protect against supply chain attacks with these approaches:
Dependency Scanning
Add dependency scanning to your pipeline:
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run dependency scanning
run: |
npm install
npm audit
Lock Dependencies
Use lockfiles to ensure consistent, verified dependencies:
{
"dependencies": {
"express": "4.18.2",
"lodash": "4.17.21"
}
}
5. Validate Build Artifacts
Implement artifact signing and verification:
# Generate a signature for your artifact
gpg --detach-sign --armor target/application.jar
# Verify the signature before deployment
gpg --verify target/application.jar.asc target/application.jar
6. Implement Pipeline Security Scanning
Integrate security scanning directly into your pipelines:
✅ Secure Example (Adding security scans to a pipeline):
jobs:
security-checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run SAST scan
run: |
npm install
npx eslint --no-eslintrc --config security-rules.json .
- name: Run container scan
run: |
docker build -t myapp:latest .
trivy image myapp:latest
- name: Check for secrets in code
run: |
git clone https://github.com/gitleaks/gitleaks
cd gitleaks
make build
./gitleaks detect --source=../
Security Controls by CI/CD Phase
Let's explore security measures for each phase of the CI/CD pipeline:
Source Code Management Security
- Enforce code reviews and approval processes
- Implement branch protection rules
- Scan for secrets in code
- Validate commit signatures
Build Phase Security
- Use trusted build environments
- Lock dependencies with checksums
- Scan dependencies for vulnerabilities
- Implement build reproducibility
Test Phase Security
- Run security-focused tests
- Perform static application security testing (SAST)
- Implement dynamic application security testing (DAST)
- Test infrastructure as code (IaC) for misconfigurations
Deployment Phase Security
- Verify artifact signatures before deployment
- Implement progressive delivery with canary deployments
- Use immutable infrastructure
- Automate compliance checks
Implementing CI/CD Security: A Practical Example
Let's walk through a complete example of a secure CI/CD pipeline for a Node.js application using GitHub Actions:
name: Secure CI/CD Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Check for secrets in code
uses: gitleaks/gitleaks-action@v2
- name: Run dependency vulnerability scan
run: npm audit --production
- name: Run static code analysis
run: |
npm install -g eslint
eslint --config .eslintrc.json .
build:
needs: security-scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test
- name: Build application
run: npm run build
- name: Create artifact hash
run: sha256sum build/ > build.sha256
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: app-build
path: |
build/
build.sha256
deploy:
needs: build
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
environment: production
steps:
- name: Download artifact
uses: actions/download-artifact@v3
with:
name: app-build
- name: Verify artifact hash
run: sha256sum -c build.sha256
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::123456789012:role/DeployRole
aws-region: us-east-1
- name: Deploy to S3
run: |
aws s3 sync build/ s3://my-secure-website/ --delete
This pipeline includes:
- Security scanning for secrets and vulnerabilities
- Secure dependency installation with
npm ci
(uses lockfile) - Artifact verification with checksums
- Secure credential handling with AWS IAM roles
- Environment-based deployment controls
Best Practices for CI/CD Security Monitoring
Implement these monitoring practices to maintain security:
1. Audit Logging
Enable comprehensive audit logging for your CI/CD systems:
# Example: Enable detailed logging in Jenkins
jenkins.model.Jenkins.instance.setLogLevel(java.util.logging.Level.FINE)
2. Monitor for Unusual Activities
Set up alerts for suspicious patterns:
- Failed authentication attempts
- Pipeline changes
- Unusual build durations
- Off-hours deployments
3. Regular Security Assessments
Schedule regular security reviews:
- Credential rotation
- Permission audits
- Vulnerability scans
- Pipeline configuration reviews
Implementing CI/CD Security in Popular Platforms
GitHub Actions Security
name: Secure GitHub Actions Workflow
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
# Use GITHUB_TOKEN with limited permissions
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:latest
GitLab CI/CD Security
stages:
- test
- build
- deploy
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: "/certs"
security_scan:
stage: test
image: owasp/zap2docker-stable
script:
- zap-baseline.py -t https://example.com -g gen.conf -r testreport.html
build_image:
stage: build
image: docker:20.10.16
services:
- docker:20.10.16-dind
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG .
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
deploy:
stage: deploy
environment: production
script:
- kubectl set image deployment/app container=$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
rules:
- if: $CI_COMMIT_BRANCH == "main"
Real-World Case Studies of CI/CD Security Incidents
Case Study 1: SolarWinds Supply Chain Attack
The SolarWinds attack demonstrated how compromise of a build system can affect thousands of customers:
- Attackers gained access to SolarWinds' build environment
- Malicious code was inserted into the build process
- Signed updates were distributed to customers
- The compromised software provided backdoor access
Lessons Learned:
- Validate all code that enters your build process
- Implement defense-in-depth strategies
- Don't rely solely on digital signatures
Case Study 2: Codecov Bash Uploader Compromise
In 2021, Codecov's Bash Uploader script was modified by attackers:
- Attackers accessed Codecov's CI environment
- Modified a script used by thousands of pipelines
- Extracted secrets and tokens from CI systems
Lessons Learned:
- Verify the integrity of third-party tools used in pipelines
- Rotate credentials regularly
- Implement least-privilege access policies
Implementing a Security Maturity Model for CI/CD
You can progressively improve your CI/CD security:
Level 1: Basic Security
- Remove hardcoded secrets
- Implement access controls
- Run basic security scans
Level 2: Enhanced Security
- Implement secrets management
- Add dependency scanning
- Deploy from protected branches only
Level 3: Advanced Security
- Sign and verify artifacts
- Implement infrastructure as code security
- Add runtime application protection
Level 4: Comprehensive Security
- Automate compliance checks
- Implement chaos engineering
- Develop secure-by-default pipelines
Summary
Securing your CI/CD infrastructure is critical for maintaining the integrity of your software delivery process. Key takeaways include:
- Protect your secrets - Use proper secrets management solutions
- Implement least privilege - Grant only necessary permissions
- Secure configurations - Validate and protect pipeline definitions
- Validate dependencies - Scan and lock your dependencies
- Verify artifacts - Ensure what you're deploying is what you expect
- Monitor continuously - Detect and respond to suspicious activities
By implementing these practices, you create a secure CI/CD infrastructure that delivers reliable software without compromising security.
Additional Resources
Here are some exercises to help you apply what you've learned:
Exercise 1: Audit Your CI/CD Permissions
Review the permissions granted to your CI/CD system and determine if they follow the principle of least privilege.
Exercise 2: Secrets Scan
Run a secrets scanning tool like GitLeaks on your repository to identify any hardcoded secrets.
Exercise 3: Create a Secure Pipeline
Design a CI/CD pipeline with security controls for each phase of the delivery process.
Exercise 4: Implement Artifact Verification
Add checksum verification to your deployment process to ensure artifacts haven't been tampered with.
Further Learning
- OWASP CI/CD Security Guide
- NIST Secure Software Development Framework (SSDF)
- DevSecOps Practices and Principles
- Supply Chain Levels for Software Artifacts (SLSA)
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)