keppel icon indicating copy to clipboard operation
keppel copied to clipboard

JWT authentication and authorization

Open bittermandel opened this issue 1 year ago • 2 comments

We've finally gotten to the point of experimenting with Keppel.

I started today with implementing Ory Hydra support, but quickly reverted and went on to supporting JWTs better. We plan to have our JWT token as part of the docker login password, with an empty username (or a single letter). This way we can make it a bit more custom and not rely on Dockers built in OAuth support, which isn't flexible enough for us.

When it comes to supporting authentication directly with JWTs, internal/auth/token.parseToken() basically does what we are trying to do, but perhaps with a few Keppel specific features.

Would it be a good idea to move the JWT support into it's own driver and make it more configurable? It would be great for example if we could select which fields in Claims should be included for scopes.

Happy to discuss any solution that might work!

bittermandel avatar Feb 16 '24 22:02 bittermandel

We plan to have our JWT token as part of the docker login password, with an empty username (or a single letter). This way we can make it a bit more custom and not rely on Dockers built in OAuth support, which isn't flexible enough for us.

As already discussed earlier, we wanted to implement OIDC ourselves at some point, too but didn't start with it yet and happily accept PRs for it. Since I don't think docker login can display URLs or any other information while logging in, I think repurposing the password field is our best approach currently.

I think having an empty username or just throwing it away is fine. If it turns out to be not as compatible as we thought or we need a username/email later, we can always make this configurable or rethink it later.

The section about applicationcredential in the keystone doc is pretty similar to this. I am not sure if the JWT token has something comparable to the application credential ID.

Would it be a good idea to move the JWT support into it's own driver and make it more configurable?

We definitely want a new driver for this authentication method. I didn't look into how we can refactor/reuse existing code for that, I would need to refer to @majewsky for that but in general from my perspective nothing speaks against refactoring that method/subpackage a bit to make it more reusable and avoid code duplication.

I don't think we can remove the JWT tokens issued by keppel itself but I only have a basic understanding of that part. @majewsky can answer that for sure.

We usually try to design things to have as little configuration option as possible but as many as needed. Any fields that are related to the JWT/OIDC provider used ofcourse must be configurable but anything that only has one possible value right now can be hardcoded for the time.

You can take the keystone driver as a baseline https://github.com/sapcc/keppel/blob/master/internal/drivers/openstack/keystone.go and the trivial driver to know which functions must be implemented. I think we should place the new driver here https://github.com/sapcc/keppel/blob/master/internal/drivers/oidc/auth.go but moving that later should be easy.

The OIDC driver should become another driver option for KEPPEL_DRIVER_AUTH like keystone.

It would be great for example if we could select which fields in Claims should be included for scopes.

I am not an expert in this area but at first sight this sounds reasonable to me. Maybe we can make this as simple as matching the prefix of the claim (eg: keppel: or registry:).

SuperSandro2000 avatar Feb 19 '24 13:02 SuperSandro2000

JWT needs to stay in Keppel core because the part where Keppel itself issues tokens is irrespective of which auth driver is used. If you want to reuse parts of internal/auth/, feel free to refactor some new public methods out of the existing stuff as needed and include that in the PR adding the auth driver.

It would be great for example if we could select which fields in Claims should be included for scopes.

Can you please elaborate on what the requirement here is? The intended way to transfer authorizations is to implement UserIdentity.HasPermission() in order to have Keppel interrogate the provided authorization scope and generate Keppel-specific scopes from that. If you have a usecase that is not covered by this structure, I would like to know more details.

majewsky avatar Feb 26 '24 09:02 majewsky