Friday, May 10, 2013

Limit Mail With Policyd


This document is geared towards using Policyd (cluebringer) on Ubuntu to limit mail with Postfix.

As the name implies, Policyd is a policy server for MTAs. From their website:
Policyd v2 (codenamed “cluebringer”) is a multi-platform policy server for popular MTAs. This policy daemon is designed mostly for large scale mail hosting environments. The main goal is to implement as many spam combating and email compliance features as possible while at the same time maintaining the portability, stability and performance required for mission critical email hosting of today. Most of the ideas and methods implemented in Policyd v2 stem from Policyd v1 as well as the authors’ long time involvement in large scale mail hosting industry.
Even if you don’t have a “large scale mail hosting environment”, you can still greatly benefit from Policyd.
Currently, I only use the Quota module with Policyd, which allows for limiting the rate of mail based on its attributes.
This document is written for Ubuntu 12.04 LTS Server. Older versions of Ubuntu (10.04 at least), used the older version of policyd, which will not be covered.
Table of Contents 
  • 1 What this guide is
  • 2 Install the prerequisites
  • 3 Download the source
  • 4 Setup SQL
  • 5 Setup Config Files
  • 6 Install Program
  • 7 Configure it
  • 8 Start the daemon
  • 9 Install WebUI
  • 10 Integrate with Postfix
  • 11 Completion
  • 12 Creating policies

What this guide is

This guide mostly covers installing the software and getting it setup on your server. I haven’t gone into detail on how to actually create policies and such, as that can be figured out with the web interface.
Ubuntu comes with a cluebringer package in the repos, but it’s fairly outdated and doesn’t really do most of what you actually need to do to get it functional (the database setup, the web interface setup, and the Postfix implementation). That said, this guide will walk through installing it from source.

Install the prerequisites

You need:
  • MySQL, PostgreSQL, or SQLite
  • Net::Server >= 0.96
  • Net::CIDR
  • Config::IniFiles
  • Cache::FastMmap
  • Mail::SPF
If you want the web interface, you’ll also need:
  • PHP 5+ with PDO support for your DB

Download the source

Visit http://devlabs.linuxassist.net/projects/policyd/files
Download the latest of the 2.0.x branch.
Once downloaded, extract it.

Setup SQL

Create a database for it. If using MySQL:
CREATE DATABASE policyd;
GRANT ALL ON policyd TO 'cluebringer'@'localhost' IDENTIFIED BY 'secret';
Now go to the source directory and to the “database” directory.
If you’re using MySQL: there’s one modification:
#sed -i -e 's/Type=InnoDB/Engine=InnoDB/g' convert-tsql
Run the following:
for i in  core.tsql access_control.tsql quotas.tsql amavis.tsql checkhelo.tsql checkspf.tsql greylisting.tsql
do
  ./convert-tsql mysql $i
done > policyd.mysql
Substitute ‘mysql’ for pgsql or sqlite. Make sure you put core.tsql FIRST in the for loop!
Now load the SQL into your database. If you’re using MySQL:
#mysql -u root -p policyd < policyd.mysql

Setup Config Files

#mkdir /etc/cluebringer
Copy the cluebringer.conf file from the source directory to the path you just created (/etc/cluebringer)

Install Program

Copy the program to the correct locations:
#cp -r cbp /usr/local/lib/policyd-2.0/
#cp cbpadmin /usr/local/bin/
#cp cbpolicyd /usr/local/sbin/
You’ll also need an init script. Mine’s just a modified version of one the Ubuntu package comes with:
postfix-cluebringer.init
Download that and move it to /etc/init.d/postfix-cluebringer. Make sure it’s owned by root and #chmod 755
That sources a defaults file:
postfix-cluebringer.default
Download that and move it to /etc/default/postfix-cluebringer. Give it root ownership and
#chmod 644
Edit it as needed.
Finally, create a user/group:
#useradd -d /etc/cluebringer -u 125 cluebringer

Configure it

Open up /etc/cluebringer/cluebringer.conf in an editor.
The items in this file are pretty self-explanatory. If in doubt, leave things as default.
Set the user and group variables to cluebringer
You also might want to set log_mail to mail@syslog:native for now to see log entries in your mail.log
Towards the end of the file, you’ll need to edit the variables under [database] with the appropriate values for the database you created.
Don’t worry about firing it up and breaking mail – there aren’t any rules that do anything by default.

Start the daemon

You should be able to start the daemon at this point.
#/etc/init.d/postfix-cluebringer start
Watch /var/log/cbpolicyd.log for output.

Install WebUI

This is optional, but highly recommended. Otherwise, you’ll have to configure the software via SQL.
Copy the webui directory to your desired location. For example:
#cp -r webui /var/www/cluebringer
To make things easy, I modify the file includes/config.php and replace everything with:
<?php
require_once("/etc/cluebringer/cluebringer-webui.conf");
?>
Then, create the file /etc/cluebringer/cluebringer-webui.conf with the following contents:
<?php
# mysql:host=xx;dbname=yyy
# pgsql:host=xx;dbname=yyy
# sqlite:////full/unix/path/to/file.db?mode=0666
#
#$DB_DSN="sqlite:////tmp/cluebringer.sqlite";
#$DB_DSN="pgsql:host=xx;dbname=yyy";
#$DB_DSN="mysql:host=xx;dbname=yyy";

