authentik icon indicating copy to clipboard operation
authentik copied to clipboard

Client Certificate authentication

Open scheibling opened this issue 2 years ago • 8 comments

I've been looking into client certificate authentication a bit lately on behalf of work, and I was wondering if this is something you've had a look into at any point. From my end, it looks like it shouldn't need any major implementation in authentik but rather just a stage like the webauthn/totp-stages, with some slight modifications to the go proxy.

I think there would be a couple of benefits to this long-term:

  • Certificate authentication would enable certain users and organizations to use their countries eID and company-specific electronic IDs for authentication within authentik.
  • Would also enable certain types of smart card authentication (depending on the users existing infrastructure)
  • Can also be utilised for API authentication with heightened security

The major part of this as it stands would be an implementation into the go proxy, since that's the part currently handling certificate authentication. I don't have a lot of experience with go as of right now, but if this is something that would appeal to a broader audience I'd be happy to look into a couple of PRs on the subject.

I've managed to run some tests by integrating it into gunicorn separately, but since that server doesn't handle the TLS parts of authentik I don't think that's the way forward.

A basic implementation of this would be:

  1. Go proxy asks for client certificate when accessing certain flows (by URI? or does the proxy have any awareness of states in the application?)
  2. The proxy sets a header (e.g. X-Client-Cert-CN, X-Client-Cert-Issuer, X-Client-Cert-CA-Cert) to the authentik flow
  3. Authentik verifies the certificate against a certificate currently in storage
  4. Uses the certificate CN (configurable mapping) to map the authentication to a user, either as single-factor or multi-factor after sign-on with another stage.

scheibling avatar May 13 '22 11:05 scheibling

duplicate of #2294 but yes that is roughly how I'd implement it too, however there are a couple issues with doing it that way:

  • In go, client certificate options can be configured globally or per Host header, but there is an option to always request client certificates and just continue if the client doesn't have a certificate
  • Go would need access to the CA to verify the certificate (since client's don't have to send a full chain, I would assume a pretty good percentage of them only send the client certificate and not the CA)

Now the last point is technically not an issue since the go proxy can already get the certificates via the API, and it does already do that if you configure a web certificate in a tenant. However, certificates for this would (probably) be configured on a stage level, which would make it a bit harder to correlate.

Allthough I guess the proxy could just fetch and check against all CAs configured in the backend, and set the headers if any of them are valid, and then the checking for the correct CA is done in the stage

The other reason I haven't looked into this too much is that this wouldn't work (easily) with reverse proxies, there'd need to be another setting to trust headers from a range of upstream proxies

BeryJu avatar May 13 '22 11:05 BeryJu

Wouldn't a global setting for trusted proxies, like the native one in Django, be a good idea security-wise anyway? It could probably be used for this as well as securing an instance against certain kinds of attacks where authentik isn't specifically configured to only accept certain hosts, which might be the case with certain configurations.

Although a potential issue with the global/per-host certificate requests is that the user would then either be queried for the certificate at first page load, or on every page load, with pin entry and all depending on the security software involved. I can imagine some scenarios in which the former could be problematic, and the latter isn't really an option.

I'm gonna have a look over how some other applications implement it and see if there are any other alternative strategies.

Edit: A "simpler" (more basic, not easier) implementation would probably be a stage for authentication via HTTP headers, that way a user could inject the headers via their own reverse proxy and handle the authentication themselves. This would still require a trusted proxy functionality though.

e.g. something like this for HAProxy

listen frontend-name
    bind *:443 transparent ssl crt server-cert.pem ca-file cert-ca.crt verify optional crl-file cert.crl
    ...
    acl restricted_path path_beg,url_dec -m beg -i /api/v3/flows/executor/http-header-auth

    http-request set-header X-SSL-Issuer           %{+Q}[ssl_c_i_dn] if restricted_path and { ssl_c_verify } 
    http-request set-header X-SSL-Client-NotBefore %{+Q}[ssl_c_notbefore] if  restricted_path and { ssl_c_verify }
    http-request set-header X-SSL-Client-NotAfter  %{+Q}[ssl_c_notafter] if  restricted_path and { ssl_c_verify }

    # Adding this if the request should be denied entirely if no client certificate is present
    # http-request deny if restricted_path !{ ssl_c_used 1 } || restricted_path !{ ssl_c_verify 0 }

scheibling avatar May 13 '22 12:05 scheibling

Would love to see this added. I have been enjoying exploring Authentik, and I think its structure and layout are much more intuitive than traditional IDP/Auth/SSO solutions.

Unfortunately, I need the ability to issue end-user x.509 certificates and use PKI for direct authentication, and currently to do that I’d have to set up some wonky stage to verify the cert as a second factor and use the CN to set the username.

I have been dragging my feet before standing up KeyCloak for this purpose, because I’d rather just keep using Authentik. Can’t blame anybody for not spending a lot of time and effort on very low-volume requests

cwilson613 avatar Nov 12 '23 23:11 cwilson613

is there any solution to have a client logged in foreve rcurrently? (client is on Wndows Server 2022 and uses chrome browser). sadly configuring a session timeout in authentik to 9999 days doesn't work.

ne0YT avatar Nov 22 '23 16:11 ne0YT

Is my understanding correct that the header suggestion that @scheibling made is currently not possible? I’ve configured my proxy to indeed send the email, and fingerprint of the cert to Authenik via headers. But im failing to figure out how to configure Authentik to read these headers, find and set the pending user, and execute a login.

It seems that only the build in identification stage can be used? Setting pending user in an expression policy for example does not work 🤔

OGKevin avatar Dec 27 '23 13:12 OGKevin

Lots of users needing Smartcard/PIV/PKI Auth, which works in KC. I don’t have any skills in development, but I’ve implemented it a ton of times. If anyone goes through with it, don’t forget:

  1. you need a way to trust third party CAs by uploading root/intermediate certs.
  2. you have to support CRL OR OSCP. OCSP in keycloak is not ideal, right now. If the root OCSP is slow or times out, it fails the Auth flow. It would be way cool for someone to figure out how to do OCSP caching. Google was working on it, but nothing I’ve seen in a project yet. CRL is big enterprises are huge, btw.
  3. the certs dont all have the same attributes. So you’ll need to fish certain fields out of SAN or CN, but it’s not always 100% certain which in each org.

allebone avatar Jan 06 '24 20:01 allebone

Has there been much activity on this? I've been looking at this but PKI authentication is pretty much a requirement, especially compared to Keycloak that does have a PKI authentication option.

I feel like all the issues mentioned here are non-issues in my environment, some of them not even central to what authentication service needs to do itself to be fair.

My environment has all the ca's available for validation. In fact we primarily use PKI authentication.

OSCP, I'm not sure about but there is a central API used for certificate status checks.

Another party does the issuing certificates, the authentication server only need to validate so then we can issue a bearer token for our services.

wjbrf avatar Feb 10 '24 21:02 wjbrf