Sunday, March 21, 2010

Postfix + Cyrus SASL + TLS

Setting up Postfix as a relay:

A. Postfix basic configuration:

1. You need to install Posftix and Cyrus for authentication (you definitely do not want an open relay).
#---
yum -y install \
postfix \
cyrus-sasl \
cyrus-sasl-lib \
cyrus-sasl-md5 \
cyrus-sasl-ntlm \
cyrus-sasl-plain
#---


1.1. If you want Postfix, remove sendmail.
#---
yum -y remove \
sendmail
#---


2. Edit your IPtables configuration file and add the following line (you will change it when we are done) to the file [/etc/sysconfig/iptables]:

-A INPUT -m state --state NEW -m tcp -p tcp --dport 25 --source 127.0.0.1 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 587 --source 127.0.0.1 -j ACCEPT


3. Restart Postfix and check if you can access it:
#---
service postfix restart
telnet 127.0.0.1 25
#---


3.1. You must become something like this:
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
220 note ESMTP Postfix


4. Configuring Postfix for relay:
#---
postconf -e 'smtpd_recipient_restrictions = permit_sasl_authenticated,permit_mynetworks,reject_unauth_destination'
service postfix reload
#---


4.1. This has the same effect as adding the parameter directly to [/etc/postfix/main.cf].

5. Set your relay host:
#---
postconf -e 'relayhost ='
postconf -e 'myhostname = <your mail server, such as mx.yourdomain.com>'
service postfix reload
#---


5.1. Check if you can send emails:

5.2. On the telnet prompt give the following commands, but on another terminal keep track of the file [/var/log/maillog]

5.2.1. Terminal A:
#---
tail -f /var/log/maillog
#---


5.2.2. Terminal B:
#---
telnet 127.0.0.1 25


EHLO localhost
MAIL FROM: root@localhost
RCPT TO: <some external valid email>
DATA
Subject:Test mail

Testing email relay
.
QUIT

#---

5.2.3. It should come something like this by Terminal A:
Mar 20 16:59:43 note postfix/smtpd[8705]: connect from localhost[127.0.0.1]
Mar 20 16:59:50 note postfix/smtpd[8705]: improper command pipelining after HELO from localhost[127.0.0.1]
Mar 20 16:59:50 note postfix/smtpd[8705]: 6694A6AB62: client=localhost[127.0.0.1]
Mar 20 16:59:50 note postfix/cleanup[8722]: 6694A6AB62: message-id=<20100320195950.6694A6AB62@localhost>
Mar 20 16:59:50 note postfix/qmgr[8691]: 6694A6AB62: from=<root@localhost.localdomain>, size=376, nrcpt=1 (queue active)
Mar 20 16:59:52 note postfix/smtpd[8705]: disconnect from localhost[127.0.0.1]
Mar 20 16:59:53 note postfix/smtp[8694]: 20C526AB51: to=<some external valid email>, relay=<external mail server>[<ip address>]:25, delay=1215, delays=1167/0.02/6.9/41, dsn=2.0.0, status=sent (250 2.0.0 OK 1269115192 10si2969636yxe.131)
Mar 20 16:59:53 note postfix/qmgr[8691]: 20C526AB51: removed


Your email wont be delivered if the destination server checks if you are an actual registered mail exchanger (mx entry of your domain). But you may get lucky (for instance, google accepted my emails, even though it threw them in the Spam box).

6. If everything worked until this point you need to setup authentication (remember until here you are an open relay, even though you blocked external incoming connections via IPtables).

B. Prepare Postfix for using TLS.

