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

Client credentials grant allowing command line and server-to-server access to VP protected resources #362

Open
bselu-cso opened this issue Feb 15, 2021 · 17 comments

Comments

@bselu-cso
Copy link

I figured that VouchProxy currently supports the regular "authorization code grant" only.

I'm looking for a possibility to get the "client credentials grant" working, like described here https://tools.ietf.org/html/rfc6749#section-4.4. I am thinking about extending VP so that it supports this kind of authorization flow.

Does this make sense anyway? Where in the code would it be a good idea to integrate this?

@bnfinet
Copy link
Member

bnfinet commented Feb 15, 2021

@bselu-cso I think I know where you're headed but for posterity could you clarify and expand your use case a bit? What problem are you trying to solve? Is this about api access using bearer tokens? Would this bypass Nginx?

VP is currently very focused on humans interacting with browsers but if this for could be accommodated with reasonable expansion and you'd be willing to support the work for at least a year I'd consider it.

@bselu-cso
Copy link
Author

My use-case is indeed not the typical human-browser interaction. Instead, I have a client app which needs to talk to some service. Nginx would not be bypassed. The service itself is not secured in any way, security would be provided by nginx / VP by verifying the client-id and client-secret against an oauth-server. As the client app doesn't have any means of interaction with a user, the client credentials would be either built-in or provided by a secure storage facility.

For clarity, please have a look at the client credentials flow I found in the Okta docs: https://developer.okta.com/docs/concepts/oauth-openid/#client-credentials-flow

As for the support I'd need to clarify this with my contractee but it might be possible. To proceed I'd need to know, whether I'm headed in the right direction and it makes sense at all to extend Vouch for this feature, or I'm totally mistaken and should rather fork, or even start something new from scratch.

@aaronpk
Copy link
Collaborator

aaronpk commented Feb 15, 2021

I have wanted to do something similar as well, I have nginx+Vouch sitting in front of a MediaWiki install, and I want to write a script that uses the MediaWiki API, but it needs to get through Vouch first. Because it's a script, it would be a lot easier to use something like the client credentials grant to get through Vouch instead of trying to emulate an OAuth flow in a browser.

@bnfinet
Copy link
Member

bnfinet commented Feb 16, 2021

@bgehman that sounds reasonable

As a first step towards integration and design could you outline how you'd like to trigger/request and manage this flow with the existing endpoints /validate, /login, /auth, /logout and any new endpoints that might be required. Just a quick outline would suffice.

@aaronpk
Copy link
Collaborator

aaronpk commented Feb 17, 2021

hmm this doesn't really map to the client credentials grant in OAuth, this is more of its own thing. I would not recommend sending the client secret in a GET request, that goes against the spec and all best practices. I'll try to come up with an alternative flow that I think would map better to existing specs.

@bselu-cso
Copy link
Author

@aaronpk IMHO this pretty much corresponds to the OAuth spec in https://tools.ietf.org/html/rfc6749#section-4.4. Where do you think does it deviate?

@aaronpk
Copy link
Collaborator

aaronpk commented Feb 17, 2021

Places where your diagram deviates from OAuth:

  • You have a GET instead of POST for sending the client credentials, that is not allowed in OAuth and is also not a good idea
  • The GET request to the auth endpoint contains a url parameter describing the resource it's asking for. This is fine, but is not part of OAuth at all
  • The response to the request using the credentials is a redirect with a Cookie header, rather than in OAuth it would be a JSON response containing an access token
  • The authorized request for the resource uses a cookie instead of an HTTP Authorization header you'd see in OAuth

This isn't to say all of these points are bad, but I would not call this OAuth, and I would definitely also fix the GET request so that credentials aren't sent in the query string.

@bselu-cso
Copy link
Author

Thanks a lot for your post. I see your points. I think I looked at it from a different perspective. For me, the client app including nginx and vouch would be what is depicted as "Client" in RFC6749:

 +---------+                                  +---------------+
 |         |                                  |               |
 |         |>--(A)- Client Authentication --->| Authorization |
 | Client  |                                  |     Server    |
 |         |<--(B)---- Access Token ---------<|               |
 |         |                                  |               |
 +---------+                                  +---------------+

                 Figure 6: Client Credentials Flow

I guess you relate ngnix / vouch rather as part of the authorization server. In this case not much of what is part of my sequence diagram is covered by OAuth, that's for sure. :-)

My intention was to make things as transparent as possible. For the service this is not a problem at all, as it's hidden behind ngnix / vouch. However, the client must be tought some way of authentication. That's how the credentials ended up in the GET request. But of course you're right, credentials shouldn't be in a GET. Maybe I should separate the authentication completely by a seperate POST. This would only make a small difference for the client implementation.

I'd love to see your idea of an OAuth-compliant flow.

@bnfinet
Copy link
Member

bnfinet commented Feb 24, 2021

@aaronpk wrt to...

I'll try to come up with an alternative flow that I think would map better to existing specs.

Would love to hear your thoughts if you're in a position to flesh out some design thinking. VP is definitely an odd hybrid of OAuth client and server. Should rename it "Janus" :)

