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...

Symfony 2 + DoctrineMongoDBBundle + FOSUserBundle Tutorial

It's been a while I have not added an entry to my blog. I have been busy playing with Symfony 2, MongoDB, and FOSUserBundle for a while now so here is a tutorial to integrate Symfony 2, MongoDB, and FOSUserBundle. Objectives * Install DoctrineMongoDBBundle * Install FOSUserBundle * Create user model ** Utilize groups ** Add additional properties to user model * Create customized registration form and handler At this point I am going to assume that you have a running Symfony 2 and MongoDB installation in place already and a basic understanding of how to configure Symfony 2 services. I will also exclude view related steps from this tutorial. Setting Up DoctrineMongoDBBundle Add the following to your deps file: [doctrine-mongodb] git=http://github.com/doctrine/mongodb.git [doctrine-mongodb-odm] git=http://github.com/doctrine/mongodb-odm.git [DoctrineMongoDBBundle] git=http://github.com/symfony/DoctrineMongoDBBundle.git target=/bundles/Symfony/Bundle/Doctrin...