Secure relaying for outgoing mail - Postfix with Dovecot SASL

October 31st, 2008

Update, January 2011: Many aspects have changed in Ubuntu 10.10 "Maverick Meerkat". It is now much simpler than as described in this article, because the Ubuntu server packages are designed to work together now.

This is Part 2 of four parts:


As we explained in the introduction of Part 1, we're migrating from a Postfix / Dovecot / CyrusSASL based system to one which uses Psotfix and Dovcot IMAP and Dovecot SASL. Under Suse 10.1, the Postfix version that shipped did not work with Dovecot SASL. The version which ships with Ubuntu 8.04 does, so we won't need to use Cyrus. Cyrus SASL isn't involved at all in our setup.

We'll also activate IMAP service with Dovecot in this part, but there's basically nothing to do for that. Dovecot starts serving IMAP correctly when it is turned on.

What is the purpose of SASL? Why do we need it?

We have mail users in offices, and also at home, and traveling. They may use laptops to send a message from any location in the world. These messages must route through our mail server. Our mail server must relay messages from our users. But if we create an open relay, that relays for everyone, spammer will detect it and exploit it, causing problems for us and a lot of other people also.

The solution is to use authenticated relaying. In this usage, the mail user agent (MUA) is configured to offer authentication before it attempts to relay. Relaying is forbidden before authentication, and is permitted after. The SMTP protocol has an AUTH command that allows the MUA to supply credentials. We must configure Postfix to process this type of transaction correctly.

But the difficulty is that Postfix has no concept of users or authentication. It must rely on some external source for this. In the Linux world, the PAM system is normally used to authenticate users in a flexible way. In networked systems, LDAP is used. But neither of these is exactly suited to MTA use. PAM is Linux-only, whereas Postfix can run on a wide range of operating systems, many of which do not have PAM. LDAP is a somewhat complex server to set up and it doesn't provide all the authentication data Postfix might use, such as a way to process client certificates. Therefore, the Simple Authentication and Security Layer (SASL) is used.

The original "standard" SASL server for Linux was Cyrus. Cyrus is still widely used but it is a large and complex system. Fortunately, Dovecot is a simpler system, provides a good IMAP server, and can now provide SASL service. We're using Dovecot.

This is what the final result will look like:

Please install a SVG plugin for your browser, or use Firefox to view this image.

Step 1: Install Dovecot

Very easy:

apt-get install dovecot

Step 2: Configure Dovecot to serve SASL so Postfix can do secure relaying

Find the auth default clause of the /etc/dovecot/dovecot.conf file. The default config file that comes with Dovecot has many notes and options, but is nearly correct the way it is. Change the auth default clause to be:

auth default {
  mechanisms = plain login

  # NOTE that this requires /etc/pam.d/dovecot to be configured
  # an alternative is to just use passdb passwd which will
  # then use the password file, or userdb passwd-file which 
  # specifies a plain text file directly
  passdb pam {
  }
  
  # at least one userdb must be specified
  userdb passwd {
  }

  # run as root, to be able to write into the Postfix spool directory
  user = root
  
  socket listen {
    client {
      path = /var/spool/postfix/private/dovecot-sasl-auth
      mode = 0660
      user = postfix
      group = postfix
    }
  }
}

Postfix SMTPD, and most of the other Postfix processes, normally run within a chroot environment. Using chroot provides some additional security, or at least protection against misconfigurations. Postfix' use of chroot came about as a reaction against Sendmail's numerous security problems. The Postfix designers decided to use small, isolated processes, and run them in chroot as non-root users to give them the minimum access possible, in contrast to Sendmail, which, at the time, had one very complex do-everything process which ran as root all the time. Therefore, SMTPD does not have access to file outside of /var/spool/postfix.
This means that if you put the Unix socket path for SASL somewhere outside of that directory, Postfix SMTPD will not be able to find it, and you will get errors from postfix/smtpd like warning: SASL: Connect to /path/not/in/chroot failed: No such file or directory, even though the file clearly exists, and smtpd will exit with fatal: no SASL authentication mechanisms. The solution is to make sure that the socket path is within SMTPD's chroot jail, normally /var/spool/postfix, and make sure that Postfix is configured to use a path relative to the jail, not to the root of the real filesystem.

The path specified in the client is the socket endpoint that Postfix will use to access SASL. Later on, we will make another change to require client SSL certificates, and this clause is where we would add that requirement. Passwords are great, but a client certificate provides another even stronger security layer.

Restart Dovecot and see that the auth socket is available:

sudo ls -l /var/spool/postfix/private/dovecot-sasl-auth
srw-rw---- 1 postfix postfix 0 2008-10-29 10:30 /var/spool/postfix/private/dovecot-sasl-auth

We see that there is a socket owned by postfix / postfix. The path is under the /var/spool/postfix directory, which becomes the root directory for SMTPD when it runs with chroot.

Step 3: Create a Postfix SMTPD for relaying that talks to Dovecot

Normally configuration of Postfix is done within the /etc/postfix/main.cf file. However, in our configuration, we are running three different instances of Postfix SMTPD:

  1. External SMTPD, listening on port 25, to receive incoming mail (configured in Part 1)
  2. Internal SMTPD, listening on Port 10026, for re-injected mail from Amavisd (configured in Part 1)
  3. Secure relaying SMTPD, on Port 10025, which we are configuring in this part

