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 support for new bundle specification for attesting/verifying OCI image attestations #3889

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

codysoyland
Copy link
Member

@codysoyland codysoyland commented Sep 25, 2024

Summary

This PR adds support for the new Cosign Bundle Specification in cosign attest and cosign verify-attestation.

Related: #3139

To test, run the following (replacing MY_IDENTITY, MY_ISSUER, MY_TRUSTED_ROOT and MY_IMAGE as needed -- trusted root is optional). Note that the new OCI support requires passing --new-bundle-format into both commands.

go run ./cmd/cosign attest --predicate my-predicate.json --new-bundle-format MY_IMAGE
go run ./cmd/cosign verify-attestation --certificate-identity MY_IDENTITY --certificate-oidc-issuer MY_ISSUER --new-bundle-format --trusted-root=MY_TRUSTED_ROOT MY_IMAGE

Full example (using crane, but can instead use docker tag/docker push):

make cosign
docker run -d -p 5050:5000 ghcr.io/project-zot/zot-linux-arm64:latest
crane copy busybox:latest localhost:5050/busybox
echo '{"foo": "bar"}' > predicate.json
./cosign attest --predicate predicate.json --new-bundle-format localhost:5050/busybox:latest
# Dex workflow, assuming GitHub as provider
./cosign verify-attestation --certificate-identity=yourname@example.com --certificate-oidc-issuer=https://github.com/login/oauth --new-bundle-format localhost:5050/busybox:latest

To show that it uses the OCI 1.1 referrers API, you can use oras:

oras discover localhost:5050/busybox:latest
Discovered 1 artifact referencing latest
Digest: sha256:db142d433cdde11f10ae479dbf92f3b13d693fd1c91053da9979728cceb1dc68

Artifact Type                                   Digest
application/vnd.dev.sigstore.bundle.v0.3+json   sha256:3fb46d845fe437667a6b3ed45d2b11dea11c43f8fbe76dd642eb71de2a9b8b77

Release Note

Documentation

Copy link

codecov bot commented Nov 6, 2024

Codecov Report

Attention: Patch coverage is 23.57955% with 269 lines in your changes missing coverage. Please review.

Project coverage is 36.46%. Comparing base (2ef6022) to head (597f74d).
Report is 332 commits behind head on main.

Files with missing lines Patch % Lines
pkg/oci/remote/write.go 0.00% 92 Missing ⚠️
cmd/cosign/cli/verify/verify_attestation.go 0.00% 38 Missing ⚠️
pkg/oci/remote/signatures.go 0.00% 37 Missing ⚠️
cmd/cosign/cli/attest/attest.go 0.00% 32 Missing ⚠️
pkg/cosign/verify.go 71.81% 22 Missing and 9 partials ⚠️
cmd/cosign/cli/attest/common.go 0.00% 10 Missing ⚠️
cmd/cosign/cli/options/verify.go 0.00% 8 Missing ⚠️
cmd/cosign/cli/verify/verify.go 0.00% 7 Missing ⚠️
cmd/cosign/cli/attest/attest_blob.go 14.28% 6 Missing ⚠️
cmd/cosign/cli/verify.go 0.00% 5 Missing ⚠️
... and 2 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3889      +/-   ##
==========================================
- Coverage   40.10%   36.46%   -3.64%     
==========================================
  Files         155      210      +55     
  Lines       10044    13734    +3690     
==========================================
+ Hits         4028     5008     +980     
- Misses       5530     8099    +2569     
- Partials      486      627     +141     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@codysoyland codysoyland force-pushed the verify-attestation-bundle-spec branch from af5093d to 524f558 Compare November 22, 2024 16:44
@codysoyland codysoyland marked this pull request as ready for review November 22, 2024 19:55
@codysoyland codysoyland changed the title Add support for new bundle specification in cosign verify-attestation Add support for new bundle specification for attesting/verifying OCI image attestations Nov 22, 2024
// Wrap TrustedMaterial
vTrustedMaterial := &verifyTrustedMaterial{TrustedMaterial: co.TrustedMaterial}

