# SLSA [SLSA] is a framework to guide developers and help them secure their software supply chain. In this document we are describing how we incrementally reach [SLSA] level 4, and explain why we meet each criteria. ## SLSA 1 SLSA level 1 does not do much, but helps us get on track to build a resilient system. We only have 2 requirements to satisfy. ### ✅ [Build - Scripted build] > All build steps were fully defined in some sort of “build script”. The only > manual command, if any, was to invoke the build script. We use a GitHub Workflow to execute all the CI steps. ### ✅ [Provenance - Available] > The provenance is available to the consumer in a format that the consumer > accepts. The format SHOULD be in-toto SLSA Provenance, but another format MAY > be used if both producer and consumer agree and it meets all the other > requirements. We provide provenance using the SLSA [github-actions-demo] and attach it to the GitHub Release. ### Things to notice - The attestation will not be uploaded to crates.io, but will live in GitHub release. This is not ideal and will complexify the process to verify it. Ideally all should be managed by `cargo.` - The attestation does not mention which commit was used to build the crate. - Following [cosign]'s convention, we named the attestation `trauma.${{ github.sha }}.att` ## SLSA 2 We keep adding to the security here, by requiring automated CI systems and introducing signing. ### ✅ [Source - Version controlled] > Every change to the source is tracked in a version control system that meets > the following requirements: > > - [Change history] There exists a record of the history of changes that went > into the revision. Each change must contain: the identities of the uploader > and reviewers (if any), timestamps of the reviews (if any) and submission, > the change description/justification, the content of the change, and the > parent revisions. > - [Immutable reference] There exists a way to indefinitely reference this > particular, immutable revision. In git, this is the {repo URL + > branch/tag/ref + commit ID}. We are using `git` as our VCS, which meets these requirements, so we're good here ✅. ### ✅ [Build - Build service] > All build steps ran using some build service, not on a developer’s > workstation. We use GitHub Actions as the automated build system. ### ✅ [Provenance - Authenticated] > The provenance’s authenticity and integrity can be verified by the consumer. > This SHOULD be through a digital signature from a private key accessible only > to the service generating the provenance. For this requirement, we are using [cosign] to sign the provenance attestation. The attestation signature will be attached to the GitHub release, next to the attestation itself. Here is the trauma public key `trauma.pub`: ```pgp -----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE9REilH9skU+RaK9Pcs3PhAKOSsjH hSt+Gu73ChvvFNZd5u9LDU7BpdJUG5vKBVMaHnOlPY1Az/dC2DxqQa5iRQ== -----END PUBLIC KEY----- ``` The signature could be verified using cosign as well: ```bash $ cosign verify-blob --key trauma.pub --signature trauma.sig trauma.att Verified OK ``` And we're good here. ### ❌ [Provenance - Service generated] > The data in the provenance MUST be obtained from the build service (either > because the generator is the build service or because the provenance generator > reads the data directly from the build service). > > Regular users of the service MUST NOT be able to inject or alter the contents, > except as noted below. > > The following provenance fields MAY be generated by the user-controlled build > steps: > > - The output artifact hash from Identifies Artifact. Reasoning: This only > allows a “bad” build to falsely claim that it produced a “good” artifact. > This is not a > security problem because the consumer MUST accept only > “good” builds and reject “bad” builds. > - The “reproducible” boolean and justification from Reproducible. We are generating the provenance through a custom action as a step in our GitHub Workflow. It is not a service offered by GitHub Actions itself. Therefore we do not meet the criteria. ### Things to notice - It is best practice to add a password to the signing key, but it was not required to be SLSA 2 compliant. - Could probably further improve the verification workflow by using [rekor]/[fulcio]. - Using the GitHub OIDC provider would also be a nice addition, but this feature is still marked as experimental at the time of writing. See the [openid signing] reference for more information. ## SLSA 3 Now we are getting serious! ### ✅ [Source - Verified history] > Every change in the revision’s history has at least one strongly authenticated > actor identity (author, uploader, reviewer, etc.) and timestamp. It must be > clear which identities were verified, and those identities must use two-step > verification or similar. (Exceptions noted below.) Here are the elements allowing us to match this requirement: - We are using GitHub. - We can identify the author of a pull-request. - A GitHub account is required to submit a pull-request. - This repository is not in an organization, BUT 2FA is enabled. - This repository requires pull-request to add changes and the main branch has been protected. So we should be in compliance here. ### ✅ [Source - Retained indefinitely] (18 months for SLSA 3) > The revision and its change history are preserved indefinitely and cannot be > deleted, except when subject to an established and transparent policy for > obliteration, such as a legal or policy requirement. > > [Immutable history] It must not be possible for persons to delete or modify > the history, even with multi-party approval, except by trusted platform admins > with two-party approval following the obliterate policy. Since we are using GitHub we think we are in compliance with this item. Besides `git` does not allow to modify a commit without altering the child commits. ### ✅ [Build - Build as code] > The build definition and configuration is defined in text files, stored in a > version control system, and is executed by the build service. Our build operations are defined in the our GitHub workflow `ci-rust.yml`. ### ❓ [Build - Ephemeral environment] > The build service ensured that the build steps ran in an ephemeral > environment, such as a container or VM, provisioned solely for this build, and > not reused from a prior build. [github hosted runners] are ephemeral VMs. Therefore each job will be run in a different VM, **but not each step**. So if we follow the definition strictly, we are not in compliance here. But since our jobs are isolated from each others, we may still be good. ### ❓ [Build - Isolated] > The build service ensured that the build steps ran in an isolated environment > free of influence from other build instances, whether prior or concurrent. > > - It MUST NOT be possible for a build to access any secrets of the build > service, such as the provenance signing key. > - It MUST NOT be possible for two builds that overlap in time to influence one > another. > - It MUST NOT be possible for one build to persist or influence the build > environment of a subsequent build. > - Build caches, if used, MUST be purely content-addressable to prevent > tampering. We think we are in compliance here, but the secrets are usable to each step of the workflow, even though the contant cannot be viewed direclty. GitHub actions lets admin share secrets either at the organization level, either at the repository level. This part will require more digging to see if the way GitHub Actions is implemented is compliant or not. ### ❌ [Provenance - Non-falsifiable] > Provenance cannot be falsified by the build service’s users. > > NOTE: This requirement is a stricter version of Service Generated. > > - The provenance signing key MUST be stored in a secure key management system > accessible only to the build service account. > - The provenance signing key MUST NOT be accessible to the environment running > the user-defined build steps. > - Every field in the provenance MUST be generated or verified by the build > service in a trusted control plane. > - The user-controlled build steps MUST NOT be able to inject or alter the > contents, except as noted below. We clearly don't meet this criteria since our signing key is stored as a git secret, therefore accessible anywhere throughout the workflow. ### Things to notice - Although we can identify the authors of a pull-request, commit signing is not required. - Some definitions could use some clarification. - There is no standard naming and each CI system uses different words to mean the same thing, or the same words to mean different things. | GitHub | Tekton | | -------- | -------- | | Workflow | Pipeline | | Job | Task | | Step | Step | ## SLSA 4 Since we believe we are SLSA 3 compliant, let's continue this excercise and see if we can reach level 4. ### ❌ [Source - Two-person reviewed] > Every change in the revision’s history was agreed to by two trusted persons > prior to submission, and both of these trusted persons were strongly > authenticated. We are failing this requirement since the repository only has 1 maintainer. ### ✅ [Build - Parameterless] > The build output cannot be affected by user parameters other than the build > entry point and the top-level source location. In other words, the build is > fully defined through the build script and nothing else. We are using Github Actions in this manner. The only parameters are information coming from the source to build itself (commit sha, repository name, etc.) ### ❌ [Build - Hermetic] > All transitive build steps, sources, and dependencies were fully declared up > front with immutable references, and the build steps ran with no network > access. All the dependencies are strongly specified in the `Cargo.lock` file. However the dependencies are being fetched from crates.io every time the build runs (even though we are using caching), so we may be failing this requirement. A way to satisfy this requirement would be to use `cargo vendor` to vendor all dependencies locally. ### ❓ [Build - Reproducible] (best effort) > Re-running the build steps with identical input artifacts results in > bit-for-bit identical output. Builds that cannot meet this MUST provide a > justification why the build cannot be made reproducible. We think we are doing good on this one, mainly dur to the use of the lock file, but this item would require deeper investigation. ### ❌ [Provenance - Dependencies complete] > Provenance records all build dependencies that were available while running > the build steps. This includes the initial state of the machine, VM, or > container of the build worker. We may provide an SBOM, but that does not seem to be enough to satisfy this criteria. ### 🚫 [Common - Security] > The system meets some TBD baseline security standard to prevent compromise. > (Patching, vulnerability scanning, user isolation, transport security, secure > boot, machine identity, etc. Perhaps NIST 800-53 or a subset thereof.) This criteria seems to only apply does services which are deployed somewhere, therefore not apply here. ### 🚫 [Common - Access] > All physical and remote access must be rare, logged, and gated behind > multi-party approval. This criteria seems to only apply does services which are deployed somewhere, therefore not apply here. ### ❌ [Common - Superusers] > Only a small number of platform admins may override the guarantees listed > here. Doing so MUST require approval of a second platform admin. Since we have one admin, we're also failing this criteria. But they are talking about a platform admin, so it may no apply here. ### Things to notice - A lot of projects/tools/libraries only have one maintainer. Therefore it rules them out from being SLSA 4 compliant right away. - Such a high level of details in the provenance seems ideal, but it looks like such a tool does not exist yet. - The criteria in the "Common" category seem to only applied to deployed services. [build - build as code]: https://slsa.dev/spec/v0.1/requirements#build-as-code [build - isolated]: https://slsa.dev/spec/v0.1/requirements#isolated [build - build service]: https://slsa.dev/spec/v0.1/requirements#build-service [build - ephemeral environment]: https://slsa.dev/spec/v0.1/requirements#ephemeral-environment [build - hermetic]: https://slsa.dev/spec/v0.1/requirements#hermetic [build - reproducible]: https://slsa.dev/spec/v0.1/requirements#reproducible [build - parameterless]: https://slsa.dev/spec/v0.1/requirements#parameterless [build - scripted build]: https://slsa.dev/spec/v0.1/requirements#scripted-build [common - security]: https://slsa.dev/spec/v0.1/requirements#security [common - access]: https://slsa.dev/spec/v0.1/requirements#access [common - superusers]: https://slsa.dev/spec/v0.1/requirements#superusers [cosign]: https://github.com/sigstore/cosign [fulcio]: https://github.com/sigstore/fulcio [github-actions-demo]: https://github.com/slsa-framework/github-actions-demo [github hosted runners]: https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners [openid signing]: https://docs.sigstore.dev/cosign/openid_signing [provenance - authenticated]: https://slsa.dev/spec/v0.1/requirements#authenticated [provenance - available]: https://slsa.dev/spec/v0.1/requirements#available [provenance - dependencies complete]: https://slsa.dev/spec/v0.1/requirements#dependencies-complete [provenance - non-falsifiable]: https://slsa.dev/spec/v0.1/requirements#non-falsifiable [provenance - service generated]: https://slsa.dev/spec/v0.1/requirements#service-generated [rekor]: https://github.com/sigstore/rekor [slsa]: https://slsa.dev/ [source - retained indefinitely]: https://slsa.dev/spec/v0.1/requirements#retained-indefinitely [source - two-person reviewed]: https://slsa.dev/spec/v0.1/requirements#two-person-reviewed [source - version controlled]: https://slsa.dev/spec/v0.1/requirements#version-controlled [source - verified history]: https://slsa.dev/spec/v0.1/requirements#verified-history