Authenticated SMTP Submission (SMTP AUTH) with Postfix and saslauthdSo, you've got Postfix working and it's nice. Except for one little thing. Your users are roaming the earth with their laptops connecting to any old wifi hotspot or dormitory LAN. And they need to relay their outbound mail through your Postfix, securely. And half the places they plug into don't let them send anything on port 25. They need relay control based on knowing a secret, not on their IP address. And it can't be sent in the clear. You need to get SMTP AUTH working. There are, apparently, a gazillion really complicated ways to do it, and a bunch of howtos about those ways. Let's keep things simple. There are at least six ways the client can authenticate (prove its identity) to the server. The DIGEST-MD5 and CRAM-MD5 methods use encryption, so the password isn't exposed to an eavesdropper. But the messages themselves will still be exposed to anybody in the coffee shop who's got a tool like tcpdump. PLAIN and LOGIN send in the clear. If you allow those methods, or your users expect privacy, you'll have to protect the entire session with TLS. I'm using Debian-3.1 "Sarge" and 4.0 "Etch." I built Postfix-2.4 from source on Sarge because I wanted some new features. Postfix-2.3 on Etch is out-of-the-box. Part 1. SMTP AUTHMost of my users get shells and use SSH+SFTP. On GNU+Linux, those logins get authenticated through a set of subroutines called Pluggable Authentication Modules (PAM). Some users prefer RSA or DSA key-pairs instead of passwords, and the sshd handles those itself instead of consulting PAM. I don't want those credentials involved in sending mail. So I created some pairs of user names and passwords just for SMTP AUTH.The Postfix smtpd daemon knows how to do the SMTP part of SMTP AUTH. But it doesn't know anything about user passwords or PAM or Kerberos or RADIUS or any other authentication scheme. So the job of accepting or declining the user's credentials is outsourced to an saslauthd daemon. saslauthd knows how to use PAM. It knows how to look at /etc/passwd and /etc/shadow directly in case PAM isn't available. It knows how to look in a Berkeley DB file that nothing else on the system knows or cares about. That's what I'm using. And it can deal with credentials that were presented in clear text, or encoded in CRAM-MD5 or DIGEST-MD5. Clear text credentials might sound dangerous, but the whole SMTP session might be happening in a TLS or SSH tunnel, which would make them okay. Install the Cyrus Simple Authentication and Security Layer daemon: apt-get install sasl2-bin
The Debian package installs a file /etc/default/saslauthd which is a fragment of a shell script. The start-stop script /etc/init.d/saslauthd sources it to set some variables. Edit the file and uncomment the "START=yes" line. Also, change the MECHANISMS line to read MECHANISMS="sasldb". (Should you want to use your unix /etc/passwd and /etc/shadow files via PAM, instead of SASL-only credentials, it's MECHANISMS="pam".) Postfix needs to be in saslauthd's group or it can't talk to it. adduser postfix sasl And in Etch, Postfix runs chrooted in /var/spool/postfix, which means saslauthd needs to run in there too or Postfix can't see saslauthd's socket. This is mentioned in a comment in /etc/default/saslauthd, and in /usr/share/doc/sasl2-bin/README.Debian but they don't really tell you what's going on. mkdir -p
/var/spool/postfix/var/run/saslauthd
dpkg-statoverride --add root sasl 710 /var/spool/postfix/var/run/saslauthd Now it is time to create a credential for sending mail. In SASL, that's a domain name, which is known as a "realm," a user name, and a password. Let's say example.net, joeblow, and TheSecret. saslpasswd2 -c -u example.net joeblow
You'll be prompted for that password. This will cause a file /etc/sasl2db to appear. Tell your user joeblow that his login name for the SMTP server is joeblow@example.net. I suppose this looks like an email address so you can make it the same as his address and there's less to remember. Now, Postfix. Create a directory sasl in your postfix configuration directory, probably /etc/postfix. Create a file in there called smtpd.conf. Its contents are pwcheck_method:
saslauthd
mech_list: digest-md5 cram-md5 Now edit your master.cf file. This file tells the master postfix daemon what daemons to run, whether to chroot them, and what arguments to give them. Each line begins in column 1 with a word which could be a port number, or the name of that port number in the file /etc/services, or something you defined in main.cf. The SMTP daemon we will use to accept mail for relaying is called a submission daemon, and generally belongs on port 587. I added this "line" to master.cf: submission inet
n
-
n
-
- smtpd
-o smtpd_sasl_auth_enable=yes -o smtpd_sasl_security_options=noanonymous -o smtpd_sasl_local_domain=myhost.example.org -o header_checks= -o body_checks= -o smtpd_client_restrictions=permit_sasl_authenticated,reject_unauth_destination -o smtpd_sasl_security_options=noanonymous,noplaintext -o smtpd_sasl_tls_security_options=noanonymous The last two options define a policy where you'll only accept the encrypted authentications options unless the whole session uses TLS. That gives your users the choice of encrypting the session or not. If you're sure they all have modern TLS-capable clients, force them to use TLS with this: -o smtpd_tls_auth_only
Leading space in master.cf means the previous line continues. This says to run an instance of Postfix smtpd listening to port 587, and don't chroot it. It will start with the many compiled-in Postfix configuration defaults, then read any which apply to smtpd from main.cf, and then read the options given here. Notice there are no spaces around the equals signs. Notice I had to override the header and body checks. I've got about a hundred regular expressions that stop a lot of junk before it gets to amavis-new. I don't want outbound mail checked against those regexes. Now start saslauthd and restart Postfix /etc/init.d/saslauthd start
postfix reload And check your new submission daemon to see what it offers. $
telnet myhost.example.net submission
Trying 192.168.220.136... Connected to myhost.example.net. Escape character is '^]'. 220 myhost.example.net ESMTP Postfix ehlo myclient.example.net 250-myhost.example.net 250-PIPELINING 250-SIZE 10000000 250-ETRN 250-AUTH NTLM LOGIN PLAIN DIGEST-MD5 CRAM-MD5 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN quit 221 2.0.0 Bye Connection closed by foreign host. $ Now open your email client and set up an outbound SMTP server that requires DIGEST-MD5 authentication. Give it the user@realm and password in the sasl2db file. Try sending through it. Tail your postfix log while you're doing that. On Debian that's tail -f /var/log/mail.log
mm Part 2. Transport Layer Security TLSFirst you need a Certificate from an Authority. If you're an ISP, you need to buy one from a company who has managed to get its Root Certificate compiled into popular clients like Apple Mail and Outlook Express. If you're just a do-it-yourselfer, you can be your own Certificate Authority and sign your own postfix Certificate. The clients will complain (with scary popups) to your users until they figure out how to import your Certificate into their clients.Here is how I make a self-signed Root Certificate. You will need a secret passphrase. Write it down. Be able to type it twice without looking. This recipe is from The Book of Postfix, except they generate their certs in /usr/local/ssl/misc and I do it in root's home directory. Root's a user and I back him up. mkdir /root/ssl
cd /root/ssl locate CA.pl /usr/lib/ssl/misc/CA.pl -newca (answer the questions)
chmod go-rw demoCA/private/cakey.pem That creates a directory /root/ssl/demoCA containing cacert.pem and private/cakey.pem. Make sure nobody but root can read cakey.pem. Now that you have a self-signed Root Certificate, you can generate a postfix certificate from it. openssl req -new -nodes -keyout
postfix_private_key.pem \
-out postfix_private_key.pem -days 3650 and answer the questions. That creates a file postfix_private_key.pem. Finally we need to sign it. You'll need that passphrase to validate your self-signed root cert: openssl ca -policy policy_anything
-out postfix_public_cert.pem \
-infiles postfix_private_key.pem and you answer the questions. You'll need the passphrase you entered for your self-signed root cert. That causes postfix_public_cert.pem to appear. Now make a directory and copy them there. chmod go-rw postfix_private_key.pem
mkdir /etc/postfix/certs cp -p demoCA/private/cakey.pem /etc/postfix/certs cp -p demoCA/cacert.pem /etc/postfix/certs cp -p postfix_private_key.pem postfix_public_cert.pem /etc/postfix/certs Now all the certificate files are in one place. The next step is to verify that your Postfix installation was built with TLS. If it was, then postconf -d | grep tls
will show about 92 defaults with tls in their names. If it was built with TLS, you're ready to configure Postfix. (If not, you have to either find the version that was, in your GNU+X+Linux distribution, or compile a brand new Postfix from source code. That's not very hard, because Postfix is a very well written work. You can do it from the instructions that come with it.) Edit master.cf and add an option to that submission line. -o smtpd_use_tls=yes And edit main.cf, telling Postfix where the certs are. smtpd_tls_key_file =
/etc/postfix/certs/postfix_private_key.pem
smtpd_tls_cert_file = /etc/postfix/certs/postfix_public_cert.pem /* is this true? But that's not enough. You need a collection of Certificate Authority Certificates so Postfix will be able to verify the certs presented by the clients. Your operating system distribution probably came with Apache with mod_ssl, and for that to work it needs a CA cert collection. Debian packages that collection separately. So we'll use that. Not only will it save you the trouble of collecting them yourself, but it will update them as long as your release's security support lasts. apt-get install ca-certificates
Debian's installer will ask whether you want to trust all of them, or none, or some. The answer to that is outside the scope of these notes. Now you should have a bunch of .crt and .pem files in /usr/share/ca-certificates and some symlinks in /etc/ssl/certs pointing at them. */ Tell Postfix where to find that self-signed root cert, and where to look for more if it's not enough. While you're at it, tell it what device node to read random numbers from. Edit main.cf and add this: smtpd_tls_CAfile = /root/ssl/cacert.pem
smtpd_tls_CApath = /etc/ssl/certs tls_random_source = /dev/urandom To verify that random generator works do this shell command: dd if=/dev/urandom count=1 | od -x
You should get three lines of chatter from dd, and 32 lines of random hex numbers, and no errors. At this point certs are ready so add this option to the submission line in master.cf. -o smtpd_use_tls=yes Restart Postfix and test. Part 3. Things you should already have taken care of in Postfix.You're not an open relay, because your smtpd_mumble_restrictions begins with permit_mynetworks and ends with reject. Right?You figured out why the postmaster address gets spam you would have blocked for any other user, right? It's in the source code. grep -n -B1 -A5 'XX 2821'
src/smtpd/smtpd_check.c
It's otherwise not explicitly
documented. It was implicitly documented by the statement that
Postfix complies with RFC2821. That RFC defines two special
recipients: postmaster@example.net
and <>.
You're required to accept email for those, and Postfix enforces that
whether you like it or not. |
||