@aaronpk
Copy link
Collaborator

aaronpk commented Mar 1, 2021

The way I was thinking about it is Vouch is actually already its own authorization server by the fact that it is issuing its own JWTs and validating them. The current method of issuing them is to redirect the browser to some other authorization server to figure out who the user is, and then it sets the JWT cookie down to the browser. This is a pretty typical flow where one AS delegates user authentication to another AS, we see it all the time between various OIDC servers, a prominent example being how you can configure your Google Workspace domain to redirect users to your own OIDC server to authenticate them. In that situation, Google is still its own AS issuing its own tokens for its own services, but the user accounts live in your own OIDC server. With that background, here is what I would suggest for Vouch:

  • Create a new endpoint in Vouch, let's call it the "token endpoint"
  • This endpoint accepts client credentials (client_id and client_secret) which could either be registered ahead of time in Vouch somewhere, or be passed on to the configured OAuth provider
  • The endpoint returns a JSON response with an access token. This access token is actually the same format as the JWT cookie that it currently uses, but the claims would be different (we'd need to decide what to include in the $upstream_http_x_vouch_user variable, or just use the client_id value itself)
  • The validate method would be updated to look for both the HTTP cookie as well as the access token in the Authorization header

Here's a sequence diagram

image

This maps exactly to the OAuth client credentials grant, and also makes it very straightforward to work with from scripts and code rather than messing around with redirects or setting Cookie headers from code.

@bnfinet
Copy link
Member

bnfinet commented Mar 2, 2021

@aaronpk fantastic stuff! Thanks for fleshing that out and for the diagram.

wrt..

This endpoint accepts client credentials (client_id and client_secret) which could either be registered ahead of time in Vouch somewhere, or be passed on to the configured OAuth provider

IMHO it'd be preferable for Vouch Proxy to delegate that authority to the upstream OAuth provider if possible. The more VP can glean from the IdP the better.

@bselu-cso how does that strike you? That would seem to provide what you're looking for, yeah?

@bselu-cso
Copy link
Author

Thanks for the nice diagram, @aaronpk. That would be working for my use-case, I guess.

One note: From my point of view it would make more sense to have the client send its POST authentication not to vouch directly but rather over ngnix forwarding it to vouch. Reasons:

  1. Minimize the number of entities talking to vouch (simpler firewall rules).
  2. Increase security by not exposing vouch endpoints to the outer world.
  3. In theory, instead of TCP/IP vouch could also be bound to nginx over UDS, given that nginx + vouch are running on the same machine. With direct communication from clients you'd always need to support TCP/IP as well.

What do you guys think of that?

@bnfinet
Copy link
Member

bnfinet commented Mar 17, 2021

@bselu-cso thanks for those...

VP doesn't really care where a request originates. It tries to be as dumb a service as possible.

For VP development there's always a few common setups that I consider to be the ones which must be accommodated in order to not break existing setups in the field...

Everything behind nginx....

  • nginx
    • secureapp.yourdomain.com/validate
      • auth_request --> VP running at 127.0.0.1:9090/validate
    • vouch.yourdomain.com
      • proxy all requests to VP running at 127.0.0.1:9090

Vouch lives "somewhere else"

  • nginx
    • secureapp.yourdomain.com/validate
      • auth_request --> VP running at vouch.yourdomain.com/validate
  • vouch.yourdomain.com
    • all direct requests honored

The second case allows for round robin scalability. It's very likely that the VP instance is running behind an Nginx instance, but you don't know. That setup accommodates Kubernetes as well.

Essentially, I assume that all endpoints can be accessed directly or proxied.

If we tied VP tightly to Nginx we'd get into akward testing setups and an additional layer of abstraction for only marginal improvement. And it would likely break existing setups which we always try to avoid.

Running on a socket is an interesting use case and I see how it could be more secure though I'm unsure of the gains. If you cared to work on that I'd prefer we separate that out into another issue and PR to carry the concept.
It would require some accommodations on the VP end...
https://stackoverflow.com/questions/23747791/how-to-make-unix-socket-listener

@sp-manuel-jurado
Copy link

Hi @bnfinet @bselu-cso @aaronpk

I would really be interested in this feature.
For issues of securing server-to-server API calls using okta (openid) client_credentials and vouch-proxy.

Currently, I understand that vouch proxy is only intended for use with a browser with openid grant type Authorization Code (associated with a named user).

But it was to ask if you plan to develop it. And if so, with your guide, offer to collaborate.

Thank you in advance.

@bnfinet
Copy link
Member

bnfinet commented Sep 12, 2021

@sp-manuel-jurado thanks for chiming in here. Yes it seems like this would be a good addition to VP.

Am I hearing that you would have some interest in working on this? That would be most excellent.

@bnfinet bnfinet changed the title Client credentials grant Client credentials grant allowing command line and server-to-server access to VP protected resources Oct 8, 2021
@cbjartli
Copy link

@bnfinet This is a use case for us too. I would like to chime in and say I'd be interested in contributing to this feature and its support.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants