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

Authentication delegation to a trusted front-end #84

Open
nbarrientos opened this issue Apr 16, 2021 · 12 comments
Open

Authentication delegation to a trusted front-end #84

nbarrientos opened this issue Apr 16, 2021 · 12 comments

Comments

@nbarrientos
Copy link

Requirements

In our environment we have existing front-ends that provide Kerberos and OIDC authentication to users. These front-ends are already available and serving diverse back-ends running different services. What they do is to set some HTTP headers to be consumed by back-ends that can only talk to these front-ends. These headers contain information about the identity of the caller and are blindly trusted by the isolated backends.

Typically the front-ends are implemented with Apache using for instance mod_auth_openidc and mod_auth_gssapi although the technologies vary.

Hence, we'd like to contribute a patch to allow configuring aaasvc in a way that it delegates authentication to a trusted front-end by consuming for instance the REMOTE_USER HTTP header. This could be addressed by an userlist-like authenticator with a few changes where:

  • No passwords will be stored whatsoever.
  • Users known to aaasvc will be served the way they're served by the userlist authenticator.
  • Optionally, tokens with a default profile containing default policies will be served for unknown users (not in the local DB).

In short, if aaasvc was configured this way, it would sign tokens for any user as presented by the front-end if there's a default profile, otherwise only for users explicitly declared in the local database.

This new feature could perhaps cover issue#33, as the caller could have the desired Kerberos support almost for free by configuring an Apache daemon in front.

Implementation ideas

Some ideas for implementation that of course are open for discussion:

Extend userlist.go

It's obvious that there are things in common between the already existing authenticator userlist and the one needed to implement the proposed change. As an initial idea, userlist could be patched in a way that, if a given config setting is enabled, it would ignore any user/password pair fed via /login and simply look at REMOTE_USER and continue. Other changes would be required to implement the optional no-user-found fallback explained above.

Write a new authenticator

Another obvious approach would be to write an authenticator from scratch, strongly inspired by userlist.go. It's not clear to me how it would fit with the existing URL handlers so perhaps it makes sense to evaluate separately using the existing API entrypoint or declare a new one for this.

  1. Reuse (abuse) /login

    I haven't looked into detail but I imagine that, as things stand today, the way Swagger implements the API it'll make the request to fail if the user and the password are not fed. If we wanted to reuse this API entry point, that would have to be relaxed and the value of certain headers should be embedded into LoginRequest to be consumed by the authenticator, I guess.

  2. Create a new API entrypoint (for instance /delegated_login)

    This would allow us to avoid overloading LoginRequest and have a separate model for this type of "lightweight" authentication request. However, I don't know if the code base is currently flexible enough to assign different authenticators to different API entrypoints. I haven't looked that deep, to be honest.

Write a generic userlist authenticator and extend it

Put the common functionality of both authenticators (user list lookups, claims generation, token building, etc) in a higher class and then subclass two implementations, namely userlistpasswd and userlistdelegated (just examples). API-wise, make /login work with any of these. I'm not familiar with Go so I don't know if this is possible.

Conclusions

As you can probably feel from my proposals, I'm not very familiar with the code base. That's precisely why I wanted to have a discussion first to see what would be in your opinion the most cost-effective way of action or even if this proposal makes any sense at all.

@ripienaar
Copy link
Member

Thanks for reaching out, we've had similar requests before but opted to not over complicate matters. Happy to reconsider.

As a side note - which might make this much easier for you - you can just write your own authenticator in any language. There's no need to extend/patch/aaasvc. The system supports seperating authentication with signing cross entirely different systems, we provide userlist as a convenient starting point.

But by the very nature of this thing we'll never support all the, frankly, insanity that big companies have around authentication. So I designed it so that rather than forcing everyone to contribute their special brand of crazy into this package - perhaps forcing them to use Go that they dont know - you can just write your own and turn it off in here.

Either way, happy to explore what it might take but though I'd just point it out that if you didnt want the headache of contributing code in Go on a weird code base that's avoidable - and as designed.

Let me know if you wish to explore that and we can go deeper there, else we can talk about changes here - we can perhaps have a zoom session to help.

@nbarrientos
Copy link
Author

Thanks for replying! We thought about writing our own authenticator and leave it in a corner, and even the idea of writing yet another authority in other language crossed our minds. However, we thought that this could be an abstract enough use-case that many people out there could profit from, so thinking about contributing it back as part of this project sounded like a good idea. It's also our policy to at least try to contribute code back for the projects we profit from.

