So, I ran into an interesting problem tonight, and I figured I would share my solution. I have been doing some additional hardening of my site, such as re-encrypting certain passwords to use stronger encryption standards. And rather than using the old NIS+/YP protocols which came out of the SunOS world and which quickly made its way into the BSD world and eventually into other UN*X OSes including Linux, I have been using LDAP, and specifically OpenLDAP with SSSD. While by default, OpenLDAP supports SSHA, or "seeded SHA" encryption, I decided to take things to the next level and see about using the PBKDF2 group of encryption algorithms (PBKDF2-SHA1, PBKDF2-SHA256 and PBKDF2-SHA512), only, this is not a part of OpenLDAP out of the box. Instead, while the source is distributed with OpenLDAP in the contrib/ directory, it must be compiled, installed into a system location, and then have OpenLDAP re-configured to load it as a loadable module. All this seemed pretty easy at first, particularly given that I was looking at this for a much stronger password encryption at the best level available to both OpenLDAP and RHEL's IdM, which I am preparing to implement. But like any battle plan, it never survives the first contact with the enemy.
The first skirmishes came when I wanted to compile the module. I actually had to fall back to downloading and installing the source RPM for the openldap package from Rocky's repository. And then, rather than just unpacking the source archive, going into the directory and running make to create it, I got errors since it was looking for build artifacts. So, I ended up having to do the following command:
rpmbuild -bb --noclean SPECS/openldap.specafter installing a bunch of -devel RPMs so that I could do the build. Once that was done, I could go into that subdirectory, which was now under BUILD/openldap-2.6.8/openldap-2.6.8/contrib/slapd-modules/passwd/pbkdf2/ and do the make followed by a sudo make install. But then came the real fight.
The next step was to find out whether my OpenLDAP was configured with a cn=module,cn=config entry in the configuration database (database 0), and either modify it with ldapmodify or add it with ldapadd. It turns out, I needed to add it, so I created the following LDIF file, pw-pbkdf2.ldif:
dn: cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
olcModulePath: /usr/local/libexec/openldap
olcModuleLoad: pw-pbkdf2.laOnly now, when I ran sudo ldapadd -Y EXTERNAL -H ldapi:/// -f pw-pbkdf2.ldif, I got the following:
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
adding new entry "cn=module{0},cn=config"
ldap_add: Insufficient access (50)
It was seeing that I was root and the configuration file was correct, but try as I might, search as I might, no solution. OpenLDAP was refusing to let me modify the configuration to add that configuration entry.😡😤
After about 45 minutes of digging, I finally figured it out. In spite of everything indicating that root should be able to modify the LDAP database containing the configuration, it turns out this is not the case. When I used slapcat to dump the configuration database, the database entry for cn=config started with:
dn: olcDatabase={0}config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: {0}config
olcAccess: {0}to * by * nonebut a sample LDIF config I found had:
dn: olcDatabase=config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: config
olcAccess: to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,c
n=auth" manage by * none(Don't worry, if that last "line" looks broken, it isn't... the fact that the second part starts indented by a space indicates that it is a continuation of what came before, and this can be for just one line, or hundreds, in the case of a base-64 encoded JPEG image, in the case of the jpegPhoto attribute on my own LDAP record, which continues for 364 lines in total. It is just how LDIF lines are wrapped.at 76 characters for a LDIF file, per RFC 2849.)
The net result was that when I first initialized my LDAP database (mumble) years ago, probably from a .conf formatted file, it might not have even been necessary to have a line like the latter, but it was now. And so, I had to fall back and do what in American football would be called a "fake punt attempt". Specifically, I started out by doing the following:
# systemctl stop slapd
# slapcat -n 0 -l database-0.ldif
# slapcat -n 1 -l database-1.ldifThen, I edited database-0.ldif to add a line like the olcAccess line in the sample file above before the one which was already there, so that it read like this:
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,c
n=auth" manage by * none
olcAccess: {0}to * by * none
(only, that was not entirely 100% correct, as I will note in a second).
And since I was already editing the config, I went ahead and added the following:
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulepath: /usr/lib/openldap:/usr/lib64/openldap:/usr/local/libexec/openldap
#olcModuleload: check_password.la
#olcModuleload: home.la # homedir.la ??
# nestgroup.la
olcModuleload: pw-pbkdf2.laI included some comments (which start with a '#`) just for my reference. And, at the same time, I took the time to upgrade the password for my LDAP administrator account from an old encryption format to a stronger one (but not the one which I am adding... that will come later, once I test it and prove things are working). Then, I did the following to rebuild the OpenLDAP databases from the modified backup I had made:
# rm -rf /etc/openldap/slapd.d/* /var/lib/ldap/*
# slapadd -n 0 -F /etc/openldap/slapd.d -l database-0.ldif.new
# chown -R ldap:ldap /etc/openldap/slapd.d/ /var/lib/ldap/
# slapadd -n 1 -F /etc/openldap/slapd.d -l database-1.ldif
# chown -R ldap:ldap /etc/openldap/slapd.d/ /var/lib/ldap/
# restorecon -Rv /etc /var
# systemctl restart slapdOnly, the restart failed. After a couple of minutes, it came to me... the SELinux file context for the new modules was probably not right. So, I did some looking around, saw that the directory containing the new module had a SELinux file context of unconfined_u:object_r:etc_t:s0 rather than system_u:object_r:lib_t. So, I did the following:
# semanage fcontext -a -t lib_t -s system_u /usr/local/libexec
# restorecon -Rv /usr/local/libexec
# systemctl restart slapdAnd things started fine. 😁🥳
I am debating where to go from here. Right now, there are a couple of issues. The first is, that all this is a bunch of manual customizations, with nothing preventing me from having to break the DRY philosophy and do it all again manually. But, I am also likely migrating to RHEL's IdM server. But still... maybe somebody else might find this useful as well beyond just having a blog post to read and follow. And, I don't know how long I will be in replacing the server where my OpenLDAP, cobbler, DNS master, dhcpd and other key services are running. Partly, because I want to replace my current cobbler 3 server with the new cobbler 4 version which is in the process of being released right now. I may just kick this down the field a few yards, and focus on getting cobbler 4 ready. And that means getting into a discussion with the maintainer to get some build issues solved, including re-adding the build infrastructure for RHEL 9 based systems, which for some reason got removed, and then testing the SELinux related parts of the packaging.