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

Upgrade to TUF v2 client #3844

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft

Conversation

cmurphy
Copy link
Contributor

@cmurphy cmurphy commented Aug 20, 2024

Swap the use of the go-tuf v0.7.0 client from sigstore/sigstore to the
v2.0.0 client from sigstore/sigstore-go.

This change strictly adds logic to attempt to use the sigstore-go TUF
client if possible, and falls back to the old TUF client. The new client
can only fetch targets by name, not by custom metadata. This means that,
on its own, the new client cannot support renaming/rotating keys, so the
old client must be used to support that case. A future change will add
support for fetching or reading a trusted_root.json file, which has
better support for rotating keys. Once this later change is introduced, using
the old client can be deprecated.

The logic in this change works as follows:

  • if a path fo a key is provided by a SIGSTORE_ environment variable,
    read that file and use it (same as previously)
  • if new environment variables TUF_MIRROR and TUF_ROOT_JSON are set, use
    those to instantiate a TUF client that fetches keys from the given
    mirror
  • else, try reading the mirror URL from remote.json, which set set by
    cosign initialize, and try reading the root.json from the mirror's
    cache directory which may have been created by a previous TUF v2 run
  • if fetching keys using the new client with the given mirror did not
    work, fallback to the v1 client

Also not that the use of the "status" field in the custom TUF metadata
is removed, as it was only used for human-readable feedback.

TODO:

Fixes #3548

Summary

Release Note

Documentation

@cmurphy
Copy link
Contributor Author

cmurphy commented Aug 20, 2024

There is still work to do here but I will be out for a couple of weeks so it might be worth getting some eyes on in the meantime.

Copy link

codecov bot commented Aug 20, 2024

Codecov Report

Attention: Patch coverage is 16.56250% with 267 lines in your changes missing coverage. Please review.

Project coverage is 35.91%. Comparing base (2ef6022) to head (84e4712).
Report is 218 commits behind head on main.

Files with missing lines Patch % Lines
pkg/cosign/tsa.go 8.16% 87 Missing and 3 partials ⚠️
pkg/cosign/fulcio.go 0.00% 84 Missing ⚠️
pkg/cosign/tuf.go 32.95% 49 Missing and 10 partials ⚠️
pkg/cosign/tlog.go 31.03% 17 Missing and 3 partials ⚠️
pkg/cosign/ctlog.go 26.66% 9 Missing and 2 partials ⚠️
cmd/cosign/cli/verify/verify.go 0.00% 1 Missing ⚠️
cmd/cosign/cli/verify/verify_attestation.go 0.00% 1 Missing ⚠️
cmd/cosign/cli/verify/verify_blob_attestation.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3844      +/-   ##
==========================================
- Coverage   40.10%   35.91%   -4.19%     
==========================================
  Files         155      205      +50     
  Lines       10044    12977    +2933     
==========================================
+ Hits         4028     4661     +633     
- Misses       5530     7751    +2221     
- Partials      486      565      +79     

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

@cmurphy cmurphy force-pushed the upgrade-tuf branch 2 times, most recently from e59faee to 07e1c38 Compare August 21, 2024 00:12
@cmurphy cmurphy force-pushed the upgrade-tuf branch 4 times, most recently from 00b4edb to 820d6a8 Compare September 12, 2024 23:22
@jku
Copy link
Member

jku commented Sep 13, 2024

There is still work to do here but I will be out for a couple of weeks so it might be worth getting some eyes on in the meantime.

sorry, I missed this at the time: I will have a look today or monday

@jku
Copy link
Member

jku commented Sep 13, 2024

Sigstore-go provides a way to check for a trusted root and automatically use it if available, but can also fetch individual targets as needed if the provided TUF mirror does not supply a trusted_root.json.

Can you specify what cosign does with sigstore-go? I can see there are some invidual target fetches in the code but does cosign now use trusted_root.json by default?

@cmurphy
Copy link
Contributor Author

cmurphy commented Sep 13, 2024

Can you specify what cosign does with sigstore-go?

Cosign uses sigstore-go piecemeal for various things, but the goal of this PR is to adopt sigstore-go's TUF client wrapper instead of the client wrapper provided by sigstore/sigstore.

does cosign now use trusted_root.json by default?

It does not, that's part of the purpose of this PR and #3548. There is another PR in progress #3854 that adds a --trusted-root flag that I will have to adjust this PR to conform with.

sorry, I missed this at the time: I will have a look today or monday

I may now have to wait for that other PR to be fleshed out before I can make active progress on this, so don't feel rushed to review this. I can ping you again when it's in a more stable state.

