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

Authorization Callouts #3719

Merged
merged 2 commits into from Jan 3, 2023
Merged

Authorization Callouts #3719

merged 2 commits into from Jan 3, 2023

Conversation

derekcollison
Copy link
Member

An implementation for a server-signed authorization request mechanism. The mechanism will be used in both server configuration and operator mode servers. This allows external NATS applications to securely authorize users with external AuthN.

Signed-off-by: Derek Collison derek@nats.io

/cc @nats-io/core

Copy link
Member

@philpennock philpennock left a comment

Choose a reason for hiding this comment

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

Reviewed everything except server/auth_callout_test.go

server/accounts.go Outdated Show resolved Hide resolved
// Check for server configured auth callouts.
if opts.AuthCallout != nil {
// Make sure we have a valid account and auth_users.
_, err := s.lookupAccount(opts.AuthCallout.Account)
Copy link
Member

Choose a reason for hiding this comment

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

Is it guaranteed that lookupAccount will be fully populated, in all account resolver modes, so that this must succeed during initial parse of the config file?

Copy link
Member Author

Choose a reason for hiding this comment

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

lookupAccount can reach out. Like SYSTEM account, if you are running in operator mode, this account should also be part of the preloads. But if it isn't we will try to fetch it. If that fails we will error.

server/auth.go Outdated Show resolved Hide resolved
server/auth.go Show resolved Hide resolved
@@ -557,6 +578,54 @@ func (s *Server) processClientOrLeafAuthentication(c *client, opts *Options) boo
err error
ao bool // auth override
)

// Check if we have auth callouts enabled at the server level or in the bound account.
defer func() {
Copy link
Member

Choose a reason for hiding this comment

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

This is a lot of security-critical work to be happening inside a deferred function. I'm worried about this being triggered after a panic. Is this something which could be put into a new intermediary function instead?

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 needs to be a defer to be able to reference the result of authorized which is a return variable.

server/auth_callout.go Outdated Show resolved Hide resolved
server/auth_callout.go Outdated Show resolved Hide resolved
server/auth_callout.go Outdated Show resolved Hide resolved
return
}

// Do it this way to fail to compile if fields are added to jwt.ClientInformation.
Copy link
Member

Choose a reason for hiding this comment

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

I don't see what would cause a compilation failure here: the other fields would just be left on their default values.

Copy link
Member Author

Choose a reason for hiding this comment

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

The assignment part. Left side, not right side.

server/auth_callout.go Show resolved Hide resolved
@ripienaar
Copy link
Contributor

ripienaar commented Dec 16, 2022

I have a few comments / wishes to add here:

  • Can we extend the client connect event to include information that this was a user authorized by a callout. Maybe include the issuer pub key.
  • Can we have events about callout fails which might include reasons from the auth callout side.
  • Server should log that this is setup in static config mode, just a warning at start saying a callout is in use.
  • In this pr the nil reply is all thats accepted, I think we should consider also accepting a json document with optional error details that could be logged or included in an event (first point) to asist with debugging. JSON because we might want to extend later.
  • Please include server tags in server_id so I can for example say some user is only allowed to connect in the eu
  • More logging

@derekcollison
Copy link
Member Author

I have a few comments / wishes to add here:

  • Can we extend the client connect event to include information that this was a user authorized by a callout. Maybe include the issuer pub key.

This is visible in the account of the user and not the service, so might be considered leaking info.

  • Can we have events about callout fails which might include reasons from the auth callout side.

Phil asked about this as well. I think starting with server logs is right approach, and we can add in events. Not opposed.

  • Server should log that this is setup in static config mode, just a warning at start saying a callout is in use.

Can you give me an example of what would be helpful?

  • In this pr the nil reply is all thats accepted, I think we should consider also accepting a json document with optional error details that could be logged or included in an event (first point) to assist with debugging. JSON because we might want to extend later.

Possibly, we would need to go back into the jwt lib and add a response claim that would include the user claim such that we could trust the error response etc. So non-trivial.

  • Please include server tags in server_id so I can for example say some user is only allowed to connect in the eu

