Zabbix 6.4 finally brings a very much waited feature called “Just-In-Time user provisioning”. Zabbix “What’s new in 6.4” LDAP/SAML user provisioning paragraph is very brief and can not (not that I am saying it should) deliver any excitement about this new really game changing feature. This blog post was born to address two points:

  • explain in more details why it is “game changing” feature
  • configuration of this feature is very flexible and as it often happens flexibility brings complexity and sometimes confusion about how to actually not only get it working but also to get the most of this feature

NOTE: I am talking about LDAP in this blog post but SAML works exactly the same way so you can easily apply this article to SAML JIT user provisioning configuration.

Old times (before 6.4)

Let’s do a quick reminder how it worked before Zabbix 6.4:Obvious problem here is that a User must be pre-created in Zabbix to be able to log in using LDAP. The database user records do not have any fields noticing that the user will be authenticated via LDAP, it’s just users’ passwords stored in the database are ignored, instead, Zabbix goes to an LDAP server to verify whether:

  • a user with a given username exists
  • user provided the correct password

no other attributes configured for the user on the LDAP server side are taken into account.

So when Zabbix is used by many users and groups, user management becomes not a very trivial task as new people join different teams (or leave).

Zabbix 6.4 with JIT user provisioning enabled

Now let’s take a look at what is happening in Zabbix 6.4 (very simplified picture). The picture depicts what happens when memberOf method is selected for Group Configuration (more on that later):Now when Zabbix gets a username and password from the Login form it goes to the LDAP server and gets all the information available for this user including his/her LDAP groups membership and e-mail address. Obviously, it gets all that only if the correct (from LDAP server perspective) username and password were provided. Then Zabbix goes through pre-configured mapping that defines users from which LDAP group goes to which Zabbix user group. If at least one match is found then a user is created in the Zabbix database belonging to a Zabbix user group and having a Zabbix user role according to configured “match”. So far sounds pretty simple, right? Now let’s go into detail about how all this should be configured.

LDAP server data

To experiment with the feature I built a Docker container which is a fully functional LDAP server with some pre-configured data, you can easily spin it up using this image. Start the container this way:

docker run -p 3389:389 -p 6636:636 --name openldap-server --detach bgmot42/openldap-server:0.1.1

To visually see LDAP server data (and add your own configuration like users and groups) you can start this standard container

docker run -p 8081:80 -p 4443:443 --name phpldapadmin --hostname phpldapadmin --link openldap-server:ldap-host --env PHPLDAPADMIN_LDAP_HOSTS=ldap-host --detach osixia/phpldapadmin:0.9.0

Now you can access this LDAP server via https://<ip_address>:4443 (or any other port you configure to access this Docker container), click Login, enter “cn=admin,dc=example,dc=org” in Login DN field and “password” in Password field, click Authenticate. You should see the following structure of the LDAP server (picture shows ‘zabbix-admins’ group configuration):All users in this container for convenience are configured with “password” word as their passwords.

General LDAP authentication configuration in Zabbix

No surprises here, you need to enable LDAP authentication, just a couple of additions here:

  • You must provide Deprovisioned users group. This group must be literally “disabled” otherwise you won’t be able to select it here. This is the Zabbix user group where all “de-provisioned” users will be put into so effectively will get disabled from accessing Zabbix.
  • Enable JIT provisioing check-box which obviously needs to be checked for this feature to work.

And again already familiar interface to configure a LDAP server and search parameters, however, this picture depicts how we actually fill in these parameters according to data in our LDAP server:

