Auth proxy with Authentik and Traefik
Many web applications these days support some form of centralized user management (LDAP, OAuth2/OIDC, SAML …). For those that don’t a special type of reverse proxy can be installed “in front of” the application to handle user authentication. This authentication proxy makes sure all HTTP requests coming from outside are authenticated and only authenticated requests are forwarded to the application. It completely removes the need for the application to integrate with native authorization and authentication protocols - which can be a daunting task and challenging to do correctly! Instead the application just needs to look at HTTP headers to determine the properties of the authenticated user: name, groups, roles etc.
|
|
A popular open-source project that implements this concept is OAuth2 Proxy. Fortunately, Authentik already comes with an “embedded” authentication proxy, therefore it is not necessary to set up a separate instance of the reverse proxy - handy!
In this post I want to document how to set up such an authentication proxy with Authentik Identity Provider and Traefik Proxy, since I’m sure I’ll be using this more often in the future, thus it might be useful for you, too. The setup is also described in the Authentik documentation (referred to as forward authentication), although very terse and without much context.
For reference, at the time of writing I’m using Authentik 2023.10
and Traefik v2.9
(both installed via their official Helm charts).
# Demo application
For testing purposes we’ll use the whoami server: it returns all received HTTP headers as the body of the response plus some additional metadata, like this:
|
|
Create Kubernetes Deployment
, Service
and Ingress
resources in a new namespace:
|
|
Assuming that the cluster has functional external DNS and an ingress controller, the application should now be available at test-auth-proxy.example.com
:
|
|
We can see that the HTTP request was routed through Traefik before reaching the whoami application, since Traefik injects various X-Forwarded-*
headers.
# Configure Authentik
At this point we need to log in as an administrator to Authentik and switch to the Admin interface.
Go to the Applications > Providers
tab and Create
a new Provider as follows:
- Type:
Proxy Provider
- Name:
test-auth-proxy
- Authentication flow:
default-authentication-flow
- Authorization flow:
default-provider-authorization-implicit-consent
- Mode:
Forward auth (single application)
- External Host:
https://test-auth-proxy.example.com/*
Next create a new Application as follows:
- Name:
Test Auth Proxy
- Slug:
test-auth-proxy
- Provider:
test-auth-proxy
- this is the most important setting, make sure to use the provider created in the previous step
Finally, we must not forget to enable the Application on the Outpost: edit the authentik Embedded Outpost
(Type: Proxy) and shift-click on the Test Auth Proxy
Application created in the previous step.
# Create Authentik Middleware
At this point we’re good to go from the Authentik point of view, so we can proceed with the Traefik configuration. Traefik Middlewares allow inspecting and manipulating requests before they are send to the application (the backend in Traefik’s terminology). These middlewares can be configured from a variety of providers. Since I’m deploying Traefik in a Kubernetes cluster, I’m opting for the Custom Resource Definition (CRD) approach (Traefik calls this “dynamic configuration”):
|
|
The middleware is named authentik-auth-proxy
.
It must be deployed in the same namespace as the Ingress
(which will reference the Middleware
in the next step).
It is critical that the spec:forwardAuth:address
setting has the correct address of the embedded-outpost-service
Service: http://<SERVICE_NAME>.<NAMESPACE_NAME>.svc.cluster.local:9000
is the most common variant - double check it by looking up the service name, namespace and port number of your Authentik deployment.
If you use Network Policies in your Kubernetes cluster, these must allow connections from the Traefik pods to the Authentik (server) pods.
For all available configuration options of the ForwardAuth
Middleware, refer to the upstream documentation or kubectl explain middleware.spec.forwardAuth
.
# Reconfigure Ingress for Middleware
By adding the Middleware declared in the previous step into the original Ingress created in the first step, we instruct Traefik that all requests coming to this endpoint must be authenticated. If a request is missing the necessary authentication, then Traefik will redirect it to the authentication provider.
|
|
The value of the annotation is in the format <NAMESPACE_NAME>-<MIDDLEWARE_NAME>@<PROVIDER>
.
Test it:
|
|
# Troubleshooting
As you can guess by the fact that I’m writing all of this down, I didn’t get it working on the first try.
The first issue was that my authentik-worker
had to lost connection to the authentik-server
and it was marked as “unhealthy” in the admin interface (apparently this can happen when Redis restarts).
This caused the error message no app for hostname
to appear when visiting https://test-auth-proxy.example.com
- meaning Authentik didn’t fully process the newly created Application (see also authentik issue #3745).
I restarted all Authentik pods, then the worker was “healthy” again and I could authenticate.
Next I had an a redirection loop between the Traefik Middleware and Authentik: a request to https://test-auth-proxy.example.com
was redirected to https://auth.example.com/...
, after the login I was redirected back to https://test-auth-proxy.example.com
and the whole process would repeat again.
I managed to fix / workaround this by enabling the Compatibility mode in the default-authentication-flow
(can be found under Behavior settings
).
At the time of writing, this actually seems to be a bug in Authentik: see authentik issue #7374.
For more troubleshooting steps, see also the dedicated Authentik documentation page.
Happy proxying!