Keyless Git commit signing with Gitsign and GitHub Actions
Let's take a look at Sigstore's latest tool, Gitsign, and how we can use this tool to sign commits for CI/CD within GitHub Actions!
Why Gitsign?
Source code is an important piece of any software supply chain. It is the base that's used to build everything else: if you can't trust your source, how can you trust the binaries and images you build from it? Signing Git commits should be a goal for everyone, and will likely be important for many organizations to meet SLSA L3 Source - Verified History requirements.
Git commit signing has historically been done with GPG keys, with recent support being added for SSH and x509 certs. However, managing and securing long-lived signing secrets is challenging to do right over time. With Gitsign, Sigstore aims to make signing with Git easy by bringing keyless signing to commit signing, just like Cosign did for container signing! This is useful not only for signing your own Git commits, but also for CI/CD workflows that may create a commit or pull request (for example, GitOps flows, Dependabot, import flows, etc.), since Sigstore can enable tools to sign data with their own OIDC identity without the need to provision long-lived secrets.
How Gitsign works
Keyless signing isn't really keyless — it uses ephemeral keys with Sigstore's Fulcio to generate a certificate using OIDC credentials. This certificate is short-lived, and contains information about the identity that generated it.
With GitHub Actions, GitHub automatically provides short-lived OIDC tokens to Action Runners - Gitsign knows to detect these and automatically uses them to generate a signing certificate via Fulcio. With this we can generate ephemeral code-signing certificates without ever needing to provide GitHub with a long-lived secret. This helps secure your software supply chain by:
Ensuring no long-lived secrets are in CI/CD workers — even if the key were to be exfiltrated it would only be valid for a short amount of time, severely limiting the window where it could be used. Commits can be verified even after certificate expiration, by using Sigstore's transparency log - Rekor.
Providing authentication information about who/what signed the commit into the commit itself, including the exact action workflow identity that generated the signature.
For a more concrete example, let's take a look at a certificate was issued issued by Fulcio for a real GitHub Action. Commit signatures produced by Gitsign are CMS (Cryptographic Message Syntax) formatted signatures, containing an x509 certificate. Here are some of the interesting fields included in the certificate:
Certificate:
Data:
Issuer: O=sigstore.dev, CN=sigstore
Validity
Not Before: May 18 15:41:46 2022 GMT
Not After : May 18 15:51:45 2022 GMT
X509v3 extensions:
X509v3 Key Usage: critical
Digital Signature
X509v3 Extended Key Usage:
Code Signing
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Subject Alternative Name: critical
URI:https://github.com/wlynch/gitsign-action/.github/workflows/main.yml@refs/heads/main
1.3.6.1.4.1.57264.1.6:
refs/heads/main
1.3.6.1.4.1.57264.1.3:
f6ad30f71c1719e4e9446cdee3e72bc3136c8492
1.3.6.1.4.1.57264.1.1:
https://token.actions.githubusercontent.com
1.3.6.1.4.1.57264.1.2:
push
1.3.6.1.4.1.57264.1.4:
.github/workflows/main.yml
1.3.6.1.4.1.57264.1.5:
wlynch/gitsign-action
Interesting things to point out about this certificate:
It was issued by the public sigstore.dev instance.
It is only valid for 10 minutes.
It includes several custom ASN.1 OIDs provided by Fulcio that give us useful identifiers as to what GitHub Actions workflow signed the commit:
This lets us identify not only that it was automation that generated this commit, but it also tells us the exact workflow and event that caused this change. This is valuable for being able to trace back through the supply chain where a particular change came from, and gives us identifiers to define policies for what identities are allowed to submit code to the repo.
How to use Gitsign in GitHub Actions
To help you get started, we've created a GitHub Action that allows you to easily set up Gitsign with any other GitHub Action: chainguard-dev/actions/setup-gitsign. To use it within your own workflows requires minimal setup:
jobs:
gitsign:
permissions:
id-token: write # Enable OIDC
steps:
- uses: chainguard-dev/actions/setup-gitsign@main
- <your steps go here>
This Action sets the necessary config options to use Gitsign with the Git CLI in your environment - i.e. with this Gitsign will be compatible with almost all other Actions that use Git without any other changes needed!
This can be used to create signed commits using a GitHub Action Runner's identity without needing to provision secrets! Because the keys are derived from the Runner's OIDC credentials, it is much harder for an attacker to forge their own commits using an external key.
For example, if we wanted to open a pull request with a signed commit:
on:
workflow_dispatch:
schedule:
# Every day
- cron: "0 0 * * *"
jobs:
new_pr:
permissions:
id-token: write # Enable OIDC
pull-requests: write
contents: write
runs-on: ubuntu-latest
name: Make a new pull request
steps:
- uses: actions/checkout@v3
with:
ref: main
- uses: chainguard-dev/actions/setup-gitsign@main
- name: Change files
shell: bash
run: |
# Modify repo here
date > date.txt
- name: Create Pull Request
uses: peter-evans/create-pull-request@v4.0.2
with:
title: "New PR!"
Here at Chainguard, we use this exact approach for several of our own Actions! This makes it really simple to have Actions sign the commits they generate – we hope this makes it easier to get started signing your own commits everywhere.
Things to watch out for
While Gitsign tries to limit the data that is uploaded to the Rekor transparency log, the authentication information embedded in the Fulcio certificate for GitHub Actions (for example, repo name, branch names, etc.) may be considered sensitive for your organization — if this is the case then the public Sigstore instance may not be appropriate for your needs and you may need to run your own.
Learn more
We hope this gives you some inspiration for how Gitsign can be used in your CI/CD workflows! Gitsign is something Chainguard is enthusiastic about, with many of us using Gitsign everywhere in our own development.
We have a few things cooking to help make using keyless signatures in your repos easy - stay tuned for more info!
If you're interested in learning more about Git commit signing, running your own Sigstore instance, or have any other questions about securing your software supply chain - reach out to us at https://www.chainguard.dev/contact!
Ready to Lock Down Your Supply Chain?
Talk to our customer obsessed, community-driven team.