Integrasi LDAP dengan postfix dan dovecot

Integrasi Postfix + Dovecot + OpenLDAP

Integrasi Postfix + Dovecot + OpenLDAP

Virtual users via LDAP — Debian 12 · LKS ITNSA Ready

✓ Tested & Working result_attribute = mail Virtual Users

Konsep & Arsitektur

Tiga komponen bekerja bersama: Postfix terima dan route email, Dovecot simpan email dan handle login, OpenLDAP jadi database sentral user. Semua user bersifat virtual — tidak punya akun Linux di /etc/passwd.

Email Masuk Postfix → query LDAP (validasi field mail) → Dovecot LDA /home/budi@example.com/Maildir/
Login IMAP Dovecot → auth LDAP → buka /home/budi@example.com/Maildir/
Penyebab error umum: Domain example.com ada di mydestination sekaligus di virtual_mailbox_domains. Postfix akan anggap email ke domain itu sebagai local delivery → cari user di /etc/passwdunknown user. Solusi: domain hanya boleh ada di salah satu.

Bagian 1 — Postfix

1 /etc/postfix/main.cf
/etc/postfix/main.cf
# FQDN server — Fully Qualified Domain Name
# Digunakan sebagai identitas server saat handshake SMTP
myhostname = mail.example.com

# mydestination = daftar domain yang di-deliver sebagai LOCAL user (/etc/passwd)
# KRUSIAL: example.com TIDAK boleh ada di sini
# Kalau ada, Postfix cari budi di /etc/passwd → unknown user error
mydestination = $myhostname, localhost.$mydomain, localhost

# Domain yang di-handle sebagai virtual mailbox
# Dipisah dari mydestination agar Postfix tahu ini virtual, bukan local
virtual_mailbox_domains = example.com

# Postfix tanya ke LDAP: "apakah user tujuan email ini ada?"
# Format "ldap:/path/ke/file.cf" = konfigurasi query ada di file terpisah
virtual_mailbox_maps = ldap:/etc/postfix/ldap-users.cf

# Setelah email divalidasi, teruskan ke Dovecot untuk disimpan secara fisik
# "dovecot" merujuk ke nama transport yang didefinisikan di master.cf
virtual_transport = dovecot

# SASL — Simple Authentication and Security Layer
# Postfix delegasikan proses verifikasi password ke Dovecot via unix socket
# smtpd_sasl_type = dovecot → pakai implementasi SASL milik Dovecot, bukan Cyrus
smtpd_sasl_type = dovecot

# Path socket relatif terhadap /var/spool/postfix/
# WAJIB relatif di Debian karena Postfix berjalan dalam chroot
# Chroot = Postfix terisolasi, root filesystem-nya adalah /var/spool/postfix/
# Kalau pakai absolute path, socket tidak ditemukan
smtpd_sasl_path = private/auth

# Aktifkan SASL authentication di Postfix
smtpd_sasl_auth_enable = yes

# noanonymous = tolak siapa pun yang coba auth tanpa identity
smtpd_sasl_security_options = noanonymous

# Aturan relay:
# permit_mynetworks = izinkan dari jaringan lokal
# permit_sasl_authenticated = izinkan user yang sudah login via SASL
# reject_unauth_destination = tolak semua yang lain
smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
2 /etc/postfix/ldap-users.cf

File ini dibuat manual (tidak ada by default). Isi dan strukturnya bisa dilihat via man 5 ldap_table.

/etc/postfix/ldap-users.cf
# Alamat server LDAP
server_host = ldap://127.0.0.1

# Titik awal pencarian di pohon direktori LDAP
# "dc=example,dc=com" = representasi domain example.com dalam format LDAP
search_base = dc=example,dc=com

# Bind = login ke LDAP server sebelum bisa query
# bind_dn = akun service khusus Postfix, bukan akun email biasa
bind = yes
bind_dn = cn=postfix,dc=example,dc=com
bind_pw = passwordPostfix

# Query filter = kondisi pencarian di LDAP
# %s = alamat email LENGKAP tujuan (budi@example.com)
# Berbeda dari %u yang hanya username pendek
# Cari entry LDAP yang field "mail"-nya cocok dengan tujuan email
query_filter = (mail=%s)

# Field LDAP yang dikembalikan sebagai hasil query
# Nilai field "mail" = budi@example.com
result_attribute = mail

# Format path mailbox yang dikirim ke Postfix
# %s diganti dengan nilai result_attribute (budi@example.com)
# Hasil akhir: "budi@example.com/"
# Postfix akan deliver email ke path ini secara langsung
result_format = %s/Maildir

