To use OpenLDAP for authentication on FreeBSD, we're going to need to customize our cosine.schema, and install/configure a few additional ports.
Another working guide at ldap_auth.
First, we need to install the following ports: If you are using OpenLDAP 2.4, run the following command before installing these ports:
echo "WANT_OPENLDAP_VER=24" >> /etc/make.conf
Once the above ports are installed, we need to build our ldap.conf file. What's interesting is that Luke H over at PADL Software, Ltd has done, is made his pam_ldap module configuration compatible with OpenLDAP's configuration. The end result is both pieces of software will use /usr/local/etc/ldap.conf. nss_ldap also follows this pattern.
A good ldap.conf file to use is as follows:
# LDAP Configuration URI ldap://ldap.example.com ldap://ldap2.example.com bind_timelimit 1 bind_policy soft base dc=example,dc=com ldap_version 3 scope sub #ssl start_tls #tls_checkpeer no #tls_ciphers TLSv1 #TLS_CACERT /usr/local/etc/ca.crt # We don't want the Unix NAS client to pick it's own encryption, but instead use the server's (SSHA). pam_password exop pam_filter objectclass=posixAccount pam_check_host_attr yes pam_login_attribute uid:caseExactMatch: pam_member_attribute memberUid #nss_connect_policy oneshot nss_base_group ou=group,dc=example,dc=com nss_base_netgroup ou=group,dc=example,dc=com nss_initgroups_ignoreusers root,ldap
The config above has the following effect:
- use ldap server at ldap.example.com
- use dc=example,dc=com for the search base
- connects with ldap version 3 only
- issues a start_tls command to encrypt the connection
- instructs pam_ldap to accept the certificate
- set tls_ciphers to TLS version 1
- uses the ca certificate found in /usr/local/etc/openldap/ca.crt to verify the server's certificate
- gets group names from cn=group,dc=example,dc=com (finger,pw, directory listings, etc)
- gets group names from ou=group,dc=example,dc=com
- is case-sensitive in uid lookup due to :caseExactMatch: after uid on pam_login_attribute
uri ldap://ldap.example.com base ou=people,dc=example,dc=com ldap_version 3 ssl start_tls tls_checkpeer no tls_ciphers TLSv1
This config does the same things as above, specific to nss_ldap port.
## Define lookups for users and groups. passwd: files ldap group: files ldap ## Optimize the nss_ldap searches for these databases. #nss_base_passwd ou=staff,ou=people,dc=claimlynx,dc=com #nss_base_group ou=staff,ou=people,dc=claimlynx,dc=com group_compat: nis hosts: files dns networks: files shells: files
The part we're most concerned with is the first two non-comment lines. These tell the system to first look in files (/etc/master.passwd and /etc/group) for uid/gid and authentication, followed by ldap. The rest of the files is what was there by default.
The next task is to roll our changes into PAM so that it's using our LDAP installation for authentication. First, we're going to configure sshd:
Edit the /etc/pam.d/sshd file, and add the following lines in their respective places:
auth sufficient /usr/local/lib/pam_ldap.so no_warn try_first_pass account required /usr/local/lib/pam_ldap.so ignore_unknown_user ignore_authinfo_unavail session required /usr/local/lib/pam_mkhomedir.so
At this point, (no need to restart SSHd or anything), you should be able to log in via ssh to the newly configured host. In addition, you should be able to finger and pw to glean information out of LDAP regarding user accounts:
root@oliver:/etc/pam.d-> finger foobeans Login: foobeans Name: Eric F Crist Directory: /home/foobeans Shell: /bin/csh Office: x842, (411) 555-9000 Home Phone: (411) 555-1234 Last login Wed Apr 23 10:23 (CDT) on ttyp7 from nat.example.com No Mail. No Plan. root@oliver:/etc/pam.d-> pw usershow foobeans -P Login Name: foobeans #400 Group: (invalid) #400 Full Name: Eric F Crist Home: /home/foobeans Class: Shell: /bin/csh Office: x842 Work Phone: (411) 555-9000 Home Phone: (411) 555-1234 Acc Expire: [None] Pwd Expire: [None]
When you log in for the first time, pam_mkhomedir.so automatically creates the user's home directory. The last item to verify is that the home directory was created (/usr/home/<username>) and that it's owned by that user/group:
root@oliver:/etc/pam.d-> ls -lah /usr/home drwxr-xr-x 2 foobeans 400 512B Apr 23 10:23 foobeans
What you'll notice above is that the foobeans user ID is correctly mapped in LDAP, but I've yet to build the group subtree with user group names. As such, GID 400 doesn't map to a group name at this time.
Locking It Down
To further lock down your LDAP authentication scheme, I'd recommend you do host-based verification. This means that, if the user isn't listed as having access to a specific host, they'll be denied with the following error:
ecrist@redoct:~$ ssh foobeans@oliver Password: Access denied for this host Permission denied (publickey,keyboard-interactive).
Without this extra protection, ALL ldap users with a PosixAccount will be given shell access to ALL servers on your network using LDAP for authentication. The method described here lists hosts within a user's LDAP entry for hosts they have access to. An alternative, not covered here, is to enter hosts, with user entries for each user with access.
To get this host verification, we're going to add a custom schema to allow for the host attribute on a posixAccount objectClass. You can download the new schema here. To use this new schema, unzip and save the scn.schema file to /usr/local/etc/openldap/schema and add the following line to your slapd.conf file:
You'll need to restart your slapd daemon for this change to take effect. Any use that's currently got the posixAccount objectClass will now be allowed to have multiple host attributes.
Next, add the following line to /usr/local/etc/ldap.conf on all of your client systems:
No restart of anything needed for this change.
Lastly, we need to make certain the appropriate entry exists in the LDAP directory entry. You should now be able to add a host attribute (multiple host attributes are OK), with the FQDN for each host to give access to. From there you should be able to log into hosts you have access to, and be denied access to hosts that aren't explicitly allowed.