#$DB_DSN="_DBC_DBTYPE_:host=_DBC_DBSERVER_;dbname=_DBC_DBNAME_";
$DB_DSN="mysql:host=localhost;dbname=policyd";
$DB_USER="cluebringer";
$DB_PASS="secret";
?>
Edit that accordingly with the variables you used to setup your database.
Now you need a config for your web server. Nothing crazy here. Look at my examples if you need to:
Apache vhost (SSL+LDAP auth)
Nginx (SSL+auth)

Integrate with Postfix

You need to tell Postfix about it. The INSTALL file says add:
check_policy_service inet:127.0.0.1:10031
in BOTH smtpd_recipient_restrictions and smtpd_end_of_data_restrictions
Wherever you add it, make sure you put it before other permit lines as appropriate. For example, if you want to rate limit outgoing mail, you might want to place it before permit_mynetworks
Re[start|load] postfix and watch mail.log for errors connecting to 10031!

Completion

You should be done at this point and able to navigate to the webui.

Creating policies

If you explore the web interface, you should pick up on how to add rules. It comes with a few defaults to give you an idea.
First, you’ll want to navigate to Policies -> Groups and change the values for internal_domains and internal_ips
You do that by selecting the item and choosing Members from the action drop-down menu. From there, you’ll see the default items. You can change them by selecting the item and choosing Change from the action drop-down menu.
One thing to watch for is that adding entries will be disabled by default. Once you add one, you’ll need to Change it and enable it if you want to use it.
For limiting the number of messages coming in/going out, you’ll look under the Quotas module.
Here, you’ll create polices such as Limit sender@domain messages on the Default Inbound policy. Then, you’ll add a Limit to that policy. So, create a policy and save it, select the policy and choose Limits from the action drop-down. Add a number of messages for the time period you defined, save it. Then, make sure you Change the limit after saving and enable it. You’ll also have to enable the quota you created.
In SQL, it looks like this:
mysql> select * from policyd.quotas;
+----+----------+---------------------+-----------------------+--------+---------+------+----------------------------------------------------------+----------+
| ID | PolicyID | Name                | Track                 | Period | Verdict | Data | Comment                                                  | Disabled |
+----+----------+---------------------+-----------------------+--------+---------+------+----------------------------------------------------------+----------+
|  6 |        3 | Limit incoming user | Sender:user@domain    |   3600 | REJECT  | 501  | Limit incoming mail from a user to 700 messages per hour |        0 |
|  7 |        3 | Limit incoming IP   | SenderIP:/32          |   3600 | REJECT  | 699  |                                                          |        0 |
|  8 |        2 | Limit outgoing      | Sender:user@domain    |   3600 | REJECT  | 300  | Limit outgoing to 300 per hour                           |        0 |
|  9 |        3 | Incoming to user    | Recipient:user@domain |   3600 | REJECT  | 499  |                                                          |        0 |
+----+----------+---------------------+-----------------------+--------+---------+------+----------------------------------------------------------+----------+
mysql> select * from policyd.quotas_limits;
+----+----------+--------------+--------------+---------+----------+
| ID | QuotasID | Type         | CounterLimit | Comment | Disabled |
+----+----------+--------------+--------------+---------+----------+
|  7 |        6 | MessageCount |          501 |         |        0 |
|  8 |        7 | MessageCount |          699 |         |        0 |
|  9 |        8 | MessageCount |          300 |         |        0 |
| 10 |        9 | MessageCount |          499 |         |        0 |
+----+----------+--------------+--------------+---------+----------+
So in a period of 3600 seconds (1 hour), I’m limiting incoming mail from a single sender to 501 messages, and REJECTing them beyond that.
In this example, we’re also limiting outgoing messages from a single user to 300 messages in a 1 hour period.
Once you get a policy, and ensured it’s enabled (and all its components are enabled), watch mail.log for output (tail -f mail.log | grep cbpolicy)
Be aware of the whole “chain” to policyd. As you can see above, a quota doesn’t do any good without a limit set, and both need to be enabled. A quota also won’t do anything if it isn’t associated with a policy. Polices are determined by their members (e.g. matching IP addresses).

5 comments:

  1. Hi,
    Amazing guide, Before trying this I was wondering if this policyd could i also limit some users attachments? and also restrict them from sending emails outside?

    Thank you

    ReplyDelete
  2. Hi,
    First I want to thank you for making this great tutorial. Now I want to know, is it possible to delay the emails for next hour? Something like I want to send 100 emails per hour from a server. If I send 200 emails then 100 emails will be sent and the another 100 emails will be wait for next hour and when time time reach the emails will be sent automatically.

    Thanks in advanced.

    ReplyDelete
  3. This comment has been removed by a blog administrator.

    ReplyDelete
  4. Hi.

    Does this guide work with Centos 6 as well?

    ReplyDelete
  5. I dont understand the line :

    Copy the webui directory to your desired location. For example:
    #cp -r webui /var/www/cluebringer

    PLEASE CAN YOU TELL ME which one is the "webui" directory?

    ReplyDelete