domain = example.com
Karena virtual_mailbox_base dihapus, Postfix pakai nilai dari result_format sebagai path absolut. Pastikan path /home/budi@example.com/ benar-benar ada dan sudah di-chown ke mail:mail.
3 /etc/postfix/master.cf
/etc/postfix/master.cf — tambahkan di baris paling bawah
# Mendefinisikan transport bernama "dovecot"
# Ini yang dipanggil oleh "virtual_transport = dovecot" di main.cf
#
# "pipe" = Postfix pipe email ke program eksternal (dovecot-lda)
# flags=DRhu:
#   D = tambahkan header Delivered-To
#   R = tambahkan Return-Path header
#   h = hostname case-insensitive
#   u = username case-insensitive
# user=mail:mail = jalankan dovecot-lda sebagai user mail, group mail
#   Format user:group — eksplisit agar tidak ambiguous
#
# -f ${sender} = envelope sender (From address)
# -d ${recipient} = tujuan pengiriman dalam format FULL address (budi@example.com)
#   Dovecot LDA pakai nilai ini untuk userdb lookup
#   Harus full address agar sinkron dengan user_filter (mail=%u) di Dovecot
dovecot   unix  -       n       n       -       -       pipe
  flags=DRhu user=mail:mail argv=/usr/lib/dovecot/dovecot-lda -f ${sender} -d ${recipient}

Bagian 2 — Dovecot

4 /etc/dovecot/conf.d/10-auth.conf
10-auth.conf — edit baris berikut
# Nonaktifkan autentikasi sistem lokal (/etc/passwd)
# Tanda "!" di depan = disable/exclude file ini
# Semua user ada di LDAP, bukan di Linux
#!include auth-system.conf.ext

# Aktifkan autentikasi LDAP
!include auth-ldap.conf.ext

# Mekanisme auth yang diizinkan
# plain = kirim password as-is (aman kalau pakai TLS)
# login = kompatibilitas dengan email client lama (Outlook, dll)
auth_mechanisms = plain login
5 /etc/dovecot/conf.d/auth-ldap.conf.ext
auth-ldap.conf.ext
# passdb = database untuk verifikasi password
# driver = ldap → cek password ke OpenLDAP
# args → tunjuk ke file detail koneksi LDAP
passdb {
  driver = ldap
  args = /etc/dovecot/dovecot-ldap.conf.ext
}

# userdb = database untuk informasi filesystem user (home dir, UID, GID)
# driver = static → semua virtual user dipetakan ke nilai yang sama (statis)
#
# uid=8, gid=8 = paksa semua virtual user pakai identitas sistem "mail"
# UID 8 = user "mail" di Debian — user sistem khusus untuk proses email
# Ini mencegah permission denied saat Dovecot akses folder
#
# home=/home/%u → %u = full address (budi@example.com)
# Hasil: /home/budi@example.com — sinkron dengan path di ldap-users.cf
userdb {
  driver = static
  args = uid=8 gid=8 home=/home/%u
}
6 /etc/dovecot/dovecot-ldap.conf.ext
dovecot-ldap.conf.ext
# Alamat server LDAP
hosts = 127.0.0.1

# DN dan password untuk bind (login) ke LDAP
# Akun service khusus Dovecot — bukan user email
dn = cn=dovecot,dc=example,dc=com
dnpass = passwordDovecot

# Titik awal pencarian di pohon direktori LDAP
base = dc=example,dc=com

# Filter untuk mencari entry user saat login
# %u = full address (budi@example.com) karena -d ${recipient} di master.cf
# Cari entry LDAP yang field "mail"-nya cocok
user_filter = (mail=%u)

# Mapping field LDAP → atribut Dovecot untuk verifikasi password
# userPassword (field LDAP) → password (yang dicek Dovecot)
pass_attrs = userPassword=password

# Paksa UID dan GID ke 8 terlepas dari nilai di LDAP
# "=" di depan = override, bukan mapping dari field LDAP
# Mencegah permission denied saat akses Maildir
user_attrs = =uid=8,=gid=8

# Filter untuk verifikasi password — compound filter (dua kondisi)
# & = AND: kedua kondisi harus terpenuhi
# objectClass=inetOrgPerson = entry harus bertipe inetOrgPerson
# mail=%u = field mail harus cocok dengan user yang login
# Lebih aman dari filter tunggal karena mencegah false positive
pass_filter = (&(objectClass=inetOrgPerson)(mail=%u))
7 /etc/dovecot/conf.d/10-mail.conf
10-mail.conf
# Format dan lokasi penyimpanan email tiap user
# maildir: = format Maildir (satu file per email, recommended)
# /home/%u = path fisik, %u = budi@example.com
# Hasil: /home/budi@example.com/ — sinkron dengan result_format di ldap-users.cf
# TIDAK ada /Maildir di belakang — konsisten dengan result_format = %s/Maildir
mail_location = maildir:/home/%u/Maildir

# Dovecot default tolak user dengan UID di bawah 1000 (dianggap akun sistem)
# Diubah ke 8 agar user "mail" (UID 8) bisa dipakai sebagai virtual user
# Tanpa ini: Dovecot throw "user not found" meski LDAP auth sudah sukses
first_valid_uid = 8
8 /etc/dovecot/conf.d/10-master.conf
10-master.conf — tambahkan/edit dua blok ini
# Buka socket agar Postfix bisa minta validasi SASL ke Dovecot
# Path relatif terhadap /var/spool/postfix/ (chroot Postfix)
# mode = 0660 → hanya owner dan group yang bisa akses
# user = postfix, group = mail → Postfix bisa tulis, Dovecot bisa baca
service auth {
  unix_listener /var/spool/postfix/private/auth {
    mode = 0660
    user = postfix
    group = mail
  }
}

# Fix permission untuk stats-writer socket
# Dovecot LDA berjalan sebagai user "mail" (UID 8)
# Tanpa ini: LDA gagal akses stats-writer → error saat delivery
# user = dovecot → owner socket adalah proses dovecot utama
# group = mail → proses LDA (yang jalan sebagai mail) bisa akses
service stats {
  unix_listener stats-writer {
    mode = 0660
    user = dovecot
    group = mail
  }
}

Bagian 3 — Persiapan Maildir

Virtual user tidak punya home directory otomatis — harus dibuat manual. Nama folder pakai full address karena %u = budi@example.com.

bash
# Buat struktur Maildir untuk tiap user
# Format Maildir wajib punya tiga subfolder: new, cur, tmp
# new/ = email baru belum dibaca
# cur/ = email yang sudah pernah dibuka (dipindah IMAP client dari new/)
# tmp/ = email sedang dalam proses ditulis (atomic write, prevent corruption)
# Tanda "" di sekeliling path karena ada karakter @ di nama folder
mkdir -p "/home/budi@example.com/"{new,cur,tmp}
mkdir -p "/home/boaz@example.com/"{new,cur,tmp}

# Ubah kepemilikan ke user "mail" (UID 8) dan group "mail" (GID 8)
# -R = recursive, berlaku ke semua subfolder
# Harus sinkron dengan uid=8 gid=8 di auth-ldap.conf.ext
chown -R mail:mail "/home/budi@example.com" "/home/boaz@example.com"

# Set permission 700 = hanya owner (mail) yang bisa akses
# Mencegah user atau proses lain membaca isi mailbox
chmod -R 700 "/home/budi@example.com" "/home/boaz@example.com"
Nama folder mengandung karakter @ — selalu gunakan tanda kutip " saat referensi path ini di command line, contoh: ls "/home/budi@example.com/"

Bagian 4 — Verifikasi

bash
# Restart kedua service
systemctl restart postfix dovecot
systemctl status postfix dovecot

# Test LDAP query dari Postfix
# Harus return: budi@example.com/
postmap -q budi@example.com ldap:/etc/postfix/ldap-users.cf

# Cek konfigurasi Dovecot — tidak boleh ada error
dovecot -n

# Monitor log real-time saat kirim email test
tail -f /var/log/mail.log

# Test SMTP manual via telnet
telnet localhost 25
EHLO test
MAIL FROM:<test@example.com>
RCPT TO:<budi@example.com>
DATA
Subject: Test LDAP
.
QUIT

Summary Perubahan dari Versi Sebelumnya

File Parameter Lama → Baru Alasan
main.cf virtual_mailbox_base /homedihapus Path sudah absolut dari result_format
ldap-users.cf query_filter (uid=%u)(mail=%s) Query pakai field mail, %s = full address
ldap-users.cf result_format %s/Maildir/%s/ Sinkron dengan mail_location tanpa /Maildir
master.cf argv dovecot pipe -d ${user}@${nexthop}-d ${recipient} Lebih simpel, langsung pakai full envelope recipient
master.cf user flag user=mailuser=mail:mail Eksplisit user dan group
10-mail.conf mail_location maildir:/home/%u/Maildirmaildir:/home/%u/Maildir Sinkron dengan result_format = %s/Maildir
dovecot-ldap.conf.ext user_filter (uid=%n)(mail=%u) %u = full address sekarang, cari by field mail
dovecot-ldap.conf.ext pass_filter (objectClass=inetOrgPerson)(&(objectClass=...)(mail=%u)) Compound filter, lebih presisi
10-master.conf service stats tidak adastats-writer fix Fix permission Dovecot LDA ke stats socket
Maildir path nama folder /home/budi//home/budi@example.com/ Sinkron dengan %u = full address

Checklist kompetisi: mydestination tidak mengandung domain email · postmap -q return path yang benar · Maildir dibuat dengan nama domain lengkap · chown dan chmod sudah dijalankan · stats-writer fix ada di 10-master.conf

Comments

Post a Comment

Popular posts from this blog

Apa itu Link Aggregation?

Apa Itu Port Security di Switch Cisco