Configuring OpenLDAP to Provide Name Services in Solaris 11.4
By: Date: July 1, 2018 Categories: Enterprise Computing,Solaris / Illumos Tags:

## Overview

This post will walk through setting up an OpenLDAP server to provide LDAP name services for Solaris clients.  Having previously gone through this process with a different LDAP server, I was interested in what seems to be better support for using OpenLDAP for this purpose in Solaris 11.4.  There doesn’t seem to be a single, up-to-date document for all of the steps needed. Most of the pieces can be found in the Oracle Solaris documentation, but the replication pieces are elsewhere.

This post will walk through setting up two OpenLDAP servers, and configuring a Solaris integrated load balancer to balance requests between the two servers.  Our configuration will use tls:simple for the authentication between the LDAP client and server.

## Needed Configuration Information

Document the following needed configuration items:

Please Note ﻿that I have used simple passwords in this post.  You should use good passwords and keep them protected.

## Acquire or Generate a Certificate

You will need a certificate that matches the host name you plan to use for your LDAP server.  I’ve used a generic﻿ name I assign to the LDAP function, and do not tie this to a specific server name.  For example, ldap.toddalancox.com﻿.

To ease replication between the servers using TLS, you’ll want to put the individual server names into the certificate as SANs (Subject Alternate Names).  In my case, the content of the certificate is:

FQDN:  ldap.toddalancox.com
SANs:
ldap1.toddalancox.com
ldap2.toddalancox.com
ldap3.toddalancox.com

You can either acquire a certificate for your openldap server through a 3rd party CA, or generate your own certificate.  If you are creating your own certificate, you will need to create your own CA as well.

Instructions for configuring your own CA and generating a certificate with it can be found in the StackOverflow article here.  Follow those instructions to produce a certificate.  When you create your CSR, use a configuration file to specify the SANs:

cat csr.config
[ req ]
default_bits = 2048
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no
[ req_distinguished_name ]
countryName = US
stateOrProvinceName = Alabama
localityName = Birmingham
organizationName = toddalancox.com
commonName = ldap.toddalancox.com
[ req_ext ]
subjectAltName = @alt_names
[alt_names]
DNS.1 = ldap1.toddalancox.com
DNS.2 = ldap2.toddalancox.com
DNS.3 = ldap3.toddalancox.com

And run with the command line:

openssl req -out ldap.toddalancox.com.csr -newkey rsa:2048\
-nodes -keyout ldap.toddalancox.com.key -sha256 -days 3650\
-config csr.config

You should end up with three files that we need (though with different names likely):

• cacert.pem — This is the certificate from your CA authority.  If you are using an already-trusted 3rd party CA, you won’t need this.
• certdb.pem — This is the certificate for your LDAP service.  In my case, the FQDN is ldap.toddalancox.com.
• server.key — This is the key used to produce the CSR for ldap.toddalancox.com﻿.

### Add Certificate CA to the Host ca-certificates

If you are using a 3rd party CA already recognized by your Solaris system, you can skip this step.  Otherwise, you need to install your CA certificate into each Solaris system.

My CA certificate is in a file named ca_toddalancox_com.pem﻿.  Copy this file to /etc/certs/CA/﻿, then refresh the ca-certificates﻿ service:

cp ~/cacert.pem /etc/certs/CA/ca_toddalancox_com.pem
svcadm restart ca-certificates

## Install Solaris 11.4

Using the install media for 11.4, install the Solaris operating system.  We’ll ultimately configure four different systems in this post.  At a minimum, you will want to configure a server system and a client system.  For our post, we will configure:

• LDAP Server One (ldap1)
• LDAP Server Two (ldap2)
• A Solaris Load Balancer (ilb1)
• A Solaris Client (sol01)

Perform a base install of 11.4 on each of the above systems.  I am installing the group solaris-large-server which is the default when you install from the  .iso medium.  If you are performing a jumpstart, you might need to install the solaris-large-server group.  Note that you can also use zones﻿ for these servers, which happens to be the approach I took.  After you setup one, you can quickly clone the other three from the first zone.

### Configure DNS Entries

Make sure that you put your ldap﻿ servers in the local hosts﻿ file on both of your ldap servers:

192.168.1.51 ldap1 ldap1.toddalancox.com
192.168.1.52 ldap2 ldap2.toddalancox.com

## Configure OpenLDAP Server ldap1

Our first step is to configure the OpenLDAP server on our first LDAP server, ldap1﻿.

#### Configure SMF OpenLDAP Settings

We will use the ldapserverconfig tool to configure our OpenLDAP server.  In order to run the automatic configuration, we need to populate a few fields in the service svc:/network/ldap/server:openldap.  These should most likely be cleared after you have completed the setup.  In addition, if you are concerned about storing these values in the SMF repository, you can run ldapservercfg﻿ in a non-automatic mode.  Use the values you documented above.

svccfg -s server:openldap
setprop cred/backend_passwd = "secret"
setprop profile/default/search_base = "dc=toddalancox,dc=com"
setprop profile/default/server_list = "ldap.toddalancox.com"
exit
svcadm refresh server:openldap

Note that if you don’t specify a backend_passwd﻿, the root password will be used.

#### Run ldapservercfg﻿ Utility

Now that we have configured the SMF, we can run the ldapservercfg﻿ utility in automatic mode.  You need to run this as the openldap﻿ user:

su openldap
ldapservercfg -a openldap

Save the output of the above command for future reference to ensure that all went well.

#### Replace the LDAP Server’s Certificates

Shutdown the LDAP server and replace its certificate and key with the files you built earlier.  Remember to add your CA certificate to the trusted CA store if you are using your own CA:

svcadm disable openldap
cp ca_toddalancox_com.pem /etc/certs/CA/
svcs ca-certificates
STATE          STIME    FMRI
online          3:40:42 svc:/system/ca-certificates:default
cp ldap.toddalancox.com.pem /etc/openldap/certs/certdb.pem
cp ldap.toddalancox.com.key /etc/openldap/certs/server.key
svcs openldap
STATE          STIME    FMRI
online          3:41:28 svc:/network/ldap/server:openldap

You can check that your certificate is correctly recognized with:

openssl s_client -host ldap.toddalancox.com -port 636

Check the output to make sure that your certificate is recognized as valid.  This is essentially testing that your CA root certificate is being used properly.

Several of the opendlap﻿ utilities didn’t seem to honor the system-wide CA certificates file, so I made the following change to /etc/openldap/ldap.conf:﻿

TLS_CACERT /etc/certs/ca-certificates.crt

## Configure The Second LDAP Server

Install another Solaris server, ldap2﻿, if you haven’t already.  Next, repeat the configuration that you ran for configuring the server ldap1﻿ above.

The steps to repeat are:

• Use svccfg to configure cred and profile as before
• Run ldapservercfg
• Replace the certificates

## Configure LDAP Replication

Our setup will replicate the mdb﻿ data (ie, dc=toddalancox,dc=com﻿), but will not replicate configuration data.  Again, make sure that each host has an entry in its hosts file to resolve the other server.

### Turn on Logging

While we setup the initial replication, you may want to setup some very verbose logging.  First, setup syslog to process log entries from openldap which by default uses local4.debug﻿.

touch /var/adm/ldap.log
egrep local4.debug /etc/syslog.conf || cat >>/etc/syslog.conf <<EOF
EOF
svcs system-log:default

ldapmodify -D 'cn=config' -w secret <<EOF
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: any
EOF

svcs openldap

Repeat the above on both servers.

### Preliminary Configuration for ldap1

We need to configure the syncprov overlay and set the olcServerID.

ldapmodify -D 'cn=Manager,dc=toddalancox,dc=com' -w secret <<EOF
dn: cn=config
changetype: modify
EOF

ldapmodify -D 'cn=config' -w secret <<EOF
dn: olcOverlay=syncprov,olcDatabase={1}mdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
EOF


### Preliminary Configuration for ldap2

The only difference in the initial two ldap modify operations is to specify a different olcServerID﻿.

ldapmodify -D 'cn=Manager,dc=toddalancox,dc=com' -w secret <<EOF
dn: cn=config
changetype: modify
EOF

ldapmodify -D 'cn=config' -w secret <<EOF
dn: olcOverlay=syncprov,olcDatabase={1}mdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
EOF


