FreeBSD + Postfix + Dovecot2 + LDAP + MySQL

Пост считать устаревшим. Новый цикл тут.
На работе решил заточить почтовый сервер (на замену старому). Что требуется от сервера? Авторизация как по MySQL так и по LDAP. По хорошему, надо NTLM, но только на внутреннюю сеть. Также желательно нацепить антивирус, антиспам, квотирование, и т. п. Выбор пал на связку Dovecot 2 + Postfix (SASL dovecot 2).
В качестве операционной системы выбрал FreeBSD 10, так как считаю, что в корпоративном сегменты это лучший выбор из бесплатного.
Почему не Debian и производные? Ну не люблю я debian. Допиливание того, что «из коробки», пляски с репозиториями, попытки совместить несовместимое, неинтуитивные решения некоторых проблем... Ну не лежит у меня верхняя часть туловища к нему.
Почему не rpm? Честно, мне нравится OpenSUSE. Но как настольная операционка. В серверной части она не отстаёт только при 1 условии: отсутствие yast. То есть все плюсы этой операционки отсекаются в серверном решении. А это значит, что разобраться в моих конфигах будет сложнее на порядок.
FreeBSD. По сути, не нуждается в обновлениях. Не так уж то и много неявных решений. То есть если делать по уму, то разобраться сможет любо знакомый с этой системой. На мой взгляд самое то.
Начнём.

Настройка FreeBSD


На тему установки литературы море. Делаем всё штатно. При выборе параметров установки не выбрал ничего. Всё, что нужно настрою после. В обязательно указываем SSHD. Остальное на вкус. Добавил пользователя. В дополнительных группах указал wheel, чтобы удачно выполнять sudo. Ребут. Заходим под рутом (я зашёл по ssh, а значит сначала под своей учётной записи, а потом «su»)
Займёмся портами.
# portsnap fetch
# portsnap extract

Эти команды будут выполняться около 5 минут (зависит от скорости тырнета). Первая команда скачивает коллекцию портов, а вторая эту коллекцию распаковывает. Так, как коллекции у меня на данный момент нет, то необходима именно распаковка.
Дальше нужно обновить исходные коды:
# svnlite co https://svn.freebsd.org/base/head /usr/src

Ждёмс...
После получения исходных кодов можно обновлять операционку:
# freebsd-update fetch
# freebsd-update install


Теперь перед перезагрузкой я бы посоветовал установить необходимые программы. А именно: sudo, portupgrade, nano, subversion. Я косервативен. Плюс люблю всё контролировать. Поэтому make =))

  • nano
    # cd /usr/ports/editors/nano
    # make config-recursive
    # make config-recursive

    2 раз бывает необходим, если вы правили зависимости у зависимых пакетов. Советую поначалу ставить всё по умолчанию. Если вы, конечно, не знаете, что делаете.
    # make install clean
    # rehash


    Сразу же правлю
    # nano /root/.cshrc

    #setenv EDITOR vi
    setenv EDITOR nano

    Не привык я в своё время к vi =(.
  • sudo
    # cd /usr/ports/security/sudo
    # make config-recursive
    # make config-recursive
    # make install clean
    # rehash


    Правлю
    # visudo

    Закомментировал строчку
    #root ALL=(ALL) ALL

    Эта строчка разрешает запуск sudo всем пользователям
    Раскомментировал
    %wheel ALL=(ALL) ALL

    Эта строчка разрешает запуск sudo только пользователям группы wheel (а мы как раз и в ней)
    Добавил строчку
    Default timestamp_timeout=30

    Эта магичаская строчка добавит возможность не вводить пароль в течение 30 минут простоя. Кстати! Обратил внимание на строчку
    #Defaults targetpw

    Эта строчка требует ввод пароль от РУТА! Если закомментирована запуск sudo требует пароль пользователя.
  • portupgrade. Этот пакет поможет следить за обновлениями.
    # cd /usr/ports/ports-mgmt/portupgrade
    # make config-recursive
    # make config-recursive
    # make install clean
    # rehash
  • subversion. Этот пакет поможет обновлять исходные коды системы.
    # cd /usr/ports/devel/portupgrade
    # make config-recursive
    # make config-recursive
    # make install clean
    # rehash
  • Подтянул UTF-8 на русском:
    # nano /etc/login.conf

    russian|Russian Users Accounts:\
    :charset=UTF-8:\
    :lang=ru_RU.UTF-8:\
    :tc=default:
    ….
    # cap_mkdb /etc/login.conf
  • Добавил себе русский язык:
    # pw usermod -n croatoan -L russian
  • И напоследок создал скрипт обновления:
    # cat << DELIMITER > /etc/update.sh
    #!/bin/sh
    cd /usr/src
    make update SVN_UPDATE=yes
    freebsd-update fetch
    freebsd-update install
    portsnap fetch
    portsnap update
    portupgrade -aR
    DELIMITER
    # chmod +x /usr/update.sh


Всё. Перезагружаемся (Перезагрузка может повиснуть.Долго висит строчка про синхонизацию буфера. Ребутнул вручную). После загрузки испытал скрипт. Шик =))

