Amavisd-new, ClamAV and SpamAssassin

/!\ THIS IS A DRAFT ONLY, FOR USE BY DOCUMENTATION WRITERS AND EDITORS. DO NOT RELY ON IT FOR ANY ADVICE UNTIL THIS NOTICE DISAPPEARS AND THE DOCUMENT IS PUBLISHED AS FINAL.

1. Introduction

Amavisd-new is a reliable high-performance interface between an email server (MTA) and content checkers such as virus scanners (ClamAV), and/or SpamAssassin. Amavisd-new supports both (E)SMTP and LMTP protocols as well as UNIX sockets for communicating with the MTA and content checkers. In addition, it may also use dedicated helper programs such as the Mail::SpamAssassin Perl module.

Amavisd-new supports a number of MTA's. As the Amavisd-new documentation states, Amavisd-new works "best with Postfix, fine with dual-sendmail setup and Exim v4, works with sendmail/milter, or with any MTA as a SMTP relay". This guide was written and tested on Postfix and can be used to compliment the basic Postfix guide here. Other MTA's may get added later.

We are going to configure Amavisd-new's daemon, amavisd, to accept mail from our MTA, pass it to ClamAV and SpamAssassin for checking, and then return it back to our MTA for delivery. Amavisd will use lmtp listening on TCP port 10024 to accept mail from our MTA and then pass it to ClamAV using a local UNIX socket and SpamAssassin using the Mail::SpamAssassin Perl module. Scanned mail will then be returned to our MTA using smtp on TCP port 10025 for delivery.

Amavisd-new doesn't have to reside on the same physical server as the MTA, and in high load environments it is not uncommon to have Amavisd-new, ClamAV and SpamAssassin on a physically separate server than the MTA.

2. Installation

Amavisd-new and ClamAV were installed from the RPMForge repository. To enable the RPMForge repository, please see the RPMForge instructions.

SpamAssassin is part of the CentOS base repository, but RPMForge carries a more current version of it. You should consider using the version from RPMForge. To do so (especially if you use the priorities plugin for yum), add the following to the [base] and the [updates] sections of your /etc/yum.repos.d/CentOS-Base.repo file:

[base]
exclude=spamassass*
...
[updates]
exclude=spamassass*
...

First, install amavisd-new, clamav and spamassassin:

yum install amavisd-new clamav clamd spamassassin

This will likely also install a bunch of dependencies including various perl modules and archive packages. If all went well, two new users, amavis and clamav should have been installed onto the system:

# cat /etc/passwd | grep "amavis\|clamav"
clamav:x:101:102:Clam Anti Virus Checker:/var/clamav:/sbin/nologin
amavis:x:102:103:Amavis email scan user:/var/amavis:/bin/sh

In addition, the clamav user should automatically have been added to the amavis group:

# groups clamav
clamav : clamav amavis

If not, you can manually add clamav to the amavis group:

gpasswd -a clamav amavis

Finally, three new services should have been added to the system

# chkconfig --list | grep "amavisd\|clamd\|spamassassin"
amavisd         0:off   1:off   2:on    3:on    4:on    5:on    6:off
clamd           0:off   1:off   2:on    3:on    4:on    5:on    6:off
spamassassin    0:off   1:off   2:off   3:off   4:off   5:off   6:off

The spamassassin service, which starts spamd, can be set to off as Amavisd-new doesn't actually use the spamassassin daemon (spamd) but rather loads spamassassin as a module.

3. Configuration

SpamAssassin actually requires no special configuration to work with Amavisd-new and will work out of the box. This does not mean that you cannot configure it via /etc/mail/spamassassin/local.cf, or your own cf-files in that directory.

3.1. ClamAV

ClamAV's configuration is stored in /etc/clamd.conf. We must edit /etc/clamd.conf to tell ClamAV that Amavisd-new will communicate using a local UNIX socket rather than a tcp socket, and where to find that socket. Edit the LocalSocket setting and comment out the TCPSocket like so:

### /etc/clamd.conf
#
# Set the LocalSocket for clam
# Note this *MUST* match that set in /etc/amavisd.conf
#
LocalSocket /var/run/clamav/clamd
#
# Comment out the TCPSocket setting:
# TCPSocket 3310

3.2. Amavisd-new

Amavisd-new keeps it's configuration settings in /etc/amavisd.conf.

Due to the power and flexibility of Amavisd-new, there is actually quite a lot to look at, so we'll cover some of the more important settings a few at a time.

First up, we can disable either virus or spam checking by uncommenting the following lines (by default, both virus and spam checking is enabled as the lines are commented out):

### /etc/amavisd.conf:
#
# To disable virus or spam checks, uncomment the following:
#
# @bypass_virus_checks_maps = (1);  # controls running of anti-virus code
# @bypass_spam_checks_maps  = (1);  # controls running of anti-spam code
# $bypass_decode_parts = 1;         # controls running of decoders & dearchivers

