Postfix

From Segfault
Jump to navigation Jump to search

Installation

We want to enable ClamAV and Spamassassin scanning, but without AMaViS inbetween:

 # apt-get install postfix spamassassin spamc clamav-daemon clamsmtp

ClamSMTP is needed as a proxy between the MTA and clamd. Although clamd can listen on a network socket, postfix cannot talk directly to it.

Configuration

This is basically explained here, here's the short version again, with snippets from the configuration files:

master.cf

 # ClamSMTPd
 smtp      inet  n       -       -       -       -       smtpd
       -o content_filter=scan:127.0.0.1:10025
 [...]
 
 # Maildrop
 maildrop  unix  -       n       n       -       -       pipe
 flags=DRhu argv=/usr/bin/maildrop -d ${recipient}
 
 # SpamAssassin
 spamassassin unix -     n       n       -       -       pipe
       user=mail argv=/usr/bin/spamc -u ${user} -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
 
 # ClamAV
 scan    unix    -       -       n       -       16      smtp
       -o smtp_send_xforward_command=yes
 
 127.0.0.1:10026 inet n  -       n       -       16      smtpd
       -o content_filter=spamassassin
       -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
       -o smtpd_helo_restrictions=
       -o smtpd_client_restrictions=
       -o smtpd_sender_restrictions=
       -o smtpd_recipient_restrictions=permit_mynetworks,reject
       -o mynetworks_style=host
       -o smtpd_authorized_xforward_hosts=127.0.0.0/8

