Skip to main content

Securing Postfix and Dovecot with TLS

SSL/TLS vs STARTTLS

This seemed to be confusing at first but here is what it boils down to:

With STARTTLS, an existing TCP connection is upgraded to an encrypted one after the SMTP handshake. On the other hand, with SSL/TLS, an ecnrypted connection is negiotiated right away before an SMTP handshake takes place. In other words, STARTTLS is "TLS inside SMTP", while SSL/TLS is "SMTP inside TLS".

See this page for more information.

Another important difference between these two schemes is that STARTTLS does not require a separate port. You can continue to use the same smtp (25) or imap (143) port. SSL/TLS on the other hand requires separate smtp (465) and imap (993) ports.

Setup

I wanted to implement a STARTTLS scheme; however, I decided to revert back to SSL/TLS due to:

1. I am running Dovecot dovecot-1.0.7 on CentOS release 5.5. Unfortunately for me, I was not able to require SSL connections since the "ssl = required" configuration option is not available until v1.2+. WIthout this I could not force TLS for non-plaintext authentication.
[http://wiki.dovecot.org/SSL/DovecotConfiguration]

2. Outlook related issues described here.

SSL/TLS

Securing Postfix
The "smtpd_tls_wrappermode=yes" argument disables STARTTLS and enables SSL/TLS. It basically overrides the "smtpd_tls_security_level" flag inside /etc/postfix/main.cf. One thing to remember is that, you are not supposed to put this flag inside main.cf; it needs to be inside master.conf.
/etc/postfix/master.cf
smtp      inet  n       -       n       -       -       smtpd
smtps     inet  n       -       n       -       -       smtpd -o smtpd_tls_wrappermode=yes 
Since we are using the smtps service, we need to punch a hole in our firewall for port 465.
/etc/postfix/main.cf
smtpd_tls_cert_file = /etc/pki/tls/certs/mail.crt
smtpd_tls_key_file = /etc/pki/tls/private/mail.key
smtpd_tls_CAfile = /etc/pki/tls/certs/ca.crt
smtpd_tls_loglevel = 1
smtpd_tls_received_header = no
smtpd_tls_security_level = may
smtpd_tls_auth_only = yes
smtpd_tls_session_cache_timeout = 3600s
Testing
openssl s_client -tls1 -crlf -connect mail.domain.com:465
Securing Dovecot
/etc/dovecot.conf
protocols = imaps # we need to open port 993 for this

disable_plaintext_auth = yes # Allows plaintext authentication only when SSL/TLS is used first.
ssl = required # v1.2+ only. Requires SSL/TLS also for non-plaintext authentication. 

ssl_cert_file = /etc/pki/tls/certs/mail.crt
ssl_key_file = /etc/pki/tls/private/mail.key
Testing Dovecot setup:
openssl s_client -tls1 -crlf -connect mail.domain.com:993

STARTTLS

Securing Postfix
/etc/postfix/master.cf
smtp      inet  n       -       n       -       -       smtpd
#submission inet n       -       n       -       -       smtpd
As described previously, we can use an existing port with STARTTLS. Since we are using the usual smtp service, we need to punch a hole in our firewall for port 25. One other option is to use the submission service on port 587 to bypass ISP blocks.
/etc/postfix/main.cf
smtpd_tls_cert_file = /etc/pki/tls/certs/mail.crt
smtpd_tls_key_file = /etc/pki/tls/private/mail.key
smtpd_tls_CAfile = /etc/pki/tls/certs/ca.crt
smtpd_tls_loglevel = 1
smtpd_tls_received_header = no
smtpd_tls_security_level = encrypt # This setting requires STARTTLS
smtpd_tls_auth_only = yes
smtpd_tls_session_cache_timeout = 3600s
If you are using a Postfix version older than v2.3, see smtpd_enforce_tls flag.

Testing
openssl s_client -starttls smtp -crlf -connect mail.domain.com:25
Securing Dovecot
/etc/dovecot.conf
protocols = imap # No need for a separate port. We will stick with port 143.

disable_plaintext_auth = yes # Allows plaintext authentication only when SSL/TLS is used first.
ssl = required # v1.2+ only. Requires SSL/TLS also for non-plaintext authentication. 

ssl_cert_file = /etc/pki/tls/certs/mail.crt
ssl_key_file = /etc/pki/tls/private/mail.key
Testing Dovecot setup:
openssl s_client -starttls imap -crlf -connect mail.domain.com:143

Comments

Popular posts from this blog

Securing Symfony2 REST services with FOSOAuthServerBundle

Overview In my previous article, I wrote about setting up a Symfony2 REST service using FOSRestBundle. However, this REST service was behind a firewall protected by a generic form_login provider. Not really ideal if you wish to open your REST API to other applications. So in this article, I will try to explain how to set up FOSOAuthServerBundle to protect your REST API methods using OAuth2. Before we start getting into the gritty details, it is a good idea to have a look at the official OAuth2 documentation . Let's begin... FOSOAuthServerBundle Installation You have to install v1.1.0 of FOSOAuthServerBundle if you are using Symfony 2.0.x. If not, see the docs . First, add the following entries to your deps file: [FOSOAuthServerBundle] git=git://github.com/FriendsOfSymfony/FOSOAuthServerBundle.git target=bundles/FOS/OAuthServerBundle version=origin/1.1.x [oauth2-php] git=git://github.com/FriendsOfSymfony/oauth2-php.git Run the vendors script to install these...

Adding post-login logic to FOSUserBundle

Having finally figured out how to use FOSUserBundle in my project, I decided to keep track of all logins next. The implementation turned out to be a breeze thanks to Symfony2's security listener mechanism. As usual, the first step is to create a MongoDB document for this purpose. This is a very simple document that contains a user's id, session id, IP address, and login date. src/Acme/UserBundle/Document/LoginHistory.php namespace Acme\UserBundle\Document; class LoginHistory { protected $id; protected $userId; protected $sessionId; protected $ip; protected $createdAt; /** * Get id * * @return custom_id $id */ public function getId() { return $this->id; } /** * Set userId * * @param int $userId */ public function setUserId($userId) { $this->userId = $userId; } /** * Get userId * * @return int $userId */ public function getUserId...

Setting up a Symfony2 REST service with FOSRestBundle

Installation First thing is to download and setup the FOSRestBundle. If you are running Symfony 2.0.x, get the FOSRestBundle version 0.6, otherwise, download the code in the master branch. The FOSRestBundle depends on the JMSSerializerBundle so the following instructions are going to include some extra information for setting up this bundle to complete our REST service. First thing is to install our dependencies. Add the following to your deps file: [metadata] git=http://github.com/schmittjoh/metadata.git version=1.1.0 [JMSSerializerBundle] git=git://github.com/schmittjoh/JMSSerializerBundle.git target=bundles/JMS/SerializerBundle [FOSRest] git=git://github.com/FriendsOfSymfony/FOSRest.git target=fos/FOS/Rest [FOSRestBundle] git=git://github.com/FriendsOfSymfony/FOSRestBundle.git target=bundles/FOS/RestBundle version=origin/0.6 Run the vendors script to install these bundles: php bin/vendors install Next, update your app/autoload.php file...