github.com/goreleaser/goreleaser@v1.25.1/www/docs/blog/posts/2023-10-08-slsa-generation-for-your-artifacts.md (about) 1 --- 2 date: 2023-10-11 3 slug: slsa-generation-for-your-artifacts 4 categories: 5 - tutorials 6 authors: 7 - developerguy 8 - dentrax 9 --- 10 11 # Stay Calm and SLSA: Generating SLSA Provenance for Your Artifacts with GoReleaser and slsa-github-generator 12 13 In an age where software is at the heart of nearly every aspect of our lives, software supply chain security has become paramount. It involves a series of measures and practices aimed at ensuring the reliability and safety of the software we use daily. As cyber threats continue to evolve, the need for robust software supply chain security has never been greater. Organizations must take steps to protect their software development and distribution processes from potential vulnerabilities and attacks. 14 15 <!-- more --> 16 17 SLSA provenance, short for Supply Chain Levels for Software Artifacts, is an emerging concept that revolutionizes the way we think about software supply chain security. It offers a comprehensive framework to track the lineage and trustworthiness of software components, thereby enhancing overall security. 18 19 The core idea behind SLSA provenance is to create a transparent and auditable trail of every software component's journey, from its creation to deployment. This ensures that any tampering or unauthorized changes can be quickly identified and mitigated. Software supply chain security and SLSA provenance are intrinsically linked, as the latter serves as a critical tool to bolster the former. 20 21 Together, they provide a robust defense against the growing threats posed by malicious actors in the digital realm. In a world where software vulnerabilities can have far-reaching consequences, the adoption of SLSA provenance is a proactive step toward fortifying our software supply chains and making them more resilient to cyberattacks. 22 23 GoReleaser takes the ever-growing risks in the realm of software supply chain security incredibly seriously. From the onset of this era of heightened security concerns, GoReleaser has been at the forefront, continuously adding features to safeguard your artifacts against potential software supply chain attacks such as [generating an SBOMs](https://goreleaser.com/customization/sbom/), [signing your artifacts](https://goreleaser.com/customization/docker_sign/), and more. 24 25 > _If you want to learn more about the general software supply chain security features supported by GoReleaser, check out our [blog post](/blog/supply-chain-security/) on the topic._ 26 27 In this blog post, we will explore how GoReleaser can help you generate SLSA provenance for your artifacts and how you can leverage the slsa-github-generator to automate the process. 28 29 ## slsa-github-generator 30 31 I would like to start with my favorite quote: 32 33 > _Each of these attacks could have been prevented if there were a way to detect that the delivered artifacts diverged from the expected origin of the software. But until now, generating verifiable information that described where, when, and how software artifacts were produced (information known as provenance) was difficult. This information allows users to trace artifacts verifiably back to the source and develop risk-based policies around what they consume._ - [Improving software supply chain security with tamper-proof builds](https://security.googleblog.com/2022/04/improving-software-supply-chain.html) 34 35 Unfortunately, provenance generation is not widely supported yet but hopefully will be in the future. And this is where the slsa-github-generator comes into play. 36 37 Thanks to the SLSA community, they developed a collection of GitHub reusable workflows called [slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) that can help us with the solving of the problem we mentioned in the quote. It is a powerful tool designed to simplify the process of generating SLSA provenances for your GitHub-hosted projects. It seamlessly integrates with your GitHub repositories, providing an efficient way to enhance the security and trustworthiness of your software supply chain by automatically creating and managing SLSA provenance records. 38 39 There are different types of workflows/builders that you can use depending on your needs provided by the slsa-github-generator. 40 41 - [Docker](https://github.com/slsa-framework/slsa-github-generator/tree/main/internal/builders/docker) 42 - [Generic](https://github.com/slsa-framework/slsa-github-generator/tree/main/internal/builders/generic) 43 - [Go](https://github.com/slsa-framework/slsa-github-generator/tree/main/internal/builders/go) 44 - [Maven](https://github.com/slsa-framework/slsa-github-generator/tree/main/internal/builders/maven) 45 - [Nodejs](https://github.com/slsa-framework/slsa-github-generator/tree/main/internal/builders/nodejs) 46 47 and many [more](https://github.com/slsa-framework/slsa-github-generator/tree/main/internal/builders)... 48 49 Without much further ado, let's jump right into the demo and see how we can use the slsa-github-generator to generate SLSA provenance for our artifacts. 50 51 > You can find all the code used in this demo in the [goreleaser-example-slsa-provenance](https://github.com/goreleaser/goreleaser-example-slsa-provenance) repository on GitHub. 52 53 We said artifacts a lot, but what are artifacts really? In the context of this blog post, artifacts are the binaries and the container images that GoReleaser generates for your project. If you are familiar enough with GoReleaser _-if you are not please refer to the [Quick Start](https://goreleaser.com/quick-start/) guide-_, GoReleaser uses a configuration file called `.goreleaser.yml` to define how to build and release your project. In this file, you can define the artifacts that you want to generate for your project. 54 55 Let's take a look at the `.goreleaser.yml` file of our demo project: 56 57 ```yaml 58 --- 59 builds: 60 - env: 61 - CGO_ENABLED=0 62 goos: 63 - linux 64 - windows 65 - darwin 66 67 kos: 68 - repository: ghcr.io/goreleaser/goreleaser-example-slsa-provenance 69 tags: 70 - "{{.Tag}}" 71 - "{{ if not .Prerelease }}latest{{ end }}" 72 bare: true 73 preserve_import_paths: false 74 sbom: none 75 platforms: 76 - all 77 flags: 78 - -trimpath 79 ldflags: 80 - -s -w 81 ``` 82 83 I trimmed the file a bit to make it easier to read. As you can see, we are building our binaries for the `linux`, `windows`, and `darwin` operating systems as we defined in the `builds` section, thanks to the built-in cross-compliation support in Golang. We are also using the [kos](https://goreleaser.com/customization/ko/) integration to build a container image for our project. It is a new way to build container images your project using [ko](https://ko.build). We are also using the `ghcr.io/goreleaser/goreleaser-example-slsa-provenance` repository to push our container image both with the `latest` and the `{{.Tag}}` tag. 84 85 > _If you want to learn more about the ko tool, check out our [blog post](https://blog.kubesimplify.com/getting-started-with-ko-a-fast-container-image-builder-for-your-go-applications/)._ 86 87 Now that we have a better understanding of what artifacts are and the `.goreleaser.yml' is, let's see how we can use the slsa-github-generator to generate SLSA provenance for our artifacts. 88 89 Before than that we should talk a little bit about the [GitHub Actions](https://docs.github.com/en/actions/quickstart) platform. 90 91 GitHub Actions is an automation and continuous integration/continuous deployment (CI/CD) platform provided by GitHub, which is a widely used web-based platform for version control and collaboration among software developers. GitHub Actions allows you to automate various tasks and workflows in your software development process directly within your GitHub repositories. 92 93 To use GitHub Actions, you need to create a workflow file in your repository (_under .github/workflows_). A workflow file is a YAML file that contains a set of instructions that define the steps of your workflow. You can create a workflow file manually or use a workflow template provided by GitHub. GitHub Actions provides a wide range of workflow templates that you can use to automate various tasks and processes in your software development lifecycle. You can also create your own custom workflow templates to suit your specific needs for better reusability and consistency. This is where [reusable workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows) comes into play. 94 95 GitHub Actions and reusable workflows are powerful tools for streamlining your development process, improving code quality, and ensuring consistent practices across your projects. They provide the flexibility and scalability needed to automate tasks and customize your development workflow to meet the specific needs of your software projects. 96 97 It's important to understand reusable workflows since the slsa-github-generator is mostly about reusable workflows. 98 99 Let's have a first look at the GitHub workflow file that we will use to generate SLSA provenance for our artifacts: 100 101 ```yaml 102 --- 103 binary-provenance: 104 needs: [goreleaser] 105 permissions: 106 actions: read # To read the workflow path. 107 id-token: write # To sign the provenance. 108 contents: write # To add assets to a release. 109 uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v1.9.0 110 with: 111 base64-subjects: "${{ needs.goreleaser.outputs.hashes }}" 112 upload-assets: true # upload to a new release 113 114 image-provenance: 115 needs: [goreleaser] 116 permissions: 117 actions: read 118 id-token: write 119 packages: write 120 uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v1.9.0 121 with: 122 image: ${{ needs.goreleaser.outputs.image }} 123 digest: ${{ needs.goreleaser.outputs.digest }} 124 registry-username: ${{ github.actor }} 125 secrets: 126 registry-password: ${{ secrets.GITHUB_TOKEN }} # you should provive registry-password, if you are using private registry like ghcr.io 127 ``` 128 129 At the time of writing this `1.9.0` is the latest version of the slsa-github-generator. As you can see, we are using two different reusable workflows to generate SLSA provenance for our artifacts. The first one is the `generator_generic_slsa3.yml` workflow, which is used to generate SLSA provenance for our binaries. The second one is the `generator_container_slsa3.yml` workflow, which is used to generate SLSA provenance for our container images. 130 131 That's it, we are done. We can now generate SLSA provenance for our artifacts. Confess, you didn't expect this task to be so straightforward. 🤣 132 133 Let's continue with explaining them in more detail. 134 135 First, as you might have noticed, we are using the `needs` keyword to define the dependencies of our workflow. In this case, we are saying that our workflow depends on the `goreleaser` job. This means that our workflow will run after the `goreleaser` job is completed successfully. This is important because we need the artifacts generated by the `goreleaser` job to generate SLSA provenance for them. 136 137 Next, we are using the `permissions` keyword to define the permissions of our job. This is a new feature of GitHub Actions that allows you to define the permissions of your workflow. This is important because we need to define the permissions of our workflow to be able to generate SLSA provenance for our artifacts. In this case, we are saying that our workflow needs the `read` permission to read the workflow path, the `write` permission to sign the provenance, and the `write` permission to add assets to a release. 138 139 As we mentioned we have to wait until the `goreleaser` job to be finished before we generate SLSA provenance because we need some output from the `goreleaser` job to generate SLSA provenance. 140 141 We are using the `outputs` keyword to define the outputs of our job. In this case, we are saying that our workflow needs the `hashes` output from the `goreleaser` job. This is important because we need the hashes of our artifacts to generate SLSA provenance for them. We are also saying that our workflow needs the `image` and the `digest` output from the `goreleaser` job. This is important because we need the image and the digest of our container image to generate SLSA provenance for them. 142 143 Finally, we are using the `with` keyword to define the inputs of our job. In this case, we are saying that our workflow needs the `hashes`, `image.name` and `image.digest` output from the `goreleaser` job. 144 145 Let's have a look at the how we generate these outputs in the `goreleaser` job: 146 147 ```yaml 148 ... 149 jobs: 150 goreleaser: 151 outputs: 152 hashes: ${{ steps.binary.outputs.hashes }} 153 image: ${{ steps.image.outputs.name }} 154 digest: ${{ steps.image.outputs.digest }} 155 ... 156 157 - name: Generate binary hashes 158 id: binary 159 env: 160 ARTIFACTS: "${{ steps.goreleaser.outputs.artifacts }}" 161 run: | 162 set -euo pipefail 163 164 checksum_file=$(echo "$ARTIFACTS" | jq -r '.[] | select (.type=="Checksum") | .path') 165 echo "hashes=$(cat $checksum_file | base64 -w0)" >> "$GITHUB_OUTPUT" 166 167 - name: Image digest 168 id: image 169 env: 170 ARTIFACTS: "${{ steps.goreleaser.outputs.artifacts }}" 171 run: | 172 set -euo pipefail 173 image_and_digest=$(echo "$ARTIFACTS" | jq -r '.[] | select (.type=="Docker Manifest") | .path') 174 image=$(echo "${image_and_digest}" | cut -d'@' -f1 | cut -d':' -f1) 175 digest=$(echo "${image_and_digest}" | cut -d'@' -f2) 176 echo "name=$image" >> "$GITHUB_OUTPUT" 177 echo "digest=$digest" >> "$GITHUB_OUTPUT" 178 ... 179 ``` 180 181 For the `Generate binary hashes` step, we are using the `jq` tool to parse the `artifacts` output which is one of the outputs of the [goreleaser/goreleaser-action](https://github.com/goreleaser/goreleaser-action) from the `goreleaser` job and extract the checksum file path. We are then using the `base64` tool to encode the checksum file and save it to the `hashes` output. 182 183 In essence, the artifacts output consists of the contents of the artifacts.json file that GoReleaser generates in the dist/ folder, starting from version 1.2, as explained in this v1.2 release. This file contains information regarding the artifacts produced by GoReleaser. 184 185 During the process of generating SLSA (Supply Chain Levels for Software Artifacts) provenances for both our binaries and container images, we utilize specific jq operations to extract the necessary information such as the `hashes` for the binaries and the `image` and `digest` of our container image from the artifacts.json file. 186 187 At the end of the day, you will be having a succesfull workflow run like this: 188 189  190 191 ## Further Steps 192 193 As you can see, generating SLSA provenance for your artifacts with GoReleaser and slsa-github-generator is a straightforward process. You might be asking yourself what's next? Well, the answer is simple because we added verification steps to our workflow to show you how you can verify the SLSA provenance of your artifacts since they were signed by the slsa-github-generator and uploaded to the transparency log server (Rekor). 194 195 ```yaml 196 ... 197 - name: Verify assets 198 env: 199 CHECKSUMS: ${{ needs.goreleaser.outputs.hashes }} 200 PROVENANCE: "${{ needs.binary-provenance.outputs.provenance-name }}" 201 run: | 202 set -euo pipefail 203 checksums=$(echo "$CHECKSUMS" | base64 -d) 204 while read -r line; do 205 fn=$(echo $line | cut -d ' ' -f2) 206 echo "Verifying $fn" 207 slsa-verifier verify-artifact --provenance-path "$PROVENANCE" \ 208 --source-uri "github.com/$GITHUB_REPOSITORY" \ 209 --source-tag "$GITHUB_REF_NAME" \ 210 "$fn" 211 done <<<"$checksums" 212 213 214 - name: Verify image 215 env: 216 IMAGE: ${{ needs.goreleaser.outputs.image }} 217 DIGEST: ${{ needs.goreleaser.outputs.digest }} 218 run: | 219 slsa-verifier verify-image "$IMAGE@DIGEST" \ 220 --source-uri "github.com/$GITHUB_REPOSITORY" \ 221 --source-tag "$GITHUB_REF_NAME" 222 ``` 223 224 > _[slsa-verifier](https://github.com/slsa-framework/slsa-verifier) is a tool for verifying SLSA provenance that was generated by CI/CD builders. slsa-verifier verifies the provenance by verifying the cryptographic signatures on provenance to make sure it was created by the expected builder (default to GitHub CI/CD) and the source repository the artifact was built from._ 225 226 > _[cosign](https://github.com/sigstore/cosign) allows developers to sign artifacts with digital signatures, ensuring the authenticity and integrity of the artifacts. It also enables users to verify signatures on artifacts to confirm that they haven't been tampered with._ 227 228 Both cosign and slsa-verifier play crucial roles in enhancing the security and trustworthiness of software supply chains, particularly in containerized and cloud-native application development. To get the latest information and updates on these tools, it's recommended to refer to their respective documentation and GitHub repositories or official websites. 229 230 ## Conclusion 231 232 In this blog post, we explored how GoReleaser can help you generate SLSA provenance for your artifacts and how you can leverage the slsa-github-generator to automate the process. We also discussed the importance of software supply chain security and how SLSA provenance can help you enhance the security and trustworthiness of your software supply chain. We hope that this blog post has been helpful in understanding how GoReleaser can help you generate SLSA provenance for your artifacts and how you can leverage the slsa-github-generator to automate the process. If you have any questions or feedback, please feel free to reach out to us on GoReleaser discord channel. We would love to hear from you!