Note: somehow it's important that the spamassassin filter has a user= option, otherwise we might get errors like:

 postfix/pipe[9911]: fatal: missing user= command-line attribute
 postfix/qmgr[9876]: warning: private/spamassassin socket: malformed response
 postfix/qmgr[9876]: warning: transport spamassassin failure -- see a previous warning/fatal/panic
                     logfile record for the problem description
 postfix/master[9874]: warning: process /usr/lib/postfix/pipe pid 9911 exit status 1
 postfix/master[9874]: warning: /usr/lib/postfix/pipe: bad command startup -- throttling
 postfix/error[9922]: DD05E3DD5C: to=<bob@localhost>, relay=none, delay=1.1, delays=0.07/1/0/0.05,
                      dsn=4.3.0, status=deferred (unknown mail transport error

main.cf

A few basic configuration parameters[1]:

[...]
home_mailbox = Maildir/
mailbox_command = /usr/bin/maildrop -d ${USER}
maildrop_destination_recipient_limit = 1
mailbox_size_limit = 0
message_size_limit[2] = 0

smtpd_tls_cert_file=/etc/ssl/private/server.crt
smtpd_tls_key_file=/etc/ssl/private/server.key
smtp_tls_security_level[3] = may
 
mydestination = mail.example.com, mail, localhost, 127.0.0.1
mynetworks = 127.0.0.0/8 10.0.0.0/24 [::ffff:127.0.0.0]/104 [::1]/128

Postfix settings can be queried (and modified) via postconf:

$ postconf inet_protocols
inet_protocols = ipv4

$ postconf inet_protocols="ipv4 ipv6"
$ service postfix restart

clamsmtpd.conf

 OutAddress: 10026
 Listen: 127.0.0.1:10025
 ClamAddress: /var/run/clamav/clamd.ctl
 TempDirectory: /var/spool/clamsmtp
 Action: pass

Note: setting TempDirectory is important too, otherwise clamsmtpd may not be able to access TMPDIR, which may be set in root's environment and will produce errors like:

 clamsmtpd: 100058: clamav error: /var/spool/clamsmtp/clamsmtpd.1Lp6Vz: Can't create temporary directory ERROR
 clamsmtpd: 100058: from=alice@example.com, 
                    to=bob@localhost, status=CLAMAV-ERROR
 postfix/smtp[16155]: E563C11E89: to=<bob@localhost>, relay=127.0.0.1[127.0.0.1]:10025, delay=0.08,
                      delays=0.03/0/0.04/0, dsn=4.0.0, status=deferred (host 127.0.0.1[127.0.0.1]
                      said: 451 Local Error (in reply to end of DATA command))

While we're at it, we might want to set "LocalSocketMode 0660" in /etc/clamav/clamd.conf to restrict permissions to the control socket. Be sure to make clamav (i.e. the group "clamd" is running under) the primary group of clamsmtp:

$ usermod -g clamav -G clamsmtp clamsmtp
$ service clamsmtp restart

$ ps -e -o pid,user,group,euser,egroup,comm | grep cla[m]
10103 clamav   clamav   clamav   clamav   clamd
10396 clamsmtp clamav   clamsmtp clamav   clamsmtpd

For added security, disable the login shell for the system users:

for i in postfix clamav clamsmtp mail; do echo $i; chsh -s /bin/false $i; done

TODO: When clamsmtp is scanning, it sets the following variables, which can be used by VirusAction afterwards:

 RECIPIENTS
 SENDER
 VIRUS
 SERVER
 CLIENT
 REMOTE

I'm still looking for a way to pass these variables to maildrop...

DKIM

As OpenDKIM development seems to have stalled, we'll use dkimpy-milter now.

We need to generate some keys:

dknewkey --ktype rsa     key0
dknewkey --ktype ed25519 key1

This should have produced:

$ ls -go key*
-rw------- 1  420 Jul 12 22:47 key0.dns
-rw------- 1 1675 Jul 12 22:47 key0.key
-rw------- 1   66 Jul 12 22:47 key1.dns
-rw------- 1   44 Jul 12 22:47 key1.key

Note: if opendkim were installed, RSA key generation would look like this:

$ opendkim-genkey --bits=2048 --hash-algorithms=sha256 --domain=example.net --selector=key0

But opendkim-genkey is not able to generate Ed25519, so this could be done manually:[4]

$ openssl genpkey -algorithm ed25519 -out key1.private
$ openssl pkey -in key1.private -pubout -out key1.txt

$ ls -go key*
-rw------- 1 1679 Jul 12 22:36 key0.private
-rw------- 1  501 Jul 12 22:36 key0.txt
-rw------- 1  119 Jul 12 22:35 key1.private
-rw------- 1  113 Jul 12 22:35 key1.txt

While key0.txt already contains the DNS record needed, we'll need to manually construct the same for the Ed25519 key:

$ openssl asn1parse -in key1.txt -offset 12 -noout -out /dev/stdout | openssl base64 | sed 's/^/key1._domainkey IN TXT ( "v=DKIM1; k=ed25519; p=/;s/$/")/'
key0._domainkey IN TXT ( "v=DKIM1; k=ed25519; p=U12Vr3xzvXBjzNErIk5CRQxS3NniRxCWocrjnmZWNCs=")

Once the TXT records have been published in DNS, dkimpy-milter itself can be configured:

$ grep ^[A-Z] /etc/dkimpy-milter/dkimpy-milter.conf 
Syslog                  yes
UMask                   007

Domain                  example.net

KeyFile                 /etc/dkimkeys/key0.private
Selector                key0

KeyFileEd25519          /etc/dkimkeys/key1.private
SelectorEd25519         key1

Canonicalization        relaxed/relaxed
Mode                    sv
Socket                  inet:8892@localhost
PidFile                 /run/dkimpy-milter/dkimpy-milter.pid
UserID                  dkimpy-milter
SyslogSuccess           yes

With dkimpy-milter running on localhost:8892 now, we can configure Postfix to use it:

smtpd_milters                   = inet:localhost:8892
non_smtpd_milters               = inet:localhost:8892
# smtpd_milters                 = unix:private/opendkim
# non_smtpd_milters             = unix:private/opendkim
milter_default_action           = tempfail

We'll use milter_default_action with:

tempfail - Reject all further commands in this session with a temporary status code.

DMARC

SPF

TBD

Troubleshooting

Sometimes postfix is running, but its transports (spam engines, virus scanners) or its destinations (/home not mounted to deliver mails) are still missing. Nasty error messages are generated:

 postfix/master[21760]: daemon started -- version 2.5.5, configuration /etc/postfix
 postfix/qmgr[21763]: 4B63511EA5: from=<alice@example.com>, size=7763, nrcpt=1 (queue active)
 postfix/qmgr[21763]: warning: connect to transport spamassassin: Connection refused
 [...]
 postfix/error[21765]: 4B63511EA5: to=<bob@localhost>, relay=none, status=deferred (mail transport unavailable)

Often it's just a matter of requeueing the messages:

 postqueue -p                         # print mail queue (mailq)
 postsuper -r ALL                     # requeue all messages
 postqueue -f  or  postfix flush      # flush mail queue (exim -qff), should happen automatically[5]

Open Relay Tests

Once our MTA is configured, we should make sure that it's not an open relay. While this could be accomplished by telnet or netcat, we can use more modern tools as well,[6] like swaks:

$ swaks --to foo@example.org --from root@localhost --server mail.example.net
=== Trying mail.example.net:25...
=== Connected to mail.example.net.
<-  220 mail.example.net ESMTP Postfix
 -> EHLO localhost
<-  250-mail.example.net
<-  250-PIPELINING
<-  250-SIZE 10240000
<-  250-VRFY
<-  250-ETRN
<-  250-STARTTLS
<-  250-ENHANCEDSTATUSCODES
<-  250-8BITMIME
<-  250-DSN
<-  250-SMTPUTF8
<-  250 CHUNKING
 -> MAIL FROM:<root@localhost>
<-  250 2.1.0 Ok
 -> RCPT TO:<foo@example.org>
<** 454 4.7.1 <foo@example.org>: Relay access denied
 -> QUIT
<-  221 2.0.0 Bye
=== Connection closed with remote host.

Links

References