Fairly-Secure Anti-SPAM Gateway Using OpenBSD, Postfix, Amavisd-new, SpamAssassin, Razor and DCC
By Scott Vintinner
Last Edited 5/6/2004 9:00 AM EDT (Changelog at bottom)
Latest version of this document always available at http://www.flakshack.com/anti-spam
Read and post comments here (note
that you don't need to create an account to post).
The old after-queue based version of this doc is
available here as
a reference.
Index
What is this document?
Where to find help
Hardware Requirements
Notes and conventions
Provide firewall access
Installing OpenBSD
Configuring OpenBSD
Removing Sendmail
Add User Accounts
Installing and Configuring Postfix
Installing Needed Perl Modules
Installing and Configuring SpamAssassin
Installing Razor
Installing DCC
Installing and configuring Amavisd-new
Installing Postfix Email Reporting
What if I want to disable Amavisd-new/SpamAssassin?
Performance
Performance Expectations
Configuring for Multiple Domains
Notes about running under other OS
Adding Anti-Virus Support
Download My Scripts
Changelog
Legal Stuff
What
is this document?
This document describes how to setup a spam-blocking email gateway based on
open source and freely available software. This procedure is designed for
a
small to medium sized company with a single domain (multiple domains are possible...just
not described here in full detail). I will describe how to setup a new computer
that is meant
to run on your network's DMZ in between the Internet and a corporate email
server like Lotus Notes or Microsoft Exchange.
This entire procedure has been developed with security as a primary focus.
The operating system is OpenBSD (www.openbsd.org),
which is a "Secure by Default" system with a good track record
for security. The
email MTA is Postfix
(www.postfix.org)
which also has a good record for security and is the easier of the 2 main competitors
to the troubled sendmail program. Amavisd-new
(www.ijs.si/software/amavisd) is the main filter which processes email
from postfix and ensures that we don't lose any mail. Amavisd-new is an
huge improvement
over the original amavis which was a simple virus scanner, and I think it is
the best way of implementing SpamAssassin
(www.spamassassin.org). SpamAssassin is the main anti-spam component
which works by comparing messages to a ruleset and by using a statistical
analysis
that is custom built based on your email. In addition to the SpamAssassin spam
detection software, we will be using 2 online SPAM databases: DCC
(www.rhyolite.com/anti-spam/dcc) and Vipul's
Razor (razor.sourceforge.net). These databases work by comparing
hashes of our email messages with hashes of known spam. As a final
security precaution,
we will run all network processes in a restricted-user/chroot environment,so
if an attacker were able to compromise one of the modules, the amount
of damage
they could do would be seriously limited.
There are many different ways to customize the handling of SPAM with amavisd-new.
The following
directions use Postfix's Before-Queue Content
Filtering proxy to immediately reject spam while still
connected to the sending server. The sender of the rejected
spam will get a postmaster "undeliverable" message from their mail server
which
includes
an error line that we can customize with directions in case of a false-positive. The
sender can follow these directions to be added to a "whitelist" of approved
email addresses which get to bypass the spam filter. In
the end, you get an anti-spam system that requires NO work on your user's
part and has a very small percentage of false positives.
I've been receiving an average of 5 new emails per day from people asking me
to help debug their setups. In nearly all of these cases, the problem is due
to a typo in the configuration files or some minor fluke caused by using a slightly
different version of one of the components. Unfortunately I no longer have the
time to answer everyone's questions personally.
The best place to go for help is the amavisd mailing list (https://lists.sourceforge.net/lists/listinfo/amavis-user).
Please search through the archive (http://marc.theaimsgroup.com/?l=amavis-user)
for answers to your problem before posting a question. Mark Martinec does a
very good job of answering most questions quickly, so please
don't waste his time. Do some research first and try to ask good questions.
I also subscribe to the list, so when posting your question be sure to mention
that you are using OpenBSD. Also please do not email huge copies of your config
files or debug output unless asked to do so.
If your question is specific to SpamAssassin, DCC, Razor, or Postfix, please refer to their respective home pages (listed above) for more assistance.
Hardware
Requirements
Since computers with 256 MB of RAM are increasingly common, I
have
decided
to set the configuration in these directions optimized for a computer with that
much memory. If you have more or less memory, you should see the section on Performance near
the end of the document before putting your server into production. This configuration
will allow up to 8 simultaneous connections to your server. If you need to support
more connections at a time, you will need to add more memory to the system (amavisd
is a bit of a memory hog).
Notes
and Conventions
This document is not really meant for the unix newbie. If you
have never worked with linux or unix before, you may experience some difficulty
with these directions. Specifically, I expect that you will know how to use
vi to edit files (here's a vi
cheat sheet). (Actually I've been informed that you can set the EDITOR environment
variable to get OpenBSD to use whatever editor you want for vipw and crontab
-e, so I guess you can use whatever editor you want.)
Also, you'll want to grab a copy of PuTTY
and WinSCP. These
2 utilities will help you configure your server remotely without the need for
a GUI running
on the server itself.
PuTTY is an awesome SSH client that you can use to talk to your OpenBSD server
over a secure link. It has 2 great features: anything you select with your
mouse
is copied to the Windows clipboard, and right-clicking the mouse anywhere in
the window will paste the contents of the clipboard. It works great in insert
mode in vi to paste hundreds of lines. My servers are rack-mounts, so usually
as soon as I get the network running on the OS, I head back to my PC and pull
up PuTTY. WinSCP is a gui file browser for SSH. It will let you easily copy
files back and forth between your Windows PC and the OpenBSD server.
Text listed in blue are commands that you type
into the console. Text listed in red are edits
in text files. Text listed in gray tables are full files. The #
sign followed by a blue command indicates a shell
prompt (so don't type it). The # sign in configuration files or text edits is
used as a comment block, and may be included in the actual files without harming
anything.
I have received many many emails from people telling me that I'm going straight
to hell for not using SUDO.
As you look through my directions, you will see that the directions have you
logged
in as root during this entire procedure. The "best-practices" for
OpenBSD say that you should login as an unpriviledged account to do most of
the work and
use the sudo command
whenever
root access
is required.
I'll be the first to admit that I'm not conscientious enough to follow
those guidelines 100% of the time. I certainly suggest that you read up on
the sudo
command if you are unfamiliar
with it.
Personally
I
think
there
is
a time
and
a place
for
using
sudo and
an efficient administrator knows
the
difference.
One last note: obviously these directions require some customization to fit
into your network. Specifically you'll want to replace the sample server
names
and IP addresses with your own. Here's a little diagram of what we'll be
setting up:
For our examples, our internal network numbering uses the 10.0.0.0/8 private domain range. The 10.1.0.0/16 network is our main network. The 10.2.0.0/16 network is our DMZ network. Our pretend public internet class C is 65.0.0.0/24. Additionally, the server we will be setting up will be called mta1 in these directions. You can call your server whatever you want, just replace it with your name where ever you see it. For simplicity, we'll pretend that our company's domain name is domain.com.
Hopefully you have a firewall at your company. Here's a list of what traffic you will need to allow through your firewall to make all of this work.
| Source |
Destination |
Type |
Port |
Description |
| 10.2.1.50 |
10.1.1.50 and any External |
TCP |
25 |
Outgoing SMTP |
| 10.1.1.50 |
10.2.1.50 |
TCP |
25 |
SMTP from Exchange to our MTA |
| any External | 10.2.1.50 | TCP | 25 | Incoming SMTP |
| 10.2.1.50 |
any External |
UDP |
6277 |
Outgoing from our MTA to the DCC servers |
| any External | 10.2.1.50 | UDP | 6277 | Incoming from DCC Servers to our MTA |
| 10.2.1.50 |
any External |
TCP |
2703 |
Outgoing from our MTA to the Razor servers |
| 10.2.1.50 | any External | TCP | 7 | Outgoing ping from our MTA to the Razor servers |
| 10.2.1.50 | any External | TCP | 22 | Outgoing SSH (used to update our source code from the
OpenBSD servers using CVS) |
| 10.2.1.50 | any External | TCP | 21 | Outgoing FTP (so we can download files that we need) |
| 10.2.1.50 | any External | TCP | 80 | Outgoing HTTP (also so we can download files) |
Additionally mta1
needs to have access to a DNS server. In my configuration the DNS is on the
DMZ so no extra firewall rules were required.
Installing
OpenBSD
The OpenBSD
FAQ Chapter 4 provides an excellent step by step explanation of how to install
the latest version of OpenBSD, so I won't repeat it all here. I'll just give
some minor tips:
NOTE: these directions assume that this is a new server that is not currently being used. If your server was previously running sendmail or some other MTA, you will want to check the postfix INSTALL file for better instructions on migrating to postfix.
Add User AccountsWhen possible, you never want to run anything as root. The root account has
unrestricted access to everything, so if there is a bug or security hole in
anything you run as root, it could potentially compromise your entire system.
To further tighten the security of our system, we will run different modules
as different user accounts.
Use vipw to edit the password file. You could also use the adduser or useradd
commands, but this is the easiest way for us. Go to the bottom of the file and
add the following lines:
postfix:*:2000:2000::0:0:Postfix
Mail Daemon:/var/empty:/sbin/nologin
amavisd:*:3000:3000::0:0:Amavis Mail Scanner Daemon:/var/amavisd:/sbin/nologin
Next we want to add the group accounts for our new users. To do this, edit
the /etc/group file. Add the following lines (preferrably in numeric order with
any other groups in the list):
postfix:*:2000:
postdrop:*:2001:
amavisd:*:3000:
Here's a quick
explanation of what we'll use the new accounts for: The postfix account is
the account that postfix will run under, and likewise the amavisd account is
the
account that the amavisd program will run under. Running these programs in
non-root accounts is good for security, since if an attacker compromises either
program,
they are still limited by those accounts.
BTW, the * in the first section is in place of where a normal password would
be. The star tells the operating system that the user cannot login. The /sbin/nologin
is the user's shell that is launched when they login...which in this case is
another indicator to the operating system that these users shouldn't be able
to login.
You can install Postfix from the OpenBSD port collection using the directions included in the Ports & Packages FAQ. The postfix port is located at /usr/ports/mail/postfix. You may want to double-check which version you are getting with that method, as it must be version 2.1.0 or higher. Below I describe how to install Postfix directly from the source.
# queue_directory = /var/spool/postfix mail_owner = postfix myhostname = mta1.domain.com local_recipient_maps = smtpd_banner = $myhostname ESMTP transport_maps = hash:/etc/postfix/transport # Install Time Configuration |
| Explanation of Postfix configuration settings: | |
| queue_directory | Postfix's work directory. Where all the mail will be temporarily stored until it is delivered. |
| daemon_directory | Specifies the location of all the postfix programs. |
| mail_owner | Specifies the user account that will own the mail queues. |
| myhostname | The name of this computer including the domain part. This is used when adding received by headers in email messages. |
| mydomain | This specifies the domain of this current computer. |
| myorigin | This name is added to locally originating email. So if you sent yourself a message from root, it would appear to come from root@mta1.domain.com. |
| mydestination | This setting tells postfix what domains it will accept email for. Please note this should not be used for virtual domains, or for backup MX hosts. In our case, we set it so it would receive mail for something@mta1.domain.com, something@localhost.domain.com, something@domain.com, and something@mail.domain.com |
| mynetworks | This setting tells postfix what networks it should consider local. In other words, computers connecting from any of these networks will be able to relay mail, etc. In our case, we put 127.0.0.0 (for localhost), 65.0.0.0 (for any other computers on our external network), and 10.0.0.0 (for any internal computer). |
| local_recipient_maps | This setting tells postfix where to find the names of local users to accept mail for. We just want to leave this blank (note that removing it all together will cause errors). |
| biff | This setting tells postfix not to use the biff program to let local users know that they have new email. |
| empty_address_recipient | This setting is the destination for undeliverable mail from <> |
| queue_minfree | This setting tells postfix not to accept any messages for delivery if there are less than 120 megs of disk space available. This number should be 1.5 times the message_size_limit or you will get an error message. |
| message_size_limit | This sets the maximum size of a message. Messages larger than 80 megs will be rejected. You can increase or decrease this based on your own server requirements. |
| mailbox_size_limit | This sets the maximum size of local mailbox files. We set it to 100 megs, although it should never reach this high because our only local mailboxes are spam and notspam |
| smtpd_banner | This is the banner that is displayed to connecting computers. It is a good security practice to give as little information as possible. I've included just the essentials. |
| transport_maps | This setting tells postfix where to find the transport information. The transport file is where we tell Postfix where to route certain mail. In our case, this file is where we tell Postfix that mail for domain.com should be delivered to our exchange server. |
| local_transport | This setting tells postfix that all local mail should be delivered using the local delivery agent. |
| smtpd_helo_restrictions, smtpd_sender_restrictions, smtpd_recipient_restrictions | These settings are used to deny access to postfix based on the HELO command, the sender, or the recipient. The recipient restrictions settings are used to prevent our mail server from being used as an open relay. As configured, the helo and sender restrictions are left open. If you want to play around with these you can, just look them up in the postfix documentation. Normally these settings can be used to help block SPAM. Unfortunately they depend on the assumption that all legitimate senders have their systems correctly configured. In my experience this is never the case, so these settings are more trouble than they are worth. Like the RBL lists, I found that enabling these settings meant that I spent too much time teaching other mail administrators how to correctly configure their systems (Note that we'll use Realtime Blackhole lists (RBLs) in SpamAssassin, not in Postfix because there positive hits will simply result in higher spam scores.) |
| notify_classes | This setting tells postfix to send all sorts of notifications to the
postmaster email account. Here's a list of the available options: bounce: Send the postmaster copies of the headers of bounced mail. 2bounce: Send undeliverable bounced mail to the postmaster. delay: Send the postmaster copies of the headers of delayed mail. policy: Send the postmaster a transcript of the entire SMTP session when a client request was rejected because of (UCE) policy. If you enable this, you will get 1 email for every spam message that was rejected by amavisd. Good for testing, not good for production. protocol: Send the postmaster a transcript of the entire SMTP session in case of client or server protocol errors. resource: Inform the postmaster of mail not delivered due to resource problems. software: Inform the postmaster of mail not delivered due to software problems. |
| Install Time Configuration | This section holds the settings we used when we installed postfix. We keep them in the config file so that future upgrades will be easier. |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Both amavisd-new and SpamAssassin are written in perl and have a number of
other perl modules as dependencies. Fortunately perl has a built-in way to download
and install these modules. To start the perl command environment use the command:
# perl
-MCPAN -e shell
This command will popup a little cpan> prompt where you can
enter commands. To install a module, type install followed by the module
name (ex. install MIME::Words ). If you need help,
type help.
Here is a list of the modules required. Note that same may return saying they
are up to date, so just move on to the next one. Also note that you don't
necessarily need to run the latest version of all these modules in order for
amavisd to work correctly. If the module is already installed, it may work
fine without needing to be updated (especially since some module upgrades may
require a newer version of perl!).
If you are feeling really impatient, you can install them all with a single install command: (install MD5 LWP Mail::Internet Archive::Tar Archive::Zip IO::Wrap IO::Stringy Unix::Syslog MIME::Words MIME::Head MIME::Body MIME::Entity MIME::Parser Net::SMTP Net::DNS Net::Ping Net::Server Net::Server::PreForkSimple Convert::TNEF Convert::UUlib MIME::Decoder::Base64 MIME::Decoder::Binary MIME::Decoder::Gzip64 MIME::Decoder::NBit MIME::Decoder::QuotedPrint MIME::Decoder::UU Time::HiRes Digest::SHA1 Digest::Nilsimsa Getopt::Long File::Copy Bit::Vector Date::Calc)
Occasionally you will be prompted with the following message:
---- Unsatisfied dependencies detected
during [G/GA/GAAS/Somefile.tar.gz] -----
Name of Dependency
Shall I follow them and prepend them to the queue
of modules we are processing right now? [yes]
This is just telling you that the module you are installing needs some other
module to work properly. It is asking your permission to go ahead and install
it first. Go ahead and press enter to accept the default of yes.
Similarly you will be prompted with a number of other questions during this install process. Just press enter to accept the defaults on most of them.
If you run into any errors, try to read the error to figure out what you should
do. In some cases you may get an error when a test that is run as part of the
install fails. To install anyway use the force install
modulename command. For more assistance with cpan and perl go
to www.cpan.org.
Once everything is installed type 'q' to quit.
rewrite_subject 1 use_bayes 1 |
| Explanation of SpamAssassin configuration settings: | |
| rewrite_subject | (1|0) Tells SpamAssassin to change the subject on SPAM messages to include the subject_tag |
| report_safe | (0|1|2) This setting configures how to handle SPAM. A setting of 0 puts the SpamAssassin report into the headers. A setting of 1 puts it in the main email and attaches the original email as an attachment. Setting 2 is similar to setting 1, plus it changes the type of attachment to text/plain (as a security measure). NOTE: this setting has no affect when spamassassin is run through amavisd, so just leave it set to 0. |
| use_terse_report | (0|1) Setting this to 0 gives the normal length explanation of why the message was considered SPAM. Setting it to 1 gives a shorter report. (Note that this report only appears if you change the report_safe setting, or if you configure blocking like we will do...in which case the sender gets this report). |
| use_bayes | (0|1) This setting turns the Bayesean Learning on or off. In our case we want it on. |
| bayes_path | (path) Location of systemwide bayes database. We need to set this so that the root account can run the sa-learn program to update the bayes database normally used by the amavisd user. |
| auto_learn | (0|1) If turned on (1), this will cause SA to automatically add very SPAM or very not-SPAM messages to the Baysean statistics database. |
| skip_rbl_checks | (0|1) Definitely turn this off (0). Unlike using the Blackhole lists from within Postfix, using them in SpamAssassin allows you to selectively use the RBLs. For example, if you have a client that has an open relay and is unwilling to change it, you can simply add their domain to your whitelist, while still being able to use the RBLs for everyone else. |
| use_razor2 | (0|1) Tells SA that we want to use Razor version 2 |
| use_DCC | (0|1) Tells SA that we want to use DCC (Distributed Checksum Clearinghouse) |
| use_pyzor | (0|1) Tells SA that we don't want to use Pyzor (since we won't be installing it). |
| dcc_add_header | (0|1) Tells SA to add a header from DCC containing statistics about the message |
| dns_available | (yes|test|no) Normally SA tests to see if it has access to a DNS server to do lookups. Since I know my server has access to DNS, I tell it to skip this test. It saves on initial amavis startup time. |
| LOCAL_RCVD rules | The last lines header, describe and score are used to prevent my outgoing
mail from being tested for spam. If you're like me, your users would
be upset if their mail was tagged as spam before a client read it. This
rule basically checks the header for the Received from: lines
showing the message route. You will need to customize this rule to fit your system. To do this, send a message to your test hotmail account (or some account outside of your system). Check the headers for lines that look like this: Received: from mta1.domain.com (mta1.domain.com [64.132.107.5]) by law122.ms.hotmail.com (8.12.6/8.12.2) with ESMTP id h3EI48pL002768 for <forge@hotmail.com>; Mon, 14 Apr 2003 14:04:08 -0400 (EDT) Received: from exchange.domain.com (exchange.domain.com [10.1.1.50]) by mta1.domain.com (Postfix) with ESMTP id F3B7117EFD for <forge@hotmail.com>; Mon, 14 Apr 2003 14:04:07 -0400 (EDT) Received: by exchange.domain.com with Internet Mail Service (5.5.2653.19) id <GKFZ3XPK>; Mon, 14 Apr 2003 14:04:03 -0400 The rule is a standard SpamAssassin rule and uses Regular Expression syntax. To explain it in regular terms, it looks for *.domain.com (*[*]) on the received line (where the stars are anything). When it finds a match, it gives the message a SPAM score of -50 (ensuring it is not counted as SPAM). |
| Optional Score Increases | In this section, I turn up the value of several of the rules. The default score for a spam that turns up in the DCC database is only 2.756 when we're using Bayes and network checks. This seemed a little low for me, so I upped it to 4 points. If you wanted every message listed in the DCC database to be tagged as SPAM, you'd set this to 6.3 points. You can check the default scores for everything in the file /usr/local/share/spamassassin/50_scores.cf. You may see 4 different scores listed next to some rules. The file has different scores for whether or not you are using Bayes and network checks. When there is only 1 score, that score applies all the time, otherwise the 4th score is for bayes and network checks like we are using. |
Unfortunately I couldn't get Razor working correctly when not running as chroot. For some reason it had a hard time figuring out what its razorhome directory was (even though it was explicitly set in the config file). Fortunately it works great in chroot mode. If you are not going to run amavisd-new in chroot mode, you may want to just disable the razor checks in your /etc/mail/spamassassin/local.cf file.
Download latest v2 razor-agents Untar and run
# cd /root
# ftp http://unc.dl.sourceforge.net/sourceforge/razor/razor-agents-2.40.tar.gz
# tar -zxvf razor-agents-2.40.tar.gz
# cd razor-agents-2.40
# perl
Makefile.PL
# make
# make
test
# make
install
Create the default configuration files in /etc/razor
#
razor-client
# razor-admin
-create
Register yourself with the razor network. Substitute your exchange email address
for the address listed.
# razor-admin
-register -user postmaster@domain.com
Copy the razor config files to the chroot directory
# cp -r /root/.razor /var/amavisd
# chown -R amavisd.amavisd
/var/amavisd/.razor
You can enable or disable Razor by editing your etc/mail/spamassassin/local.cf
file: use_razor2 1
One last note, razor has its own logfile in /var/amavisd/.razor called
razor-agent.log. Unchecked, this file could potentially grow to fill your entire
/var volume. Therefore, once you are sure that razor is working properly, you
will want to edit the razor config to turn off logging. Unfortunately you can't
use newsyslog to rotate this logfile without having to stop and restart amavisd.
Edit /var/amavisd/.razor/razor-agent.conf and change:
debuglevel = 5
to
debuglevel = 0
then restart amavisd.
Download and extract the latest DCC (http://www.dcc-servers.net/dcc/)
#
cd /root
# ftp http://www.dcc-servers.net/dcc/source/dcc-dccd.tar.Z
# tar -zxvf dcc-dccd.tar.Z
# cd dcc-dccd-1.2.36
# ./configure
# make
# make
install
Make sure udp port 6277 is allowed out from this computer on your firewall.
# /usr/local/bin/cdcc
'info'
If everything is working, you should see a bunch of lines like:
dcc.rhyolite.com, - RTT+0 ms anon
# 153.19.44.233,- coral.ely.pg.gda.pl WEiAPG server-ID 1072
# 100% of 3 requests ok 1687.64+0 ms RTT 113 ms queue wait
# 192.188.61.3,- calcite.rhyolite.com Rhyolite server-ID 101
# 100% of 2 requests ok 755.52+0 ms RTT 50 ms queue wait
Since amavisd-new will be running in chroot mode, we need to copy DCC
and all the files it needs to the chroot directory. The way DCC is called by
SpamAssassin requires /bin/sh in order to work properly. You should be aware
that this it reduces the security of the system. Without it, you'll receive
this error when running amavisd debug: DCC -> check failed: no response
# mkdir -p /var/amavisd/var
/var/amavisd/usr/bin /var/amavisd/usr/libexec /var/amavisd/var/dcc
# mkdir -p /var/amavisd/usr/lib /var/amavisd/bin
# cp -r /var/dcc /var/amavisd/var/
# cp /usr/local/bin/dccproc
/var/amavisd/usr/bin
# cp /usr/libexec/ld.so /var/amavisd/usr/libexec
# chown -R amavisd:amavisd
/var/amavisd/var/dcc
# cp /bin/sh /var/amavisd/bin/
DCC uses several OpenBSD libraries, which we need to copy to the chroot directory. Since the version numbers on these libraries seem to change regularly, rather than just telling you which files to copy, you can run the following command:
# ldd /usr/local/bin/dccproc
This will output something like this:
/usr/local/bin/dccproc:
Start End Type Ref Name
00000000 00000000 exe 1 /usr/local/bin/dccproc
00008000 2000f000 rlib 1 /usr/lib/libm.so.1.0
00019000 20063000 rlib 1 /usr/lib/libc.so.30.0
00002000 00002000 rtld 1 /usr/libexec/ld.so
Just copy the listed files (except dccproc) to their chroot directory under
/var/amavisd. So for example, you would copy /usr/lib/libm.so.1.0
to /var/amavisd/usr/lib/libm.so.1.0.
You can enable or disable DCC by editing your etc/mail/spamassassin/local.cf file: use_dcc 1
Installing and Configuring Amavisd-new
use strict; $MYHOME = '/var/amavisd'; $QUARANTINEDIR = "$MYHOME/quarantine"; $max_servers=8; $forward_method = 'smtp:127.0.0.1:10025';
@bypass_virus_checks_acl
= qw( . ); $DO_SYSLOG = 1; # (1 = syslog,
0 = logfile) $final_spam_destiny = D_REJECT; # Set to D_REJECT, D_PASS to pass through read_hash(\%whitelist_sender,
'/var/amavisd/whitelist'); $path = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/sbin:/usr/bin:/bin'; $sa_tag_level_deflt = 3.0;
# controls adding the X-Spam-Status and X-Spam-Level headers, $sa_spam_subject_tag = '***SPAM*** '; 1; # insure a defined return |
| Explanation of Amavisd-new configuration settings: | |
| $MYHOME, $mydomain | These are really just variables used in this config file so we don't have to type the same things over and over again. MYHOME is our default work directory, mydomain is the name of our domain. |
$daemon_user, |
This is the user and group that amavisd and all its helper programs will run under for security reasons. |
| $daemon_chroot_dir | This option tells amavisd to run in chroot mode. Chroot is a security trick that traps the program in a certain directory, in our case $MYHOME. By turning this on, amavisd will not be able to access anything on the computer other than what is in the /var/amavisd directory. |
| $QUARANTINEDIR |
This is the location where amavisd would place quarantine files if you were using it for virus scanning. Even though we aren't virus scanning, it is still needed. |
| $TEMPBASE | When amavisd does its thing, it creates a bunch of temp files. Normally it would just store them in $MYHOME. By storing them in $MYHOME/tmp, we can easily cleanup the temp directory whenever we need to by stopping amavisd and deleting everything in $MYHOME/tmp/* |
| $ENV{TMPDIR}, $helpers_home |
I found that both of these setting help SpamAssassin, Razor and DCC work better by explicitly telling these helper programs their home and tmp directories. |
| $max_servers | Specifies the number of instances of amavisd child processes to spawn. You should increase or decrease this number depending on how much memory your PC has installed. Make sure that this number is synchronized to the smtpd maxproc setting in the postfix/master.cf file (so that you don't end up with postfix trying to connect to a non-existant queue). |
| $child_timeout | Here we need to increase the timeout for the amavisd process.
The default is only 8 minutes. When amavisd is used with other mail
packages
in a post queue structure, the message is transferred locally only
(from the local mail queue to the amavisd loopback) and is therefore
very fast. When we use the postfix before-queue filter, the message
is being
transferred
directly
from
the remote smtp through postfix to amavisd . So for example if
the remote smtp is sending a 20 megabyte message, it may take longer
than 8 minutes
to transmit the message (depending on network bandwidth). In my testing,
amavisd would timeout before the message had been transferred and
the end user would get the following message: |
| $forward_method, $notify_method, $inet_socket_port, $inet_socket_bind, $inet_acl |
These settings set up the communications between amavisd and postfix. Basically the two programs communicate using different ports. Postfix sends email it wants to filter to amavisd on port 10024. Amavis processes the message and returns it to postfix on port 10025. The $inet_acl setting makes sure that it accepts only packets from the local computer. |
| @bypass_virus_checks_acl | Since we won't be using the anti-virus features of amavisd, this line is used to turn them off. |
| @local_domains_acl | This setting is used to determine if a message is incoming or outgoing. |
| $DO_SYSLOG, $LOGFILE, $log_level |
These settings describe how amavisd should do logging for debugging.
The $log_level can be set from 0-5 with 5 producing the most logging
output. Even though we aren't using it, the $LOGFILE setting is required.
Also don't be surprised to see an empty file with this name in the $MYHOME
directory. You should also note that when running amavisd in debug mode,
logging doesn't occur to the syslog. Note #1: the main reason we don't want to log to file is because when chrooted, amavisd can't be restarted with a HUP command. Therefore to rotate the logfile with newsyslog, you'd need to stop and restart amavisd. It's easier just to log to syslog. Note #2: if you want to have amavisd log to /var/log/messages instead of /var/log/maillog, you can add a config line here: $SYSLOG_LEVEL = 'user.info'; |
| $final_spam_destiny | You should set this to either D_REJECT or D_PASS. When set to D_PASS, the spam will be delivered to your users. They can then setup inbox assistant rules looking for the X-Spam-Flag header to move the messages to another folder, or delete the messages. The D_REJECT setting will reject the email message during the original connection. The sender will get an undeliverable bounce message from their smtp server (more details about this later). You can also configure D_BOUNCE mode, see the amavisd documentation for more info. At my company, we used the D_PASS method for the first 60 days after turning on SpamAssasssin to make sure everything was working right (auto-whitelisting had been done, and the bayesian db had been built). Then we switched over to D_BOUNCE mode. Once postfix supported before-queue filtering, we switched to D_REJECT mode. |
| read_hash(\%whitelist_sender, read_hash(\%blacklist_sender, read_hash(\%spam_lovers |
These settings point to 3 files that identify our whitelist, blacklist
and spam lovers. Each file should have 1 email address (or part of an
email address) per line. The whitelist identifies senders that should
always be passed through even if they are identified as spam. The blacklist
identifies senders that should always be marked as spam. The spam_lovers
identifies our users that want to opt-out of our system and receive
all their spam. Note that these files are read only on startup of amavisd, so if you edit them be sure to stop and restart amavisd. Also, not shown here is the ability of amavisd to support per-recipient whitelists and blacklists and MySQL based whitelists and blacklists. |
| $MAXLEVELS, $MAXFILES, $MIN_EXPAN... | This whole section is part of the anti-mail bomb measures of the anti-virus software. I thought it should be kept in there just in case. |
| $path | Tells amavisd where to look for programs it needs. |
| $sa_local_tests_only | Set this to 1 to disable DCC and Razor for debugging. The default for this is false, so I initially didn't include it in my config file, but I have been told that leaving it out causes problems. |
| $sa_auto_whitelist | Great feature of spamassassin that automatically whitelists people that send you lots of non-spam mail. |
| $sa_mail_body_size_limit | Since few spammers send large attachments, we don't even bother checking messages over a certain size (in this case 64KB). |
| $sa_tag_level_deflt, $sa_tag2_level_deflt, $sa_kill_level_deflt |
As you know, SpamAssassin assigns each email a positive or negative score to indicate its "spamminess" (yes I know its not a word). These settings tell SA when to take anti-spam measures. At the tag level, the message's headers are modified with the spam score. At the tag2 level, in addition to the actions from the tag level, it adds a header indicating that the message is spam, and it modifies the subject. At the kill level, the system will take action based on the $final_spam_destiny setting. In most cases, you want tag2 and kill to happen to any message that is spam, so they are usually equal. |
| $sa_spam_subject | This text is added to the front of any spam message that receives a high enough score. |
| $sa_debug | This setting turns on spamassassin debugging. Comment it out once everything is running smoothly for better performance. |
| From "Mail Delivery Subsystem" MAILER-DAEMON@mail.somecompany.com Subject Returned mail: see transcript for details Date Sat, May 1, 2004 8:57 pm To person@somecompany.com -------------------------------------------------------------------------------- ----- The following addresses had permanent fatal errors ----- < sentto@domain.com > (reason: 550 5.7.1 Message content rejected, UBE, id=3452) ----- Transcript of session follows ----- |
Change: : "550 5.7.1 Message content rejected, $reason") To: : "550 5.7.1 Message content rejected:looks like SPAM. Visit http://www.domain.com/spam or call 704-555-1212") ); |
| body LOCAL_AMAVISTEST /800-320-9895 x2068/ describe LOCAL_AMAVISTEST Phone number in spam test message score LOCAL_AMAVISTEST 10 |
Install Postfix Email Reporting
Our last step in this process is to setup email summary reports. Once a day, right before the maillog is rotated with newsyslog, we'll run a program on the maillog to generate a nice summary report and email it to root. There are a couple different reporting scripts for postfix available on freshmeat.net. I didn't try them all because pflogsumm.pl (http://jimsun.linxnet.com/postfix_contrib.html) worked fine and did what I wanted.
To get this running, simply download the .pl file from his website, check the
MD5 signature to make sure it matches, make it executable, and add it to the
crontab.
# cd /root
# ftp http://jimsun.linxnet.com/downloads/pflogsumm-1.0.4.pl
# mv pflogsumm-1.0.4.pl /usr/local/sbin/
# chmod 500 /usr/local/sbin/pflogsumm-1.0.4.pl
Every night at midnight, the newsyslog program rotates out the maillog
file. As part of its process, it renames the /var/log/maillog file to /var/log/maillog.0
then gzips it. We want our script to unzip this file, process it and generate
the report, then zip it up again. To do this we'll create a new script file.
# vi /usr/local/sbin/my-postfix-report.sh
Add the following lines into this file:
|
#!/bin/sh zcat /var/log/maillog.0.gz |/usr/local/sbin/pflogsumm-1.0.4.pl | mail -s "Report" root |
# chmod 500 /usr/local/sbin/my-postfix-report.sh
Now edit root's crontab:
# crontab -e
Add the following line to root's crontab to run our new script every day at
4:00 AM:
Reporting on SPAM
I have written a perl script that also generates several reports (in
the same format as pflogsumm) about your spam. The reports include: 1. All spam
senders listed by SA Score, 2. All spam sender domains listed by number of messages,
3. All recipients by number of messages, and 4. Total number of spam. I'm no
perl expert, but this script runs fine on my system. You can download it (and
all my other scripts) from the bottom of this doc.
If you want to use it, just copy the my-spamreport.pl and my-postfix-report.sh
files over top of the ones you have already created. (I updated the my-postfix-report.sh
script so that it includes the spam report in a single email message).
Update: Kris Nosack has written an updated version of my script to include
percentages. You can download this new version of the script here: http://www.flakshack.com/anti-spam/nosack-spamreport.pl.
I've also written a script (my-summary.pl) that will count the total number
of messages, spam and size per day and store it in an ongoing file. You can
then
download
this
file and load it into Excel to graph your spam. Here's an example of the output
(date, number of messages sent, total bandwidth of all messages, number of
blocked spam):
1/3/2004,18099,363151k,5894
1/4/2004,16176,106379k,6370
1/5/2004,16083,90243k,6449
1/6/2004,25380,609m,6147
1/7/2004,26420,708m,6272
What if I want to disable Amavisd-new/SpamAssassin for a while?
To disable amavisd, all you have to do is comment out the line in the master.cf that directs postfix to pass incoming mail through its filter. Locate the smtpd_proxy_filter line and put a comment (#) symbol in front of it.
| #-o smtpd_proxy_filter=127.0.0.1:10024 |
Now just run # postfix
reload
and all incoming mail will now just be routed normally.
The configuration as described above is for a PC with 256 MB of RAM and will allow your mail server to accept 8 incoming connections at one time. Once those 8 connections are in use, any further connections will be refused. In this case, the remote SMTP client should continue trying to deliver the message to your mta until it times out, usually in 5 days. If you have less than 256 MB of RAM, you must reduce the number of amavisd and postfix servers, otherwise you will overwhelm the computer (usually amavisd or postfix crashes). If you have more than 256 MB of RAM, you can increase the number of servers to allow for more connections at one time.
You can use the following directions to boost or reduce the number of connections the server can accept at one time. After you make a change, you will want to check your system memory usage using top. When you run the top command, you will see a line that looks something like this:
Memory: Real: 113M/144M act/tot Free: 103M Swap: 0K/512M used/tot
The important number here is the one labeled "Free." It shows how much
free memory is available on your computer. The line above was taken from one of
my server running 8 processes. As you can see we are currently using 144 MB
of RAM and have 103 MB free. I could probably run 10-12 servers instead of
8, but I like to play it safe.
Since there need to be enough amavisd processes to handle each smtpd process,
you need to make sure that you have configured the same number in both locations.
Edit the /etc/amavisd.conf file and edit the following line:
$max_servers = 8;
The default when this line is not present is 2. Increase or decrease the number
as needed.
Now edit /etc/postfix/master.cf. Look for the line that says:
|
And increase or decrease the maxprocs count for the smtpd line to match the number of amavisd servers you just indicated in the amavisd.conf.
Restart amavisd and postfix. Run the top command, press the "o" key and type
"res" to sort the display by memory usage. Be sure to watch the display
as mail is delivered through the system, since more memory is used by a running
system than by an inactive one.
Performance
Expectations
Here are some quotes from people that are using these directions
with notes on their performance. If you send me your experience, I'll post it
here.
| My Performance: We run 2 of these systems for redundancy and load balancing. Both are Pentium III, 900 mhz Dell PowerEdge Rackmount systems with 256 MB ram and 20 GB HD. On an average week day, each server delivers 700-1000 MB of email (according to my maillog reports) which is usually around 12,000 messages each. Each server detects and blocks about 6000 SPAM messages per day. Performance with this setup seems to be great...no complaints. Load balancing and redundancy is setup by configuring both servers' MX records with the same weight, and by configuring my Exchange server's SMTP connector smart host setting with both addresses (mta1.domain.com;mta2.domain.com). |
Configuring for multiple domains
Since I get this question all the time, here are some quick directions for running with multiple domains. Please note that this is untested, but should give you some guidance. In the examples below, I've added a new domain which I called "domain2.com" to the system.
1. Edit /etc/postfix/main.cf
Modify the mydestination variable to include references
to the extra domains (the example below adds a new domain called domain2.com):
mydestination = $myhostname, localhost.$mydomain, $mydomain,
mail.$mydomain.com, localhost.domain2.com, domain2.com, mail.domain2.com
2. Edit /etc/postfix/transports
Here is where you tell postfix where to send email for that domain. So add
the new domain(s) under the one you already added:
domain.com smtp:[10.1.1.50]
domain2.com smtp:[10.1.1.50]
3. Edit /etc/amavisd.conf
Add the domain(s) to the @local_domains_acl hash variable:
@local_domains_acl = ( ".$mydomain", 'domain2.com'
);
Here is an untested script that someone contributed that should add multiple domains to your setup: add-domain.sh. Be sure to edit the DEFAULTTRANSPORT variable to equal the full servername before running the script.
Notes about running
this setup on other Operating Systems
I've received a number of emails from users that have followed these directions
to setup an anti-spam system on operating systems other than OpenBSD. This
section
will include their tips. If you get this system working on any other OS
and want to include your OS specific changes, please send them to me.
Slackware (tips by Derek Shaw)
When creating the symbolic link in the chroot directory, he advises
using the following command:
# cd /var/amavisd &&
mkdir var && ln -s ../ var/amavisd