Skip to main content
Version: 0.0.1

Authentication

389-ds

Using openldap I found overtime that docker images for it were not the most actively maintained, and it took extremely long for find a reliable and up-to- date image. During that time I got curious to know if there were any ldap alternatives that were more maintained, and found 389-ds which is maintained by Red Hat. It's also a component in FreeIPA so I'd imagine it stays maintained for a long time. There was some issues that made it not the easiest to migrate to, one being that it doesn't currently support argon2 password encryption, and the docker image for it requires a bit of a fixup to create the ldap tree and even the memberOf plugin to be used in my other applications. Eventually I finally figured out how to use 389-ds cli tool and suprisingly it was much more simple than openldap. I have now replaced openldap with this and plan to keep using it moving forward.

Authelia

warning

Deprecated (12/16/24)

Single Sign On service that unifies the authentication for all of the applications I have deployed. Getting this configured took a long time but has been one of the best applications I have. Using authelia I can define domain restrictions for certain users, based on groups. With authelia you can define a list of users through yaml files, but it's recommended to use an ldap service that will be used as the backbone for user/group management. It provides an simple login interface and password reset functionality with the configuration of smtp (is necessary).

It was really easy to integrate authelia with traefik forward auth to properly authenticate applications and ensure only certain users can access them. Most of the complication in setting up authelia was translating lldap identification of resources. I did at one point also used it's oauth functionality but it was cumbersome to configure for every app with needing to modify the configuration file and restart the deployment. Up until recently I found authelia perfect for my user management, but I realized it's lacking in functionality compared to authentik and keycloak (mostly lack of integration from other IDP providers like Google).

Authentik

warning

Deprecated (7/27/25)

Before using authelia I started researching and working with authentik which provides all of the same functionality and actually even more. It comes with user management as well as outposts that can be configured to run proxy authentication and active directory (ldap). I could not easily get the ldap outpost to run and it became a deal breaker as jellyfin was dependent on using it. I did eventually figure it out the second time I used it, but configuring flows for different actions felt so daunting. One really cool thing to see was it's ability to synchronize users from an external source so I could continue to use lldap as a backup.

Updated (12/16/24)

Took a second stab at setting up authentik but I think it's working perfectly well for my service setup. It took some time to understand how flows/outposts integrations worked, but after all of that was settled it has been super straightforward. I needed to deploy authentik completely manual. Giving authentik RBAC control to the cluster allows it to automatically deploy outposts, but the LDAP outpost had weird behavior when making changes to it. It would consistently ping the authentik server causing it to be overloaded. It did require a two step deployment where I needed to grab the token from authentik to use in the deployment for the outpost but it was totally fine as a one time setup.

After figuring out how to synchronize over information from lldap I was able to easily migrate all logins without losing any data. In addition I needed to create new flows for invitations and reset password actions. But a really cool new feature I was able to add was using google as a login solution. Because most emails for accounts are using gmail I can automatically map google logins to existing accounts so users could login without needing their password. After recreating the service accounts for nextcloud and jellyfin I was able to use ldap for them. But a really cool new addition was that I was able to also add SSO for Jellyfin.

Updated (7/27/25)

I was hesistant integrating authentik due to many issues around it's stability and the team's unwillingness to address core issues wrong with the software. I've ran into two instances of frustration, the last one being a final straw. The first was issues connecting with the LDAP provider that caused auth issues with services that depended on it. The last was literally an error with sending a reset password email, with an issue open that was not closed for inactivity. Such a basic functionality breaking in a release was unacceptable to me and decided to move one from it.

Migrating applications that supported OIDC logins to use keycloak was pretty easy since keycloak supported all OIDC standards. One thing that I needed to do for all created clients, was adding a group membership mapper to their configurations. This allowed applications to read the groups a user belonged to.

Keycloak

Towards the end of 2024 I decided to mess around with Keycloak after discovering a bug with authentik that broke the websocket connection between it's outposts and the server, leaving me needing to restart the server every time I added a new application or provider. It took quite some time to get this going, but only after I found the necessary environment variables to configure it behind a reverse proxy. Once that was completed most of remaining work was integrating it with openldap to provide a two way sync of user data, as using lldap was not possible due to it being written as a read only server.

In order to get keycloak to run in production mode behind a reverse proxy you needed to define KC_PROXY_HEADER=xforwarded and KC_HTTP_ENABLED=true and everything would work perfectly fine. I did learn a lot in how to map ldap attributes to keycloak, and it was mostly on understanding what the different attributes mean. I have come to have a lot of appreciation for authentik after learning all the complexities of that.