Подготовка дополнительного диска.


Захожу по ssh. У мнея на root очень сложный пароль — задалбываюсь набирать. Регламент тудыть его... Поэтому
# sudo -s

Ищу диски
# gpart list

У меня полуаппаратный рэйд, который я уже поднял на уровне контроллера. FreeBSD прекрасно с ним работает, а значит, мне не придётся колошматить mdadm =). Вижу, что есть raid/r0 с разметками и неразмеченный raid/r1. Challenge accepted. ВНИМАНИЕ! Дальнейшие действия могут навредить данным, вашей нервной системе и существенно навредить здоровью (нервы, побои). Очень много думать над вводом.
# gpart create -s GPT /raid/r1
# gpart add -t freebsd-ufs /raid/r1
# gpart list

Вот теперь есть и раздел, и область. Разметил
# newfs -U /dev/raid/r1p1

Дальше. Создал папку
# mkdir /data

И примонтировал диск тудыть:
# mount /data /dev/raid/r1p1

Добавил в автомонтирование:
# nano /etc/fstab

/dev/raid/r1p1 /data ufs rw 1 1


MySQL


Тут ничего сложного.
# cd /usr/ports/databases/mysql56-server
# make config-recursive
# make config-recursive
# make install clean
# rehash


Добавил в сервисы:
# sysrc mysql_enable=YES


Запустил
# service mysql-server start


Настроил безопасность
# mysql_secure_installation


Задал пароль root, запретил ему удалённый доступ, удалил тестовую базу и прочее... Добавил себя =))
# mysql -u root -p
<password>
mysql> Grant all privileges on *.* to <myname>@localhost identified by '<mypass>' with grant option;
mysql> Grant all privileges on *.* to <myname>@'192.168.0.%' identified by '<mypass>' with grant option;
mysql> flush privileges;
mysql> quit;


Разрешил себе входить с самого сервера и с компов сети. (Замени <myname>, <mypass> и сеть на свои)
Всё.

Dovecot 2


Пришло время почтового сервера. Покажу только основные настройки. Дальше — гугл в помощь.
# cd /usr/ports/mail/dovecot2
# make config-recursive

Выбираем поддержку LDAP и MySQL.
# make config-recursive
# make install clean
# rehash


Конфиги по умолчанию (или примерные конфиги) в рабочую папку.
# cp -R /usr/local/etc/dovecot/example-config/* /usr/local/etc/dovecot/


Добавил запуск службы
# sysrc dovecot_enable=YES


Пока не запускаю.
Нужно добавить учётную запись для почтового сервиса.
Добавил группу с заранее заданным ID
# pw groupadd vmail -g 5000


Добавил пользователя с запретом входа с заранее заданным id
# pw useradd vmail -u 5000 -g vmail -s /usr/sbin/nologin -d /nonexistent -c «Virtual Mail User»


Создал папку для хранения почты и привязал её к новому пользователю
# mkdir /data/mail
# chown vmail:vmail /data/mail


Дальше правлю конфиги.
# nano /usr/local/etc/dovecot/dovecot.conf

