slsa-framework / slsa

Supply-chain Levels for Software Artifacts
https://slsa.dev
Other
1.52k stars 220 forks source link

Trustworthiness of provenances in Build L2 #863

Open behnazh-w opened 1 year ago

behnazh-w commented 1 year ago

The trustworthiness of provenances in Build L2 needs clarification. The requirement states that the trustworthiness of the provenance is ensured. However, without hardening the build platform, this requirement will not be possible. In other words, if an attacker can access the signing material by breaking out of the build environment the trustworthiness of provenances cannot be ensured for Build L2.

This problem makes the Forge values of the provenance (other than output digest) threat example hard to understand because without some level of hardening the build platform, I'm not sure how this attack can be prevented at level 2.

mlieberman85 commented 1 year ago

So the way I read it, and maybe we can make it clearer here is the build is not the same as the build platform. The build platform should always be secured against tampering from the build itself.

Build L3 focuses on builds tampering with each other.

houdini91 commented 1 year ago

I was thinking about this , IMHO untrusted build platform may mean many things .

For example , That may actually prevent runs from influencing one another, even within the same project.

But does not prevent secret material used to sign the provenance from being accessible to the user-defined build steps.

In this case if you trust the developers who have access to a specific project you can still trust the prov was not effected by the other projects users and builds.

You can also further harden access to users using commit signatures restriction users to specific files.

Another approach compare the prov details with the build platform API directly. For example verify the build number and commit and timestamp of the prov match the event seen in the platform API.

Verifing prov against the rekor transparency.

Another thing I was thinking about is basic key management tricks, rolling keys, replacing keys (past and future protection), Signing using Multiauple keys

As well a range of key management tools services that you may want to use instead of the untrusted build platform one..