### Setup Replication from ldap1 to ldap2

Openldap ﻿replication is pull replication, so we will work on configuring ldap2﻿ to pull from ldap1﻿.  We are first going to clear out the mdb﻿ database on ldap2﻿ and configure its replication to pull from ldap1﻿ to repopulate the database:

#on ldap2
cd /var/openldap/openldap-data
\rm *mdb
svcs openldap

Now that the mdb﻿ database has been cleared, we will configure the initial replication and then check that it has pulled the database from ldap1﻿.

#on ldap2
ldapmodify -D 'cn=config' -w secret <<EOF
dn: olcDatabase={1}mdb,cn=config
changetype: modify
olcSyncRepl: rid=001 provider=ldap://ldap1.toddalancox.com binddn="cn=Manager,dc=toddalancox,dc=com" bindmethod="simple" credentials=secret searchbase="dc=toddalancox,dc=com" type=refreshAndPersist retry="5 5 300 5" timeout=1 starttls=critical
-
olcMirrorMode: TRUE
EOF


Wait a few seconds and then check:

#on ldap2
slapcat | grep Manager

You should have plenty of output.

### Setup Replication From ldap2 to ldap1

#on ldap1
ldapmodify -D 'cn=config' -w secret <<EOF
dn: olcDatabase={1}mdb,cn=config
changetype: modify
olcSyncRepl: rid=001 provider=ldap://ldap2.toddalancox.com binddn="cn=Manager,dc=toddalancox,dc=com" bindmethod="simple" credentials=secret searchbase="dc=toddalancox,dc=com" type=refreshAndPersist retry="5 5 300 5" timeout=1 starttls=critical
-
olcMirrorMode: TRUE
EOF


## Configure the ilb Load Balancer

This will be a straightforward configuration of vrrp﻿ to provide a high availability IP address, and ilb﻿ to provide a load-balancer for our ldap servers.  We are going to configure DSR for our ilb rules, but you should read the documentation and decide if a half or full-NAT solution might be better for your case.

First, install the packages and enable the services:

#on ilb1
pkg install vrrp
pkg install ilb
svcs vrrp
svcs ilb


### Configure the Virtual IP Address

You need to assign a virtual router number which will be unique for this IP address on your network.  I’m using 100﻿.  You also need to assign a unique virtual IP address that will will use to represent ldap.toddalancox.com.  Once you have these, you can setup the virtual router for this IP address.  This will allow up to add a redundant load balancer later if we like.

vrrpadm create-router -T l3 -V 100 -A inet -I net0 -p 255 ldaprtr
vrrpadm show-router

Now that we have our virtual IP address, we need to configure the load balancing rules.  The very first thing we need to do is create a check script﻿ which can be used to verify that a tested ldap server is working.  My script will search for an object guaranteed to be present: me.  Edit your check script to search for an object that should always be found in your directory:

mkdir /scripts
chmod 755 /scripts
cat >/scripts/check_ldap <<EOF
#!/bin/bash
VIP=\$1 SERVER=\$2
PROTO=\$3 LOADB=\$4
PORT=\$5 TIME=\$6

if ! timeout \$TIME ldapsearch -x -h \$SERVER -b 'dc=toddalancox,dc=com' 'uid=toddc' >/dev/null; then
echo -1
else
echo 0
fi
EOF
chmod 755 /scripts/check_ldap

Once you have your check script, you can define a health check:

ilbadm create-hc -n -h hc-test=/scripts/check_ldap,hc-timeout=3,hc-count=1,hc-interval=4 hc-ldap

Next, define a server group with your two ldap servers:

ilbadm create-servergroup -s server=192.168.1.51,192.168.1.52 sg-ldap

Now, create a rule using our health check, server group, and virtual IP.  We will create one rule for port 389 and one for port 636:

ilbadm create-rule -e -i vip=192.168.1.55,port=389,protocol=tcp -h hc-name=hc-ldap -m lbalg=hipp,type=DSR -o servergroup=sg-ldap ldap389
ilbadm create-rule -e -i vip=192.168.1.55,port=636,protocol=tcp -h hc-name=hc-ldap -m lbalg=hipp,type=DSR -o servergroup=sg-ldap ldap636