NOTE: Because this documentation is "education"-purposed only I will skip the proper TLS configuration (this means that I'm skipping the certificate generation step) but you can easily get further information at: http://www.postfix.org/TLS_README.html

#---
postconf -e 'smtpd_tls_cert_file = none' # no CA signed file
postconf -e 'smtpd_tls_loglevel = 1' # get at least handshake logging
service postfix restart
#---


C. Setting Cyrus up as its authentication server:

NOTE: You have basically two authentication options: internal authentication (using local users) or external authentication (using an additional user/password database). I will approach the 'shadow' (internal authentication) and 'sasldb' (Cyrus built-in external authentication database). You may customize for your own needs, like LDAP, SQL (MySQL for instance), etc. But that is not my concern here.

C.1. Using the internal authentication (local users):

1. This is the simplest method and pretty straight forward. So first you create a local test user:
#---
adduser -b /tmp -s /sbin/nologin -c "Cyrus SASL authentication test account" -p tst smtptst
#---


2. Set SASL tu use local authentication by editing [/etc/sysconfig/saslauthd] and setting the MECH variable to shadow:

...
MECH=shadow
...


3. Restart and test if it is working:
#---
service saslauthd restart
testsaslauthd -u smtptst -p tst -s smtp
#---


You should get:
0: OK "Success."

C.2. Using 'sasldb' to authenticate users:

1. First and MOST important step: setup PAM at [/etc/pam.d/smtp]
#---
cat > /etc/pam.d/smtp << __END__
#%PAM-1.0
auth required pam_permit.so
account required pam_permit.so
session required pam_permit.so
password required pam_permit.so
__END__
#---


2. Set Cyrus to use PAM by editing [/etc/sysconfig/saslauthd] and setting the MECH variable to pam:

...
MECH=pam
...


3. Set Cyrus to use sasldb:
#---
cat > /usr/lib/sasl2/smtpd.conf << __END__
pwcheck_method: auxprop
auxprop_plugin: sasldb
mech_list: plain login cram-md5 digest-md5 ntlm
__END__
#---


3.1. To add a user to sasldb:
#---
## this one is for domain specific
saslpasswd2 -c -u <your domain> smtptst2
## this is for internal services that also send emails
saslpasswd2 -c smtptst2
#---


NOTE: for testing purposes I assume that you set the password to 'tst'

3.2. Check if it was included:
#---
sasldblistusers2 ## password will be substituted by the 'userPassword' string
#---


3.3. Set the right permissions:
#---
chmod 640 /etc/sasldb2
chown root:mail /etc/sasldb2
#---


4. Restart and test if it is working:
#---
service saslauthd restart
testsaslauthd -u smtptst2 -p tst -s smtp
#---


You should get:
0: OK "Success."

D. Setting Postfix up to enforce authentication using TLS through SASL:
#---
postconf -e 'myhostname = localhost' ## change for your actual hostname
postconf -e 'smtpd_client_restrictions = permit_sasl_authenticated,reject' ## some protection
postconf -e 'smtpd_sasl_type = cyrus' ## just be explicit about this
postconf -e 'smtpd_sasl_path = smtpd' ## just be explicit about this
postconf -e 'smtpd_sasl_auth_enable = yes' ## use authentication
postconf -e 'smtpd_sasl_authenticated_header = yes'
postconf -e 'smtpd_sasl_security_options = noanonymous' ## enforce authentication
postconf -e 'smtpd_sasl_tls_security_options = $smtpd_sasl_security_options'
postconf -e 'broken_sasl_auth_clients = yes' ## for Outlook
service postfix restart
#---


1. Testing everything together:
#---
telnet localhost 25
#---


1.1. Type:
EHLO localhost
AUTH LOGIN


Then enter the full qualified username encoded in base64:

1.1.1. Internal user:
#---
perl -MMIME::Base64 -e 'print encode_base64("smtptst\@localhost")'
#---


1.1.2. SASLDB user:
#---
perl -MMIME::Base64 -e 'print encode_base64("smtptst2\@localhost")'
#---


Then enter the password encoded in base64:
#---
perl -MMIME::Base64 -e 'print encode_base64("tst")'
#---


Then follow as usual:

MAIL FROM: smtptst@localhost
RCPT TO: <some external valid email>
DATA
Subject:Test mail

Testing email relay
.
QUIT


#---

1.2. It all should look like this:

telnet 0 25
Trying 0.0.0.0...
Connected to 0.
Escape character is '^]'.
220 localhost ESMTP Postfix
EHLO tst
250-localhost
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH NTLM PLAIN CRAM-MD5 DIGEST-MD5 LOGIN
250-AUTH=NTLM PLAIN CRAM-MD5 DIGEST-MD5 LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
AUTH LOGIN
334 VXNlcm5hbWU6
bXh1c2VyQGxvY2FsaG9zdA==
334 UGFzc3dvcmQ6
dHN0
235 2.7.0 Authentication successful
MAIL FROM: smtptst@localhost
250 2.1.0 Ok
RCPT TO: <some external valid email>
250 2.1.5 Ok
DATA
Subject:Test mail

Testing email relay
.
QUIT

354 End data with <CR><LF>.<CR><LF>
250 2.0.0 Ok: queued as 0C4B861845
221 2.0.0 Bye
Connection closed by foreign host.


2. Cleaning up:
#---
userdel smtptst
saslpasswd2 -d smtptst2
#---


3. Opening IPTables up at [/etc/sysconfig/iptables]:
-A INPUT -m state --state NEW -m tcp -p tcp --dport 25 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 587 -j ACCEPT


Relevant configuration files:
SASL: /usr/lib/sasl2/smtpd.conf
SASL user mapping: /etc/postfix/sasl_passwd
Postfix: /etc/postfix/main.cf
IPtables: /etc/sysconfig/iptables


Relevant log files:
Security/authentication related: /var/log/secure
Mail: /var/log/maillog
General process: /var/log/messages

2 comments:

Anonymous said...

a guide with ldap sso
http://wiki.lepr-e.com/wiki/index.php/Ubuntu_Smtp_Server

Leo said...

Thank you very much, for sharing your knowledge.

With your instructions (D. Setting Postfix up to enforce authentication using TLS through SASL:) I finally able to enforce SMTP auth in my vps.

Thank you.