In part 3 we’ve looked at ACLs and how to use them to restrict privileges of directory users. Unfortunately it’s still possible to access the 389 Directory Server instance that we’ve created all the way back in part 1 anonymously (i.e. without authenticating as a directory user) which renders the ACLs somewhat pointless. So it’s time to tighten up security a bit.
5. Securing an instance
5.1. Disabling anonymous binds
Connecting to an LDAP server without a user name or password is called an anonymous bind. This is frequently used to simplify searching the DIT for common information such as group names or email addresses since it doesn’t require to authenticate with a service account first. By default the 389 Directory Server allows anonymous binds for search and read operations.
This introduces some security concerns however: Not only need the ACLs to be watertight to prevent access to sensitive information (especially if the GDPR is applicable) but anonymous binds can also be used for denial of service attacks or other attack vectors.
To disable anonymous binds we can make use of
dsconf localhost config replace nsslapd-allow-anonymous-access=off
5.2. TLS encryption with Let’s Encrypt
Non-encrypted communication with an LDAP server is simply just a bad idea. Even in LAN environments it’s just best practise to use TLS to meet potential threats with defense in depth.
The 389 Directory Server supports encrypted communication via the LDAPS protocol (TLS encryption is used right after the connection has been established) or STARTTLS over LDAP (the connection is not encrypted until the STARTTLS command is sent by the client). For both we need a valid certificate.
While it’s possible to use a self-signed certificate (which can be conveniently created by setting
True in an inf answer file, see part 1) it can be quite laborious (or maybe not even possible) to ensure that the certificate authority is trusted by all applications that want to communicate with out LDAP server. And if the certificate can’t be verified, applications won’t (or at least shouldn’t) establish a connection.
Let’s encrypt is a CA that’s run by the Internet Security Research Group and is trusted by almost all applications. Certificates are free, easy to create and use and can be automatically renewed with
certbot, so we might as well just use that.
To install certbot and enable automatic certificate renewal:
# dnf install certbot # systemctl enable certbot-renew.timer Created symlink /etc/systemd/system/timers.target.wants/certbot-renew.timer → /usr/lib/systemd/system/certbot-renew.timer.
and assuming our 389ds instance is reachable on port 80 from the internet we can use the standalone mode to create a certificate (for other methods on how to create certificates, have a look at the certbot documentation):
# certbot certonly --standalone -m <your_email> --agree-tos -d ldap.example.com Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator standalone, Installer None Requesting a certificate for ldap.example.com Performing the following challenges: http-01 challenge for ldap.example.com Waiting for verification... Cleaning up challenges IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/ldap.example.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/ldap.example.com/privkey.pem Your certificate will expire on 2021-08-11. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le
The certificates and private key were installed to
/etc/letsencrypt/live/ldap.example.com/ so all that’s left to do is to import them into the 389ds instance and enable TLS:
dsctl localhost tls import-server-key-cert \ /etc/letsencrypt/live/ldap.example.com/fullchain.pem \ /etc/letsencrypt/live/ldap.example.com/privkey.pem dsconf localhost config replace nsslapd-securePort=636 nsslapd-security=on dsctl localhost restart
We can now communicate with our LDAP server via LDAPS on port 636 or using STARTTLS on port 389.
5.3. Requiring secure binds
So now we can communicate securely with our LDAP server. However, it’s not required and unencrypted communication is still possible on port 389. To require secure, enctypted communication, we set
dsconf localhost config replace nsslapd-require-secure-binds=on dsctl instance_name restart
5.4. Password storage schemes
Passwords are not stored in the directory server database in cleartext but hashed. The algorithm that’s used to hash the passwords is called the password storage scheme.
There are two separate password storage schemes, one for the directory manager (
nsslapd-rootpwstoragescheme) and another one for user passwords (
nsslapd-pwstoragescheme). Both default to
PBKDF2_SHA256, which is considered to be susceptible to GPU or ASIC brute force attacks. Unfortunately, more modern hashing algorithms that would solve this problem by requiring larger amounts of RAM like bcrypt or scrypt are currently not supported by the 389 Directory Server (see the list of available password storage schemes)
Changing the password storage schemes is rather straighforward though. Assuming we wanted to change both, the directory manager scheme as well as the user password scheme to
CRYPT-SHA512, we can run
dsconf localhost pwpolicy set --pwdscheme=CRYPT-SHA512 dsconf localhost config replace nsslapd-rootpwstoragescheme=CRYPT-SHA512
Of course, since the clear text is unknown all passwords have to be rehashed. To rehash the directory manager password:
dsconf localhost config replace nsslapd-rootpw="mysecret"
Note that’s it’s questionable if
CRYPT-SHA512 offers more resilience to brute force attacks than the default
Now that our 389ds instance is completely configured and we’ve tightened up security it’s time to look at how to back it up and – in case of a disaster – restore it in part 5.