// If TrustedMaterial is not set, fetch it from TUF (TODO: should this even be done? Old verifier requires co.RootCerts to be set)
Copy link
Contributor

Choose a reason for hiding this comment

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

If they haven't set --trusted-root then they could be using other flags or relying on the TUF v1 setup which might be pointed to something other than the public good instance. I understand that this is only meant to be called when --new-bundle-format is set but I'm worried that this would be surprising behavior if the PGI trusted root is used while the cached TUF metadata is pointed somewhere else.

}

for _, verified := range bundlesVerified {
atLeastOneBundleVerified = atLeastOneBundleVerified || verified
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you clarify why it's okay for only one bundle to be verified?

Copy link
Member Author

Choose a reason for hiding this comment

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

This logic was copied from

func VerifyImageAttestation(ctx context.Context, atts oci.Signatures, h v1.Hash, co *CheckOpts) (checkedAttestations []oci.Signature, bundleVerified bool, err error) {
, but I renamed bundleVerified to atLeastOneBundleVerified so it's more clear. The effect is that if there are multiple bundles associated with an image, verification will succeed if at least one of them is verified.

I can write a comment about this if it helps!

Copy link
Contributor

Choose a reason for hiding this comment

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

Adding onto this - Do we want to support multiple bundles on a single container? We shouldn't be bound to Cosign's previous decisions and it might be worth revisiting this now.

There are valid use-cases for multiple bundles (rotating a signing key/identity for example), but I just want to take a second to make sure we really do want to support this.

Copy link
Member Author

Choose a reason for hiding this comment

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

IMO, there are not many downsides to supporting multiple bundles and it's pretty much "free" with OCI, but it's good to challenge that assumption. I guess you could say a downside is that we need this logic here to decide if invalid attestations should cause a verification failure, but I would argue that this logic is natural if the principle of monotonicity is followed.

I would also highlight that each bundle may only contain one attestation, so if a user wishes to store both an SBOM and vulnerability scan attestation referencing the same image, multiple bundles must be allowed.

@@ -361,7 +377,7 @@ func attestVerify(t *testing.T, predicateType, attestation, goodCue, badCue stri
}

// Now attest the image
ko := options.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc}
ko := options.KeyOpts{KeyRef: privKeyPath, PassFunc: passFunc, NewBundleFormat: newBundleFormat}
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe out of scope for this PR but a note for the future, this is setting NewBundleFormat without setting TrustedRootPath, which means the TrustedMaterial will default to using PGI. We're trying to avoid making external network calls to live services. The only reason that isn't a problem here is because this test is using a local key pair and is not uploading to Rekor, so it doesn't matter what verification material is used. But a useful test in the future might be to have this use ephemeral keys from Fulcio (localhost:5555) and upload the entry to Rekor (localhost:3000) so that the full verification path with a locally generated trust root could be tested.

@codysoyland
Copy link
Member Author

I rebased and squashed all commits into one as there have been a couple of items refactored into separate PRs (#4006 and #4013) and this ongoing PR was getting a bit messy.

I still need to finish #4013 and rebase this one again, at which point I will be ready for another review pass.

Thanks everyone who has been patiently reviewing and helping me iterate on this!

Comment on lines -225 to -229
NewBundleFormat bool
TrustedRootPath string
Copy link
Member Author

Choose a reason for hiding this comment

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

Note these have moved to CommonVerifyOptions

@codysoyland
Copy link
Member Author

codysoyland commented Feb 7, 2025

This has been rebased again and is ready for review.

Copy link
Member

@steiza steiza left a comment

Choose a reason for hiding this comment

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

There's a lot here! Sorry this took me so long to review; just a few minor questions on the changes.

Do I understand the Codecov report correctly that 1% of these changes are covered via tests? Any thoughts on how to increase that?

@codysoyland
Copy link
Member Author

Do I understand the Codecov report correctly that 1% of these changes are covered via tests? Any thoughts on how to increase that?

True, there are no remaining unit tests in this PR after the last rebase, but Codecov may not take into account the new e2e tests which should cover quite a bit. I'll try manually running coverage and see what I can reasonably cover with more tests.

@dmitris
Copy link
Contributor

dmitris commented Feb 17, 2025

@codysoyland - thanks for pushing this forward, eagerly awaiting this feature! If I can help with testing or anything else, please let me know!

Could you resolve the conflicts, please? Thanks.

Copy link
Contributor

@haydentherapper haydentherapper left a comment

Choose a reason for hiding this comment

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

This is really amazing work @codysoyland!

Going to read up on OCI 1.1 and take another pass later, though we should ask the authors of the original OCI 1.1 code as well to review those bits.

}

for _, verified := range bundlesVerified {
atLeastOneBundleVerified = atLeastOneBundleVerified || verified
Copy link
Contributor

Choose a reason for hiding this comment

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

Adding onto this - Do we want to support multiple bundles on a single container? We shouldn't be bound to Cosign's previous decisions and it might be worth revisiting this now.

There are valid use-cases for multiple bundles (rotating a signing key/identity for example), but I just want to take a second to make sure we really do want to support this.

@codysoyland codysoyland force-pushed the verify-attestation-bundle-spec branch from 6d7fbf2 to f440737 Compare February 18, 2025 19:03
@codysoyland
Copy link
Member Author

codysoyland commented Feb 18, 2025

@codysoyland - thanks for pushing this forward, eagerly awaiting this feature! If I can help with testing or anything else, please let me know!

Thank you! I'd be interested in any manual test results you may have!

Could you resolve the conflicts, please? Thanks.

I just rebased and resolved the conflict. 👍🏻

Edit: I realized just now that the verification logic here is kind of broken due to the rebase. I'm actively working on fixing that!

@codysoyland
Copy link
Member Author

codysoyland commented Feb 20, 2025

I generated coverage with e2e testing. Here is a link to the report. TL;DR: Most of the "happy paths" are covered, but many error cases are not covered. I'll take another pass to see if there's any low hanging fruit for additional testing, but I don't think the coverage of this PR is much different from our existing coverage. However I would still like to improve it.

@dmitris
Copy link
Contributor

dmitris commented Feb 24, 2025

@codysoyland "stepped on" some of the files you're modifying with #3889 - could you rebase and resolve the conflicts, please?

@codysoyland codysoyland force-pushed the verify-attestation-bundle-spec branch from c4f6cbb to 2c72624 Compare February 25, 2025 19:43
Signed-off-by: Cody Soyland <codysoyland@github.com>
Signed-off-by: Cody Soyland <codysoyland@github.com>
Signed-off-by: Cody Soyland <codysoyland@github.com>
Signed-off-by: Cody Soyland <codysoyland@github.com>
Signed-off-by: Cody Soyland <codysoyland@github.com>
Signed-off-by: Cody Soyland <codysoyland@github.com>
Signed-off-by: Cody Soyland <codysoyland@github.com>
Signed-off-by: Cody Soyland <codysoyland@github.com>
Signed-off-by: Cody Soyland <codysoyland@github.com>
@codysoyland codysoyland force-pushed the verify-attestation-bundle-spec branch from 2c72624 to adfe2e3 Compare February 25, 2025 19:53
…e-format

Signed-off-by: Cody Soyland <codysoyland@github.com>
Signed-off-by: Cody Soyland <codysoyland@github.com>
@codysoyland
Copy link
Member Author

Going to read up on OCI 1.1 and take another pass later, though we should ask the authors of the original OCI 1.1 code as well to review those bits.

This is a great idea! The parts that I think need attention from a reviewer with more OCI experience would be the logic in:

  • pkg/oci/remote (WriteAttestationNewBundleFormat and Bundle)
  • pkg/cosign (getBundles)

Perhaps @hectorj2f or @vaikas might be able to take a look?

Signed-off-by: Cody Soyland <codysoyland@github.com>
Signed-off-by: Cody Soyland <codysoyland@github.com>
@codysoyland
Copy link
Member Author

I found github.com/google/go-containerregistry/pkg/registry which was very easy to use to add some unit tests to the OCI interactions on top of what is already covered by e2e tests. I just pushed a test that verifies the response when there are no attestations. I'll try to add a few more test cases to improve coverage.

Signed-off-by: Cody Soyland <codysoyland@github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants