Setting up Postfix for SMTP Auth with the Dovecot SASL backend

The Postfix MTA makes it easy to setup SMTP Auth so that remote users can relay mail out through your server. While the official documentation on this is very good, we're going to run through a streamlined version that covers what is arguably the simplest and the most popular deployment option using Dovecot for the SASL backend. Because we don't want login details being passed across the internet unprotected, we'll also enforce the use of encryption to create a secure tunnel.

This might look a bit long-winded, but it's actually very simple to setup. There's plenty of sample configuration and examples below to refer to.

Assumptions

  1. You're familiar with the mail technologies in use
  2. We're implementing SMTP Auth on a Redhat Enterprise Linux 5 system, but the steps are easily translated to other distros like Debian
    • We're using the stock set of vendor package repositories
  3. You have a fully-working Postfix installation that can send/receive mail to/from the internet
  4. You're already using Dovecot for authenticated POP/IMAP access. While it's not necessary, this is the easiest way to be sure your authentication backend will Just Work
    • By extension, we assume you've got a set of authentication credentials you can use for testing

Procedure

We'll start by enabling Dovecot's SASL service, then hook Postfix into this. Postfix will then offer SMTP Auth to remote clients, provided that they're using TLS for encryption.

Dovecot

Dovecot will create a daemon socket that will listen for SASL requests.

  1. On some distributions, the Postfix daemons run chroot'ed. For this reason, it's preferred to place the socket somewhere that's guaranteed to be accessible. Use the postconf command to find your queue directory - in most cases it'll be /var/spool/postfix

    yoshino:~# postconf queue_directory 
    queue_directory = /var/spool/postfix
  2. Edit /etc/dovecot.conf. You'll need to work around whatever existing authentication you have setup, but it'll look something like this.

    auth default {
        # We support `login` for Outlook clients that use this obsolete mechanism
        mechanisms = plain login
    
        # These are the default username/password backends
        passdb pam {
        }
        userdb passwd {
        }
    
        # These should be correct for most systems, adjust the path, user and group as appropriate
        socket listen {
            client {
                path = /var/spool/postfix/private/auth
                mode = 0660
                user = postfix
                group = postfix
            }
        }
    }
  3. Restart dovecot to create the auth socket
  4. Check that the socket has been created as expected. Check your mail logs and look for problems if you're unsure.

    yoshino:~# ls -lh /var/spool/postfix/private/auth
    srw-rw---- 1 postfix postfix 0 2009-09-27 00:36 /var/spool/postfix/private/auth

Postfix - configure SASL auth

Reference documentation: http://wiki.dovecot.org/HowTo/PostfixAndDovecotSASL

  1. As a quick sanity-check, make sure your postfix has been compiled with support for Dovecot's SASL implementation

    yoshino:~# postconf -a
    cyrus
    dovecot  <-- this is what we need
  2. Edit your main.cf (/etc/postfix/main.cf) file and add the SASL directives

    # Notice that we use a relative path to the auth socket
    # This will work regardless of whether the SMTP daemon is running chroot'ed,
    # and is specified relative to the queue_directory that we discovered earlier
    smtpd_sasl_type = dovecot
    smtpd_sasl_path = private/auth
    
    smtpd_sasl_auth_enable = yes
    
    # Adds a header that reports the login name that was used. Good for accountability, bad if you're paranoid
    smtpd_sasl_authenticated_header = yes
    
    # Support those broken Microsoft clients that expect "AUTH=<mechanisms>"
    broken_sasl_auth_clients = yes
    
    # Finally, give authenticated clients free reign to relay mail
    # You'll need to massage this into any existing restrictions you have
    # Assuming default settings, it'll look something like this
    smtpd_recipient_restrictions =
        permit_mynetworks
        permit_sasl_authenticated
        reject_unauth_destination
  3. Restart Postfix so the settings take effect

Testing basic SASL

  1. We need to generate a base64-encoded auth string to send during the SMTP session. Be aware that this gives away your username and password, we'll setup encrytion for this shortly. We're going to use support@anchor.net.au for the username, and securepassword for the password. The "\0" is intentional, they represent null bytes.

    • mimencode is in the metamail package on Debian-type systems

      yoshino:~# printf '\0support@anchor.net.au\0securepassword' | mimencode
      AHN1cHBvcnRAYW5jaG9yLm5ldC5hdQBzZWN1cmVwYXNzd29yZA==
    • You can use perl on Redhat-type systems, note that you need to escape the @-sign if you're using an email address as the username

      yoshino:~# perl -MMIME::Base64 -e 'print encode_base64("\0support\@anchor.net.au\0securepassword")'
      AHN1cHBvcnRAYW5jaG9yLm5ldC5hdQBzZWN1cmVwYXNzd29yZA==
  2. Connect to your Postfix, issue an EHLO (Extended HELO) and attempt to AUTH. It should look something like this

    rosa@rokkenjima:~% telnet yoshino.meidokon.net 25
    Trying 202.4.232.68...
    Connected to yoshino.meidokon.net.
    Escape character is '^]'.
    220 yoshino.meidokon.net ESMTP Postfix
    EHLO localhost
    250-yoshino.meidokon.net
    250-PIPELINING
    250-SIZE 20480000
    250-ETRN
    250-AUTH PLAIN LOGIN
    250-AUTH=PLAIN LOGIN
    250-ENHANCEDSTATUSCODES
    250-8BITMIME
    250 DSN
    AUTH PLAIN AHN1cHBvcnRAYW5jaG9yLm5ldC5hdQBzZWN1cmVwYXNzd29yZA==
    235 2.0.0 Authentication successful
    QUIT
    221 2.0.0 Bye
    Connection closed by foreign host.
  3. If you run into problems you'll need to have a look at your mail logs to get an idea of what's going wrong. Unfortunately it's difficult to enumerate all the possible failure cases here, but the Dovecot wiki has some good advice to start with: http://wiki.dovecot.org/Debugging/Authentication

To finalise the testing, we'll send a quick mail through the system. If you don't get a "Relay access denied" error then everything is in order. Make sure you run these tests from a remote host to ensure you're not getting a free pass from being on the local machine.

...
AUTH PLAIN AHN1cHBvcnRAYW5jaG9yLm5ldC5hdQBzZWN1cmVwYXNzd29yZA==
235 2.0.0 Authentication successful
MAIL FROM: support@anchor.net.au
250 2.1.0 Ok
RCPT TO: support@anchor.net.au
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
From: support@anchor.net.au
To: support@anchor.net.au
Subject: This is a test message

Hi, have a friendly test message.
Thanks!
.
250 2.0.0 Ok: queued as A463341E2C77
QUIT
221 2.0.0 Bye
Connection closed by foreign host.

If you inspect the received message, you can trace the path taken and confirm that everything is working as expected.

Return-Path: support@anchor.net.au
Delivered-To: support@anchor.net.au
Received: from gohda.rokkenjima.net (gohda.rokkenjima.net [202.4.224.0])
        (Authenticated sender: support@anchor.net.au)        <-- the result of "smtpd_sasl_authenticated_header = yes"
        by yoshino.meidokon.net (Postfix) with ESMTP id 0745141C09EC
        for <support@anchor.net.au>; Mon, 12 Oct 2009 12:51:42 +1100 (EST)
From: support@anchor.net.au
To: support@anchor.net.au
Subject: test mail
Message-Id: <20091012015145.0745141C09EC@yoshino.meidokon.net>
Date: Mon, 12 Oct 2009 12:51:42 +1100 (EST)

Hi, have a friendly test message.
Thanks!

Postfix - Enable TLS for encryption