Check that your health check rules are correct and showing the desired output:

ilbadm show-hc-result
RULENAME      HCNAME        SERVERID      STATUS   FAIL LAST     NEXT     RTT
ldap389       hc-ldap       _sg-ldap.0    alive    0    11:39:49 11:39:51 0
ldap389       hc-ldap       _sg-ldap.1    alive    0    11:39:46 11:39:50 0
ldap636       hc-ldap       _sg-ldap.0    alive    0    11:39:49 11:39:55 0
ldap636       hc-ldap       _sg-ldap.1    alive    0    11:39:48 11:39:50 0

You can use svcadm disable openldap﻿ on one of the servers to see it fall to dead﻿ in the output of show-hc-result.

### Configure Loopback Address on LDAP Servers

Since we are using DSR﻿ (Direct Server Return) rules in ilb﻿, we need to configure each of the member servers (our ldap servers) to recognize the virtual IP address, but not answer ARP requests for it.  On both ldap1﻿ and ldap2﻿, run:

ipadm create-addr -d -a 192.168.1.55/24 lo0/vip
ipadm set-ifprop -p arp=off -m ipv4 lo0  ## not required in 11.4
ipadm up-addr lo0/vip

## Configure the First Client

You need to decide if your client will update LDAP entries or not.  If it updates entries (for example, useradd), it needs access to the admin credentials.  If not, it can get by with the just the proxy credentials.

192.168.1.55 ldap.toddalancox.com

### Configure a Client to Update Entries

ldapclient init -a authenticationMethod=tls:simple \
-a profilename=default \
-a domainname=toddalancox.com \
-a proxyDN=cn=proxyagent,ou=profile,dc=toddalancox,dc=com \
ldap.toddalancox.com

### Configure a Client that Won’t Update Entries

ldapclient init -a authenticationMethod=tls:simple \
-a profilename=default \
-a domainname=toddalancox.com \
-a proxyDN=cn=proxyagent,ou=profile,dc=toddalancox,dc=com
ldap.toddalancox.com

### Configure The Name Service Switch

By default, ldapclient init will setup host resolution which does not use DNS. I  prefer the order files ldap dns﻿. To configure this, you can either edit the /etc/nsswitch.conf file and import the configuration to SMF, or edit the properties in SMF and export to the /etc/nsswitch.conf file.

svccfg -s name-service/switch
setprop config/host="files ldap dns"
exit
nscfg export name-service/switch

### Netgroups

If you plan to limit login by netgroup, you need one further step.  Add the following line to /etc/pam.d/other﻿ to recognize netgroup syntax in the passwd﻿ and shadow﻿ files:

account required   pam_list.so.1 compat

### Configure the LDAP Client on the LDAP Servers

An LDAP server’s client cannot reference its own server, primarily because of issues at boot up.  However, since we are using the load balancer, the client can be configured on each LDAP server identically to the other clients.  Make sure you have your ldap server defined in the hosts file to point to the virtual IP address:

192.168.1.55 ldap.toddalancox.com

### Configure the LDAP Client on the Load Balancer

Generally speaking, you won’t have much success configuring the load balancer host to use the ldap VIP of the load balancer as we have defined it with the DSR rule.  At least, I couldn’t as of Solaris 11.3. I have not tried with 11.4.  As a result, you’ll need to consider how to configure the LDAP client on the load balancer hosts (that are providing load balancing for LDAP).

In my case, I configured ilb1 to point directly to ldap2﻿ and ilb2﻿ to point directly to ldap1.  You could also create a unique client configuration that references both ldap1﻿ and ldap2﻿ rather than the virtual IP address ldap﻿.  This would allow the client to perform its own failover.

I believe you can eliminate this issue by configuring full-NAT load balancing rules as well.

## Configuring an HA Load Balancer

This step will add another load balancer which will provide high availability load balancing in the event that ilb1 goes down.  This is really rather easy.  You can follow the original steps for configuring ilb1﻿, except that you need to define a lower priority on the virtual router﻿:

vrrpadm create-router -T l3 -V 100 -A inet -I net0 -p 100 ldaprtr

Other steps should be the same.  You can test your setup by halting servers, disabling services, taking down interfaces, etc.