Carbonio is a very fine e-mail server but you must take all measures to avoid the damage an infected account can do to your server reputation. Sending thousands of spams will definitively put your server in blocklists on all major Email providers.
So, this is a tutorial to enable and setup cbpolicy to create sending policies and avoid problems.
How does it work?
cbpolicyd is a smtp filter integrated with Carbonio’s postfix. It’s a very flexible tool and there are many ways to set it up, but the most common one is the sender counting one. So, when a message is sent it register it’s sender and count how many messages this sender sent. Once it reaches a defined policy, a limit, messages will not be allowed to be sent anymore and the user will get an error message.
I like to use 3 policies working together:
1 – limit of 100 messages by sender in the last 5 minutes;
2 – limit of 200 messages by sender in the last hour;
3 – limit of 400 messages by sender in the last 24 hours;
That way we control different types of possible attacks. My experience shows that regular users will never get blocked but once an e-mail is infectes it will only be able to send 100 messages before it gets locked and can’t send messages anymore.
Well, to be totally honest it will. But just one message every 5 minutes, what makes that attack useless anyway.
So, now you know how it works: counting messages by sender and limiting it under some criteria.
Activation
cbpolicyd doesn’t come activated by default on Carbonio. So to do it run the command below:
su - zextras -c "zmprov ms `/opt/zextras/bin/zmhostname` +zimbraServiceEnabled cbpolicyd"
Web Interface setup
Sadly Carbonio CE doesn’t setup it’s webserver to allow you to get into cbpolicyd web panel. So we’ll need to workaround it setting up our own webserver. We’ll use a docker container to do it.
- Install docker
apt update
apt install docker.io libnet-ssleay-perl
- Creating config.php
Move old config.php to have a backup
mv /opt/zextras/common/share/webui/includes/config.php /opt/zextras/common/share/webui/includes/config.php.orig
Create a new one with the content below
<?php
$DB_DSN="sqlite:////opt/zextras/data/cbpolicyd/db/cbpolicyd.sqlitedb";
$DB_USER="root";
$DB_TABLE_PREFIX="";
?>
- Creating cbpolicyd_docker.conf
Let’s create a file to be used by Apache container. Create a new file “/opt/containerd/cbpolicyd_docker.conf” with the content below
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<Directory /var/www/html>
Options Indexes Includes FollowSymLinks MultiViews
AllowOverride All
Require all granted
</Directory>
- Creating a .htaccess file
Create a /opt/zextras/common/share/webui/.htaccess file with this content:
AuthType Basic
AuthName "User and Password"
AuthUserFile /var/www/html/.htpasswd
Require valid-user
- Creating Apache container
Let’s create that Docker Apache container:
docker run -d -p 7780:80 --restart=always -v /opt/zextras/common/share/webui:/var/www/html -v /opt/zextras/data/cbpolicyd/db:/opt/zextras/data/cbpolicyd/db -v /opt/containerd/cbpolicyd_docker.conf:/etc/apache2/sites-available/000-default.conf --name cbpolicyd php:8.1-apache
- Admin user and password
Once the container is up and running we’ll need to setup an admin account and it’s password. Remember to replace “YOUR_PASSWORD_HERE” for your actually password
docker exec --workdir /var/www/html cbpolicyd htpasswd -b -c .htpasswd admin_policyd YOUR_PASSWORD_HERE
- Fixing quotas-limits-main.php
There is a line in that file that is not compatible with PHP 8.1. So far that’s the only issue I found. So let’s fix it.
Edit /opt/zextras/common/share/webui/quotas-limits-main.php and comment out line 40 to be like this:
#$stmt = $db->prepare("SELECT Type, CounterLimit, Disabled FROM ${DB_TABLE_PREFIX}quota_limits WHERE QuotaID = ?");
- Accessing cbpolicyd admin panel
If everything is working as expected you may be able to access the panel using the url below. Remember to replace “YOUR_SERVER_NAME” for your server name or IP address.
http://YOUR_SERVER_NAME:7780/
user: admin_policyd
password: YOUR_PASSWORD
- Restart Carbonio
su - zextras -c"zmcontrol restart"
Policies
Create policies can be tricky and will not be part of this tutorial at all. Using this interface and all the possible variations and steps it would take forever.
What I’m gonna do is provide you with my preset database so you can start from it and adapt it to your needs.
Download cbpolicy preset db files from here
Let’s decompress and copy it to the right place following the commands below
wget https://www.anahuac.eu/cbpolicyd_db.tgz
tar zxvf cbpolicyd_db.tgz
cp -a /opt/zextras/data/cbpolicyd/db/ /opt/zextras/data/cbpolicyd/db.orig
cp cbpolicyd_db/* /opt/zextras/data/cbpolicyd/db/
chown zextras: /opt/zextras/data/cbpolicyd/db/ -R
chmod 777 /opt/zextras/data/cbpolicyd -R
And if you’re wondering, yes 777 is needed because the container also needs permission to read and write on those files
Reload your browser and take a good look on those menus on cbpolicyd web panel
Policies -> Main
Policies -> Groups
* Add your domain on “internal_domains” group with @ like “@yourdomain”
Quotas -> Configure
http x https
Since ever cbpolicyd web panel has been available only through http but Carbonio brings in an easy way to get it working on HTTPS because of it’s built in Nginx custom templates.
So this is how you get it done.
- create /opt/zextras/conf/nginx/templates_custom/cbpolicyd.https
Create this file with the content below replacing all entries of YOUR_SERVER_IP, YOUR_SERVER_NAME
server {
server_name YOUR_SERVER_NAME;
listen YOUR_SERVER_IP:7781 ssl http2;
client_max_body_size 0;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 600;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128:AES256:TLS_AES_256_GCM_SHA384:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4;
ssl_ecdh_curve prime256v1;
ssl_verify_client off;
proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
proxy_ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128:AES256:TLS_AES_256_GCM_SHA384:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4;
ssl_dhparam /opt/zextras/conf/dhparam.pem;
ssl_certificate /opt/zextras/ssl/carbonio/commercial/commercial.crt;
ssl_certificate_key /opt/zextras/ssl/carbonio/commercial/commercial.key;
location / {
proxy_pass http://YOUR_SERVER_NAME:7780;
proxy_set_header Host YOUR_SERVER_NAME;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_hide_header 'x-frame-options';
rewrite ^/(.*) /$1 break;
port_in_redirect off;
}
}
- Creating custom template
To create Nginx custom template do as follows
cp -a /opt/zextras/conf/nginx/templates/nginx.conf.web.https.default.template /opt/zextras/conf/nginx/templates_custom
echo "include /opt/zextras/conf/nginx/templates_custom/cbpolicyd.https;" >> /opt/zextras/conf/nginx/templates_custom/nginx.conf.web.https.default.template
- Fixing permissions
chown zextras: /opt/zextras/conf/nginx/templates_custom/*
- Restart Carbonio
su - zextras -c"zmcontrol restart"
- Access using https
To access it using https use the as it is below:
https://YOUR_SERVER_NAME:7781/index.php
This is great and very useful documentation…. It would be great if the whole cbpolicy module would be part of the Carbonio core.. so that users don’t need to separately install this…..
Muito bom
Parabéns pelo conteúdo