The first two SMTPDs don't do relaying and so don't need to use SASL. Therefore all the SASL related parameters will be specified as overrides in the /etc/postfix/master.cf file.

Make sure Postfix uses Dovecot for handling authentication. Add these lines to the end of /etc/postfix/master.cf to create a new SMTPD instance:

10025      inet  n       -       -       -       -       smtpd
           -o smtpd_sasl_type=dovecot
           -o smtpd_sasl_path=private/dovecot-sasl-auth
           -o smtp_sasl_auth_enable=no
           -o smtpd_sasl_auth_enable=yes
           -o smtpd_use_tls=no
           -o smtp_use_tls=no
           -o smtpd_tls_auth_only=no
           -o smtpd_sasl_security_options=noanonymous
           -o smtpd_recipient_restrictions=permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination
           -o smtpd_sasl_authenticated_header=yes
           -o broken_sasl_auth_clients=no

At this point, TLS is turned off. In the next part we will change this to use TLS, but for now, we'll skip the TLS and test that auth is working. The smtpd_sasl_path is set to the location of the socket endpoint from Dovecot. The path is relative to the chroot environment. smtpd_sasl_authenticated_header is specified. It's not necessary in this particular usage, because this SMTPD isn't going through a spam filter. In other configurations, where there is only one SMTPD running, it is necessary to use smtpd_sasl_authenticated_header to prevent authenticated mail from being spam checked. smtpd_sasl_type is set to dovecot to tell Postfix to use the Dovecot variation of SASL. There are slight differences between how Dovecot and Cyrus serve SASL, and Postfix needs to know which one to use.

Restart Postfix:

# /etc/init.d/postfix restart

It didn't work; in /var/log/mail.err there is:

Oct 24 17:58:30 cl-t145-020cl postfix/master[8268]: fatal: bind 0.0.0.0 port 10025: Address already in use

What is blocking it?

# netstat -l -e -p
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       User       Inode       PID/Program name
        tcp        0      0 localhost:10025         *:*                     LISTEN      root       850762      7237/perl

Using ps we see that PID 7237 is spampd, the Spam Proxy Daemon, which we are not using in this configuration. It shouldn't have been installed. Uninstall it:

apt-get remove spampd

and restart Postfix. You shouldn't have spampd installed, but this illustrates how to find which process is holding onto a port if you ever run into Address already in use errors. Restart again:

# /etc/init.d/postfix restart
 * Stopping Postfix Mail Transport Agent postfix                              [ OK ]
 * Starting Postfix Mail Transport Agent postfix

Step 4: Test authentication

Our configuration uses the PLAIN authentication method, which requires a Base64-encoded version of the username and password. Construct a string as follows:

\0 + username + \0 + password

and encode it with Base64. The easiest way to do that is using the base64password.jar utility (source code is included in the JAR file):

% java -jar base64password.jar username password
AHVzZXJuYW1lAHBhc3N3b3Jk

Now test with telnet:

telnet 70.38.78.37 10025
Trying 70.38.78.37...
Connected to 70.38.78.37.
Escape character is '^]'.
220 cl-t145-020cl.localdomain ESMTP Postfix (Ubuntu)
EHLO HOST
250-cl-t145-020cl.localdomain
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
AUTH PLAIN Abbbbbbbbbbbbbbbbb==
235 2.7.0 Authentication successful
quit
221 2.0.0 Bye
Connection closed by foreign host.

Then try it again with a wrong password:

AUTH PLAIN Accccccccccccccccc=
        535 5.7.8 Error: authentication failed:

where, of course, the passwords are the Base64 encoded strings generated using the tool above.

Dovecot is now providing authentication for Postfix over SASL.

Step 6: test relaying, both with and without authentication

The mail will indeed be in the mailbox. Try it with a recipient on another domain:

MAIL FROM: <joe@yahoo.com>
250 2.1.0 Ok
RCPT TO: <bill@microsoft.com>
        554 5.7.1 <bill@microsoft.com>: Relay access denied

This is important. It's not relaying. If we authenticate before sending, it should now relay:

> telnet 70.38.78.37 10025
Trying 70.38.78.37...
Connected to 70.38.78.37.
Escape character is '^]'.
220 chiralsoftware.net ESMTP Postfix (Ubuntu)
AUTH PLAIN Aaaaaaaaaaaaaaaaa==
235 2.7.0 Authentication successful
MAIL FROM: <eric@chiralsoftware.net>
250 2.1.0 Ok
RCPT TO: <bill@microsoft.com>
250 2.1.5 Ok
        QUIT

Relaying does work after authentication. That shows that relaying is active and it is secured through the Dovecot SASL interface. Note that I quit before sending anything, so I didn't actually generate a spam to bill@microsoft.com.

Conclusion

We have created an SMTPD instance which performs secure relaying by using SASL to authenticate with Dovecot. Next steps are to turn on TLS

Also, Dovecot is now serving IMAP correctly. Test this with a mail client.

Now we can go on to Part 3: secure IMAP and SMTP relaying with TLS for Dovecot and Postfix.