1

Topic: Securing LDAP with Lets Encrypt Certificate

==== REQUIRED BASIC INFO OF YOUR IREDMAIL SERVER ====
- iRedMail version (check /etc/iredmail-release): 0.9.9
- Deployed with iRedMail Easy or the downloadable installer? Installer
- Linux/BSD distribution name and version: Ubuntu 18.04
- Store mail accounts in which backend (LDAP/MySQL/PGSQL): LDAP
- Web server (Apache or Nginx): Nginx
- Manage mail accounts with iRedAdmin-Pro? No
- [IMPORTANT] Related original log or error message is required if you're experiencing an issue.
====

Since a long time I'm trying to secure the connections to the LDAP installed by iRedMail with my LetsEncrypt-Certificate. With no success. I've found out that openldap doesn't have the permission to read the files in the letsencrypt-folder. So I copied them to /etc/certs/ and I was able to restart slapd.

Here comes the relevant part of my /etc/ldap/slapd.conf:

# TLS files.
TLSCACertificateFile /etc/ssl/certs/example.com.fullchain.pem
TLSCertificateFile /etc/ssl/certs/example.com.cert.pem
TLSCertificateKeyFile /etc/ssl/private/example.com.privkey.pem

I've tried some modifications of my /etc/ldap/ldap.conf but with no effect:

BASE    dc=example,dc=com
URI     ldap://127.0.0.1:389 ldaps://127.0.0.1:636 ldaps://example.com:636
#TLS_CACERT /etc/ssl/certs/iRedMail.crt
TLS_CACERT /etc/ssl/certs/example.com.fullchain.pem

The encryption seems to work on the machine itself but if I try to connect from another on I get this error message (using -d 1 option in ldapsearch):

