Skip to content

Conversation

milosgajdos
Copy link
Member

@milosgajdos milosgajdos commented Oct 8, 2023

This PR replaces all the docker/libtrust JWT machinery with go-jose/go-jose module. Some of the code has been adopted from the libtrust and adjusted for some of the use cases covered by the token authorization code, especially in the unit tests.

NOTE: docker/libtrust module has been archived for several years now.

Closes #1820

@thaJeztah
Copy link
Member

So from the discussion on slack; did we actually still need it at all? /cc @dmcgowan

@thaJeztah
Copy link
Member

Oh! Should've looked; it somehow found it's way into auth as well, not just for signing v1 images

@milosgajdos
Copy link
Member Author

milosgajdos commented Oct 8, 2023

It is indeed. This PR is in a draft because its a ghetto code that needs cleaning up.

Basically you can sign your token with different types of keys etc and we need to make sure they're legit and that the token hasn't been tampered with.

@milosgajdos milosgajdos marked this pull request as ready for review October 9, 2023 19:39
@milosgajdos
Copy link
Member Author

Ok, I've cleaned up my last night's horrible code and I think we can proceed to getting this reviewed and iterated on.

PTAL @thaJeztah @dmcgowan @corhere @Jamstah

Copy link
Collaborator

@Jamstah Jamstah left a comment

Choose a reason for hiding this comment

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

I still think we need to separate the test code more cleanly.

I'd like to remove the libtrust kid format if we can. I know we're no longer depending on the package, but consumers would either need to depend on the libtrust package to make the kid, or also have their own code. It doesn't seem to be a standards thing.

@Jamstah
Copy link
Collaborator

Jamstah commented Oct 10, 2023

FYI, the export regulation disclaimer worried me too, so I raised this: go-jose/go-jose#61

@milosgajdos
Copy link
Member Author

I'd like to remove the libtrust kid format if we can. I know we're no longer depending on the package, but consumers would either need to depend on the libtrust package to make the kid, or also have their own code. It doesn't seem to be a standards thing.

What are your thoughts @dmcgowan? I kinda agree but we need some replacement for that if we do rip that out.

@milosgajdos
Copy link
Member Author

I kinda wonder if we could replace the KeyID with a fingerprint similar to the SSH one: https://pkg.go.dev/golang.org/x/crypto/ssh#FingerprintSHA256

@Jamstah
Copy link
Collaborator

Jamstah commented Oct 10, 2023

I'd like to remove the libtrust kid format if we can. I know we're no longer depending on the package, but consumers would either need to depend on the libtrust package to make the kid, or also have their own code. It doesn't seem to be a standards thing.

What are your thoughts @dmcgowan? I kinda agree but we need some replacement for that if we do rip that out.

Do we need a replacement?

The kid is really for picking a key from a JWKS that is provided by an issuer. I don't think that inventing one from the key material itself is valuable unless someone is coding an issuer implementation specifically for us that also matches (like what libtrust did and expected).

I guess one option would be to ask the user to specify the kid for each public cert. Another option would be to accept a JWKS url and pick up the kid/cert pairs from that. A final slightly less secure option would be to ignore the kid and test all the roots.

@milosgajdos
Copy link
Member Author

Do we need a replacement?

Well accesscontroller maintains a map of trusted publick keys

trustedKeys map[string]libtrust.PublicKey

Those are optionally supplied by config

fp, err := os.Open(config.rootCertBundle)

@Jamstah
Copy link
Collaborator

Jamstah commented Oct 10, 2023

The key of the map is what we're talking about though, its the libtrust format. Its only valuable if the token issuer uses the same mapping for the keys in its JWKS. Considering that no one should be using libtrust any more, that's a big ask.

We really need the user to specify kid/root pairs so they can match them to their issuer. Even better would be to accept a JWKS and use that instead.

@milosgajdos
Copy link
Member Author

The key of the map is what we're talking about though

Yes very much so - too many overloaded terms!

@Jamstah
Copy link
Collaborator

Jamstah commented Oct 10, 2023

I think this might be the right option:

  • If the user specifies roots, then we only verify tokens that are x5c.
  • If the user specifies a file that contains a JWKS, then we give it to go-jose and let it do the work.

So, auth.rootCertBundle and auth.jwks in the configuration.

@milosgajdos
Copy link
Member Author

I think this might be the right option:

* If the user specifies roots, then we only verify tokens that are x5c.

* If the user specifies a file that contains a JWKS, then we give it to go-jose and let it do the work.

So, auth.rootCertBundle and auth.jwks in the configuration.

Correct me if I'm wrong but there should be an option to specify both, right 🤔 It should be your choice what tokens your registry trusts. I may be overthinking this though...

@Jamstah
Copy link
Collaborator

Jamstah commented Oct 11, 2023

Yes, I don't see why not. If there are both roots and a JWKS configured, use whichever is appropriate for the token.

Or, if there is an x5c in the token, we could verify that with any roots found in the JWKS (which is like our behaviour now). Then we would only have the JWKS option in the config.

If there is a kid in the token, we use it to pick something from the JWKS.

@milosgajdos
Copy link
Member Author

Alright, so I got a first step in the direction we agreed on - unless I misunderstood 🙃

PTAL @Jamstah Mind you, it's a bit of a ghetto code that will need cleaning up, but would like your take on this 😬

