How we proxyed OpenLDAP to AD via cn=config
I want to dedicate this post to a case from a large IT project that our company was doing. As part of the project, a large number of services were implemented, and for them it was necessary to provide LDAP authentication for the following operations:
– Access to GUI-interfaces of services
– Access via SSH to servers where services are running, with access restriction based on user membership in groups of the LDAP directory
The customer already had a Microsoft Active Directory directory service deployed. The requirement of the project was the absence of direct access between the implemented services and AD. On the service side, the parameters of AD service accounts should not have been written. Also, only one host was allowed network access to the MS AD controller.
Under the cut – details on how we solved this problem.
To solve this problem, we chose OpenLDAP in the mode of proxying authentication requests towards MS AD controllers. To enter the servers, we used the SSSD module, which processes LDAP(S) requests with additional filtering by MS Active Directory groups.
The task of proxying requests through OpenLDAP does not look like something difficult. There is enough information on the Internet on this subject. The catch was that they basically describe how the OpenLDAP configuration is done through the sladp.conf file. However, starting with OpenLDAP 2.4, configuration is not done using slapd.conf, but via the cn=config LDAP configuration context. The option to configure via slapd.conf has been deprecated and is no longer supported. There are very few similar examples of settings through cn=config in the public domain.
In the article I tried my best describe in detail the technique for configuring OpenLDAP 2.6 and SSSD via cn=config on Rocky Linux 8.5 and describe how we solved the problems that arose in the process.
Installing OpenLDAP
To install OpenLDAP, follow these steps:
1. Install dependencies:
# dnf install wget vim cyrus-sasl-devel libtool-ltdl-devel openssl-devel libdb-devel make libtool autoconf tar gcc perl perl-devel -y
2. Connect the Symas repository to download OpenLDAP from it:
#wget -q https://repo.symas.com/configs/SOFL/rhel8/sofl.repo -O /etc/yum.repos.d/sofl.repo
3. Install the server and client parts of OpenLDAP:
#dnf install symas-openldap-clients symas-openldap-servers -y
4. Add OpenLDAP (slapd.service) to startup and enable the service:
#systemctl enable slapd
#systemctl start slapd
Setting up OpenLDAP
On the OpenLDAP server (opld.test.local in our example), you need to do the following:
1. Add information about BASE and URI to the /etc/openldap file:
BASE dc=test,dc=local
URI ldap://opld.test.local ldaps://opld.test.local:636
2. When OpenLDAP is running in proxy mode, the Microsoft Active Directory domain controller will be the backend database of the LDAP type for OpenLDAP. To be able to connect OpenLDAP to a domain controller, the back_ldap module must be loaded.
For this:
a. Verify that the back_ldap.la file exists on the OpenLDAP server. If it is not present, then this library must be loaded onto the OpenLDAP server.
b. Create an ldif file like this:
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: /usr/lib64/openldap
olcModuleLoad: back_ldap.la
c. Load back_ldap.ldif file into OpenLDAP server configuration:
#ldapadd -Y EXTERNAL -H ldapi:/// -f back_ldap.ldif
3. Create a backend database of the ldap type, which will be Active Directory:
a. Create ldap_db.ldif file as:
dn: olcDatabase=ldap,cn=config
objectClass: olcDatabaseConfig
objectClass: olcLDAPConfig
olcDatabase: ldap
olcDbIDAssertBind: bindmethod="simple" binddn="CN=tech_test_local,OU=Tech
Accounts,DC=test,DC=local" credentials="password"
olcDbURI: ldaps://dc01.test.local
olcReadOnly: TRUE
olcRootDN: cn=openldap,dc=test,dc=local
olcRootPW: password
olcSuffix: dc=test,dc=local
olcDbChaseReferrals: FALSE
· olcDbIDAssertBind: Specifies the connection method, distinguishedName, and ID password to connect to the MS Active Directory controller.
· olcDbURI: AD controller URI
· olcReadOnly: Operating mode (read/write) with MS Active Directory.
· olcRootDN: OpenLDAP service root. With it, services will be connected to OpenLDAP.
· olcRootPW: OpenLDAP Service OZ Password
· olcSuffix: Domain suffix
· olcDbChaseReferrals: Determines whether the referral mechanism can be used
To encrypt the olcRootPW password, run the command:
# slappasswd -s password
and specify the generated hash value in the olcRootPW attribute.
b. Run the following command on the OpenLDAP server:
#ldapadd -Y EXTERNAL -H ldapi:/// -f ldap_db.ldif
Set up a secure TLS connection between OpenLDAP and AD.
The certificate chains of the CAs that issued the certificates for the domain controller must be provided:
a. Put the certificate chain (cacerts.pem) on the OpenLDAP server (for example, in /etc/openldap/certs).
b. Specify the path to the certificate in the /etc/openldap/ldap.conf file:
TLS_CACERT /etc/openldap/certs/cacerts.pem
5. Provide the ability to connect services to OpenLDAP via LDAPS:
a. Issue a key and certificate for the OpenLDAP server. Put the certificate (oldap.crt) and key (oldap.key) on the OpenLDAP server (for example, in /etc/openldap/certs).
b. Create opldcert.ldif file:
dn: cn=config
objectClass: olcDatabaseConfig
objectClass: olcLDAPConfig
olcDatabase: cn=config
changetype: add
olcTLSCertificateFile: /etc/openldap/certs/oldap.crt
olcTLSCertificateFileKey: /etc/openldap/certs/oldap.key
olcTLSVerifyClient: never
c. Run command:
#ldapadd -Y EXTERNAL -H ldapi:/// -f opldcert.ldif
This completes the configuration of OpenLDAP in proxy mode. After completing this configuration, the server can process incoming LDAP/LDAPS requests from clients and proxy requests to the MS Active Directory domain controller. A secure connection is configured between the OpenLDAP server and the MS Active Directory domain controller.
Below I will describe the implementation of setting up the SSSD module in terms of SSH authentication to client servers, taking into account filtering according to membership in MS Active Directory groups.
Setting up the SSSD service
Install SSSD packages:
# sudo yum install sssd-tools sssd oddjob oddjob-mkhomedir samba-common-tools
Configure the ldap.conf file on the client servers. Download the OpenLDAP server certificate and set the path to it:
URI ldap://opld.test.local ldaps://opld.test.local:636
BASE dc=test,dc=local
TLS_CACERT /etc/openldap/certs/oldap.crt
TLS_CACERTDIR /etc/openldap/certs
<![if !supportLineBreakNewLine]>
<![endif]>
Create sssd.conf file. (etc/sssd/sssd.conf):
[domain/test.local]
ldap_schema = ad
id_provider = ldap
autofs_provider = ldap
auth_provider = ldap
chpass_provider = ldap
ldap_uri = ldaps://opld.test.local:636
ldap_search_base = dc=test,dc=local
ldap_id_use_start_tls = True
ldap_tls_cacertdir = /etc/openldap/certs
cache_credentials = False
ldap_tls_reqcert = allow
ldap_default_bind_dn = cn=openldap,dc=test,dc=local
ldap_default_authtok_type = obfuscated_password
ldap_default_authtok = #зашифровать и ввести в следующем шаге
ldap_access_order = filter
ldap_id_mapping = True
ldap_referrals = False
access_provider = ldap
ldap_access_filter = (|(memberOf= CN=Admins,DC=test,DC=local)(memberOf=CN=Support,DC=test,DC=local))
use_fully_qualified_names = False
# Object Mappings
ldap_user_object_class = user
ldap_user_name = sAMAccountName
ldap_group_object_class = group
ldap_group_name = cn
# ID Mappings
ldap_user_objectsid = objectSid
ldap_group_objectsid = objectSid
ldap_idmap_range_size = 1048576
ldap_user_primary_group = primaryGroupID
override_homedir = /mnt/home/%u
default_shell = /bin/bash
fallback_homedir = /home/%u@%d
[sssd]
config_file_version = 2
services = nss, pam,autofs
domains = test.local
[nss]
homedir_substring = /home
In the example below, I used the ldap_access_filter parameter with AD groups (Admins, TechSupport). Only those users who are members of these MS AD groups will be able to connect to the server.
Give permissions to the sssd.conf file:
# chmod 600 /etc/sssd/sssd.conf
To prevent the password from being stored in clear text, encrypt it:
# sss_obfuscate -d test.local
Add to the /etc/hosts file or configure the OpenLDAP address on your DNS server:
# (IP OpenLDAP) opld.test.local
Restart sssd, test the service with the id command:
# systemctl restart sssd.service
#id {username}
#User Found (id=1234567) # Пример вывода строки, найденного пользователя
Switch Linux login profile to use sssd (LDAP authentication):
# authselect select sssd --force
Set up sudo rights for domain accounts:
# echo "sudoers: files sss" >> /etc/nsswitch.conf
Ensure creation of home directories for domain users:
# systemctl enable --now oddjobd
# echo "session optional pam_oddjob_mkhomedir.so skel=/etc/skel/ umask=0022" >> /etc/pam.d/system-auth
# systemctl restart oddjobd
Check if SSSD is working:
# sssctl domain-status test.local
If you get this kind of output, then SSSD is configured correctly, you can try to authenticate to the server:
# sssctl domain-status test.local
Online status: Online
Active servers:
LDAP: test.local
Discovered LDAP servers:
- test.local
If you get Offline status, then you made a mistake at some stage above, check again.
Problems and solution
After connecting one of the systems and setting up LDAP authentication, we found a problem that authentication in the Web UI did not pass. The same problem was noticed when trying to authenticate via SSH. The authentication session was timed out. This behavior was found if the whole domain was searched. At the same time, if we narrowed the search boundaries, for example, to the level of only a certain OU, then the problem went away, and users could authenticate.
Client calls to OpenLDAP and OpenLDAP to MS AD were dumped. They found out that when searching the entire domain, in addition to the response to the request, there was an appeal to DomainDNSZones using the Referrals mechanism.
Referral is the process by which the LDAP server, instead of returning the result of the query, returns a link (referral) to another LDAP server or, in our case, a domain controller, which may contain additional information. When receiving a referral to DomainDNSZones, OpenLDAP made a request to MS AD domain controllers to which there was no network access. In this regard, the session from the OpenLDAP server to MS AD hung, and then it was interrupted by a timeout.
Accordingly, to solve the problem, it was necessary to find a way to manage referrals. Basically, all articles related to this problem described settings using the slapd.conf configuration file, and not cn=config.
Examining the OpenLDAP schema, the olcDbChaseReferrals parameter was found, which was precisely responsible for sending when accessing MS AD. If you use the value olcDbChaseReferrals=FALSE, then LDAP, when receiving a referral to DomainDNSZones, ignores this and does not contact other domain controllers.
In the documentation for SSSD, we also found a parameter responsible for sending – ldap_referrals. After applying this parameter with the value FALSE SSSD has stopped crashing and losing connection with the domain controller.
Another interesting point that we noticed was related to configuring access filtering based on membership in AD groups. We saw that after setting up the filter, users could not access the server. The problem was that when subtracting objects from SSSD, they were not assigned the correct unique ID. The ID was generated by the Linux machine itself, and should have been obtained in the objectSID attribute from MS Active Directory. Thus, SSSD could not obtain a correct list of the AD groups that the user is a member of (SSSD must match user and group IDs from the ldap_user_objectsid and ldap_group_objectsid attributes instead of relying on Linux-generated IDs). The solution to the problem was to use the parameter ldap_id_mapping with meaning TRUE.
I hope this post was helpful and helped solve problems faster. If someone has a similar experience in the settings, share your knowledge, I will be ready to update and supplement the article with fresh information.
Post author: senior presale engineer Vladislav Alyoshin