“Special” Distinguished Name (DN) cn=ldap_search,dc=example,dc=org is used for searching, i.e. Zabbix uses this DN to connect to LDAP server and of course when you connect to LDAP server you need to be authenticated – this is why you need to provide Bind password. This DN should have access to a sub-tree in LDAP data hierarchy where all your users are configured. In our case all the users configured “under” ou=Users,dc=example,dc=org, this DN is called base DN and used by Zabbix as so to say “starting point” to start searching.
Note: technically it is possible to bind to LDAP server anonymously, without providing a password but this is a huge breach in security as the whole users sub-tree becomes available for anonymous (unauthenticated) search, i.e. effectively exposed to any LDAP client that can connect to LDAP server over TCP. The LDAP server we deployed previously in Docker container does not provide this functionality.

Group configuration method “memberOf”

All users in our LDAP server have memberOf attribute which defines what LDAP groups every user belongs to, e.g. if you perform a LDAP query for user1 user you’ll get that its memberOf attribute has this value:
memberOf: cn=zabbix-admins,ou=Group,dc=example,dc=org
Note, that your real LDAP server can have totally different LDAP attribute that provides users’ group membership, and of course, you can easily configure what attribute to use when searching for user’s LDAP groups by putting it into User group membership attribute field:

In the picture above we are telling Zabbix to use memberOf attribute to extract DN defining user’s group membership (in this case it is cn=zabbix-admins,out=Group,dc=example,dc=org) and take only cn attribute from that DN (in this case it is zabbix-admins) to use in searching for a match in User group mapping rules. Then we define as many mapping rules as we want. In the picture above we have two rules:

  • All users belonging to zabbix-users LDAP group will be created in Zabbix as members of Zabbix users group with User role
  • All users belonging to zabbix-admins LDAP group will be created in Zabbix as members of Zabbix administrators group with Super admin role

Group configuration method “groupOfNames”

There is another method of finding users’ group membership called “groupOfNames” it is not as efficient as “memberOf” method but can provide much more flexibility if needed. Here Zabbix is not querying LDAP server for a user instead it is searching for LDAP groups based on a given criterion (filter). It’s easier to explain with pictures depicting an example:

Firstly we define LDAP “sub-tree” where Zabbix will be searching for LDAP groups – note ou=Group,dc=example,dc=org in Group base DN field. Then in the field Group name attribute field we what attribute to use when we search in mapping rules (in this case we take cn, i.e. only zabbix-admins from full DN cn=zabbix-admins,ou=Group,dc=example,dc=org). Each LDAP group in our LDAP server has member attribute that has all users that belong to this LDAP group (look at the right picture) so we put member in Group member attribute field. Each user’s DN will help us construct Group filter field. Now pay attention: Reference attribute field defines what LDAP user’s attribute Zabbix will use in the Group filter, i.e. %{ref} will be replaced with the value of this attribute (here we are talking about the user’s attributes – we already authenticated this user, i.e. got all its attributes from LDAP server). To sum up what I’ve said above Zabbix

  1. Authenticate the user with entered Username and Password against LDAP server getting all user’s LDAP attributes
  2. Uses Reference attribute and Group filter fields to construct a filter (when user1 logs in the filter will be (member=uid=user1,ou=Users,dc=example,dc=org)
  3. Performs LDAP query to get all LDAP groups with member attribute (configured in Group member attribute field) containing constructed in step 2 filter
  4. Goes through all LDAP groups received in step 3 and picks cn attribute (configured in Group name attribute field) and finds a match in User group mapping rules

Looks a bit complicated but all you really need to know is the structure of your LDAP data.

Demo time

Finally let’s see what happens when user1 belonging to zabbix-admins LDAP group and user3 belonging to zabbix-users LDAP group log in:

That’s it. Happy JIT user provisioning!

Subscribe
Notify of
12 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
gregco
1 year ago

Thank you for detailed explanation on how LDAP configuration works!

Snowflake71
Snowflake71
1 year ago

This explanation is indeed awesome. The problem is that it’s still not working. I followed each step here from the dockerized ldap and all those things – LDAP bind does not work without the selinux settings and ldap.conf certificate finetune… The group mapping does not work without changing a faulty strtolower in CLdap.php, And that only fixes the login test, he regular login still fails.
Anyway, this blog entry is a must, no doubt, thank you for it! We were waiting for it for years.

Snowflake71
Snowflake71
1 year ago

Yes, that bug report helped me with the strtolower issue workaround. And this blogpost helped me understanding the whole idea. As such I love it. 🙂
For the LDAP, I have the LDAP config, certs, bind working nicely, the testing works, it picks up the groups, media, everything is green – on the test page. However at the login screen it is still Incorrect user name or password or account is temporarily blocked.
Anyway, I guess that one belongs to the zabbix forums, I was just thinking out loud here. 🙂 After all this blog is a very good source of info and helps tremendously, but I guess the purpose is not troubleshooting.

Anthony Somerset
Anthony Somerset
1 year ago

Hi Thanks for this

we have used LDAP auth historically and glad to see this feature, theres a missing piece of information that is not clear to me.

We use LDAP + local accounts, that is, all our staff use LDAP based accounts and then we have local accounts that don’t exist in LDAP for things like customers and for NOC screens etc to login for – its not clear if we lose the ability for local user accounts with LDAP + JIT Provisioning – the manual is clear that this is not possible for SAML but doesn’t say either way for LDAP – Any ideas?

Aigars Kadikis
Aigars Kadikis
1 year ago

Hi Evgeny,

Thank you for the extra work you put in the LDAP container – predefining those user accounts with a non-empty password just for this lab to happen. This is pure gold for beginners to play around with the setup and get it running.

I want to make few statements for everyone which will try to reproduce this lab:

1) Docker one-liners shared in this article works out from box. No need to change a character (if the ports 3389, 6636, 8081, 4443 are free to use). For the authors (bgmot42, osixia) who made these containers to happen, I would like to give a warm welcome “take my money and shut up”.