I understand that there are zillions of authentication systems to be plugged to, however supporting this generic delegation actually contributes to not having to implement any in particular here, delegating authentication workflows to industry-embraced stuff like mod_auth_openidc and mod_auth_gssapi and simply trusting them.

We wouldn't mind contributing to this code base, as long as somebody with wider knowledge of the project was happy to review our patches and offer guidance. Let us know :)

@ripienaar
Copy link
Member

All right, well I am happy to help of course. I believe this overlaps a bit with what @snakeb1t had in mind, lets see if he also wants to chime in.

Are you on slack by any chance?

@nbarrientos
Copy link
Author

All right, well I am happy to help of course. I believe this overlaps a bit with what @snakeb1t had in mind, lets see if he also wants to chime in.

Sure, happy to wait for more people to join the discussion; we're not in a rush.

Are you on slack by any chance?

Nop, sorry. I could eventually do IRC if needed :)

You might have seen nbarrientos#1, which kind of implements the second option enumerated above. It has lots of refactoring potential as there's too much duplicated code but it will help us progressing with our evaluation of the framework in the meantime. This patch is just for internal consumption of ours and will be kept in an isolate repository until a decision is made here. We're happy to put it in the bin if other approach is agreed.

@ripienaar
Copy link
Member

I had a quick look through that PR, I really like the very minimal changes to the swagger API so for sure think we're on a good course here.

Traying once more to get @snakeb1t attention else I will revisit this in details next week

thanks a lot for this work!

@ripienaar
Copy link
Member

For the client side part - the mco login or whatever - what was your thoughts there?

I intend to port the mco login to choria login and once there, it will first look in the path for choria-login executable, if that exist it will call that instead. This way if you provide custom logic yours will be called by just installing that binary.

@nbarrientos
Copy link
Author

thanks a lot for this work!

No worries, thanks for taking a look!

I intend to port the mco login to choria login and once there, it will first look in the path for choria-login executable, if that exist it will call that instead. This way if you provide custom logic yours will be called by just installing that binary.

That'd be okay for us, by having support for calling something "external" for login we could just "alias" choria login to something like:

curl -u : --negotiate --request POST -H "Content-type: application/json" https://somewhere/choria/v1/login | jq -r .token > ~/choria.token

That'd bring Kerberos support in on the client for free and would be enough for us, I'd say.

Personally I think that it's not worth spending time on having native support on the client for zillions of authentication mechanisms. It's basically the same principle we're proposing here to follow for the server (delegating auth to a front-end with an already existing and robust implementation) but for the client.

@traylenator comments?

@ripienaar
Copy link
Member

Yes agree, I dont want to support all sorts of things in the client, enterprises need to do their thing only so much I am willing to support.

OK, so will check in next week and see if we can maybe extend userlist a bit and avoid adding a new authenticator

@traylenator
Copy link
Contributor

it will first look in the path for choria-login

This seems a very flexible option. Not sure I like the shell alias as we will have to write csh which is never good and it's fragile to people doing weird stuff.

On a client related note ~/choria.token is probably not the best location. Either we use the environment variable method which gets us back into the different shell game potentially or we make the client configuration accept

plugin.choria.security.request_signer.token_file = ${XDG_RUNTIME_DIR}/choria.token

It currently does not AFAIK.

@ripienaar
Copy link
Member

Hmm, yeah we dont expand env vars in the config, but we can expand ~, it could also be a symlink I guess.

@ripienaar
Copy link
Member

The nightly being built tonight will have choria login and it has the behavior of looking for choria-login in your path and running that.

Go doesnt really support exec well so its a bit meh - I just run a subshell rather than replace my executable to set the environment.

Anyway, check it out and let me know

@ripienaar
Copy link
Member

I am doing some work on this project and might be able to get stuff in for you as well.

First a general question, now login happens via HTTP (or whatever, latest choria will call choria-login if its in the path when you invoke choria login as discussed). And then signing also happen over HTTP to the signer service.

I want to retire the HTTP version of the signer service and have that just go via the NATS network with no other ports involved. Essentially it will be like a normal choria rpc call to get the signed token.

Will this be compatible with your plans?

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

No branches or pull requests

3 participants