ldap_url_parse_ext(ldaps://example.com)
ldap_create
ldap_url_parse_ext(ldaps://example.com:636/??base)
Enter LDAP Password: 
ldap_sasl_bind
ldap_send_initial_request
ldap_new_connection 1 1 0
ldap_int_open_connection
ldap_connect_to_host: TCP example.com:636
ldap_new_socket: 3
ldap_prepare_socket: 3
ldap_connect_to_host: Trying *.*.*.*:636
ldap_pvt_connect: fd: 3 tm: -1 async: 0
attempting to connect: 
connect success
TLS: peer cert untrusted or revoked (0x42)
TLS: can't connect: (unknown error code).
ldap_err2string
ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)

What am I doing wrong? What can I do to connect from outside to the LDAP? Isn't it possible with the LDAP installed by iRedMail?

----

Spider Email Archiver: On-Premises, lightweight email archiving software developed by iRedMail team. Supports Amazon S3 compatible storage and custom branding.

2

Re: Securing LDAP with Lets Encrypt Certificate

- Is openldap listening on 127.0.0.1?
- Is port 389/636 open in server firewall?

3

Re: Securing LDAP with Lets Encrypt Certificate

ZhangHuangbin wrote:

- Is openldap listening on 127.0.0.1?
- Is port 389/636 open in server firewall?

Yes, on the server i can make requests by ldapsearch both by 127.0.0.1 and to the domain. Also the encryption works on the server itself. Only when I try to access the LDAP from outside, I get the above error message.

Both ports are open. A unencrypted bind to 389 is working. Only encrypted access from another computer does not work and fails with the above error message.

4

Re: Securing LDAP with Lets Encrypt Certificate

Did you try "ldaps://example.com:389" as the server address?

5

Re: Securing LDAP with Lets Encrypt Certificate

ZhangHuangbin wrote:

Did you try "ldaps://example.com:389" as the server address?

Tried it now. I get another error message:

ldap_url_parse_ext(ldaps://example.com:389)
ldap_create
ldap_url_parse_ext(ldaps://example.com:389/??base)
Enter LDAP Password: 
ldap_sasl_bind
ldap_send_initial_request
ldap_new_connection 1 1 0
ldap_int_open_connection
ldap_connect_to_host: TCP example.com:389
ldap_new_socket: 3
ldap_prepare_socket: 3
ldap_connect_to_host: Trying *.*.*.*:389
ldap_pvt_connect: fd: 3 tm: -1 async: 0
attempting to connect: 
connect success
TLS: can't connect: The TLS connection was non-properly terminated..
ldap_err2string
ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)

6

Re: Securing LDAP with Lets Encrypt Certificate

I wonder how you performed the test. Is it a command like "ldapsearch", or a php/python/perl/...  script? Please share it so that others can help verify.

7

Re: Securing LDAP with Lets Encrypt Certificate

ZhangHuangbin wrote:

I wonder how you performed the test. Is it a command like "ldapsearch", or a php/python/perl/...  script? Please share it so that others can help verify.

It has been an ldapsearch:

ldapsearch -H ldaps://example.com:389 -x -D "cn=vmail,dc=example,dc=com" -W -b "ou=Users,domainName=example.com,o=domains,dc=example,dc=com" "(uid=username)" -d 1

8

Re: Securing LDAP with Lets Encrypt Certificate

Could you use this Python (v2) script for testing again? Replace the ldap server address, bind dn/password.

import ldap

uri = 'ldaps://example.com:389'
basedn = 'o=domains,dc=example,dc=com'
bind_dn = 'cn=Manager,dc=example,dc=com'
bind_pw = 'passwd'

ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
conn = ldap.initialize(uri=uri, trace_level=0)
conn.start_tls_s()
conn.bind_s(bind_dn, bind_pw)

# Get all mail users.
qr = conn.search_s(basedn,
                   ldap.SCOPE_SUBTREE,
                   "(objectClass=mailUser)",
                   ['dn'])

for i in qr:
    print i

conn.unbind()

Save the code in file 'test.py', then run command:

python2 test.py

if it doesn't print users' dn, please replace the "trace_level=0" by "trace_level=1" and run again, then show us the console output. You may want to replace the sensitive info before pasting.

9 (edited by alex42 2020-04-28 15:57:25)

Re: Securing LDAP with Lets Encrypt Certificate

ZhangHuangbin wrote:

if it doesn't print users' dn, please replace the "trace_level=0" by "trace_level=1" and run again, then show us the console output. You may want to replace the sensitive info before pasting.

I've done so. Sadly with no success. Here comes the requested outpout:

*** <ldap.ldapobject.SimpleLDAPObject instance at ***> ldaps://example.com:389 - SimpleLDAPObject.set_option
((17, 3), {})
*** <ldap.ldapobject.SimpleLDAPObject instance at ***> ldaps://example.com:389 - SimpleLDAPObject.start_tls_s
((), {})
Traceback (most recent call last):
  File "test.py", line 10, in <module>
    conn.start_tls_s()
  File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 864, in start_tls_s
    return self._ldap_call(self._l.start_tls_s)
  File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 329, in _ldap_call
    reraise(exc_type, exc_value, exc_traceback)
  File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 313, in _ldap_call
    result = func(*args,**kwargs)
ldap.SERVER_DOWN: {'info': u'The TLS connection was non-properly terminated.', 'errno': 2, 'desc': u"Can't contact LDAP server"}

10

Re: Securing LDAP with Lets Encrypt Certificate

- Try port 636.
- Is OpenLDAP listening on port 389 and 636?
- Is port 389 and 636 open in firewall?

11

Re: Securing LDAP with Lets Encrypt Certificate

ZhangHuangbin wrote:

- Try port 636.
- Is OpenLDAP listening on port 389 and 636?
- Is port 389 and 636 open in firewall?

Before you recommended me to use port 389, I had already tested port 636 (see above).
Ports are both open and OpenLDAP listens on both ports. I can establish an encrypted connection directly on the same server. But if I try to connect from another server, I have the problems described above.

12 (edited by alex42 2020-05-01 08:12:05)

Re: Securing LDAP with Lets Encrypt Certificate

Found a solution. The other machine has been configured as well with iRedMail which caused the problem. In the LDAP.conf this has been set:

TLS_CACERT /etc/ssl/certs/iRedMail.crt

I've copied the fullchain.pem to this machine adjusted the path for TLS_CACERT accordingly. I've added

TLS_REQCERT demand

and restartet sdlapd. Now it is working as expected.

But what will happen if the cert is updated (which happens every 30 days). Will I have to copy the fullchain.pem again? Or is there another way to establish an encrypted connection. From my desktop it works without having to make any changes.

13

Re: Securing LDAP with Lets Encrypt Certificate

The /etc/ldap.conf file is not used by OpenLDAP server, but all other LDAP client softwares on the server, so i GUESS it's fine since each time it reads /etc/ldap.conf when you run the ldap client.