Skip to content
This repository was archived by the owner on Dec 9, 2023. It is now read-only.
Kevin Boulain edited this page Sep 17, 2017 · 1 revision

Setup

Because I don't want the post-installation script to configure slapd, create a new debconf entry specifying the preference (and as such, the unconfigured slapd should not be started):

policy=/usr/sbin/policy-rc.d
printf '#!/bin/sh\nexit 101\n' > "$policy" && chmod +x "$policy"
echo 'slapd slapd/no_configuration boolean true' | debconf-set-selections
apt-get install --no-install-recommends slapd ldap-utils gosa-schema sssd-ldap libnss-sss libpam-sss
rm "$policy"
systemctl disable slapd
systemctl disable sssd # what about sssd-secrets.socket?

There are two well known ways of representing users and groups: RFC 2307 and RFC 2307 bis, we'll use the later (which requires the gosa-schema package to retrieve rfc2307bis.schema).

Basic configuration

Necessary setup:

slapd_directory=/etc/ldap/slapd.d
mdb_directory=/var/lib/ldap/lorn.space
mkdir "$slapd_directory" "$mdb_directory"

Let's create a basic configuration:

slapadd -b cn=config -F "$slapd_directory" -l <(cat << EOF
# slapd settings
dn: cn=config
objectClass: olcGlobal
cn: config
olcToolThreads: 1
# check slapd-config(5) for the possible values, this will log basic usage
olcLogLevel: 0x100
# debian specific
olcPidFile: /var/run/slapd/slapd.pid
olcArgsFile: /var/run/slapd/slapd.args

# common database settings
dn: olcDatabase=frontend,cn=config
objectClass: olcDatabaseConfig
objectClass: olcFrontendConfig
olcDatabase: frontend
# maximum number of entries returned, defaults to 500
olcSizeLimit: unlimited
# allow unauthenticated read for schema & dn discovery
olcAccess: to dn.exact="" by * read
olcAccess: to dn.base="cn=Subschema" by * read

# configuration database
dn: olcDatabase=config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: config
# allow root access
olcAccess: to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break

# schemas (don't care much about inetorgperson & others)
dn: cn=schema,cn=config
objectClass: olcSchemaConfig
cn: schema

include: file:///etc/ldap/schema/core.ldif
include: file:///etc/ldap/schema/cosine.ldif
include: file:///etc/ldap/schema/gosa/rfc2307bis.ldif

# modules
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: /usr/lib/ldap
olcModuleLoad: back_mdb
olcModuleLoad: memberof

# defaults for mdb backends, see slapd-mdb(5)
dn: olcBackend=mdb,cn=config
objectClass: olcBackendConfig
olcBackend: mdb

# the actual database
dn: olcDatabase=mdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcMdbConfig
olcDatabase: mdb
olcSuffix: dc=lorn,dc=space
olcDbDirectory: /var/lib/ldap/lorn.space
# mdb database size, may be increased later (defaults to 1GiB, here it's 64MiB)
olcDbMaxSize: $((64 * 1024 * 1024))
# save last modification time
olcLastMod: TRUE
# indexes
olcDbIndex: objectClass eq
olcDbIndex: uid eq,sub
olcDbIndex: uidNumber,gidNumber,memberUid eq
# allow root access
olcAccess: to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break
# acl, disable writes and allow reads for everything but the userPassword field
olcAccess: to attrs=userPassword by anonymous auth by * none
olcAccess: to * by * read

# strict memberof overlay to ease maintenance
dn: olcOverlay=memberof,olcDatabase={1}mdb,cn=config
objectClass: olcMemberOf
objectClass: olcOverlayConfig
olcOverlay: memberof
olcMemberOfRefInt: TRUE
# the default is ignore
olcMemberOfDangling: error
EOF
)

Ensure permissions are okay and start slapd:

chown -R openldap: "$slapd_directory" "$mdb_directory"
systemctl start slapd

Create the basic directory structure:

ldapadd -Y EXTERNAL -H ldapi:// -f <(cat << EOF
dn: dc=lorn,dc=space
objectClass: organization
objectClass: dcObject
o: lorn.space
dc: lorn

dn: ou=users,dc=lorn,dc=space
objectClass: organizationalUnit
ou: users

dn: ou=groups,dc=lorn,dc=space
objectClass: organizationalUnit
ou: groups
EOF
)

Setup the first account and its primary group:

user=ether
password=$user
uid=$(ldapsearch -LLL -Y EXTERNAL -H ldapi:// -b dc=lorn,dc=space uidNumber | grep -Po '(?<=uidNumber: )\d+' | sort | tail -n 1)
uid=$((${uid:-9999}+1))
gid=$uid

ldapadd -Y EXTERNAL -H ldapi:// -f <(cat << EOF
dn: uid=$user,ou=users,dc=lorn,dc=space
objectClass: person
objectClass: posixAccount
cn: $user
sn: $user
uid: $user
uidNumber: $uid
gidNumber: $gid
homeDirectory: /home/$user
userPassword: $(slappasswd -s "$password")

dn: cn=$user,ou=groups,dc=lorn,dc=space
objectClass: posixGroup
objectClass: groupOfNames
cn: $user
gidNumber: $gid
member: uid=$user,ou=users,dc=lorn,dc=space
EOF
)

Some things that should not be overlooked:

  • olcThreads in cn=config: will limit the number of concurrent connections
  • you may want to add olcRootDN & olcRootPW on some databases if you want another access beside ldapi://

If everything went well, the following commands should work:

# configuration database
ldapsearch -LLL -Y EXTERNAL -H ldapi:// -b cn=config
# discovery
ldapsearch -LLL -Y EXTERNAL -H ldapi:// -b '' -s base +
ldapsearch -LLL -Y EXTERNAL -H ldapi:// -b cn=Subschema -s base +
# database
ldapsearch -LLL -Y EXTERNAL -H ldapi:// -b dc=lorn,dc=space
# memberof overlay
ldapsearch  -LLL -Y EXTERNAL -H ldapi:// -b dc=lorn,dc=space "(uid=$user)" memberOf
# authenticate (cleartext)
ldapwhoami -x -D "uid=$user,ou=users,dc=lorn,dc=space" -w "$password" -H ldap://
# anonymous search
ldapsearch -LLL -x -H ldap:// -b dc=lorn,dc=space

The following shouldn't:

# no access to the configuration by default
ldapsearch -LLL -x -D "uid=$user,ou=users,dc=lorn,dc=space" -w "$password" -H ldap:// -b cn=config
ldapsearch -LLL -x -H ldap:// -b cn=config

TLS

Note: if a self-signed certificate is good enough, playing with TLS_{CA,REQ}CERT in /etc/ldap/ldap.conf will do the trick for the ldap* commands.

Refer to the initial Let's Encrypt setup.

slapd drops its privileges before reading the SSL certificates and key, so it's a bit more involved to setup properly.

Initial setup (acme.sh leaves the file mode as 0644):

mkdir /etc/ldap/ssl
chown -R root:openldap "$_"
chmod 750 "$_"

Request the certificate (you'll need to setup a public DNS record for ldap.service.lorn.space and the web server should handle it):

acme.sh --stateless --issue --domain ldap.service.lorn.space --reloadcmd 'systemctl restart slapd' --ca-file /etc/ldap/ssl/ca.cer --cert-file /etc/ldap/ssl/ldap.service.lorn.space.cer --key-file /etc/ldap/ssl/ldap.service.lorn.space.key

Configure slapd:

ldapmodify -Y EXTERNAL -H ldapi:// -f <(cat << EOF
dn: cn=config
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ldap/ssl/ca.cer
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/ssl/ldap.service.lorn.space.key
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/ssl/ldap.service.lorn.space.cer
EOF
)

It may be nice to use recommended cipher suites as shown in Let's Encrypt. Unfortunately, OpenLDAP is linked with GnuTLS which is bit less flexible but the following should give a couple of cipher suites from the recommended modern configuration:

ldapmodify -Y EXTERNAL -H ldapi:// -f <(cat << EOF
dn: cn=config
replace: olcTLSCipherSuite
olcTLSCipherSuite: NONE:+VERS-TLS1.2:+CURVE-ALL:+SIGN-ALL:+COMP-ALL:+CTYPE-ALL:+ECDHE-ECDSA:+ECDHE-RSA:+CHACHA20-POLY1305:+AES-256-GCM:+AES-128-GCM:+AES-256-CBC:+AES-128-CBC:+AEAD:+SHA384:+SHA256
EOF
)

The -ALL stuff is required to enable basic functionality, what comes after defines the list of supported cipher suites which can be seen via gnutls-cli -l --priority $priority_string. GnuTLS will happily accept a priority list that may not be functional, verify it via gnutls-cli --debug 9999 google.com --priority $priority_string.

More information is available from GnuTLS' manual and on Mozilla's configuration generator GitHub repository's documentation.

To enable LDAPS, the URI must be added in /etc/default/slapd (else use the StartTLS extension over LDAP):

SLAPD_SERVICES="ldap:/// ldaps:/// ldapi:///"

The following command should now work:

ldapwhoami -x -D "uid=$user,ou=users,dc=lorn,dc=space" -w "$password" -H ldaps://ldap.service.lorn.space

Now that TLS properly works, it may be interesting to disable binds without TLS protection:

ldapmodify -Y EXTERNAL -H ldapi:// -f <(cat << EOF
dn: olcDatabase={1}mdb,cn=config
changetype: modify
delete: olcAccess
olcAccess: {1}to attrs=userPassword by anonymous auth by * none
-
add: olcAccess
olcAccess: {1}to attrs=userPassword by tls_ssf=128 anonymous auth by * none
EOF
)

ssf or "security strength factors" is the corresponding level of protection. In the case of tls_ssf, this is the number of bits (so for example EXPORT or DES cipher suites won't be accepted).

The following command should still work:

ldapwhoami -x -D "uid=$user,ou=users,dc=lorn,dc=space" -w "$password" -H ldaps://ldap.service.lorn.space

But not that one anymore:

ldapwhoami -x -D "uid=$user,ou=users,dc=lorn,dc=space" -w "$password" -H ldap://ldap.service.lorn.space

SSSD

SSSD or the System Security Services Daemon may be seen as a more flexible (but more complex) alternative to the more common nslcd.

A basic /etc/sssd/sssd.conf would be (don't forget the chmod 0600 or sssd will complain):

[sssd]
config_file_version = 2
services = nss, pam
domains = LDAP

[domain/LDAP]
id_provider = ldap
auth_provider = ldap
access_provider = none
chpass_provider = none
sudo_provider = none
selinux_provider = none
subdomains_provider = none
autofs_provider = none
hostid_provider = none
ldap_schema = rfc2307bis
ldap_uri = ldaps://ldap.service.lorn.space
ldap_search_base = dc=lorn,dc=space
; those are set to false by default
; enumerate = true ; required for getent passwd
; cache_credentials = true ; would allow offline login

Debian packages installation should setup /etc/nsswitch.conf and PAM with the required entries.

Clone this wiki locally