protocols = imap pop3

listen = *

#!include_try local.conf


# nano /usr/local/etc/dovecot/conf.d/10-auth.conf


Разрешил прямую передачу пароля
disable_plaintext_auth = no


Разрешённые символы в поле логина
auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890.-_@


Все логины в нижнем регистре
auth_username_format = %Lu


Механизмы авторизации
auth_mechanisms = plain login


Вчключил методы входа. Сначала LDAP а потом, если не нашёл, то MySQL
!include auth-ldap.conf.ext
!include auth-sql.conf.ext


# nano /usr/local/etc/dovecot/conf.d/10-logging.conf


На своё усмотрение. При тесте желательно включить все логи. Потом не забудь выключить!

# nano /usr/local/etc/dovecot/conf.d/10-mail.conf


Где будет физически лежать почта
mail_location = maildir:/data/mail/%d/%n


Жёстко привязал доступ к созданной учётной записи
mail_uid = 5000
mail_gid = 5000


# nano /usr/local/etc/dovecot/conf.d/10-ssl.conf


На время выключаю SSL

ssl = no
#ssl_cert = </etc/ssl/certs/dovecot.pem
#ssl_key = </etc/ssl/private/dovecot.pem


# nano /usr/local/etc/dovecot/conf.d/15-mailboxes.conf

Автосоздание и подвязка некоторых папок: Отправленные, Архив, Спам, Корзина и т.п.

auto = subscribe
...
special_use = \Archive \Drafts \Junk \Sent \Trash
...
mailbox Archive {
special_use = \Archive
}


Авторизация LDAP


Дальше идёт самое вкусное =))) Настройка авторизации из LDAP. Поехали.

# nano /usr/local/etc/dovecot/dovecot-ldap.conf.ext


Так как у меня ActiveDirectory на MS Server 2008 R2 пишу

hosts = <ip>:3268


Замени <ip> на свой
Под кем будем заходить? У меня для этого создана учётная запись с минимальными правами =)

dn = <User>@<Domain>
dnpass = <Pass>


Замени на <User>, <Domain> и <Pass> свои.
Так как у меня AD, то

tls = no

auth_bind = yes

ldap_version = 3


Где искать пользователей??? На примере домена sam.dom

base = dc=sam,dc=dom


Сразу замечу, что имя ПОЧТОВОГО домена может не совпадать с именем КОНТРОЛЛЕРА домена.
Как искать?

deref = searching
scope = subtree


Схема пользователей

user_filter = (mail=%u)
pass_filter = (mail=%u)


И последний штрих:

default_pass_scheme = CRYPT


Авторизация MySQL


Вроде всё.
А теперь весёлость. Создаю базу. По привычке все ключевые моменты на представлениях. Если будет интересно, объясню что, как и зачем. Итак.
База:
CREATE DATABASE IF NOT EXISTS `mail`;
USE `mail`;


Таблица доменов. Мало ли сколько их будет...
CREATE TABLE IF NOT EXISTS `Domains` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Domain` varchar(128) NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `UK_Domains_Domain` (`Domain`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


Таблица логинов пользователей:
CREATE TABLE IF NOT EXISTS `Logins` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`ID_Domain` int(10) unsigned NOT NULL,
`Login` varchar(128) NOT NULL,
`Password` varchar(256) NOT NULL,
`Name` varchar(512) DEFAULT NULL,
`Quota` int(11) DEFAULT NULL,
`Home` varchar(512) DEFAULT NULL,
`EditDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`ID`),
UNIQUE KEY `UK_Logins_Login` (`ID_Domain`,`Login`),
CONSTRAINT `FK_Logins_IDDomain` FOREIGN KEY (`ID_Domain`) REFERENCES `Domains` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