The same goes for separating between builds, hardware features allowing to separate trusted and untrusted code (vm, SGX, namespaces, using simply seperate build machines.

MarkLodato commented 1 year ago

The requirement states that the trustworthiness of the provenance is ensured. However, without hardening the build platform, this requirement will not be possible.

@behnazh-w I'm not sure how to interpret your comment. Do you mean:

behnazh-w commented 1 year ago
  • That ensuring trustworthiness of the provenance only really comes at Build L3, not Build L2? And that Forge values of the provenance should be marked as "Build L3" not "Build L2+"? If so, could you be more specific about what your suggested changes are?

Comparing the requirements in Build L2 and Build L3, L2 asks for trustworthiness of a provenance without giving any details. L3 makes it more concrete by stating:

prevent secret material used to sign the provenance from being accessible to the user-defined build steps.

Now, I would argue that the above property should also be required at Build L2 if we really want to trust the provenance and prevent Forge values of the provenance attacks. So, my suggestion is to add this requirement to Build L2, and come up with a stronger requirement for Build L3, e.g.,

This would be achievable in build platforms, such as GitHub Actions when they supports OpenID Connect tokens, and keyless signing as a result.

To me the specification first needs to clarify the main differences between Build L2 and L3 in terms if trustworthiness of a provenance. Next, having a Build Platform Operations track in future would help to assess whether the requirements are met.

sudo-bmitch commented 1 year ago

Perhaps a way to think of the differences is "who do you need to trust?"

MarkLodato commented 1 year ago

I agree with @sudo-bmitch's description. From https://slsa.dev/spec/v1.0/levels#build-l2:

[At Build L2:] Forging the provenance or evading verification requires an explicit “attack”, though this may be easy to perform. Deters unsophisticated adversaries or those who face legal or financial risk.

MarkLodato commented 1 year ago

Discussed at the 2023-08-14 spec meeting. Next steps:

joshuagl commented 1 year ago

Thanks for summarising @MarkLodato! I think we should move the (excellent) longer term idea into a separate issue and track only the short term item in this issue.

@behnazh-w, would the proposed short-term fix resolve this issue for you?

behnazh-w commented 1 year ago

The plan to have a short-term and a long-term fix sounds good to me.

I'm not sure though what the short-term fix would look like. @MarkLodato can you please clarify what "resists tampering by the developer" means in terms of "who/what to trust" and how the requirement would look like after the fix?

MarkLodato commented 1 year ago

I'll send out a PR to discuss potential wording.

@joshuagl do you mind filing a separate issue for the long-term fix (presumably for v1.1)?

MarkLodato commented 1 year ago

Sent #948 for review.

joshuagl commented 1 year ago

@joshuagl do you mind filing a separate issue for the long-term fix (presumably for v1.1)?

Done. https://github.com/slsa-framework/slsa/issues/949

MarkLodato commented 11 months ago

Open comment from https://github.com/slsa-framework/slsa/pull/948#discussion_r1357706452 by @behnazh-w:

Do we think we're good to submit this PR as-is, or are further changes needed? If it's strictly better than the old version but still not perfect, my preference would be to just submit it and then have a separate PR to iterate.

We can merge this PR as is and refine the following definitions and requirements in a separate PR:

  • The definition of "dedicated infrastructure" at SLSA Build L2
  • Change the Accuracy part of Provenance is Authentic requirement or add a new requirement that does not mandate the following for SLSA Build L2, so that npm provenances can satisfy L2.

The provenance MUST be generated by the control plane (i.e. within the trust boundary identified in the provenance) and not by a tenant of the build platform (i.e. outside the trust boundary)

MarkLodato commented 11 months ago

Upon further reflection (background), I think the main issue is that the security objective of Build L2 is too fuzzy. Currently we have:

Requirement L1 L2 L3
Provenance exists
Provenance authentic
Provenance unforgeable
Builds hosted
Builds isolated

The requirements "authentic" and "hosted" are wishy-washy with no clear security bar. Quote (emphasis added):

[At L2:] The build platform MUST have some security control to prevent tenants from tampering with the provenance. However, there is no minimum bound on the strength.

What if we simplify the ladder by moving "unforgeable" to L2 and drop/merge the redundant requirements? Then we'd have:

Requirement L1 L2 L3 (alternative wording)
Provenance exists Provenance existence
Provenance unforgeable Provenance integrity
Builds isolated Build integrity

In other words:

I think this might make things more clear for everyone. Thoughts?

If we agree that this is indeed better, the question is then, how disruptive would this be? It would definitely require a v2.0 since it's not backwards compatible. But I'm more wondering how many systems would this change affect, i.e. how many have already implemented something that passes v1.0's Build L2 but would not pass v2.0's?

jkjell commented 11 months ago

My experiences with build platforms would bias me toward Builds isolated at level 2 and Provenance unforgeable at level 3. The build platforms I have experience with, Concourse, Tekton, kpack (buildpacks), and I think (hope 🤞) all SaaS solutions (Google Cloud Build, Github Actions, Gitlab Pipelines, etc) offer isolated builds. It has felt like (I could be wrong) that Provenance Unforgeable has been harder to achieve. Separating out the provenance generation to a control plane requires changes to those build platforms (it's often something a consumer can't [easily] do).

mlieberman85 commented 11 months ago

I think Provenance Unforgeable can still be met with just having non-end user controlled build steps. Trusted steps that don't run arbitrary things that record evidence from the end user step should be enough.

MarkLodato commented 10 months ago

@jkjell That's a good point. However, I think Provenance unforgeable has significant value without Builds isolated, while the opposite is not really true in the context of the Build track. The thrust of the track is having trustworthy provenance:

I think the big question is, are there real-world build platforms that would meet Provenance unforgeable without Builds isolated? This needs a closer look at the definition of Builds isolated. I imagine there are many systems out that lack strong isolation within a tenants, e.g. one tenant can initiate two builds in the same project and have one influence the other because they're in the same security domain. But to know for sure we need to both better define the isolation requirements and map them to real-world systems.

What do you think?

jkjell commented 10 months ago

Yeah, that makes sense. I think I often conflate build and control plane isolation. Then I make the leap to the idea that if builds are not isolate, the control plane may not be either (viewing isolation as the prerequisite to each). I think many times the mechanism for this isolation (say containers or clusters per boundary) can be the same for each but, that's not generally true. I'm not sure that Provenance Unforgeable is a directly translation to that but, it's where my brain wants to go. 😅

This is a long way to saying ➕ to better defining isolation requirements and possibly considering its relationship to build system control planes while doing so.

behnazh-w commented 10 months ago

What if we simplify the ladder by moving "unforgeable" to L2 and drop/merge the redundant requirements?

I think its' a good idea to be more specific about unforgeable provenances:

Requirement L1 L2 L3 (alternative wording)
Provenance exists Provenance existence
Provenance unforgeable after the build Provenance integrity
Provenance unforgeable during the build (isolated) Provenance integrity
Builds isolated Build integrity

I would also keep Builds isolated separate from Provenance isolated because it is possible to have an isolated provenance generation while the build is not isolated (e.g., generic provenances that use GitHub Actions Reusable workflow produce provenances in an isolated VM but the build itself can run in the VM where untrusted code runs).

joshuagl commented 9 months ago

What if we simplify the ladder by moving "unforgeable" to L2 and drop/merge the redundant requirements?

I'm all for moving unforgeable to L2 and merging with authentic.

The hosted requirement causes a lot of confusion and I think it makes sense to remove it from L2. What happens to it then, though? I think we can all agree that we should be discouraging software producers from generating release products on users' workstations, for security and business continuity reasons. Perhaps we can make this more explicit in verifiying systems until such a time as we have a concrete control and outcome to document in the Build track?

In other words:

* At L1, provenance is simply untrustworthy.

* At L2, provenance itself is trustworthy—it really was generated from the platform and external parameters claimed—but an attacker could have tampered with it during execution. In other words, L2 protects _after the build_.

* At L3, provenance is trustworthy _and_ the build has protections against tampering. In other words, L3 protects _during or after the build_.

The stated outcomes here reflect the focus areas we document on the levels page of the v1.0 spec:

Screenshot 2023-11-20 at 11 43 01

how disruptive would this be? It would definitely require a v2.0 since it's not backwards compatible. But I'm more wondering how many systems would this change affect, i.e. how many have already implemented something that passes v1.0's Build L2 but would not pass v2.0's?

Tekton chains and npm provenance come to mind as two solutions which claim SLSA Build L2. I believe if we merge provenance authenticated & provenance unforgeable that npm packages using the npm GitHub Action will still meet SLSA Build L2 (thanks to use of per-job workflow identities and Sigstore). I'm much less familiar with Tekton & Chains, but I think we have members of the community who can help us understand whether this change to the spec would be disruptive to those projects.

sudo-bmitch commented 9 months ago

The hosted requirement causes a lot of confusion and I think it makes sense to remove it from L2. What happens to it then, though? I think we can all agree that we should be discouraging software producers from generating release products on users' workstations, for security and business continuity reasons.

I've seen a lot of that confusion. My own take is we should focus on the goal rather than a proxy for that goal. I believe we want to be sure the build server is relatively secure and maintained to reduce the likelihood of a compromised build host.

Otherwise OSS purist that refuse to use a cloud service and instead run a reproducible build on an airgapped laptop in their basement that otherwise stays locked in a cabinet will feel excluded by a technicality. While the insert name of compromised cloud build service users with compromised credentials, or even someone with an unpatched Jenkins server listening on the internet, can keep checking the box.

Perhaps phrasing it as "builds run on a well maintained and secured platform" with references to the CIS benchmarks, NIST, NSA, etc for the process to secure those hosts.

joshuagl commented 9 months ago

The discussion of removing "Builds Hosted" from Build L2 may need to be forked into a separate issue. We keep coming back to this, so I think it's worth some attention. Can we articulate the concrete security outcome we want to achieve through a hosted builds, or similar, requirement?

These don't feel very concrete, but some straw-person proposals:

arewm commented 9 months ago

Tekton chains and npm provenance come to mind as two solutions which claim SLSA Build L2. I believe if we merge provenance authenticated & provenance unforgeable that npm packages using the npm GitHub Action will still meet SLSA Build L2 (thanks to use of per-job workflow identities and Sigstore). I'm much less familiar with Tekton & Chains, but I think we have members of the community who can help us understand whether this change to the spec would be disruptive to those projects.

While I am not a member of the Tekton/Chains community, based on my experience with them, it is possible to leverage them to achieve SLSA 1.0 Build L3+. Some of the challenges come down to ensuring that the ServiceAccount running the pipeline is not over-provisioned and to ensure that data transferred between the build Tasks and steps is properly protected from tampering.

MarkLodato commented 9 months ago

To consider this issue resolved, it should be clear to most readers how to answer #1002 and the related Slack thread.

In particular:

In other words, the goal of the attacker is to say that output X was produced from a build of git repo/commit Y, which would not normally produce X. In this new threat, the attacker extracts the OIDC/x509 from a legitimate build of repo/commit Y and sign an attestation saying the output was X (which is false). But if the attacker had enough access to extract the OIDC/x509, couldn't they just have had the original build output X directly? Is that a substantially easier attack? I could go either way.