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

implement pre-forwarding auth on select RPCs #15513

Merged
merged 2 commits into from
Jan 24, 2023
Merged

Conversation

tgross
Copy link
Member

@tgross tgross commented Dec 9, 2022

In #15417 we added a new Authenticate method to the server that returns an AuthenticatedIdentity struct. This changeset implements this method for a small number of RPC endpoints that together represent all the various ways in which RPCs are sent, so that we can validate that we're happy with this approach.

A follow-up PR will do all the dirty work of adding this everywhere else.

Comment on lines 447 to 448
identity, authErr := n.srv.Authenticate(n.ctx, args.AuthToken)
args.SetIdentity(identity)
Copy link
Member

Choose a reason for hiding this comment

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

Instead of having to remember to call args.SetIdentity after every call to Authenticate, what if made Server.Authenticate (or a new wrapper around Authenticate) take an interface that could both retrieve the auth token and set the identity?

This is just a really non-idiomatic pattern to expect devs to get right in every RPC: both understanding when to call SetIdentity (always?) as well as knowing where exactly to check authErr (after forwarding?).

Copy link
Member

Choose a reason for hiding this comment

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

An alternative might be to actually update our ancient Server.forward method (or make a new method to migrate RPCs piecemeal) to just encapsulate all of this. This would reduce the per-RPC boilerplate as well as only have to write the slightly unusual "check error after a subsequent operation" authErr handling.

Copy link
Member Author

Choose a reason for hiding this comment

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

We could definitely call SetIdentity inside Authenticate, as we always want it. Should be easy enough to do.

But although I love the idea of wrapping it into Server.forward in principle, there's a bunch of leader-only RPCs like Eval.Dequeue that don't forward because we always send them to the leader. This is why I was exploring that RPC middleware notion previously (but the type signatures are terrible 😁 )

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, I've moved the SetIdentity into Authenticate, which also cleans up Authenticate's signature so that if we eventually get it to produce ACLs for claims we don't have to change it again everywhere

Copy link
Member Author

Choose a reason for hiding this comment

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

I've also updated the semgrep rule so that if we're using Authenticate we expect to return the error at some point. That should minimize the risk of misuse.

nomad/status_endpoint.go Outdated Show resolved Hide resolved
nomad/acl.go Outdated Show resolved Hide resolved
@tgross
Copy link
Member Author

tgross commented Jan 9, 2023

I've extracted a subset of this PR out into #15734 to pick up some work @schmichael and I discussed in a sidebar (and so that we're keeping the history a little easier to read)

tgross added a commit that referenced this pull request Jan 9, 2023
When reviewing #15513 we decided that forcing the request handler to call
`SetIdentity` was repetitive and error prone. Instead, the `Authenticate` method
mutates the request by setting its `AuthenticatedIdentity`.
tgross added a commit that referenced this pull request Jan 10, 2023
This changeset covers a sidebar discussion that @schmichael and I had around the
design for pre-forwarding auth. This includes some changes extracted out of
#15513 to make it easier to review both and leave a clean history.

* Remove fast path for NodeID. Previously-connected clients will have a NodeID
  set on the context, and because this is a large portion of the RPCs sent we
  fast-pathed it at the top of the `Authenticate` method. But the context is
  shared for all yamux streams over the same yamux session (and TCP
  connection). This lets an authenticated HTTP request to a client use the
  NodeID for authentication, which is a privilege escalation. Remove the fast
  path and annotate it so that we don't break it again.

* Add context to decisions around AuthenticatedIdentity. The `Authenticate`
  method taken on its own looks like it wants to return an `acl.ACL` that folds
  over all the various identity types (creating an ephemeral ACL on the fly if
  neccessary). But keeping these fields idependent allows RPC handlers to
  differentiate between internal and external origins so we most likely want to
  avoid this. Leave some docstrings as a warning as to why this is built the way
  it is.

* Mutate the request rather than returning. When reviewing #15513 we decided
  that forcing the request handler to call `SetIdentity` was repetitive and
  error prone. Instead, the `Authenticate` method mutates the request by setting
  its `AuthenticatedIdentity`.
In #15417 we added a new `Authenticate` method to the server that returns an
`AuthenticatedIdentity` struct. This changeset implements this method for a
small number of RPC endpoints that together represent all the various ways in
which RPCs are sent, so that we can validate that we're happy with this
approach.
@tgross
Copy link
Member Author

tgross commented Jan 10, 2023

Rebased and should be ready for final review.

@tgross tgross requested a review from shoenig January 20, 2023 14:00
Copy link
Contributor

@shoenig shoenig left a comment

Choose a reason for hiding this comment

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

LGTM - it does seem like some middleware could help here but I didn't get much of an improvement over what you already have

client/rpc.go Outdated Show resolved Hide resolved
@tgross tgross merged commit b79d00a into main Jan 24, 2023
@tgross tgross deleted the pre-forwarding-auth-poc branch January 24, 2023 15:52
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.

3 participants