The reason I could not adopt keycloak in my setup was due to oauth2-proxy limitation in being able to support different configurations for different applications. This would stop my ability from using different group entitlements for certain applications. In addition, it was reverting to a user management setting similar to authelia and lldap which did not feel like an improvement.

Updated (7/27/25)

Took a second stab at keycloak with oauth2-proxy and it turns out that I had approached it wrong at first. You can set up different oauth2-proxy services for each group setting that honestly was only two with majority of the services being behind an admin login. After figuring out the setup it made it super easy to apply the middleware everywhere. The only caveat was needing to bring in Authorization header pass-through values for the arr apps into traefik settings, but it was still totally fine. A really import thing when integrating openldap with keycloak was setting the password policy so that passwords are not stored in plaintext.

ldap Account Manager

warning

Deprecated (2/1/26)

After I found out that phpldapadmin image from osixia that I was using was no longer active, I had to scramble and find an alternative ldap ui for openldap. There was phpldapadminv2 which was the successor and nfrastack/fusion-directory, but both felt lacking compared to this simple to use UI. I was easily able to get the same tree view as phpldapadmin and fusion-directory had way to many options that I didn't need. This did have some finicky parts to it, where some simple object management things were hidden behind a paywall. One thing I kind of hated was that I needed to remove the unix module for users before I could make changes to them. I may go to phpldapadminv2 but going to keep messing with this and see how it goes. I decided to drop this completely since most of it's tools I don't care to use and phpldapadminv2 covered everything that I need.

LLDAP

warning

Deprecated (12/16/24)

A ldap service was necessary in order to work with authelia, but many of the ldap services I came across were incredibly complicated to understand. lldap was a recommendation to authelia that really helped me understand active directory as it was much more minimal than other tools. Here's some things I learned:

  • DN refers to the domain that users are authenticated against, usually it follows the organization domain.
  • UID is the unique field used by users in ldap. In mainstream ldap servers this would be entryUUID.
  • CN refers to a common name of an object.
  • SN refers to the last name of an object.
  • OU refers to the organizational unit such as person or group. A user belongs to a unit.

Oauth2 Proxy

Setting up oauth2-proxy was interesting to say the least and required really thinking through how authorization works with my applications. The setup was fairly easy with keycloak but applying it in traefik configurations required a lot of trial and error until I understood what I really needed. With traefik it makes it difficult to the use same oauth2-proxy instance to authorize for different groups, but the solution was to just setup a different instance for different group combinations. While it doesn't sound ideal theoretically, I only needed two group configuration types for all my applications so there was minimal overhead for that, and it's really easy to add.

I was thinking about setting it up per application, when I thought I can set Authorization headers manually after logging in with Keycloak but it turns out that it did not have that ability and just passed through the current login credentials for that. To further explain the traefik configuration issues, it does not use the /oauth2/auth endpoint that allows defining groups to limit the scope of allowed users, but it instead uses /. Also a weird issue was that oauth2-proxy scopes would be messed up when defining a group, so I needed to manually set the scope for oauth2-proxy to use.

OpenLDAP

warning

Deprecated (2/1/26)

This was a pain in the ass to setup, mostly on just finding an adequate image to use since there was so many, but there were not maintained. In addition, getting a UI application took so long as well. After finally understanding how to setup openldap it was a breeze to recreate. Using the image: tiredofit/openldap, it made it really easy to setup the admin user and handle other setup as well. The most important thing this image provided that others didn't, was introducing better password hashing, since by default openldap stores passwords in plaintext.

Using two configuration files and applying them on startup using a custom script, I was able to setup the ldap store exactly to my liking. In addition, with integrating keycloak just enabling the v3 password settings, it ensured that passwords were hashed when storing it. Using openldap is much more ideal than lldap because since it is a writable store, I can easily use this to migrate users to whatever OIDC service I want. Something not in common with lldap is that the user class is inetOrgPerson instead of user, since it contained all the attributes I needed in it's scheme versus the other person classes.

Updating here, tiredofit/openldap image went EOL and was replaced by nfrastack/openldap. While the migration was seamless thanks to ldap account manager, it turns out it cause the password hashing issue to reemerge. This was due to the old image pre-compiling argon2 into the ldap server, while in the newer version I had to create a new ldif file to auto load the password policy the trigger argon2 encryption on all passwords. Also I figured out I was using cn incorrectly the entire time as the username, when I should have been using uid. I found this when trying to update the actual names for users and noticed the hashed passwords were being stored back into openldap as plaintext.

Another update, I eventually found a much more stable image symas/openldap, which turned out to be the company that actively develops openldap. It was surprisingly hard to find and I only came across it because of Gemini. Using symas was a lot easier in getting it setup, except for memberOf plugin configuration. For whatever reason it's not enabled and turning it on is not so trivial but I do have a working example in the deprecated folder.