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 JWT bearer authorization #1149

Closed
wants to merge 5 commits into from
Closed

Conversation

kthomas
Copy link

@kthomas kthomas commented Oct 3, 2019

This effort adds the ability for a third-party to sign JWT tokens containing well-formed permissions within the payload and run NATS server configured with the public key for signature verification.

The initial version of this PR represents the result of a quick and dirty spike to get something that could be tested against a fast-moving project in the blockchain space. It makes sense to consider this functionality because it allows applications to leverage the existing NATS permissions model without the need for an account server. This is an alternative strategy to nkey auth.

When "bearer authorization mode" is configured, a connection to NATS will fail to be authorized under the following conditions:

  • when no bearer token is provided by the client
  • when a bearer token is provided but fails signature verification based on the configured JWT_SIGNER_PUBLIC_KEY
  • when the bearer token is verified but no permissions claim exists in the JWT

The authorization model under this strategy is delegated to NATS by the application, and JWT tokens which an application vends need to be issued with a short ttl; applications and NATS clients need to consider the refresh cycle. I am considering how to best support an interface for defining a configurable callback within NATS clients which will ask the application to vend a new token (i.e. "refresh" the soon-to-expire token) at the appropriate time and gracefully recycle the socket to establish a new NATS connection using the newly-authorized token, just prior to the previously-valid token exp timestamp.

There are some obvious things that need to be resolved in the course of diligence here that I am working on:

  • removing the hack of adding a third-party JWT package directly instead of updating the NATS JWT package
  • supporting JetStream
  • providing broad client support for gracefully refreshing bearer tokens just before they expire as described above

If you want to run the branch to try it out, you can check it out, go build and then run the following:

➜  nats-server git:(jwt-bearer-auth) JWT_SIGNER_PUBLIC_KEY='
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqU/GXp8MqmugQyRk5FUF
BvlJt1/h7L3Crzlzejz/OxriZdq/lBNQW9S1kzGc7qjXprZ1Kg3zP6irr6wmvP0W
YBGltWs2cWUAmxh0PSxuKdT/OyL9w+rjKLh4yo3ex6DX3Ij0iP01Ej2POe5WrPDS
8j6LT0s4HZ1FprL5h7RUQWV3cO4pF+1kl6HlBpNzEQzocW9ig4DNdSeUENARHWoC
ixE1gFYo9RXm7acqgqCk3ihdJRIbO4e/m1aZq2mvAFK+yHTIWBL0p5PF0Fe8zcWd
NeEATYB+eRdNJ3jjS8447YrcbQcBQmhFjk8hbCnc3Rv3HvAapk8xDFhImdVF1ffD
FwIDAQAB
-----END PUBLIC KEY-----' ./nats-server -DV

/cc @nats-io/core

@derekcollison
Copy link
Member

Will take a look today, thanks for the patience.

@kthomas
Copy link
Author

kthomas commented Oct 7, 2019

No rush. I still need to add some tests etc.

@kozlovic
Copy link
Member

kozlovic commented Oct 7, 2019

@kthomas I had a look, but this is early stage WIP, so no much to comment on. I would pass the server or logger to the BearerAuthFactory() function so that you can then use the logger instead of fmt.Println() calls.

@kthomas
Copy link
Author

kthomas commented Oct 7, 2019

Thanks @kozlovic -- I had begun poking around looking for how to best use the package logger. Makes sense to pass it along.

I will be pushing another commit or two shortly to clean things up, including tests, and we can discuss.

@wuhenfeike
Copy link

I see that the current sub and push limit are set when the client login, can it be changed to set the sub and push permission at any time?

@wuhenfeike
Copy link

@kthomas Or when subscribing or pushing to the server, the server can query the user's push and subscription rights from mysql or other databases to restrict the push and subscription rights。

@kthomas
Copy link
Author

kthomas commented Oct 9, 2019

@wuhenfeike if I understand your question correctly, it sounds like it could be supplied within your bearer token similarly to how permissions is being presented. You could issue a new token to update it I presume.

That is out of scope for the PR as of this moment but I will take a look to see how it could be supported as I groom this further. It seems you could present those limits as part of the signed token payload as well.

I didn't follow the question related to re-centralizing on a SQL database, you lost me there.

@wuhenfeike
Copy link

