Paranoid Penguin - Secure Mail with LDAP and IMAP, Part I
We have two goals for the remainder of this article: to leverage our existing LDAP server to authenticate IMAP users and to configure our Cyrus IMAP server to accept only SSL-encrypted connections from end users. In past articles, I've extolled the virtues of centralizing authentication, so hopefully the value of using LDAP for this step is a given by now. I may have explained in earlier columns how dangerous clear-text e-mail retrieval is. In normal POP3 and IMAP transactions, your user name, password and all subsequent e-mail data traverse the network unencrypted. Therefore, they are exposed to eavesdropping attacks, especially if you retrieve your e-mail over a wireless network or from the Internet, the largest untrusted network of them all.
Back to SASL. Because Cyrus IMAP and Cyrus SASL both come from Carnegie Mellon University, and because the Cyrus team is understandably reluctant to reinvent the wheel, Cyrus IMAP depends on Cyrus SASL for its authentication functionality. This may seem confusing: isn't this function what we're using LDAP for? Yes it is, and SASL is indeed redundant insofar as SASL was designed to use its own user database to authenticate users.
Besides using its own database, however, SASL also can be used to broker authentication transactions with other authentication sources, such as PAM or LDAP. The simplest way to do this is by configuring saslauthd, the SASL authentication dæmon, whose behavior is controlled primarily by the file /etc/saslauthd.conf. Listing 1 shows a sample saslauthd.conf file.
Listing 1. Sample /etc/saslauthd.conf
ldap_servers: ldap://localhost/ ldap_search_base: dc=wiremonkeys,dc=org ldap_bind_dn: cn=servers,dc=wiremonkeys,dc=org ldap_bind_pw: password_goes_here
ldap_servers specifies a space-delimited list of LDAP server URIs. In Listing 1, I've specified a clear-text LDAP connection to the local LDAP process. I instead could specify the encrypted ldaps protocol instead of ldap, a remote fully qualified domain name or IP address instead of localhost or both, as in ldaps://ldap.wiremonkeys.org.
ldap_search_base is the base (shared) part of your users' distinguished names (DNs). ldap_bind_dn and ldap_bind_pw are the DN and password you wish saslauthd to use to connect to your LDAP server. I recommend creating a special LDAP record for this purpose. In Listing 1, servers is the name of a special LDAP account with an objectClass of simpleSecurity Object, which means that besides its DN and objectClass, it has only one other attribute, userPassword.
If nothing else, having a dedicated server account in LDAP means that in your LDAP logs you can distinguish LDAP lookups by back-end processes and servers from end-user-initiated queries. This would be harder if IMAP used, for example, your personal LDAP account. For still more granular auditing, you even could use a different LDAP account for each service that performs LDAP queries, for example, cyrus and postfix.
Those are the options I use in my own /etc/saslauthd.conf file, but they aren't the only ones available to you. Cyrus SASL is distributed with a file, LDAP_SASLAUTHD, that documents these and other saslauthd.conf options. It's located in the source code distribution's saslauthd directory, but if you install SASL from a binary package, this file is placed wherever your distribution puts package documentation, probably some subdirectory of /usr/share/doc.
Besides editing /etc/saslauthd.conf, you also need to make sure saslauthd is started with the -a ldap option. On Red Hat, this is done by editing the file /etc/sysconfig/saslauthd so the parameter MECH is set to ldap. On SuSE, you edit the same file, but the parameter is called SASLAUTHD_AUTHMECH. Other distributions using sysconfig may have a different parameter name, and/or you may need to customize /etc/saslauthd. Again, the desired end result is for saslauthd to be passed the option -a ldap on startup.
Once you've configured and restarted saslauthd, you're ready to configure your IMAP service. As it happens, this is the easy part.
Most of Cyrus IMAP's behavior is controlled by a file named, predictably, /etc/imapd.conf. Listing 2 shows a sample imapd.conf file.
Listing 2. Example /etc/imapd.conf File
configdirectory: /var/lib/imap partition-default: /var/spool/imap admins: cyrus wongfh sievedir: /var/lib/imap/sieve sendmail: /usr/sbin/sendmail hashimapspool: true sasl_pwcheck_method: saslauthd sasl_mech_list: PLAIN tls_cert_file: /var/lib/imap/slapd3.pem tls_key_file: /var/lib/imap/slapd3key.pem tls_cipher_list: HIGH:MEDIUM:+SSLv2
As you can see, many of the options in imapd.conf simply define paths to various things Cyrus IMAP needs. I won't cover these in detail (see the imapd.conf(5) man page for complete documentation), but let's at least discuss the nondefault settings in Listing 2.
admins: specifies the Cyrus IMAP users who may administer the IMAP system using the cyradm tool. (We'll cover cyradm in a future column.) By setting sasl_pwcheck_method: to saslauthd and by already having configured saslauthd to use LDAP, we've configured Cyrus IMAP to use LDAP for all authentication. So even though, for example, the user cyrus may exist on the local Linux system (in /etc/passwd), cyrus also needs to have an LDAP entry. When you run cyradmin and are prompted for cyrus' password, provide the password defined for Cyrus in the database, not cyrus' Linux password, if indeed the Linux account has one. In other words, any account names you specify after admins: must exist on whatever user database is specified by sasl_pwcheck_method.
When you installed Cyrus IMAP, whether from binary packages or from source code, a new user (cyrus) should have been created and given ownership of most Cyrus IMAP files. As with any other good service dæmon, Cyrus IMAP runs as a special nonprivileged user rather than root most of the time.
The three other settings in Listing 2 that I had to customize were tls_cert_file:, tls_key_file: and tls_cipher_list:. These are analogous to OpenLDAP's slapd.conf parameters TLSCertificateFile, TLSCertificateKeyFile and TLSCipherSuite, respectively. I mention this because the certificate/key files specified here are the same ones I used for OpenLDAP on this system. I did this because, in my example scenario, I'm running Cyrus IMAP on the same server on which I'm running OpenLDAP; there's no reason to use different server certificates and keys for each service. I did, however, copy both files from /etc/openldap to /var/lib/imap to simplify ownership/permissions management.
If my LDAP service was running on a separate host, I would create a new TLS certificate/key pair for my LDAP server, using exactly the same procedure I described in my August 2003 column:
openssl req -new -x509 -nodes -out slapdcert.pem \ -keyout slapdkey.pem -days 365
Regardless, remember to make both your certificate and key file owned by cyrus and your key file readable only by its owner.
If you install Cyrus IMAP from source, it uses default SSL keys that fail if an IMAP client attempts to connect using TLS rather than SSL encryption. Aside from the reliability issue, it's never, ever a good idea to use default (placeholder) certificates or keys for anything. Either leverage a server certificate/key you've created already (if applicable) or create a new pair. Your IMAP server will be both more reliable and more secure.
That's it; Cyrus IMAP now can be restarted (/etc/init.d/cyrus-imapd restart) and users added with cyradm. We'll have to save that part, plus getting your local MTA to deliver mail to IMAP, for next time.