Skip to content

LDAP

LDAP is a VM running on NFS (ID 101) and connects directly to USTCnet.

Server

We use OpenLDAP server (slapd)

Setup

On a freshly installed Debian server, install slapd with all recommended packages.

The first time slapd asks for an admin password, enter anything you like (we'll change it later).

After apt completes, run dpkg-reconfigure slapd to re-configure the LDAP server. This time pay attention to each prompt.

  • First prompt is domain name, used to generate the base Distinguished Name (DN). Enter acsa to create a short base DN dc=acsa.
  • Second prompt is organization, just enter acsa. It's not known what this is used for.
  • Then enter the admin password and repeat it. All changes to the LDAP database will require this password in the future.
  • Last prompt is whether to move the old database. Answer Yes here to avoid them cluttering up the server. It's safe to clear /var/backups after this.

Make sure the server service is enabled and running. Check systemctl status slapd.service.

Create directory for users and groups

Create 00-basic.ldif with the following content:

dn: ou=user,dc=acsa
objectClass: organizationalUnit
ou: user

dn: ou=group,dc=acsa
objectClass: organizationalUnit
ou: group

Import the above definitions into LDAP database:

ldapadd -x -D "cn=admin,dc=acsa" -W -f 00-basic.ldif

Enter the admin password when prompted.

Now create a "user group" under the group directory:

dn: cn=acsastaff,ou=group,dc=acsa
objectClass: posixGroup
cn: acsastaff
gidNumber: 2000
description: ACSA staff

Save to 01-group.ldif and import it with a similar command as above.

SSL Certificate

To allow the server to be reached with different hostnames (e.g. DNS and plain IP), we created a self-signed certificate with the following Subject Alternative Names:

DNS: ldap
DNS: ldap.acsalab.com
IP: <server IPv4>
IP: <server IPv6>

XCA is an easier way to generate (and manage) your certificates than operating the openssl command.

Copy the certificate file (in PEM text format) and the private key file (also in PEM text format) onto the server. Place them under /etc/ldap and change file mode to 0644 (certificate) and 0400 (private key).

Use the following LDIF file to configure the server:

dn: cn=config
changetype: modify
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/server.key

dn: cn=config
changetype: modify
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/server.crt

dn: cn=config
changetype: modify
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ldap/server.crt

Order is important

It's not documented, but the private key must be added before the certificate. Otherwise you'll get this response:

ldap_modify: Other (e.g., implementation specific) error (80)

References: 1, 2, 3

Open /etc/default/slapd, find SLAPD_SERVICES and add ldaps:/// to the list. It's recommended to remove ldap:// to disable unencrypted connections.

Restart the server (systemctl restart slapd.service) for the changes to take effect.

ACL

By default, only the admin user can modify the "database" where user data is stored. Only the local root user can modify server settings (the tree under DN cn=config). Everyone else has read-only access to the database, including unauthenticated clients.

  • When using the admin user, specify -D cn=admin,dc=acsa -W to use password authentication.
  • When using local root user, run the ldap* commands as root and use -Y EXTERNAL to use "external authentication".

-Y EXTERNAL authentication method

The "external" authentication method defers authentication to the transport layer. There are (at least) two kinds of supported methods: Unix domain socket SO_PEERCRED (see unix(7)) and TLS client certificate. When connecting over UDS, the server knows the client's UID, GID and PID.

To list existing access control policies, use ldapsearch:

ldapsearch -Y EXTERNAL -b cn=config olcAccess

To make maintenance easier, we allow the local root user to also modify the database (in addition to server settings).

Configuration process
ldapsearch -Y EXTERNAL -b 'olcDatabase={1}mdb,cn=config' olcAccess

This yields the following result:

# {1}mdb, config
dn: olcDatabase={1}mdb,cn=config
olcAccess: {0}to attrs=userPassword by self write by anonymous auth by * none
olcAccess: {1}to attrs=shadowLastChange by self write by * read
olcAccess: {2}to * by * read

Also note how the root user is identified:

dn: olcDatabase={-1}frontend,cn=config
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break

So to allow the root user to modify the database, we need to insert a rule at top:

dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
-
add: olcAccess
olcAccess: to attrs=userPassword by self write by anonymous auth by * none
-
add: olcAccess
olcAccess: to attrs=shadowLastChange by self write by * read
-
add: olcAccess
olcAccess: to * by self write by * read

Samba support

Install slapd-contrib package so the Samba module is available on disk.

Add the module to load list:

ldapmodify -f smbk5pwd-module.ldif
dn: cn=modules{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: {1}smbk5pwd.la

Restart slapd, then add the module config:

ldapadd -f smbk5pwd-config.ldif
dn: olcOverlay={0}smbk5pwd,olcDatabase={1}mdb,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcSmbK5PwdConfig
olcOverlay: {0}smbk5pwd
olcSmbK5PwdEnable: samba
olcSmbK5PwdMustChange: 0

To enable Samba access for a user, add the following attribute:

dn: uid=ibug,ou=user,dc=acsa
changetype: modify
add: objectClass
objectClass: sambaSamAccount
-
add: sambaSID
sambaSID: S-1-5-21-0000000000-0000000000-0000000000-2001

The last group of digits should match the user's uidNumber.

The user must change their password once for the module to populate sambaNTPassword and sambaLMPassword attributes. The password need not be different.

Web UI

To ease management, we use wheelybird/ldap-user-manager as the web UI. We deploy this as a Docker container on the LDAP VM.

/root/docker.sh
#!/bin/sh

NAME=lum
docker rm -f "$NAME"
docker run -itd \
  --name="$NAME" \
  --restart=always \
  --net=host \
  --add-host=ldap.acsalab.com:127.0.0.1 \
  -v /etc/ldap/server.crt:/run/ldap/server.crt:ro \
  -v /etc/ldap/server.key:/opt/ssl/server.key:ro \
  -v /etc/ldap/server.crt:/opt/ssl/server.crt:ro \
  -v /root/.config/ldap:/run/secrets/ldap:ro \
  -e SERVER_HOSTNAME=ldap.acsalab.com \
  -e SERVER_KEY_FILENAME=server.key \
  -e SERVER_CERT_FILENAME=server.crt \
  -e CA_CERT_FILENAME=server.crt \
  -e ORGANISATION_NAME="ACSA Lab" \
  -e SHOW_POSIX_ATTRIBUTES=TRUE \
  -e LDAP_URI=ldaps://ldap.acsalab.com \
  -e LDAP_BASE_DN="dc=acsa" \
  -e LDAP_REQUIRE_STARTTLS=TRUE \
  -e LDAP_TLS_CACERT_FILE=/run/ldap/server.crt \
  -e LDAP_IGNORE_CERT_ERRORS=TRUE \
  -e LDAP_USER_OU=user \
  -e LDAP_GROUP_OU=group \
  -e DEFAULT_USER_GROUP=acsastaff \
  -e LDAP_ADMINS_GROUP=sudo \
  -e LDAP_ADMIN_BIND_DN="cn=admin,dc=acsa" \
  -e LDAP_ADMIN_BIND_PWD_FILE=/run/secrets/ldap/secret \
  -e EMAIL_DOMAIN=acsalab.com \
  -e LDAP_VERBOSE_CONNECTION_LOGS=TRUE \
  wheelybird/ldap-user-manager:v1.11

Then we can visit https://ldap.acsalab.com to manage users and groups.

Do not create users with web UI

Due to its own limitations, users created in the web UI will not have their Samba attributes populated, and thus will not be able to access our Synology NAS via SMB or OpenVPN. Create users using the LDAP command-line tools instead.

Client

Configuring an Ubuntu or Debian server to use LDAP:

Install libnss-ldapd with all recommended packages (just don't add --no-install-recommends).

When configuring libnss-ldapd, select the first three items (passwd, group, shadow) and continue.

Check /etc/nsswitch.conf to ensure ldap appears after passwd, group and shadow lines.

Copy /etc/ldap/ca.crt from another machine or just download (wget / curl) from here.

/etc/ldap/ldap.conf

Edit this file and set the following keys:

BASE    dc=acsa
URI     ldaps://ldap.acsalab.com
TLS_CACERT      /etc/ldap/ca.crt

/etc/nslcd.conf

This is the most important file. Edit the content for the following settings:

uri ldaps://ldap.acsalab.com

base dc=acsa

ssl on
tlq_reqcert demand
tls_cacertfile /etc/ldap/ca.crt

Everything else can be left as-is.

Restart both nscd and nslcd services. Now you can check the output of getent passwd to see if any additional entries show up.

PAM

Finally, append to the end of /etc/pam.d/common-session this line:

session required    pam_mkhomedir.so skel=/etc/skel umask=0022

This makes sure whoever doesn't have a home directory gets created on their first login.

Notes

Broken chsh

The chsh command doesn't work for LDAP users, while the chsh.ldap command in Ubuntu 20.04 is broken. (LP#1892482)

Fix: Manually apply this commit to the local installation of /usr/share/nslcd-utils.

Note:: Ubuntu 22.04 has the bug fixed already and chsh.ldap works fine out of the box.

Synology LDAP

By default Synology syncs user/group info from LDAP server every 1440 minutes (24 hours). This means that any changes made to LDAP server will not be reflected on the NAS until the next sync. Notably, this includes newly added users (but not password changes). This has caused confusion for new users when connecting to OpenVPN on Synology.

We have since changed that setting (Domain/LDAP → Edit → Advanced) to 5 minutes. Any new Synology systems joining our LDAP should have this setting applied manually.