Skip to content

goreleaser/example-secure

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

secure-example

This example outlines how to securely release using GoReleaser and GitHub Actions.

Components

We'll go over a few things: GitHub settings, GoReleaser configuration, and GitHub actions.

GitHub Settings

These are some things I recommend you do:

  1. General > Require contributors to sign off on web-based commits Loading
  2. General > Enable release immutability
  3. Actions > General > Require approval for all external contributors
  4. Actions > General > Read repository contents and packages permissions
  5. Rules > New Ruleset > Import a ruleset > this file
  6. Advanced Security > Private vulnerability reporting
  7. Advanced Security > Dependency graph
  8. Advanced Security > Automatic dependency submission
  9. Advanced Security > Dependabot security updates

There's much more you can change, these are the things I usually do.

GoReleaser Configuration

The provided configuration is commented out and each section links to the relevant documentation, but here's a rundown:

  1. We build for a couple of platforms using the Go mod proxy;
  2. We create archives for both the binaries as well as for the source;
  3. We create and sign a checksums file (using Cosign);
  4. We create Software Bill of Materials (SBOMs) for all the archives (using Syft);
  5. all these files are uploaded to the GitHub release;
  6. We create a Docker image manifest, which also includes SBOMs;
  7. We then sign the image.

GitHub Actions

We have 3 workflows set up, let's go over them.

Build

The build workflow doesn't do much: it checks out the code, installs Go, and runs go test.

Security

The security workflow does a lot more, as it has a couple of jobs:

  1. codeql: as the name implies, runs the recommended CodeQL queries for Go and Actions;
  2. grype: runs Grype, which scans for known vulnerabilities;
  3. govulncheck: runs the standard Go vulnerability checker;
  4. dependency-review: runs only on pull requests, and checks if any dependencies being added or updated are allowed.

All these jobs report their status using Static Analysis Results Interchange Format (SARIF), so any findings will show as security alerts in the Security > Code scanning tab.

Release

Finally, the release workflow. Its main job is to, well, release our software, and it uses GoReleaser for that (surprise!). But to do that, we first set up Docker, Cosign, and Syft. Then, we run the glorious goreleaser-action, which does all the heavy lifting. Then, after all is said and done, we attest our build artifacts.

Why all the SHA1s?

As you may have noticed, all the actions are pinned to the SHA1 of their respective tags.

This is recommended, as an attacker might take over an action and re-publish malicious code under the same tags.

Using only the major versions (like @v4) is also not so good, as you are then even more clueless about what is actually being run.

If you want to pin all the actions in your repositories, I recommend using pinata.

Releasing

To create a new release, create and push a new tag. You can get the next semantic version using svu:

git tag -s $(svu n)
git push --tags

And then go over to the actions tab and wait for the release to finish.

Verifying the artifacts

Your users will need to know how to verify the artifacts, and this is what this section is all about.

The first thing we need to do, is get the current latest version:

export VERSION="$(gh release list -L 1 -R goreleaser/example-secure --json=tagName -q '.[] | .tagName')"

Then, we download the checksums.txt and the signature bundle (checksums.txt.sigstore.json) files, and then verify them:

wget https://github.com/goreleaser/example-secure/releases/download/$VERSION/checksums.txt
wget https://github.com/goreleaser/example-secure/releases/download/$VERSION/checksums.txt.sigstore.json
cosign verify-blob \
    --certificate-identity "https://github.com/goreleaser/example-secure/.github/workflows/release.yml@refs/tags/$VERSION" \
    --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
    --bundle "checksums.txt.sigstore.json" \
    ./checksums.txt

This should succeed - which means that we can from now on verify any artifact from the release with this checksum file!

You can then download any file you want from the release, and verify it with, for example:

wget "https://github.com/goreleaser/example-secure/releases/download/$VERSION/example_linux_amd64.tar.gz"
sha256sum --ignore-missing -c checksums.txt

Which should, ideally, say "OK".

You can then inspect the SBOM file to see the entire dependency tree of the binary, check for vulnerable dependencies and whatnot.

To get the SBOM of an artifact, you can use the same download URL, adding .sbom.json to the end of the URL, and we can then check it out with grype:

wget "https://github.com/goreleaser/example-secure/releases/download/$VERSION/example_linux_amd64.tar.gz.sbom.json"
sha256sum --ignore-missing -c checksums.txt
grype sbom:example_linux_amd64.tar.gz.sbom.json

Finally, we can also use the gh CLI to verify the attestations:

gh attestation verify \
  --owner goreleaser \
  *.tar.gz

Docker images are a bit simpler, you can verify them with Cosign and Grype directly, and check the attestations as well.

Signature:

cosign verify \
  --certificate-identity "https://github.com/goreleaser/example-secure/.github/workflows/release.yml@refs/tags/$VERSION" \
  --certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
  "ghcr.io/goreleaser/example-secure:$VERSION"

Vulnerabilities:

grype "docker:ghcr.io/goreleaser/example-secure:$VERSION"

Attestations:

gh attestation verify \
  --owner goreleaser \
  "oci://ghcr.io/goreleaser/example-secure:$VERSION"

If all these checks are OK, you have a pretty good indication that everything is good.


I really hope this helps - and please feel free to open PRs improving things you think need improving, or issues to discuss any concerns you might have.

Thanks for reading!

About

A secure way to release software using GoReleaser and GitHub Actions

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

 
 
 

Contributors 2

  •  
  •