sethvargo / ratchet

A tool for securing CI/CD workflows with version pinning.
Apache License 2.0
772 stars 32 forks source link
cicd dependency security

Ratchet

ratchet logo

Ratchet is a tool for improving the security of CI/CD workflows by automating the process of pinning and unpinning upstream versions. It's like Bundler, Cargo, Go modules, NPM, Pip, or Yarn, but for CI/CD workflows. Ratchet supports:

⚠️ Warning! The README corresponds to the main branch of ratchet's development, and it may contain unreleased features.

Problem statement

Most CI/CD systems are one layer of indirection away from curl | sudo bash. Unless you are specifically pinning CI workflows, containers, and base images to checksummed versions, everything is mutable: GitHub labels are mutable and Docker tags are mutable. This poses a substantial security and reliability risk.

What you're probably doing:

uses: 'actions/checkout@v3'
# or
image: 'ubuntu:20.04'

What you should really be doing:

uses: 'actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b'
# or
image: 'ubuntu@sha256:47f14534bda344d9fe6ffd6effb95eefe579f4be0d508b7445cf77f61a0e5724'

But resolving those checksums and managing the update lifecycle is extremely toilsome. That's what ratchet aims to solve! Ratchet resolves and updates unpinned references to the latest version that matches their constraint, and then keeps a record of the original constraint.

uses: 'actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b' # ratchet:actions/checkout@v3
# or
image: 'ubuntu@sha256:47f14534bda344d9fe6ffd6effb95eefe579f4be0d508b7445cf77f61a0e5724' # ratchet:ubuntu:20.04

Installation

There are a few options for installing ratchet:

Usage

For more information about available commands and options, run a command with -help to use detailed usage instructions. Also see CLI Options.

Pin

The pin command pins to specific versions:

# pin the input file
ratchet pin workflow.yml

# pin a circleci file
ratchet pin -parser circleci circleci.yml

# pin a cloudbuild file
ratchet pin -parser cloudbuild cloudbuild.yml

# pin a drone file
ratchet pin -parser drone drone.yml

# pin a gitlab file
ratchet pin -parser gitlabci gitlabci.yml

# output to a tekton file
ratchet pin -out -parser tekton tekton.yml

# output to a different path
ratchet pin -out workflow-compiled.yml workflow.yml

Unpin

The unpin command unpins any pinned versions:

# unpin the input file
ratchet unpin workflow.yml

# output to a different path
ratchet unpin -out workflow.yml workflow-compiled.yml

Update

The update command updates all versions to the latest matching constraint:

# update the input file
ratchet update workflow.yml

# update a circleci file
ratchet update -parser circleci circleci.yml

# update a cloudbuild file
ratchet update -parser cloudbuild cloudbuild.yml

# output to a different path
ratchet update -out workflow-compiled.yml workflow.yml

Upgrade

[!NOTE] This command only works with GitHub Actions references. It does not support container or Docker-based references.

The upgrade command upgrades all versions to the latest version, changing the ratchet comment and also updating the ref.

# upgrade the input file
ratchet upgrade workflow.yml

# output to a different path
ratchet upgrade -out workflow-compiled.yml workflow.yml

[!NOTE] Performs an update if the constraint ref is for a branch.

Check

The check command checks if all versions are pinned, exiting with a non-zero error code when entries are not pinned:

ratchet check workflow.yml

Examples

CI/CD workflow

Ratchet is distributed as a very small container, so you can use it as a step inside CI/CD jobs. Here is a GitHub Actions example:

jobs:
  my_job:
    runs-on: 'ubuntu-latest'
    name: 'ratchet'
    steps:
      - uses: 'actions/checkout@755da8c3cf115ac066823e79a1e1788f8940201b' # ratchet:actions/checkout@v3

      # Example of pinning:
      - uses: 'docker://ghcr.io/sethvargo/ratchet:latest'
        with:
          args: 'pin .github/workflows/my-workflow.yml'

      # Example of checking versions are pinned:
      - uses: 'docker://ghcr.io/sethvargo/ratchet:latest'
        with:
          args: 'check .github/workflows/my-workflow.yml'

This same pattern can be extended to other CI/CD systems that support container-based runtimes. For non-container-based runtimes, download the ratchet binary from GitHub Releases.

Runnable container CLI

Ratchet can run directly from a container on your local system:

docker run -it --rm -v "${PWD}:${PWD}" -w "${PWD}" ghcr.io/sethvargo/ratchet:latest COMMAND

Create a shell alias to make this easier:

function ratchet {
  docker run -it --rm -v "${PWD}:${PWD}" -w "${PWD}" ghcr.io/sethvargo/ratchet:latest "$@"
}

Auth

Excluding

There may be instances in which you want to exclude a particular reference from being pinned. You can use the ratchet:exclude annotation as a line comment and ratchet will not process that reference:

uses: 'actions/checkout@v3' # ratchet:exclude

There cannot be any spaces in the exclusion string, and the exclusion string only applies to the line on which it appears.

Terminology

Known issues