Thanks @kthomas For example, in iot scenario application, two clients can know the restricted objects of push and subscription after determining the binding relationship, so whether can provide the function of dynamically setting push and subscription limits.

@kozlovic
Copy link
Member

@kthomas Just a note: although we have go.mod, as of now, we build/test from vendor directory. So you would have to go mod vendor and add the jwt into vendor in the commit if you want Travis to run the tests...

@kthomas
Copy link
Author

kthomas commented Oct 14, 2019

Have some tests to commit as well @kozlovic -- ty for this.

@kthomas kthomas force-pushed the jwt-bearer-auth branch 11 times, most recently from aab67f6 to eae9471 Compare October 16, 2019 20:17
@kthomas kthomas changed the title [WIP] Add JWT bearer authorization Add JWT bearer authorization Oct 16, 2019
@kthomas
Copy link
Author

kthomas commented Oct 16, 2019

@derekcollison @kozlovic this is probably ready for another pass when you have a chance.

@hastarin
Copy link

Excuse my ignorance but is this something that could tie in with an external service like auth0.com to better fit NATS server into a OIDC/OAuth 2.0 flow?

@kthomas
Copy link
Author

kthomas commented Oct 21, 2019

@hastarin this is meant to be very primitive for portability's sake.

The intent of this PR is indeed to allow third-party services to generate and sign JWT credentials (in essence delegating the NATS authorization to some service without having to run extra NATS account server infrastructure). So if the third-party service supports generating JWT tokens with arbitrary claims and signing them using the RS256 algo, then such a service would indeed be supported.

Hope this answers your question.

@kthomas
Copy link
Author

kthomas commented Aug 28, 2020

Looking forward to when this feature will become officially released. In the meantime I had a short-term need to support authentication based on Kerberos and AWS IAM credentials. So I put together this stopgap solution based on the existing NKeys support, in case anyone is interested.
^^ that is pretty interesting workaround @ebekker... thanks for sharing 👍

@kozlovic can we explore what it would take to merge this PR? The fork has +10K pulls on dockerhub...
image

I would be happy to help get it over the finish line if there is any feedback, although I think you will find there is sufficient rigor in the tests.

This PR has been open for nearly a whole year... 🎉 🎂

@kozlovic
Copy link
Member

Not sure why this is still opened because I believe we said that we are not going this direction in the past. I will let @derekcollison have the final word.

@kthomas
Copy link
Author

kthomas commented Aug 29, 2020

Not sure why this is still opened because I believe we said that we are not going this direction in the past. I will let @derekcollison have the final word.

Agree, but since it's about to celebrate it's first birthday maybe we take that as a sign and discuss if it has a place at this time...

I am good either way but it would help a whole lot if we could agree to merge it ;)

Thanks, as always 🙏

@kthomas kthomas force-pushed the jwt-bearer-auth branch 6 times, most recently from 8807f92 to 5c0b7cb Compare September 28, 2020 07:26
@kthomas kthomas force-pushed the jwt-bearer-auth branch from 4e35470 to 57ab4de Compare May 5, 2021 08:39
@kthomas
Copy link
Author

kthomas commented May 5, 2021

image

Can't compete with 50M+ pulls on the official repo :)

We should compare notes related to this PR once and for good, @kozlovic.

cc: @derekcollison

@kthomas kthomas force-pushed the jwt-bearer-auth branch 4 times, most recently from b3b01b8 to b56d72a Compare May 5, 2021 10:40
@kozlovic
Copy link
Member

kozlovic commented May 5, 2021

@kthomas Again, I think that this is a discussion that you have to have with @derekcollison. I let him know and he will touch base with you and maybe pull some other resources into a meeting.

@kthomas kthomas force-pushed the jwt-bearer-auth branch from b56d72a to 0410536 Compare May 12, 2021 07:42
@kthomas kthomas force-pushed the jwt-bearer-auth branch from 4cb0bb7 to d6f6736 Compare May 12, 2021 09:07
@snehesht
Copy link

Any thoughts on the timeline for this PR ?

@derekcollison
Copy link
Member

As our focus shifts to the marketplaces etc this will come back around. That should be in next few weeks.

@amitlin
Copy link

amitlin commented Nov 8, 2021

Any updates on this feature?

@derekcollison derekcollison added the stale This issue has had no activity in a while label Jan 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stale This issue has had no activity in a while
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants