Cara Implementasi dan Mengelola CBPolicyD di Carbonio

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.

Leave a Reply

Your email address will not be published. Required fields are marked *