Wednesday, February 24, 2010

Setting up Postfix for SMTP Auth with the Dovecot SASL backend

SkyHi @ Wednesday, February 24, 2010
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.

Contents

   1. Setting up Postfix for SMTP Auth with the Dovecot SASL backend
         1. Assumptions
         2. Procedure
               1. Dovecot
               2. Postfix - configure SASL auth
               3. Testing basic SASL
               4. Postfix - Enable TLS for encryption
               5. Test that TLS is working as expected
               6. Enabling the submission port
         3. See also:
         4. References/External Links

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
      Toggle line numbers

      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.
      Toggle line numbers

      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
      Toggle line numbers

      # 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:

    *Using the Postfix LDA for delivery

References/External Links

    *http://www.postfix.org/SASL_README.html
    *http://wiki.dovecot.org/HowTo/PostfixAndDovecotSASL
    * http://wiki.dovecot.org/Debugging/Authentication
    * http://www.anchor.com.au/hosting/dedicated/Postfix-SASL-setup