Good idea. I can add that, will also require update to jwt lib.

  • More logging

Examples?

@ripienaar
Copy link
Contributor

ripienaar commented Dec 16, 2022

I have a few comments / wishes to add here:

  • Can we extend the client connect event to include information that this was a user authorized by a callout. Maybe include the issuer pub key.

This is visible in the account of the user and not the service, so might be considered leaking info.

I mean the ones that get sent to $SYS.ACCOUNT.*.CONNECT those are system only. For failures, assuming we extend the reply with error, that would go in $SYS.SERVER.*.CLIENT.AUTH.ERR

  • Can we have events about callout fails which might include reasons from the auth callout side.

Phil asked about this as well. I think starting with server logs is right approach, and we can add in events. Not opposed.

fair

  • Server should log that this is setup in static config mode, just a warning at start saying a callout is in use.

Can you give me an example of what would be helpful?

If a server config significantly change the authentication parameters of behavior that's definitely something you want to communicate and warn about. It stands out so there's no inadvertant mistakes or no surprises.

  • In this pr the nil reply is all thats accepted, I think we should consider also accepting a json document with optional error details that could be logged or included in an event (first point) to assist with debugging. JSON because we might want to extend later.

Possibly, we would need to go back into the jwt lib and add a response claim that would include the user claim such that we could trust the error response etc. So non-trivial.

  • Please include server tags in server_id so I can for example say some user is only allowed to connect in the eu

Good idea. I can add that, will also require update to jwt lib.

cool

  • More logging

Examples?

At debug it would for sure be good to know you're calling out and when you got a response/or not/or timeout etc. It can be hard to debug this as its a bit of effect at a distance so debug info would help developers working on auth plugins.

@derekcollison
Copy link
Member Author

derekcollison commented Dec 17, 2022

Should also add in cluster to server portion if we are adding tags.

@ripienaar for the AuthorizationResponse, should it be code + description similar to how we evolved in JetStream?

@ripienaar
Copy link
Contributor

Don’t think it needs code - since this is not for internal use it’s user supplied code so would be hard to standardise on coded errors.

Yeah cluster would be good for sure

@derekcollison
Copy link
Member Author

So just error as a string an empty user_claim sounds good to you?

@ripienaar
Copy link
Contributor

So just error as a string an empty user_claim sounds good to you?

I thought maybe {"error":"X"} as a claim for now, we can also add additional fields later that way, where if we just do error string now it becomes a future pain to support both methods

server/auth.go Show resolved Hide resolved
server/auth_callout.go Show resolved Hide resolved
server/opts.go Show resolved Hide resolved
@derekcollison
Copy link
Member Author

I force pushed update that has the AuthorizationResponse now.

Still working on the correct approach to auth error events offline with the team.

@derekcollison derekcollison force-pushed the auth_callout branch 2 times, most recently from ec025ad to 3b08d96 Compare December 28, 2022 18:03
This adds the ability to augment or override the NATS auth system.

A server will send a signed request to $SYS.REQ.USER.AUTH on the specified account. The request will contain client information, all client options sent to the server, and optionally TLS information and client certificates.
The external auth service will respond with an empty message if not authorized, or a signed User JWT that the user will bind to.

The response can change the account the client will be bound to.

Signed-off-by: Derek Collison <derek@nats.io>
…on from the callout service.

Signed-off-by: Derek Collison <derek@nats.io>
Copy link
Contributor

@ripienaar ripienaar left a comment

Choose a reason for hiding this comment

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

LGTM, didnt have time to end to end test the new event but looks good

Copy link
Member

@aricart aricart left a comment

Choose a reason for hiding this comment

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

LGTM

@derekcollison derekcollison dismissed philpennock’s stale review January 3, 2023 23:33

Believe these were handled.

@derekcollison derekcollison merged commit 3c88947 into dev Jan 3, 2023
@derekcollison derekcollison deleted the auth_callout branch January 3, 2023 23:34
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.

None yet

6 participants