Skip to main content

09 - CI/CD Security Pipeline - Securing the Build and Deploy Process

CI/CD Security: Securing the Build and Deploy Process. The CI/CD pipeline is the heart of the software delivery process.

What do you think about this article?

At a Glance

CI/CD Security: Securing the Build and Deploy Process. The CI/CD pipeline is the heart of the software delivery process.

CI/CD Security: Protecting the Build and Deploy Process

The CI/CD pipeline is the heart of the software delivery process. If an attacker compromises the pipeline, they can inject malicious code into every subsequent build and deploy. Pipeline security is not just about what the pipeline tests, but how the pipeline itself is protected from tampering.

In this article, we will explore practices for securing the CI/CD pipeline: from branch protection to signed commits, from OIDC to least privilege, to audit logging and approval workflows for production deploys.

What You'll Learn

  • CI/CD pipeline threat model
  • Branch protection and code review enforcement
  • OIDC for authentication without static secrets
  • Least privilege for runners and workflows
  • Signed commits and code verifiability
  • Deployment approval workflows

CI/CD Pipeline Threat Model

To protect the pipeline, we need to understand where the attack surfaces are:

  • Source code: a malicious contributor injects code in a PR
  • Dependencies: a compromised dependency is installed during build
  • Pipeline configuration: modification of workflow files to exfiltrate secrets
  • Runner: build agent compromise for infrastructure persistence
  • Artifact: replacement of the built artifact with a malicious one
  • Deploy credentials: theft of deploy credentials for direct infrastructure access

Branch Protection Rules

Branch protection rules are the first line of defense. They ensure that no code reaches the main branch without reviews and automated checks.

Recommended Configuration

Rule Setting Rationale
Require PR reviews Minimum 2 approvals Four-eyes principle
Dismiss stale reviews Enabled Invalidate approvals after push
Require status checks SAST, SCA, test, lint Mandatory automated gates
Require signed commits Enabled Contributor verifiability
Restrict push access CI/CD bot only No direct push to main
Require linear history Enabled Clean and verifiable history

OIDC: Authentication Without Static Secrets

OpenID Connect (OIDC) allows CI/CD workflows to authenticate with cloud providers without using static secrets (API keys, service account keys). The workflow obtains a temporary token based on the repository and branch identity.


# .github/workflows/deploy-oidc.yml
name: Deploy with OIDC
on:
  push:
    branches: [main]

permissions:
  id-token: write   # Required for OIDC
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS Credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/github-deploy
          aws-region: eu-west-1
          # No secrets! OIDC token is used automatically

      - name: Deploy to AWS
        run: |
          aws s3 sync dist/ s3://my-bucket/
          aws cloudfront create-invalidation --distribution-id E123 --paths "/*"
      

Least Privilege for Workflows

Every GitHub Actions workflow has default permissions that can be too broad. The least privilege principle requires limiting permissions to the minimum necessary for each job:


# Restrictive global permissions
permissions:
  contents: read  # Read-only repository access

jobs:
  test:
    runs-on: ubuntu-latest
    # No additional permissions for tests
    steps:
      - uses: actions/checkout@v4
      - run: npm test

  deploy:
    needs: test
    runs-on: ubuntu-latest
    permissions:
      id-token: write      # Only for OIDC
      contents: read
      packages: write      # Only for image push
    environment: production  # Requires manual approval
    steps:
      - uses: actions/checkout@v4
      - name: Deploy
        run: ./deploy.sh
      

Signed Commits

Signed commits guarantee contributor identity through GPG or SSH cryptographic signatures. Without signing, anyone can create a commit with an arbitrary name and email, impersonating other developers.


# Configure GPG for signed commits
gpg --full-generate-key
gpg --list-secret-keys --keyid-format=long

# Configure Git to sign automatically
git config --global user.signingkey YOUR_KEY_ID
git config --global commit.gpgsign true
git config --global tag.gpgsign true

# Alternative: sign with SSH key
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true
      

Deployment Approval Workflows

Production deploys should require explicit approval from authorized personnel. GitHub Environments allows configuring mandatory manual approvals:


# Deploy with manual approval
jobs:
  deploy-staging:
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - name: Deploy to staging
        run: ./deploy.sh staging

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://myapp.com
    # Requires approval from a designated reviewer
    steps:
      - name: Deploy to production
        run: ./deploy.sh production

      - name: Notify team
        run: |
          curl -X POST "${{ secrets.SLACK_WEBHOOK }}" \
            -H "Content-Type: application/json" \
            -d '{"text": "Production deploy completed successfully"}'
      

Pipeline Security Hardening Checklist

Pipeline Security Checklist

  • Branch protection with mandatory reviews and status checks
  • OIDC instead of static secrets for cloud authentication
  • Minimal workflow permissions (least privilege)
  • Mandatory signed commits on the main branch
  • Action pinning with SHA instead of tags
  • Production environment with manual approval
  • Active audit log for all CI/CD operations
  • Self-hosted runners in isolated network (if applicable)
  • Secret scanning on pipeline configuration
  • SBOM generated and signed on every build

GitHub Actions Pinning


# INSECURE: uses a mutable tag
- uses: actions/checkout@v4

# SECURE: uses commit SHA (immutable)
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
      

CI/CD Security Best Practices

  1. OIDC everywhere: eliminate all static secrets for cloud provider authentication
  2. Minimal permissions: each job has only the necessary permissions, nothing more
  3. Pin actions by SHA: never use mutable tags for third-party actions
  4. Separate environments: staging and production with different configurations and approvals
  5. Audit everything: log every build, deploy, approval, and pipeline modification
  6. Ephemeral runners: runners should be recreated on each job to avoid persistence

Conclusions

CI/CD pipeline security is often overlooked, but it's a critical attack vector. A compromised pipeline can inject malicious code into every subsequent build. With branch protection, OIDC, least privilege, and deployment approvals, you build a resilient and verifiable pipeline.

In the next article, we'll explore IaC Scanning, analyzing how to validate Terraform, CloudFormation, and ARM configurations to prevent security misconfigurations.

Frequently asked questions

What is the primary concern when an attacker compromises a CI/CD pipeline?

An attacker can inject malicious code into every subsequent build and deploy.

How do branch protection rules contribute to pipeline security?

Branch protection rules ensure that no code reaches the main branch without reviews and automated checks.

What is the benefit of using OpenID Connect (OIDC) in CI/CD workflows?

OIDC allows authentication with cloud providers without using static secrets, such as API keys or service account keys.

Why are signed commits important for pipeline security?

Signed commits guarantee contributor identity through GPG or SSH cryptographic signatures.

Sources and further reading

Try These Tools

Free developer tools related to this topic.

Commenti

Caricamento commenti...

Sign in to comment

Discuss this article in the community

Join the Telegram group to discuss with other developers, ask questions and share your experiences.

Did you like this article?

Explore other content on the blog or discover my projects