Overview
CBPolicyD (dikenal juga sebagai Cluebringer) adalah policy server tingkat lanjut yang terintegrasi dengan komponen Carbonio MTA. Dengan CBPolicyD, administrator bisa menerapkan mail policy yang cukup kompleks, mulai dari access control sampai quota, sehingga alur email di dalam organisasi tetap efisien dan sesuai aturan.
CBPolicyD berjalan menggunakan SQL backend (PostgreSQL) dan penting baik untuk environment Carbonio single server maupun multi-server. Di panduan ini saya akan bahas langkah implementasi, konfigurasi, dan pengelolaan CBPolicyD di dalam Carbonio.
Prerequisites
- Carbonio MTA instance yang sudah berjalan.
- Akses administratif ke PostgreSQL server.
- Akses root atau sudo ke server.
1. Install Package yang Dibutuhkan
Pada setiap MTA Server:
Ubuntu 22.04
apt install libdbd-pg-perl -y
RHEL 8
dnf install perl-DBD-Pg -y
Pada PostgreSQL Server, buat user dan database untuk CBPolicyD:
su - postgres
psql
CREATE ROLE policyd WITH LOGIN ENCRYPTED PASSWORD 'aGoodPassword';
CREATE DATABASE policyd OWNER policyd;
Import schema database CBPolicyD dengan menyimpan konten berikut ke /tmp/pssql_policyd.sql:
SET CONSTRAINTS ALL DEFERRED;
/*
Priorities...
0 - System policy priority (fallthrough)
1-50 - System policies
50-100 - Custom policies
*/
/* Policies */
CREATE TABLE policies (
ID SERIAL PRIMARY KEY,
Name VARCHAR(255) NOT NULL,
Priority SMALLINT NOT NULL,
Description TEXT,
Disabled SMALLINT NOT NULL DEFAULT '0'
) ;
INSERT INTO policies (Name,Priority,Description) VALUES ('Default',0,'Default System Policy');
INSERT INTO policies (Name,Priority,Description) VALUES ('Default Outbound',10,'Default Outbound System Policy');
INSERT INTO policies (Name,Priority,Description) VALUES ('Default Inbound',10,'Default Inbound System Policy');
INSERT INTO policies (Name,Priority,Description) VALUES ('Default Internal',20,'Default Internal System Policy');
INSERT INTO policies (Name,Priority,Description) VALUES ('Test',50,'Test policy');
/* Member list for policies */
CREATE TABLE policy_members (
ID SERIAL PRIMARY KEY,
PolicyID INT8,
Source TEXT,
Destination TEXT,
Comment VARCHAR(1024),
Disabled SMALLINT NOT NULL DEFAULT '0',
FOREIGN KEY (PolicyID) REFERENCES policies(ID)
) ;
INSERT INTO policy_members (PolicyID,Source,Destination) VALUES (1,NULL,NULL);
INSERT INTO policy_members (PolicyID,Source,Destination) VALUES (2,'%internal_ips,%internal_domains','!%internal_domains');
INSERT INTO policy_members (PolicyID,Source,Destination) VALUES (3,'!%internal_ips,!%internal_domains','%internal_domains');
INSERT INTO policy_members (PolicyID,Source,Destination) VALUES (4,'%internal_ips,%internal_domains','%internal_domains');
INSERT INTO policy_members (PolicyID,Source,Destination) VALUES (5,'@example.net',NULL);
/* Groups usable in ACL */
CREATE TABLE policy_groups (
ID SERIAL PRIMARY KEY,
Name VARCHAR(255) NOT NULL,
Disabled SMALLINT NOT NULL DEFAULT '0',
Comment VARCHAR(1024),
UNIQUE (Name)
) ;
INSERT INTO policy_groups (Name) VALUES ('internal_ips');
INSERT INTO policy_groups (Name) VALUES ('internal_domains');
/* Group members */
CREATE TABLE policy_group_members (
ID SERIAL PRIMARY KEY,
PolicyGroupID INT8,
Member VARCHAR(255) NOT NULL,
Disabled SMALLINT NOT NULL DEFAULT '0',
Comment VARCHAR(1024),
FOREIGN KEY (PolicyGroupID) REFERENCES policy_groups(ID)
) ;
INSERT INTO policy_group_members (PolicyGroupID,Member) VALUES (1,'10.0.0.0/8');
INSERT INTO policy_group_members (PolicyGroupID,Member) VALUES (2,'@example.org');
INSERT INTO policy_group_members (PolicyGroupID,Member) VALUES (2,'@example.com');
/* Message session tracking */
CREATE TABLE session_tracking (
Instance VARCHAR(255),
QueueID VARCHAR(255),
UnixTimestamp BIGINT NOT NULL,
ClientAddress VARCHAR(64),
ClientName VARCHAR(255),
ClientReverseName VARCHAR(255),
Protocol VARCHAR(255),
EncryptionProtocol VARCHAR(255),
EncryptionCipher VARCHAR(255),
EncryptionKeySize VARCHAR(255),
SASLMethod VARCHAR(255),
SASLSender VARCHAR(255),
SASLUsername VARCHAR(255),
Helo VARCHAR(255),
Sender VARCHAR(255),
Size INT8,
RecipientData TEXT,
UNIQUE (Instance)
) ;
CREATE INDEX session_tracking_idx1 ON session_tracking (QueueID,ClientAddress,Sender);
CREATE INDEX session_tracking_idx2 ON session_tracking (UnixTimestamp);
/* Plain and simple access control */
CREATE TABLE access_control (
ID SERIAL PRIMARY KEY,
PolicyID INT8,
Name VARCHAR(255) NOT NULL,
Verdict VARCHAR(255),
Data TEXT,
Comment VARCHAR(1024),
Disabled SMALLINT NOT NULL DEFAULT '0',
FOREIGN KEY (PolicyID) REFERENCES policies(ID)
) ;
/* Main quotas table */
CREATE TABLE quotas (
ID SERIAL PRIMARY KEY,
PolicyID INT8,
Name VARCHAR(255) NOT NULL,
Track VARCHAR(255) NOT NULL,
Period INT8,
Verdict VARCHAR(255),
Data TEXT,
LastQuota SMALLINT NOT NULL DEFAULT '0',
Comment VARCHAR(1024),
Disabled SMALLINT NOT NULL DEFAULT '0',
FOREIGN KEY (PolicyID) REFERENCES policies(ID)
) ;
INSERT INTO quotas (PolicyID,Name,Track,Period,Verdict) VALUES (5,'Recipient quotas','Recipient:user@domain',3600,'REJECT');
INSERT INTO quotas (PolicyID,Name,Track,Period,Verdict) VALUES (5,'Quota on all /24s','SenderIP:/24',3600,'REJECT');
/* Limits for the quota */
CREATE TABLE quotas_limits (
ID SERIAL PRIMARY KEY,
QuotasID INT8,
Type VARCHAR(255),
CounterLimit INT8,
Comment VARCHAR(1024),
Disabled SMALLINT NOT NULL DEFAULT '0',
FOREIGN KEY (QuotasID) REFERENCES quotas(ID)
) ;
INSERT INTO quotas_limits (QuotasID,Type,CounterLimit) VALUES (1,'MessageCount',10);
INSERT INTO quotas_limits (QuotasID,Type,CounterLimit) VALUES (1,'MessageCumulativeSize',8000);
INSERT INTO quotas_limits (QuotasID,Type,CounterLimit) VALUES (2,'MessageCount',12);
/* This table is used for tracking the quotas */
CREATE TABLE quotas_tracking (
QuotasLimitsID INT8,
TrackKey VARCHAR(512),
LastUpdate INT8,
Counter NUMERIC(10,4),
UNIQUE (QuotasLimitsID,TrackKey),
FOREIGN KEY (QuotasLimitsID) REFERENCES quotas_limits(ID)
) ;
CREATE INDEX quotas_tracking_idx1 ON quotas_tracking (LastUpdate);
/* (Tabel amavis_rules, checkhelo, checkspf, greylisting, accounting, dan tracking lainnya
mengikuti schema resmi CBPolicyD. Salin schema lengkap dari dokumentasi resmi Carbonio
ke dalam file yang sama sebelum import.) */
Catatan, blok di atas saya ringkas pada bagian akhir schema. Untuk produksi, gunakan schema lengkap CBPolicyD (termasuk tabel amavis_rules, checkhelo, checkhelo_blacklist, checkhelo_whitelist, checkhelo_tracking, checkspf, greylisting, greylisting_whitelist, greylisting_autowhitelist, greylisting_autoblacklist, greylisting_tracking, accounting, dan accounting_tracking) persis seperti dokumentasi resmi.
Import schema:
PGPASSWORD=aGoodPassword psql -U policyd -h 127.0.0.1 -f /tmp/pssql_policyd.sql
Jika perlu, berikan hak login secara eksplisit ke user policyd:
ALTER ROLE policyd WITH LOGIN;
Restart service PostgreSQL:
# RHEL 8
systemctl restart postgresql-16.service
# Ubuntu 22.04
systemctl restart postgresql.service postgresql-16.service
2. Konfigurasi Koneksi CBPolicyD
Edit file cbpolicyd.conf.in dan update bagian database. Path file ada di /opt/zextras/conf/cbpolicyd.conf.in. Sebelum diubah, backup dulu filenya.
[database]
host=[DATABASE_IP]
dsn=DBI:Pg:database=policyd;port=5432;host=[DATABASE_IP]
Username= policyd
Password= aGoodPassword
Sesuaikan Username dan Password dengan setup kalian.
3. Enable Modul CBPolicyD di Carbonio
Jalankan perintah berikut:
carbonio prov -l mcf zimbraCBPolicydAccessControlEnabled TRUE
carbonio prov -l mcf zimbraCBPolicydAccountingEnabled TRUE
carbonio prov -l mcf zimbraCBPolicydQuotasEnabled TRUE
carbonio prov -l mcf zimbraCBPolicydBypassMode pass
Enable service CBPolicyD pada setiap MTA server:
carbonio prov ms $(hostname -f) +zimbraServiceInstalled cbpolicyd
carbonio prov ms $(hostname -f) +zimbraServiceEnabled cbpolicyd
zmconfigdctl restart
zmmtactl restart
Untuk skenario single node, restart semua service pada node:
zmcontrol restart
Memahami dan Mengelola Policy
CBPolicyD memakai policy untuk menentukan bagaimana traffic email dikontrol. Sebuah Policy mengaitkan:
- Source: siapa yang mengirim email (user, domain, IP, group, dll).
- Destination: siapa yang menerima email (bisa any, domain tertentu, atau user).
- Modules: aksi apa yang diterapkan (misalnya allow, reject, rate-limit).
Policy dievaluasi berdasarkan priority (angka lebih kecil diproses lebih dulu). Bisa ada banyak policy, dan policy pertama yang cocok akan diproses.
Modul utama:
- Access Control: langsung menerima atau menolak sebuah pesan.
- Quotas: menentukan berapa banyak email yang boleh dikirim sebuah source dalam satuan waktu.
- Accounting: melacak jumlah dan ukuran pesan.
Mengelola Policy CBPolicyD via SQL
Di Carbonio, pengelolaan policy bisa dilakukan efisien lewat operasi SQL langsung pada database policyd. Cara masuk ke database policyd di PostgreSQL:
su - postgres
psql
postgres=# c policyd;
policyd=# dt;
Group Management
# List groups
SELECT * FROM policy_groups;
# Add group
INSERT INTO policy_groups (name, disabled, comment) VALUES ('FilteredAccounts', 0, 'Accounts that cannot send');
# Update group
UPDATE policy_groups SET name = 'NewGroupName', disabled = 0 WHERE id = GROUP_ID;
# Delete group
DELETE FROM policy_groups WHERE id = GROUP_ID;
Group Member Management
# List members
SELECT * FROM policy_group_members;
# Add member
INSERT INTO policy_group_members (policygroupid, member, disabled, comment) VALUES (GROUP_ID, 'user@example.com', 0, '');
# Update member
UPDATE policy_group_members SET member = 'newuser@example.com' WHERE id = MEMBER_ID;
# Delete member
DELETE FROM policy_group_members WHERE id = MEMBER_ID;
Policy Management
# List policies
SELECT * FROM policies;
# Add policy
INSERT INTO policies (name, priority, description) VALUES ('DenyUsers', 10, 'Do not allow accounts to send messages');
# Update policy
UPDATE policies SET name = 'AllowUsers', priority = 20 WHERE id = POLICY_ID;
# Delete policy
DELETE FROM policies WHERE id = POLICY_ID;
Policy Member Management
# List policy members
SELECT * FROM policy_members;
# Add policy member
INSERT INTO policy_members (policyid, source, destination) VALUES (POLICY_ID, '%FilteredAccounts', 'any');
# Update policy member
UPDATE policy_members SET source = '%NewGroup' WHERE id = POLICY_MEMBER_ID;
# Delete policy member
DELETE FROM policy_members WHERE id = POLICY_MEMBER_ID;
Access Control Management
# List access control
SELECT * FROM access_control;
# Add access control
INSERT INTO access_control (policyid, name, verdict, data, comment, disabled) VALUES (POLICY_ID, 'BlockUsers', 'REJECT', 'Not Allowed to Send', '', 0);
# Update access control
UPDATE access_control SET verdict = 'HOLD' WHERE id = ACCESS_CONTROL_ID;
# Delete access control
DELETE FROM access_control WHERE id = ACCESS_CONTROL_ID;
Penjelasan Verdict Actions
- REJECT: menolak email disertai pesan.
- HOLD: menahan email untuk direview.
- DISCARD: menghapus pesan secara diam-diam.
- FILTER: meneruskan email ke content filter.
- REDIRECT: mengalihkan email ke alamat lain.
- OK: mengizinkan email lewat tanpa perubahan.
Troubleshooting CBPolicyD
Aktifkan verbose logging:
carbonio prov mcf zimbraCBPolicydLogLevel 4
zmlocalconfig -e cbpolicyd_log_detail=modules,tracking,policies
zmcbpolicydctl restart
Untuk troubleshooting, cek log di /opt/zextras/log/cbpolicyd.log.
Penutup
Sampai titik ini CBPolicyD sudah terpasang, terhubung ke PostgreSQL, dan modulnya aktif di Carbonio. Selanjutnya tinggal menyesuaikan policy sesuai kebutuhan organisasi, entah untuk access control, quota, maupun accounting. Untuk contoh konfigurasi yang lebih detail, saya sarankan merujuk ke dokumentasi policy resmi CBPolicyD.