Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SBOM Discovery with Rekor #1157

Merged
merged 8 commits into from
Aug 24, 2022
Merged

Conversation

mdeicas
Copy link
Contributor

@mdeicas mdeicas commented Aug 11, 2022

This PR adds the ability to discover build-time SBOMs of binaries with the Rekor transparency log and to create external document references for them in SPDX JSON. Explained in more detail in #1159

Signed-off-by: Marco Deicas <mdeicas@google.com>
Signed-off-by: Marco Deicas <mdeicas@google.com>
Signed-off-by: Marco Deicas <mdeicas@google.com>
Signed-off-by: Marco Deicas <mdeicas@google.com>
README.md Outdated Show resolved Hide resolved
internal/formats/spdx22json/to_format_model.go Outdated Show resolved Hide resolved
internal/formats/spdx22json/to_format_model_test.go Outdated Show resolved Hide resolved
syft/rekor/rekor.go Outdated Show resolved Hide resolved
syft/rekor/rekor.go Outdated Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
syft/rekor/rekor_test.go Outdated Show resolved Hide resolved
"github.com/stretchr/testify/assert"
)

func Test_getAndVerifySbomFromUuid(t *testing.T) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@asraa Need some help with your expertise around rekor inclusion proofs.. would you be able to help review this test? Thanks!

README.md Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
return errors.New("attestation has no sboms")
}
// take entry at index 0 because we currently do not handle multiple sboms within one attestation
expectedHash := att.Predicate.Sboms[0].Digest.Sha256
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are digest and Sha256 guaranteed to not be nil in this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sha256's default value is the empty string, which would be caught in this function. Is this what you meant?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep! I just want to be sure that the Digest field here never has a chance to throw a nil pointer exception.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Digest was ever nil then Digest.Sha256 would panic

Copy link
Contributor

@wagoodman wagoodman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very nice work! I added a few suggestions, mostly nit. From a high level there are a lot of uses of pointers that appear unnecessary --not a blocking comment, but it would be good to do another pass at trying to remove some pointer references.

syft/pkg/cataloger/rekor/rekor_cataloger.go Show resolved Hide resolved
syft/pkg/cataloger/cataloger.go Show resolved Hide resolved
syft/rekor/query.go Show resolved Hide resolved
if len(att.Predicate.Sboms) > 1 {
log.Info("attestation found on Rekor with multiple SBOMS, which is not currently supported. Proceeding with the first SBOM.")
}
uri := att.Predicate.Sboms[0].URI
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding 2 cents, sorry for the length: I agree that there is no problem since validateAttestation is indeed called before getSbom, but this could be made more obvious. Ideally validations for code should be close (or really, as close as possible) to the code that needs this validation. Additionally, we should defend against future changes which might accidentally erode/reverse assumptions made here (in this case that validateAttestation is called in advance and has the proper checks relative to what's needed here for getting the SBOM).

One way to do this is to have the caller pass a more constrained data type:

	att, err := parseAndValidateAttestation(logEntryAnon)
	...

	sbomBytes, err := getSbom(att.Predicate.Sboms[0] , client.httpClient)
	...

This way getSbom is given the data that it operates on (not the full attestation) and the assumption that ...Sboms[0] will not panic is closer to the code that does this verification (still could be made closer, and the more closer the more ideal).

Though it's a little more clear, this code could still technically panic. We can adjust this to still not have redundant checks, but also make it safer:

func getFirstSbom(sboms []sbomEntry, client *http.Client) ([]byte, error) {
	if len(att.Predicate.Sboms) > 1 {
		// log something...
	}

	var bytes []byte
	for _, s := range sboms {
		resp, err client.Get(s.URI)
		...
		// get the sbom bytes, assign to 'bytes', then "break"
	}

	if len(bytes) == 0 {
		return nil, fmt.Errorf("no sbom found")
	}
	return bytes, nil
}

And the caller:

	att, err := parseAndValidateAttestation(logEntryAnon)
	...

	sbomBytes, err := getFirstSbom(att.Predicate.Sboms, client.httpClient)
	...

Side note: renaming getSbom to getFirstSbom makes sense in this latter case, and with how it's written today.

syft/rekor/rekor.go Show resolved Hide resolved
syft/rekor/rekor.go Show resolved Hide resolved
syft/rekor/utils.go Show resolved Hide resolved
syft/rekor/verify.go Show resolved Hide resolved
@@ -0,0 +1,2 @@
# An image containing the example sample-golang-prov binary from https://github.com/lumjjb/sample-golang-prov
FROM docker.io/mdeicas/sample-golang-prov:latest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have a nice way to generate this without needing to rely on an external 3rd party docker image?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One alternative is to put the sample-golang-prov binary in test-fixtures and have FROM scratch COPY sample-golang-prov /. Does this sound better?

If this change is made, then the same should probably be done for the image-rust-auditable docker file.
@wagoodman

@spiffcs
Copy link
Contributor

spiffcs commented Aug 22, 2022

@mdeicas low priority, but there are some linting errors showing up on the static analysis:

I'm going through the rekor changes today and will add comments to that part of the codebase

@spiffcs
Copy link
Contributor

spiffcs commented Aug 23, 2022

Also @mdeicas and @lumjjb - I created the kubecon-draft branch so we can update this to be handed off and merged here before we take the plunge on main.

If you have a better name that you're using for this project I can absolutely update that branch name!

@mdeicas mdeicas changed the base branch from main to kubecon-draft August 23, 2022 18:52
@mdeicas
Copy link
Contributor Author

mdeicas commented Aug 23, 2022

kubecon-draft is good with me; I changed the PR target to it. I can file another PR with changes from these comments when it is merged.

@lumjjb
Copy link

lumjjb commented Aug 23, 2022

I created the kubecon-draft branch so we can update this to be handed off and merged here before we take the plunge on main.

SGTM!

@mdeicas
Copy link
Contributor Author

mdeicas commented Aug 23, 2022

I have changes for all of the comments in this thread ready in another branch (except for integration test w/o docker image and removing pointer references). It might be easier to merge this PR into kubecon-draft and then review these changes as another PR. Alternatively, I can just push the changes to this PR. Which approach should we take?

Regardless, should I rebase and squash the commits in this PR to a single commit?

The changes I have in this other branch include a fix for the static analysis check that failed and for the rekor cataloger integration test that failed. The integration test failed because catalogers that use external sources are now off by default.

@spiffcs
Copy link
Contributor

spiffcs commented Aug 24, 2022

I have changes for all of the comments in this thread ready in another branch (except for integration test w/o docker image and removing pointer references). It might be easier to merge this PR into kubecon-draft and then review these changes as another PR. Alternatively, I can just push the changes to this PR. Which approach should we take?

Regardless, should I rebase and squash the commits in this PR to a single commit?

The changes I have in this other branch include a fix for the static analysis check that failed and for the rekor cataloger integration test that failed. The integration test failed because catalogers that use external sources are now off by default.

I think we can merge this PR into kubecon-draft. I can do that as a squash if you're ok with it @mdeicas. I know you took care to break the commits into logical units, but also see a value in squashing this into the draft branch as a baseline.

We can then file a new PR against the draft branch with the changes you mentioned.

@mdeicas
Copy link
Contributor Author

mdeicas commented Aug 24, 2022

I think we can merge this PR into kubecon-draft. I can do that as a squash if you're ok with it @mdeicas. I know you took care to break the commits into logical units, but also see a value in squashing this into the draft branch as a baseline.

We can then file a new PR against the draft branch with the changes you mentioned.

Sounds good to me. Go ahead and squash.

@spiffcs spiffcs changed the title SBOM Discovery with Rekor Add SBOM Discovery with Rekor Aug 24, 2022
@spiffcs spiffcs merged commit 369eb3f into anchore:kubecon-draft Aug 24, 2022
@spiffcs
Copy link
Contributor

spiffcs commented Aug 24, 2022

@lumjjb @wagoodman @mdeicas - changes have been merged into anchore:kubecon-draft

feel free to file smaller PR against that branch with fixes mentioned in this thread or any additional information!

@mdeicas mdeicas deleted the rekor-cataloger branch August 24, 2022 19:52
@mdeicas
Copy link
Contributor Author

mdeicas commented Aug 24, 2022

@lumjjb @wagoodman @mdeicas - changes have been merged into anchore:kubecon-draft

feel free to file smaller PR against that branch with fixes mentioned in this thread or any additional information!

Awesome thank you! Will do

spiffcs pushed a commit that referenced this pull request Oct 21, 2022
This PR adds the ability to discover build-time SBOMs from binaries with the Rekor transparency log.
It does this by creating external document references for them in SPDX JSON.

Explained in more detail in syft issue #1159

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
spiffcs pushed a commit that referenced this pull request Oct 21, 2022
This PR adds the ability to discover build-time SBOMs from binaries with the Rekor transparency log.
It does this by creating external document references for them in SPDX JSON.

Explained in more detail in syft issue #1159

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
spiffcs pushed a commit that referenced this pull request Oct 25, 2022
This PR adds the ability to discover build-time SBOMs from binaries with the Rekor transparency log.
It does this by creating external document references for them in SPDX JSON.

Explained in more detail in syft issue #1159

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
spiffcs pushed a commit that referenced this pull request Oct 25, 2022
This PR adds the ability to discover build-time SBOMs from binaries with the Rekor transparency log.
It does this by creating external document references for them in SPDX JSON.

Explained in more detail in syft issue #1159

Signed-off-by: Christopher Phillips <christopher.phillips@anchore.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

None yet

4 participants