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

forward_auth support in kanidm #2774

Open
CEbbinghaus opened this issue May 16, 2024 · 12 comments
Open

forward_auth support in kanidm #2774

CEbbinghaus opened this issue May 16, 2024 · 12 comments
Assignees
Labels
enhancement New feature or request

Comments

@CEbbinghaus
Copy link

Is your feature request related to a problem? Please describe.

Kanidm looks to be a great replacement of OpenLDAP as it supports LDAP enough to allow most applications to query users. It's goal is to replace Authelia & co though as not just an IDM but Authentication/Authorization provider. This doesn't seem possible to me at the moment as I predominately use Authelia for forward_auth which kanidm does not seem to have.

Describe the solution you'd like

The ideal solution would be for kanidm to fully support http forward auth, This means keeping track of user sessions through cookies and verifying the user session before responding with a successful status code. A minimal example of a rust based forward auth implementation can be found here.

Describe alternatives you've considered

Continuing to use Authelia but connect to kanidm via LDAP. This seems VERY silly as kanidm aims to replace authelia.

Additional context

Caddy & Traefik both support forward auth which make integration fairly easy. Additionally forward auth is often times required as many self hosted services do not provide OAuth/OIDC functionality.

@yaleman
Copy link
Member

yaleman commented May 16, 2024

Can anyone point at a spec/RFC that actually outlines what the auth server is doing for these things, because I'd really rather have something to target instead of some vague implementation details across a bunch of backends.

I've tried to work it out in the past and it all looks vaguely terrifying from an "actually doing something secure" perspective, compared to something like oauth-proxy and friends.

@yaleman yaleman self-assigned this May 16, 2024
@yaleman yaleman added the enhancement New feature or request label May 16, 2024
@pando85
Copy link
Contributor

pando85 commented May 17, 2024

Hello @CEbbinghaus ,

I have this working with Kanidm through Nginx and oauth2-proxy. It is pretty straightforward.

I don't know if I understood well but asking to use Kanidm as a proxy doesn't make any sense to me because it is an IDM and the functionality is completely different. I would prefer to have tools with clear responsibilities and not mesh with them.

@yaleman
Copy link
Member

yaleman commented May 17, 2024

I don't know if I understood well but asking to use Kanidm as a proxy doesn't make any sense to me because it is an IDM and the functionality is completely different. I would prefer to have tools with clear responsibilities and not mesh with them.

It doesn't require Kanidm to act as a proxy, but to respond to auth requests from the proxy.

@pando85
Copy link
Contributor

pando85 commented May 17, 2024

It doesn't require Kanidm to act as a proxy, but to respond to auth requests from the proxy.

Ok, so that's something in the middle. I was checking the Traefik docs and that was the confusion for me.

Anyway something like oauth2-proxy will help @CEbbinghaus .

@CEbbinghaus
Copy link
Author

@pando85 oauth2-proxy looks like either another element in the chain or a replacement to Caddy neither of which are desirable to me. Additionally oauth2-proxy does not support forward auth which is a problem since it doesn't solve my problem at all. forward_auth will forward a http request to a specified endpoint of another http service which in turn verifies whether or not this user should be allowed to access the server. The way this is traditionally done is by storing a cookie which holds the session and just verifying that the cookie is valid. If the authentication succeeds it will respond with some additional parameters in the http response which usually include Remote-User, Remote-Email & similar. Those are then used by the service being protected to identify the user and load their data.

The danger with forward auth lies entirely outside of the authentication as anyone that can bypass the reverse proxy can just attach the Remote-User & Remote-Email headers themselves and the service would be none the wiser. This is why both Caddy & Traefik clean all incoming requests of any Remote-XXX headers.

@yaleman
Copy link
Member

yaleman commented May 18, 2024

The way this is traditionally done is by storing a cookie which holds the session and just verifying that the cookie ...

where does this cookie come from? cross-domain cookies aren't really a thing in modern browsers, and you'd have to somehow trick the calling application to pull it from the IDP in the first place?

OAuth2-Proxy doesn't need forward auth because it acts as an OAuth2 client, a well defined and standardised protocol.

@CEbbinghaus
Copy link
Author

CEbbinghaus commented May 18, 2024

its not a cross-domain cookie to the best of my knowledge. its a cookie on the root domain (e.g example.com) rather than on the specific subdomain being accessed (e.g service.example.com). Which also allow a single cookie to authenticate any of the services on any of the subdomains that use forward auth.