Comment on lines +29 to +36
const (
// This is the root in the fulcio project.
fulcioTargetStr = `fulcio.crt.pem`
// This is the v1 migrated root.
fulcioV1TargetStr = `fulcio_v1.crt.pem`
// This is the untrusted v1 intermediate CA certificate, used or chain building.
fulcioV1IntermediateTargetStr = `fulcio_intermediate_v1.crt.pem`
)
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if these filenames should be configurable somewhere for private Sigstore TUF operators. The existing metadata format allows for additional targets to be added and discovered, but TUF v2 does not allow iterating over targets, so that strategy is unsupported, meaning this current diff does not necessarily support all private TUF deployments.

We could also provide a CLI utility to convert an old TUF v1 layout to a trusted_root.json and require private TUF maintainers to use it to generate a trusted root in order to support the next version of cosign. I kind of like this option as it fast tracks the adoption of the trusted root.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wonder if these filenames should be configurable somewhere for private Sigstore TUF operators

These filenames are hardcoded in the TUF v1 code so recreating them here was an attempt to align with the old way of retrieving targets.

The existing metadata format allows for additional targets to be added and discovered, but TUF v2 does not allow iterating over targets, so that strategy is unsupported, meaning this current diff does not necessarily support all private TUF deployments.

You're right, that was an oversight on my part. I had an earlier version of this that could support discovering targets from custom metadata that I will restore.

We could also provide a CLI utility to convert an old TUF v1 layout to a trusted_root.json

We could do that as a last resort, but my hope was to maintain full backwards compatibility and ease users gently toward using trusted_root.json.

Comment on lines 82 to 138
func checkValidityPeriod(start, end time.Time) tufStatus {
now := time.Now()
if now.Before(start) {
return inactive
}
if now.After(end) {
return inactive
}
return active
}
Copy link
Member

Choose a reason for hiding this comment

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

The validity period in the TrustedRoot should be compared to the timestamp provided by the timestamping service or transparency log. I understand this is not something that is known at the time that you are assembling the CheckOpts, and that makes this a hard problem, but I'm not sure we want to enforce this in this version of the code. I believe we still want to be able to verify a signature produced prior to a timestamping service's validity end date, even if the current time is after that date.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My goal here was to have something to substitute for the Active/Expired status from TUF v1 that does not seem to have an equivalent in TUF v2. Open to discarding this entirely or finding an alternative.

Copy link
Contributor

Choose a reason for hiding this comment

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

For what it's worth, I don't think Cosign is effectively using Active/Expired now, as Cosign is only printing a message to stdout if you are verifying an entry with an "expired" key. This isn't really helpful to the user because there's nothing wrong with using an expired key, it's if the key is used to verify something outside of its validity window, which isn't currently implemented in Cosign.

If it'd be easier to just not deal with Active/Expired, I'd be supportive of that. We can either rely on sigstore-go down the line to do that check, or we can file an issue to implement that feature in Cosign's verification API when using the trusted root file. I'd lean towards the latter in line with #3879.

Swap the use of the go-tuf v0.7.0 client from sigstore/sigstore to the
v2.0.0 client from sigstore/sigstore-go.

This change strictly adds logic to attempt to use the sigstore-go TUF
client if possible, and falls back to the old TUF client. The new client
can only fetch targets by name, not by custom metadata. This means that,
on its own, the new client cannot support renaming/rotating keys, so the
old client must be used to support that case. A future change will add
support for fetching or reading a trusted_root.json file, which has
better support for rotating keys. Once this later change is introduced, using
the old client can be deprecated.

The logic in this change works as follows:

- if a path fo a key is provided by a SIGSTORE_ environment variable,
  read that file and use it (same as previously)
- if new environment variables TUF_MIRROR and TUF_ROOT_JSON are set, use
  those to instantiate a TUF client that fetches keys from the given
  mirror
- else, try reading the mirror URL from remote.json, which set set by
  `cosign initialize`, and try reading the root.json from the mirror's
  cache directory which may have been created by a previous TUF v2 run
- if fetching keys using the new client with the given mirror did not
  work, fallback to the v1 client

Also not that the use of the "status" field in the custom TUF metadata
is removed, as it was only used for human-readable feedback.

TODO:
- e2e tests

Signed-off-by: Colleen Murphy <[email protected]>
@cmurphy
Copy link
Contributor Author

cmurphy commented Sep 20, 2024

@steiza , @codysoyland , @haydentherapper and I met to discuss a path forward on this and we decided to shrink the scope of this PR by removing the fetch of trusted_root.json, to be addressed separately.

This PR dropped the fetch of trusted_root.json, but it now fails conformance tests because the SCT returned during signing from p-g-i is signed by the ctfe_2022.pub key, which the sigstore-go TUF client has no way to know about. This worked fine with p-g-i when trusted_root.json was considered, but shows that this approach will break any deployment that has rotated keys relying on custom metadata. I'm starting to think that using the new client must also be synchronized with using trusted_root.json and that the whole thing should be guarded by a flag that users can opt into. Thoughts?

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.

Upgrade to latest Sigstore TUF client
4 participants