2) Before going into configuration inside Zabbix, it’s useful to list if users are recognized at the network level. This step is required to avoid any firewall issues between frontend and LDAP server. On frontend server install “ldapsearch-clients” package and use command:

ldapsearch -x -H ldap://10.10.1.15:3389 -D “cn=ldap_search,dc=example,dc=org” -W -b “ou=Users,dc=example,dc=org” -s sub “(uid=*)” dn uid

Change only IP address!

The password is ‘password’ and the output should print user1, user2, user3

3) When configurating LDAP, do not immediately enable GIT. We still have few test perform and celebrate every progress we make in this lab. Test the LDAP relation (similarly as ldapsearch in command line). Click the test button and write “user1” with “password”. The other binding user “ldap_search” will not work for the test!

4) Only when step 2 and 3 works, enable “Configure GIT provisioning” checkbox and continue.

“Group configuration: MemberOf” did not work for me. But “Group configuration: GroupOfNames” worked perfectly. If you are testing exactly with this docker container in article the longest string, we need to copy and paste 1:1 is:

(member=uid=%{ref},ou=Users,dc=example,dc=org)

@Evgeny
“Go Away!” is a funny signature to your work 🙂 Keep it coming in future articles.

Love the last screenshot a lot. I can imagine hours of work put in that picture to happen.

Constantin Oshmyan
Constantin Oshmyan
10 months ago

Hi Evgeny, thank you very much for a great article.
The only unclear moment for me is the following.

When the configuration method “groupOfNames” is used, the parameter “Group member attribute” is required (“member” in your example). What is the purpose of this parameter?

You wrote that it is used during a LDAP search operation (step 3); however, it seems that for a LDAP search operation only the LDAP filter is necessary. In your example the search filter already contains the condition “attribute ‘member’ is equal to…”, so why the additional parameter “Group member attribute” is needed?

Last edited 10 months ago by Constantin Oshmyan
Clecimar
Clecimar
8 months ago

Hi Evgeny Yurchenko, I´d like to know more about MFA. Can you set for Zabbix ?
Thank you.

12
0
Would love your thoughts, please comment.x
()
x