oauth2-proxy does not need forward auth to know whether or not a user should be allowed to access a certain services. but it does not (to my knowledge) communicate to the services being proxied who the user is that is accessing it (which is aht the Remote-User & co headers are for). forward_auth is as much authentication as identification and involves more than just the proxy & auth server.

I haven't been able to find an official spec even after having asked around in the Authelia community. It seems to be very much designed by consensous with Traefik & Authelia being the leading 2. It all was inspired by nginx's http auth request module which has the little quirk of considering any non 200 status as a fail condition. Whereas both Traefik & Authelia treat it as the response to send back to the user.

The rough flow goes as following:

Successful Auth
User -> Proxy <-> Auth (200)
          \-> Service (`Remote-User`: Bob, `Remote-Email`: bob@bobmail.com)

Unsuccessful Auth
User <-> Proxy <-> Auth (302)
// the server can return any non 200 code. but returning a redirect to auth.example.com allows the auth server to set the example.com cookie.
// Assuming the user was able to successfully log in and the cookie set it would then redirect back to the original service.

I'll put together a proper flow diagram at some point and I want to write up something about how forward_auth could be specified. But its far too convenient a process for kanidm to ignore as so many different services support it.

@yaleman
Copy link
Member

yaleman commented May 18, 2024

Without any kind of spec to work with that'd a huge blocker for design/implementation, because that's just a deep rabbit hole of troubleshooting and mess... but hey, if someone can write up a design that looks workable and supportable, then it might get into the (very, very long) queue of planned work.

But then we get to the fact that Kanidm doesn't use/support cookie authentication, let alone setting a root-domain cookie, so that's another change to the entire architecture which would be required.

Looks like oauth2-proxy does support forward-auth, for what it's worth.

@Firstyear
Copy link
Member

its a cookie on the root domain (e.g example.com) rather than on the specific subdomain being accessed (e.g service.example.com). Which also allow a single cookie to authenticate any of the services on any of the subdomains that use forward auth.

That's a pretty scary prospect. Part of what makes Oauth2/OIDC good is that you have tokens bound to a specific client so disclosure of one token doesn't impact other services. We call this 'blast radius' to work out how damaging a leak of a credential might be.

Having a single cookie to authenticate any subdomain makes for a terrifyingly huge blast radius if that was ever disclosed.

It would be great if you could write up something around how this works so we could actually perform a security assessment first - while forward auth may be convenient we still need to do our due diligence before we promise to add it.

@CEbbinghaus
Copy link
Author

I added a blog post to website going over some of the basics it's not in depth enough to be considered close to a spec. Hoping to get something more concise in writing soon but I hope it clears up some stuff

https://beta.cebbinghaus.com/Blog/forward_auth/

(it's worth noting that the way the authentication server validates the request is not specified and probably won't be part of the spec. Cookie auth is the simplest and most common but anything could be used instead)

@Firstyear
Copy link
Member

With this "forwarded" request, won't that mean Kanidm has to catch-all routes and then answer them for the request? Won't it also mean that there are application data being sent to Kanidm? Or can it be scoped under a route or something?

@CEbbinghaus
Copy link
Author

CEbbinghaus commented May 21, 2024

The forwarded request is forwarded to a specific route. so the request would be sent to /api/auth for example. This is the configuration that would be used within Caddy for Authelia:

forward_auth authelia:9091 {
   uri /api/verify?rd=https://auth.example.com/
   copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
}

the /api/verify route is the one that actually verifies and if it fails (e.g user is not logged in) it will then redirect to the auth.example.com url to log the user in. That redirect can then include the original request uri in a query parameter which the auth server redirects back to once the login succeeds so you are instantly redirected back to the page you came from.

The reverse proxy provides these headers for the auth service to know what the original request was aimed at:

HTTP Method X-Forwarded-Method
Protocol X-Forwarded-Proto
Host X-Forwarded-Host
Request URI X-Forwarded-Uri
Source IP-Address X-Forwarded-For

Edit (because I forgot to respond):

Won't it also mean that there are application data being sent to Kanidm?

correct, there will likely be application data included in the request (headers, cookies, etc...) however it should and is ignored. The only parameters that matter are those that the auth expects (e.g cookie, X-Forwarded headers, etc..).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: 📋 Backlog
Development

No branches or pull requests

4 participants