Таблица оснований редактирования записей:
CREATE TABLE IF NOT EXISTS `Reasons` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Reason` varchar(255) NOT NULL,
`IsActive` bit(1) NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `UK_Reason_Reason` (`Reason`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


Таблица активности учётных записей:
CREATE TABLE IF NOT EXISTS `Activity` (
`ID` int(10) NOT NULL AUTO_INCREMENT,
`ID_Login` int(10) unsigned NOT NULL,
`Date` date NOT NULL,
`ID_Reason` int(11) unsigned NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `UK_Activity_IDLogin_PeriodStart` (`ID_Login`,`Date`),
KEY `FK_Activity_IDReason` (`ID_Reason`),
CONSTRAINT `FK_Activity_IDLogin` FOREIGN KEY (`ID_Login`) REFERENCES `Logins` (`ID`),
CONSTRAINT `FK_Activity_IDReason` FOREIGN KEY (`ID_Reason`) REFERENCES `Reason` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


Теперь нужно прикрепить проверку активности записей:
CREATE FUNCTION `UF_GetActivity`(`@ID_Login` INT) RETURNS bit(1)
BEGIN
Select r.`IsActive`
From `Activity` a
Join `Reasons` r on
a.`ID_Reason` = r.`ID`
Where
a.`Date` < CurDate() and
a.`ID_Login` = `@ID_Login`
Order by a.`Date` Desc
Limit 1
Into @Res;
Return @Res;
END;


Создал представления для проверки данных почтарём:

CREATE VIEW `V_Logins` AS select `l`.`ID` AS `id`,concat(`l`.`Login`,'@',`d`.`Domain`) AS `user`,`l`.`Password` AS `password`,`l`.`Login` AS `username`,`d`.`Domain` AS `domain`,ifnull(`l`.`Quota`,100) AS `quota`,ifnull(`l`.`Home`,concat('/data/mail/',`d`.`Domain`,'/',`l`.`Login`,'/')) AS `home`,ifnull(`UF_GetActivity`(`l`.`ID`),0) AS `isactive` from (`Domains` `d` join `Logins` `l` on((`l`.`ID_Domain` = `d`.`ID`)));
CREATE VIEW `V_Iterate` AS select `V_Logins`.`user` AS `User` from `V_Logins` where (`V_Logins`.`isactive` = 1);
CREATE VIEW `V_Pass` AS select `V_Logins`.`user` AS `user`,`V_Logins`.`username` AS `username`,`V_Logins`.`domain` AS `domain`,`V_Logins`.`password` AS `password` from `V_Logins` where (`V_Logins`.`isactive` = 1);
CREATE VIEW `V_User` AS select `V_Logins`.`user` AS `user`,`V_Logins`.`username` AS `username`,`V_Logins`.`domain` AS `domain`,`V_Logins`.`home` AS `home` from `V_Logins` where (`V_Logins`.`isactive` = 1);


Для удобства пару триггеров:
CREATE TRIGGER `tr_Logins_bi` BEFORE INSERT ON `Logins` FOR EACH ROW BEGIN
Set New.`Password` = SHA2(New.`Password`, 512);
END;
CREATE TRIGGER `tr_Logins_bu` BEFORE UPDATE ON `Logins` FOR EACH ROW BEGIN
if Old.`Password` != New.`Password` then
Set New.`Password` = SHA2(New.`Password`, 512);
end if;
END;


Вуаля. То есть нужно напрямую передавать пароль. За шифрование отвечает база. Осталось научить Dovecot принимать данные.
# nano /usr/local/etc/dovecot/dovecot-sql.conf.ext

Подключение к базе:

driver = mysql

connect = host=localhost dbname=mail user=<user> password=<pass>


Возможно, кто-нибудь заметил, что я использую схему шифрования паролей SHA2. Добавлю в схему совместимость:

default_pass_scheme = SHA512


Запросы:

password_query = Select user, username, domain, password From V_Pass where user = '%u'

user_query = Select user, username, domain, home From V_User where user = '%u'

iterate_query = Select user From V_Iterate


Вроде, всё.

Проверка


Проверить очень просто. Telnet. На любой машине ставим telnet и проверяем:
telnet <ip> pop3
> user <username>@<domain>
> pass <password>


Проверить как на mysql так и на ldap. У меня всё завелось... Если не получилось — читать логи.

Postfix.


Всё как обычно
# cd /usr/ports/mail/postfix
# make config-recursive

Выбрать Dovecot2 SASL authentification method
# make config-recursive
# make install clean
# rehash


При установке система спроситпро активацию в папке бла-бла-бла. Не имею возражений.
Дальше САМОЕ сложное — подружить Postfix и Dovecot. Для начала отключаю поддержку sendmail:
# cat << DELIMITER » /etc/rc.conf
sendmail_enable="NO"
sendmail_submit_enable="NO"
sendmail_outbound_enable="NO"
sendmail_msp_queue_enable="NO"
DELIMITER
# cat << DELIMITER > /etc/periodic.conf
heredoc> daily_clean_hoststat_enable="NO"
heredoc> daily_status_mail_rejects_enable="NO"
heredoc> daily_status_include_submit_mailq="NO"
heredoc> daily_submit_queuerun="NO"
DELIMITER


Заргузка:
# sysrc postfix_enable=YES


ПОНЕСЛАСЬ!!!!!
Правлю конфиги dovecot:

# nano /usr/local/etc/dovecot/conf.d/10-master.conf


service auth {
...
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}


Правлю конфиги postfix:
# nano /usr/local/etc/postfix/main.cf


Добавил

smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes


Перезаргузка...
# reboot


Проверка под почтовым клиентом. Полёт нормальный.
Итого: за рабочий день полностью установлен и настроен почтовый сервер организации.
Статья будет эволюционировать. Шлифую узкие места =)
Приурочено к дню системного администратора.
Любая копипаста с позволения автора.
  • просмотров: ~3685
  • рейтинг: ?

Комментарии (2)

Вы - anonymous, войти ?

можно использовать bbcode-теги
[b]жирный текст[/b]
[i]курсив[/i]
[u]underline[/u]
[s]зачеркнутый текст[/s]
[size=20px]размер шрифта[/size]
всякие изменения текста
[left][/left]
[right][/right]
[center][/center]
позиционирование элементов: картинки, текст и т.д
[url][/url]
[email][/email]
внутри тега [url] помещайте ссылки, а внутри [email] адрес электронной почты;
так же [url] можно использовать в виде:
[url=http://example.com]пример[/url],
[url=http://test.ru][img]http://flickr.com/givemeimg.png[/img][/url]
[code][/code]
[quote][/quote]
внутри тега [code] можно помещать программный код (подстветка попытается включиться автоматически); для выделения цитат используйте [quote]
также можно напрямую указать язык [code=cpp]int i;[/code]
[list][/list]
создаем списки, каждый элемент пишется после [*].

Можно указывать маркер - [list=marker].
возможные маркеры 1(decimal), i(lower-roman), I(upper-roman), a(lower-alpha), A(upper-alpha). Примеры:

[list][*]1 элемент[*]2 элемент[*]3 элемент[/list]
[list=1][*]1 элемент[*]2 элемент[*]3 элемент[/list]
[list=A][*]1 элемент[*]2 элемент[*]3 элемент[/list]
[table][/table]
оформляем таблицу, используя внутренние теги [tr] и [td].
[tr] - строка, [td] - поле в строке,
[table=100%] - можно задавать ширину в процентах, по-умолчанию ширина 100%
[td=2] - можно задавать сколько столбцов входит в это поле. Пример:

[table=50%][tr][td]столбец 1[/td][td]столбец 2[/td][/tr][tr][td]значение 1[/td][td]значение 2[/td][/tr][tr][td=2]сразу 2 столбца[/td][/tr][/table]
[img][/img]
тег для вставки фото или картинок, мы любим картинки. Примеры использования:

[img]http://ya.ru/logo.png[/img],
[img=100x100px]http://ya.ru/logo.png[/img]
[img=fullimg.url]thumbimg.url[/img],
Пожалуйста загружайте картинки на наш сайт, либо вставляйте с бекбоновских ресурсов.
[video][/video]
Проигрывает видео, внутрь вставляем ссылки на видео, поддерживается Play.Ykt.Ru(нужно вставить ссылку на страницу с видео) и tv.ykt.ru(нужно вставить ссылку на адрес файла)