Next, note to following lines although no change is required:

$max_servers = 2;                   # num of pre-forked children (2..30 is common), -m
$daemon_user  = "amavis";           # (no default;  customary: vscan or amavis), -u
$daemon_group = "amavis";           # (no default;  customary: vscan or amavis), -g
...
$inet_socket_port = 10024;          # listen on this local TCP port(s)
...
# $notify_method  = 'smtp:[127.0.0.1]:10025';
# $forward_method = 'smtp:[127.0.0.1]:10025';  # set to undef with milter!

$max_servers sets the number of concurrent Amavisd-new processes and must match the number set in /etc/postfix/master.cf "maxproc" column for the amavisfeed service (see configuration of Postfix below).

$daemon_user and $daemon_group should match the user and group, respectively, under which Amavisd-new will run.

$inet_socket_port defines the tcp port over which Amavisd-new will accept connections from Postfix.

$notify_method and $forward_method define the reinjection path of mail from Amavisd-new back into Postfix.

The following settings must be edited (in the case of $mydomain and $myhostname) and uncommented (remove the leading #):

$mydomain = 'example.com';                  # Edit: a convenient default for other settings
$MYHOME = '/var/amavis';                    # Uncomment: a convenient default for other settings, -H
$helpers_home = "$MYHOME/var";              # Uncomment: working directory for SpamAssassin, -S
$lock_file = "$MYHOME/var/amavisd.lock";    # Uncomment, -L
$pid_file  = "$MYHOME/var/amavisd.pid";     # Uncomment, -P
$myhostname = 'mail.example.com';           # Uncomment & Edit: must be a fully-qualified domain name!

Next up are some SpamAssassin settings which override the default SpamAssassin settings:

$sa_tag_level_deflt  = 2.0;                 # add spam info headers if at, or above that level
$sa_tag2_level_deflt = 6.2;                 # add 'spam detected' headers at that level
$sa_kill_level_deflt = 6.9;                 # triggers spam evasive actions (e.g. blocks mail)
$sa_dsn_cutoff_level = 10;                  # spam level beyond which a DSN is not sent
# $sa_quarantine_cutoff_level = 25;         # spam level beyond which quarantine is off
$penpals_bonus_score = 8;                   # (no effect without a @storage_sql_dsn database)
$penpals_threshold_high = $sa_kill_level_deflt;         # don't waste time on hi spam
$sa_mail_body_size_limit = 400*1024;        # don't waste time on SA if mail is larger
$sa_local_tests_only = 0;                   # only tests which do not require internet access?

None of these need to be changed, but it's worthwhile being aware of them as this is the most convenient place to tweak spam thresholds.

$sa_tag_level_deflt is the level at which Amavisd-new will write spam info headers such as X-Spam-Flag, X-Spam-Score and X-Spam-Status. If you would always like header info to be written to all messages, set this value to -999.

$sa_tag2_level_deflt sets the level at which spam is tagged in the subject line of the message.

$sa_kill_level_deflt sets the level at which Amavisd-new will block the message and quarantine it. This is useful as SpamAssassin doesn't do this by default.

$sa_dsn_cutoff_level is the level at which delivery failure notices are no longer sent to the sender. As most spam sender addresses are forged anyway, it makes sense not to send failure notices in response to obvious spam as you're only contributing to the problem of backscatter.

$sa_quarantine_cutoff_level is the level at which spam isn't even quarantined. By default it is commented out meaning all spam will be quarantined.

Next up are some email addresses for notifications to be sent:

$virus_admin               = "virusalert\@$mydomain";   # notifications recip.
$mailfrom_notify_admin     = "virusalert\@$mydomain";   # notifications sender
$mailfrom_notify_recip     = "virusalert\@$mydomain";   # notifications sender
$mailfrom_notify_spamadmin = "spam.police\@$mydomain";  # notifications sender

You will probably want to set these to "postmaster\@$mydomain" or some other address you would rather receive spam notifications.

Finally, we need to uncomment the section for ClamAV like so:

### http://www.clamav.net/
['ClamAV-clamd',
  \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd"],
  qr/\bOK$/, qr/\bFOUND$/,
  qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],
# # NOTE: run clamd under the same user as amavisd, or run it under its own
# #   uid such as clamav, add user clamav to the amavis group, and then add
# #   AllowSupplementaryGroups to clamd.conf;
# # NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in
# #   this entry; when running chrooted one may prefer socket "$MYHOME/clamd".

Note that the "/var/run/clamav/clamd" setting must match the "LocalSocket /var/run/clamav/clamd" we made earlier in /etc/clamd.conf.

3.3. Postfix

Next we need to configure the services in Postfix (/etc/postfix/master.cf) to allow mail to be passed to Amavisd-new for filtering and then reinjected back into Postfix.

First we will configure the Amavisd-new service to accept mail From Postfix. Amavisd-new supports both lmtp and smtp, and in this instance we have chosen to use the lmtp protocol. (FIXME: I'm not aware of any reasons for choosing one protocol over the other so selected to use lmtp on the basis that having local delivery to Amavisd-new show up in the logs as "lmtp" makes the log files somewhat easier to read).

Open /etc/postfix/master.cf and add the following service called "amavisfeed":

# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
amavisfeed unix    -       -       n        -      2     lmtp
    -o lmtp_data_done_timeout=1200
    -o lmtp_send_xforward_command=yes
    -o disable_dns_lookups=yes
    -o max_use=20

Note that the number (2) in the "maxproc" column must match the $max_servers setting in /etc/amavisd.conf. For a detailed description of the options, see the Amavisd-new documentation (/usr/share/doc/amavisd-new-2.5.4/README.postfix.html).

Then we must define a dedicated service to reinject mail back into Postfix. For this we add an smtp service listening on localhost (127.0.0.1) tcp port 10025 (the default setting in /etc/amavisd.conf) to /etc/postfix/master.cf:

# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
127.0.0.1:10025 inet n    -       n       -       -     smtpd
    -o content_filter=
    -o smtpd_delay_reject=no
    -o smtpd_client_restrictions=permit_mynetworks,reject
    -o smtpd_helo_restrictions=
    -o smtpd_sender_restrictions=
    -o smtpd_recipient_restrictions=permit_mynetworks,reject
    -o smtpd_data_restrictions=reject_unauth_pipelining
    -o smtpd_end_of_data_restrictions=
    -o smtpd_restriction_classes=
    -o mynetworks=127.0.0.0/8
    -o smtpd_error_sleep_time=0
    -o smtpd_soft_error_limit=1001
    -o smtpd_hard_error_limit=1000
    -o smtpd_client_connection_count_limit=0
    -o smtpd_client_connection_rate_limit=0
    -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks,no_milters,no_address_mappings
    -o local_header_rewrite_clients=
    -o smtpd_milters=
    -o local_recipient_maps=
    -o relay_recipient_maps=

For a detailed description of the options, see the Amavisd-new documentation (/usr/share/doc/amavisd-new-2.5.4/README.postfix.html).

After making changes to /etc/postfix/master.cf, we must reload postfix for the changes to take effect:

postfix reload

At this point it might be wise to test the Amavisd-new and Postfix daemons are listening correctly (see the Testing section below).

Once everything is in place and working, the final step is to enable message filtering in Postfix by adding the following setting to /etc/postfix/main.cf:

content_filter=amavisfeed:[127.0.0.1]:10024

and reload postfix for the changes to take effect:

postfix reload

and watch your mail logs.

tail -f /var/log/maillog

3.4. Other MTA's

Amavisd-new can be configured with other MTA's besides Postfix. README docs for other MTA's can be found here:

http://www.ijs.si/software/amavisd/#doc

If anyone would like to contribute section's on configuring other MTA's they should see the How To Contribute page here:

http://wiki.centos.org/HowToContribute

4. Testing

Now would be a good time to test that the services we've defined are working as expected.

First, start the clamd and amavisd services:

# service clamd start
Starting Clam AntiVirus Daemon:                            [  OK  ]
# service amavisd start
Starting Mail Virus Scanner (amavisd):                     [  OK  ]

Now test that the amavisd service is listening on 127.0.0.1:10024 using telnet:

$ telnet localhost 10024
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
220 [127.0.0.1] ESMTP amavisd-new service ready
ehlo localhost
250-[127.0.0.1]
250-VRFY
250-PIPELINING
250-SIZE
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 XFORWARD NAME ADDR PROTO HELO
quit
221 2.0.0 [127.0.0.1] amavisd-new closing transmission channel
Connection closed by foreign host.

If everything is working then you should see a successful connection similar to above.

Next to test the Postfix smtpd is listening on 127.0.0.1:10025:

$ telnet localhost 10025
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
220 mail.example.com ESMTP Postfix
ehlo localhost
250-mail.example.com
250-PIPELINING
250-SIZE 20480000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
quit
221 2.0.0 Bye
Connection closed by foreign host.

Again we should see a successful connection as shown above.

... Describe tests using amavisd test samples here...

5. Links

Amavisd-new is supplied with extensive documentation installed to /usr/share/doc/amavisd-new-2.5.4/ and the reader is referred to /usr/share/doc/amavisd-new-2.5.4/README.postfix.html in particular. An online version is also available here: http://www.ijs.si/software/amavisd/README.postfix.html

http://www.linuxjournal.com/article/7778

http://www200.pair.com/mecham/spam/clamav-redhat-amavis.html

http://www200.pair.com/mecham/spam/clamav-amavisd-new.html

...

HowTos/Amavisd (last edited 2008-05-15 21:15:48 by NedSlider)