Also, if @corhere has some spare cycles, that'd be dope (I'm still expecting him to open that context cleanup PR he keeps promising me 😏)

(yes we will still need to update docs with the jwks option, but I postponed it until we've agreed on the code 😄 )

@corhere
Copy link
Collaborator

corhere commented Oct 17, 2023

(I'm still expecting him to open that context cleanup PR he keeps promising me 😏)

Hey now, I only promised to review the context cleanup PR you were going to open @milosgajdos

@milosgajdos
Copy link
Member Author

Hey now, I only promised to review the context cleanup PR you were going to open @milosgajdos

Saw right through my innocuous gaslighting 🙃

@Jamstah
Copy link
Collaborator

Jamstah commented Oct 17, 2023

Should we be looking at something like this?

https://pkg.go.dev/github.com/s12v/go-jwks

@milosgajdos
Copy link
Member Author

Should we be looking at something like this?

https://pkg.go.dev/github.com/s12v/go-jwks

You mean for rotation? Yeah, seems reasonable. Let's rip libtrust out first though 😄

Copy link
Collaborator

@Jamstah Jamstah left a comment

Choose a reason for hiding this comment

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

We can rip out a load of the libtrust crypto from the test files too.

We don't have to, but it reduces the complexity.

Jamstah@f485172

@milosgajdos
Copy link
Member Author

We can rip out a load of the libtrust crypto from the test files too.

We don't have to, but it reduces the complexity.

Jamstah@f485172

I was going to look into ripping that crypto_test.go file out in the followup. There is more cleanup to be done beyond that, I feel 😅 Nice! I'll [shamelessly] adopt these changes 😄

@milosgajdos milosgajdos requested a review from Jamstah October 18, 2023 07:22
@thaJeztah
Copy link
Member

I'll try to find some time to review, but with a big disclaimer that this area is not really my expertise. I did ping @jcarter3 and @technicallyjosh on our Slack, as they are more familiar with this, and they were definitely in favor of removing libtrust (but don't know to what extent they reviewed the change in-depth).

@milosgajdos
Copy link
Member Author

milosgajdos commented Oct 18, 2023

@thaJeztah we need @dmcgowan here primarily. He was the OG creator so he likely understands the ins and outs of this code.

@dmcgowan
Copy link
Collaborator

dmcgowan commented Oct 18, 2023

Agreed that removing the KID definition here makes sense to match the spec, since it is "unspecified". It should be up to the token service and jwk creator to ensure it matches using whatever format or criteria they determine to be the most secure.

The key sets from an endpoint seem interesting as well as a future change and align nicely with the distribution architecture of horizontally scaled registry instances using a token service which owns the token private key and could potentially serve that public key on an endpoint. This would make key rotation much simpler. Going along with that, supporting multiple signing keys could aid in that rotation.

@milosgajdos
Copy link
Member Author

@Jamstah anything we're missing here that's preventing you from ✅ ? Other than the [inevitable] squash 😄

@thaJeztah
Copy link
Member

Squash (or cleanup of some of the commits at least) would be nice 😅

@milosgajdos
Copy link
Member Author

Squash (or cleanup of some of the commits at least) would be nice 😅

Yes, just wanna make sure we're done updating before I squash and merge. Otherwise all the discussion in this terrible GH Review UI will be lost in the darkness of our memories

@Jamstah
Copy link
Collaborator

Jamstah commented Oct 19, 2023

Sorry, had forgotten I had a request changes open!

Lgtm.

docker/libtrust repository has been archived for several years now.
This commit replaces all the libtrust JWT machinery with go-jose/go-jose module.
Some of the code has been adopted from libtrust and adjusted for some of
the use cases covered by the token authorization flow especially in the
tests.

Signed-off-by: Milos Gajdos <milosthegajdos@gmail.com>
@milosgajdos milosgajdos merged commit dfd191e into distribution:main Oct 19, 2023
@milosgajdos milosgajdos deleted the libtrust-wipeout branch October 19, 2023 14:52
@azr azr mentioned this pull request Dec 19, 2023
@markuskirch markuskirch mentioned this pull request May 8, 2024
zhangyoufu added a commit to zhangyoufu/distribution that referenced this pull request Jul 22, 2024
for the sake of backward compatibility

Fix distribution#4096
Fix distribution#4299

Signed-off-by: Youfu Zhang <zhangyoufu@gmail.com>
bmwiedemann pushed a commit to bmwiedemann/openSUSE that referenced this pull request Jul 1, 2025
https://build.opensuse.org/request/show/1289281
by user dirkmueller + anag_factory
- update to 3.0.0 (jsc#PED-11728):
  * This is the first v3 stable release since `v2.8.3` which is a
    culmination of years of hard work of the container community
    and registry maintainers!
  * If you are upgrading from `v2.x` and have never used any of
    the release candidates, please familiarise yourselves with
    the `v2.x` deprecations properly.
  * oss and swift storage drivers are no longer supported
  * `docker/libtrust` has been replaced with `go-jose/go-jose` in
    distribution/distribution#4096
  * `client` is no longer supported as a standalone package in
    distribution/distribution#4126
  * the default configuration path has changed to
    `/etc/distribution/config.yml`
  * `ManifestBuilder` interface in 3886
  * `manif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

libtrust code migration
7 participants