This is well and good so far, but at the moment our login details are being passed around unencrypted, which leaves them vulnerable to being sniffed by any intermediate hosts. We'll generate an x509 certificate, have Postfix offer it to clients, then disable authentication for clients that aren't using TLS encryption.

  1. Generate an RSA key for the certificate. We keep our key/certificate pairs in /etc/ssl, but you can use anywhere that's convenient for you. We take care to ensure that the key is only readable by root.

    cd /etc/ssl
    touch smtpd.key
    chmod 600 smtpd.key
    openssl genrsa 1024 > smtpd.key
  2. Now you need a certificate that matches the key. In most cases you can get away with a self-signed certificate, though clients may complain that it's not signed by a recognised CA. The alternative is to generate a Certificate Signing Request and have it signed by a CA - this will cost you money.
    1. Self-signed certificate. Just a few questions to answer here, the most important is the Common Name (CN) - this is the hostname that clients will use to connect to you, often something like mail.mycompany.com.au

      openssl req -new -key smtpd.key -x509 -days 3650 -out smtpd.crt
    2. CA-signed, you're about to generate a CSR. Answer all the questions accurately, otherwise most CAs will fail to verify your identity

      openssl req -new -key smtpd.key -out smtpd.csr
      Once the signed certificate comes back you can drop that in next to the key.
  3. Edit your Postfix main.cf to enable TLS. These lines can be added to the bottom of the file

    # Offer TLS encryption to clients
    smtpd_tls_security_level = may
    
    # As specified earlier
    smtpd_tls_key_file = /etc/ssl/smtpd.key
    smtpd_tls_cert_file = /etc/ssl/smtpd.crt
    
    # Only offer SMTP AUTH when talking over an encrypted connection
    smtpd_tls_auth_only = yes
    
    # Add some useful logging entries to track the use of TLS, you can omit this if desired
    smtpd_tls_loglevel = 1
    
    # Add a header to mail received with TLS, can make debugging easier
    smtpd_tls_received_header = yes
  4. Restart Postfix and check the mail logs for any errors.

Test that TLS is working as expected

We'll open two connections, one with TLS and one without, to ensure we see what we expect.

  • Firstly without TLS

    rosa@rokkenjima:~% telnet yoshino.meidokon.net 25
    Trying 202.4.232.68...
    Connected to yoshino.meidokon.net.
    Escape character is '^]'.
    220 yoshino.meidokon.net ESMTP Postfix
    EHLO gohda.rokkenjima.net
    250-yoshino.meidokon.net
    250-PIPELINING
    250-SIZE 20480000
    250-ETRN
    250-AUTH PLAIN LOGIN
    250-AUTH=PLAIN LOGIN
    250-ENHANCEDSTATUSCODES
    250-8BITMIME
    250 DSN
    QUIT
    221 2.0.0 Bye
    Connection closed by foreign host.
    You'll notice that STARTTLS is now available, but AUTH is not offered.
  • Now with TLS, using openssl's client feature

    rosa@rokkenjima:~% openssl s_client -connect yoshino.meidokon.net:25 -starttls smtp
    CONNECTED(00000003)
    <lots of SSL output>
    
    EHLO gohda.rokkenjima.net
    250-yoshino.meidokon.net
    250-PIPELINING
    250-SIZE 10240000
    250-VRFY
    250-ETRN
    250-AUTH PLAIN LOGIN
    250-AUTH=PLAIN LOGIN
    250-ENHANCEDSTATUSCODES
    250-8BITMIME
    250 DSN
    
    QUIT
    DONE
    openssl handles the TLS for us, and AUTH is now available, as we saw during previous testing.

Enabling the submission port

Many ISPs block access to port 25, meaning that the above setup won't work for a lot of users. For this reason, port 587 is available, and is configured only for "outbound" relay access. You can do this easily in Postfix.

  1. Edit /etc/postfix/master.cf and enable the submission port by uncommenting a couple of lines. Make sure not to mess up the whitespace - a logical line is continued by whitespace on the subsequent lines.

    # We enforce the use of TLS, and override the client restrictions to only allow authenticated relaying
    submission inet n       -       -       -       -       smtpd
      -o smtpd_tls_security_level=encrypt
      -o smtpd_sasl_auth_enable=yes
      -o smtpd_client_restrictions=permit_sasl_authenticated,reject
  2. Restart Postfix and test the submission port

    rosa@rokkenjima:~% openssl s_client -connect yoshino.meidokon.net:587 -starttls smtp


See also:

References/External Links