For a long time, I’ve maintained an internal Microsoft Active Directory deployment with 2 domain controllers. However, now that I have some free time, I’ve decided to shut it down and replace it with Authentik‘s LDAP outpost. AD has introduced a lot of complexity into my lab environment, from patching, maintenance, trying to fix DNS for the 6828th time… I wanted to reduce the amount of time I need to spend keeping my auth solution working, particularly as it’s only for a handful of users.
WTF is Authentik? LDAP outpost?
Authentik is an identity provider (IDP) that supports SAML and OAuth2. If you’re familiar with Apereo CAS, Shibboleth, WSO2 Identity Server, Keycloak, ADFS, etc., Authentik is similar, but also much simpler. I’ve been using it for the last year or so to handle SSO for all of my self-hosted apps and am also a project contributor.
Authentik offers a very interesting feature called the LDAP Outpost. Other IDPs (and indeed, all of the ones I listed earlier) don’t have any widely-supported way to externally access the users stored in the IDP’s database, if it even offers internal user storage at all. In contrast, the LDAP Outpost essentially turns the Authentik API into an LDAP server, so all users stored in Authentik can be accessed using simple – and commonly supported – LDAP queries. It eliminates the need to deploy a separate LDAP server from which applications can retrieve users, which makes life much easier for small-scale enthusiasts like me.
I use docker-compose to deploy most of my apps, and Authentik’s LDAP Outpost can be deployed using docker-compose too. There are instructions on Authentik’s documentation site to do this, so I won’t cover it here. It’s very simple though.
The hard part is getting Jira to play along with the outpost. As a side note, I’ve been using Authentik to handle SAML SSO for my Jira instance using the Kantega K-SSO plugin, while the users themselves are synced using Jira’s built-in feature from my Active Directory.
Here are the roadblocks I ran into on Jira’s LDAP User Directory configuration page:
Directory Type: Should be Generic POSIX/RFC2307 Directory
I deployed the LDAP Outpost in Docker on the same machine as my Jira install, which I thought would allow me to access the Outpost using Docker’s DNS magic (i.e., at name_of_container:389). Unfortunately Jira doesn’t consider this a valid hostname, so I had to use the container’s IP address in this field.
Update: There’s actually a way to assign any arbitrary hostname to a container in docker-compose. Just do something like this in the container’s config:
# now this container is reachable from all other containers in the "default" network at the fqdn ldap.jira.local!
Then configure Jira using that aliased hostname.
Port: Authentik’s LDAP Outpost does NOT use the default LDAP ports 389 and 636! The correct ports are 3389 for LDAP and 6636 for LDAPS.
Username: I created a new service account in Authentik to act as the user binding to the LDAP Outpost. I discovered (the hard way) that the LDAP Outpost will only accept binds using the full DN, like CN=myserviceaccount,OU=Users,DC=ldap,DC=goauthentik,DC=io. Otherwise it will throw a generic LDAP Error 1. (See #1511)
Base DN: This is set when a new LDAP provider is created in Authentik.
Additional User/Group DN: Must be set to OU=users and OU=groups respectively.
For all the schema settings, you have to manually check each attribute to make sure Authentik’s LDAP outpost sends it, otherwise Jira will throw a generic error. There’s a list of sent attributes here.
This is how my User Schema Settings turned out. Note that the upn, firstName, and lastName fields are not sent by Authentik by default – they’re remnants of when my Authentik instance synced users from my AD deployment (which did have these fields). You should either manually add these fields to the attributes for each user or change the fields to something sent by default in Authentik.
The flows in Authentik (set on the LDAP provider) were also a bit of a head-banger for me. I kept getting generic LDAP Error 49 (incorrect credentials) messages even though I was using the correct credentials in Jira. It turns out that the flow for LDAP providers also needs to be custom – the default authentication does NOT work. The flow has to contain only an identification, authentication, and login stage. Nothing else. (Any MFA stages will cause the LDAP Outpost to always return Error 49.)
This is how my working flow ended up looking. The default identification stage does work, my custom ldap-identification-stage is just a copy of it that blocks emails and UPNs from being used as identification.
One major caveat is that neither Authentik nor Jira support writing to the LDAP Outpost. This means you will need to have an alternative solution (perhaps Authentik itself?) to handle password changes/resets outside of Jira. (My Jira instance was configured with AD as a read-only directory anyways, so this caveat didn’t affect anything in my case.)
Finding group memberships also doesn’t seem to work with the LDAP Outpost, even though everything seems to be configured correctly. I’ll have to tinker with this more, but for now I’m using local groups in Jira rather than syncing them from Authentik.
In the future, when Authentik gains SCIM capability, I’ll probably replace this somewhat complex (and frankly hacky) LDAP integration with user provisioning through SCIM since Kantega K-SSO supports SCIM user provisioning.