CI/CD Pipelines

Continuous Integration (CI) is the process of frequently integrating (building, testing, packaging, etc) when code is changed. This allows developers to detect and resolve issues before their changes are accepted into the codebase. The confidence it inspires in the readiness of a codebase is a prerequisite for sane Continuous Delivery.

Continuous Delivery (CD) is the process of deploying the newly-integrated code; for example, making features live to users. In addition to a robust CI process, organizations will want comprehensive monitoring so that they can detect a failed deployment and roll it back. With a solid set of checks in place, small changes can be rolled out many times per day.

While the primary goal of implementing CI/CD pipelines is to increase confidence in the readiness of the codebase, NIST SP 800-204 identifies two broad, yet more specific, security goals for CI/CD Pipelines:

  1. Incorporate a range of defensive measures to ensure that attackers cannot tamper with software production processes or introduce malicious software updates (e.g., secure platform for build process).
  2. Ensure the integrity of the CI/CD pipeline artifacts (e.g., repositories) and activities through role definitions and authorizations for actors.

Providers

CI/CD pipelines generally run in containers or virtual machines and can be hosted on-prem or in the cloud. They consist of steps, or logical actions, which may be comprised of various modules or sub-modules and often run in their own container.

Some popular providers we’ve worked with include:

An example CI pipeline might include steps to:

  1. Authenticate to a private repository
  2. Download the code or container image from the private repository
  3. Run tests
  4. Run linters
  5. Run static analysis
  6. Generate documentation
  7. Compile artifacts
  8. Authenticate to an artifact repository
  9. Upload artifacts
  10. Authenticate to documentation website host
  11. Upload documentation

A CI/CD pipeline might expand on this to do things like:

  1. Deploy to test environment
  2. Run tests against test environment
  3. Deploy to QA environment
  4. Run tests against QA environment
  5. Wait for manual approval for staging
  6. Deploy to Staging environment
  7. Run tests against Staging environment
  8. Wait for manual approval for Production
  9. Deploy to Production environment
  10. Run tests against Production environment

Dependencies between steps can be complex, with branches, parallel execution, and conditionals. In the above example, testing, linting, and static analysis can occur in parallel, and compilation and upload can be skipped if some number of faults are detected in the software. Likewise, the documentation-related steps might only be run on merges to the main branch or tagged releases. Additionally, steps can be added to roll back an environment should tests fail (or a manual Go/No-Go decision fails).

All of this requires a mature DevOps program to manage, and automated rollout is not always wanted (or even permitted). The goal of this process is to increase confidence in the correctness or readiness of the code - constantly testing that by pushing it to customers is merely an added bonus.