Я люблю линукс, юникс и системное администрирование по странной причине. Это не оплата труда и не возможность управления сложными комплексами через консоль, а интересные, неформатные задачи, которые порой попадаются на пути самураев опенсорса. Об одной такой задаче я и расскажу.
Предпосылки
Началось всё со смены основного места работы. Полтора года назад я пошёл работать системным администратором в гражданский московский НИИ. Далеко не самый богатый и известный, но вполне современный и развивающийся. Основной челлендж был в том, что IT-отдел в институте отсутствовал. IT-инфраструктура там активно развивалась в начале нулевых отдельными энтузиастами, но люди приходили и уходили, разрозненные очаги прогресса бессистемно зажигались и гасли, многие сервисы так и остались замороженными во времени, поддерживаемые операторами без попыток глобальных обновлений.
Первой и основной моей задачей, а заодно и центральным заданием на испытательный срок, стал доменный почтовый сервер. При приёме на работу пришлось обойти довольно много сотрудников, и многие, узнав, что я устраиваюсь админом, спрашивали именно про почтовый сервер.
После сбора информации, добычи логинов, паролей и IP-адресов и некоторого исследования ситуация нарисовалась
- Почтовый сервер живёт на Slackware 10.1.0.
- Отправка писем осуществляется по SMTP по 25 порту и только с внутренних IP.
- MTA — Sendmail, все почтовые пользователи заносятся скриптом как системные и живут в /etc/passwd.
- Есть веб-интерфейс. Очень брутальный SquirrelMail. Гиперссылки в теле писем он отображать не умеет и никак не сообщает об их наличии. Последняя версия вышла в 2013 году.
- Первичная фильтрация спама осуществляется через блоклист, который пополняется вручную.
- Вторичная фильтрация спама осуществляется через старинную версию Amavis, и получение писем с кодами подтверждения регистрации от, например, «Твиттера» занимает от трёх часов — всё это время их маринует спам-фильтр. Пока идёт код подтверждения, его действие уже заканчивается.
Приветливая Slackware приветствует очередной мудрой цитатой.
Общая задача — перевести почтовый сервер на современные рельсы.
Основные подзадачи:
- Актуализировать список активных почтовых аккаунтов на старом сервере.
- Развернуть новый сервер. Как и какой — выбор за мной.
- Перенести аккаунты на новый сервер, желательно без смены паролей, вместе с алиасами, списками рассылки и адресными книгами из SquirrelMail.
- Пережить обязательную бурю недовольства, отвечая на гневные письма вежливо и спокойно. Решать проблемы, которые обязательно последуют.
Подготовка
Актуализация аккаунтов началась с изучения Sendmail, с которым сталкивался до этого лет пятнадцать назад.
В
/etc/mail/aliases
находятся алиасы, а также списки рассылки, в том числе и самый для меня на тот момент полезный — рассылка всем пользователям.В
/etc/mail/access
находятся правила обработки писем и забитая вручную первичная фильтрация. Они мне понадобятся чуть позже.Из списка рассылки получился адрес всех пользователей электронной почты, коих оказалось около пятисот. Сохранил его в файл
allusers
, отсортировал через sort
.Главам подразделений был выслан приказ предоставить список пользователей электронной почты. Из разрозненных экселевских табличек собрался единый список активных логинов по версии подразделений. Сохранил его в файл active, отсортировал через sort.
Получаю аццеслист — список активных юзеров:
#comm -12 allusers active > accesslist
Часть указанных подразделениями аккаунтов была написана с ошибкой, часть — находилась на сторонних почтовых серверах; нескольких вообще не существовало. Это норма.
Получаю чёрный список из тех, кто не вошел в acceslist:
#comm -23 allusers accesslist > blocklist
Блоклист прогоняю через простенький скрипт, генерирующий часть конфигурации sendmail:
#nano lockgen
#!/bin/bash
sed «s/^/To:/;s/$/@domain.ru REJECT/» blacklist > tmp1
sed «s/^/From:/;s/$/@domain.ru 550 Your mailbox is locked, contact your system administrator mail.support@domain.ru/» blocklist > tmp2
paste -d»\n» tmp1 tmp2
rm -f tmp1 tmp2
#chmod +x lockgen
#./lockgen > lockconf
Сгенерированный конфиг переношу в
/etc/mail/access
на старом сервере и перезапускаю sendmail.Теперь юзернеймам из чёрного списка, при попытке проверить или отправить почту, выдаётся сообщение с призывом связаться со мной. Таких набралось довольно много. И, забегая вперёд, такие пользователи появлялись и спустя полгода, уже после переезда на новый сервер.
Аццеслист же был залит и на старый сервер, и на тот, о котором пойдёт речь дальше.
Новой платформой я выбрал iRedMail и развернул его на виртуалке с CentOS 8 в Proxmox VE. Процесс в деталях описывать смысла нет, у iRedMail подробная документация и активное комьюнити, что и послужило основной причиной выбора. CentOS — чисто личное решение, так как больше всего работал именно с ним. Перенести всё на другую систему не будет проблемой.
Платная поддержка iRedMail не приобреталась, поскольку пока не сталкивался с необходимостью, хотя допускаю, что в будущем пригодится.
Процесс переезда начался с переноса аккаунтов вместе с паролями. Со старого сервера взял файл
/etc/shadow
и обработал его парой кривеньких скриптов.Чищу shadow, оставляю только строки с аккаунтами аццеслиста:
#grep -f acceslist shadow > accshadow
В данном случае было несколько аккаунтов с короткими трёхбуквенными именами, что привело к попаданию в файл также аккаунтов, где эти буквосочетания встречались в составе более длинных имен. Но мне было быстрее временно добавить к таким логинам в аццеслисте всю строку из shadow, чем писать более сложный и универсальный скрипт.
Оставляю только связку логин/хэш:
cat accshadow | cut -f1,2 -d':' > userhash
Скорее всего, стоило пойти по более простому пути и сформировать запрос на создание аккаунтов сразу из полученного файла с хэшем. Но пошёл чуть в обход.
В скрипте инструмента iRedMail для создания SQL аккаунтов меняю квоту ящика по умолчанию (параметр DEFAULT_QUOTA) и создаю импорт-файл для создания аккаунтов из аццеслиста с одним и тем же паролем:
#!/bin/bash
echo «#!/bin/bash»
sed «s/^/bash \/path\/to\/iRedMail-1.3.1\/tools\/create_mail_user_SQL.sh /;s/$/@domain.ru '12345678' >> addusers.sql/» accesslist
Обрабатываю полученный импорт-файл, заменяя SSHA512 хэши на MD5:
#nano changehash
#!/bin/bash
awk 'BEGIN{number=1;}
{
cmd=«sed \x27«number»!D;s/^.*://\x27 userhash»;
cmd|getline hash;
sub(/{SSHA512}.*\x27, \x27/,»{CRYPT}«hash»\x27, \x27»);
print;
if (/CRYPT/) number=number+1;
}' addusers_temp.sql;
#chmod +x changehash
#./changehash > addusers.sql
В БД iRedMail для хранения паролей по умолчанию используются хэши SSHA512, но можно использовать и менее надёжные хэши MD5, вытащенные из shadow. Они могут мирно сосуществовать, так что при смене пароля или введении нового пользователя MD5 хэши будут потихоньку исчезать из базы.
Делаю список внутренней рассылки по всем пользователям и добавляю модератора:
MariaDB [vmail]> INSERT INTO alias (address, domain, active) VALUES ('all-users@domain.ru', 'domain.ru', 1);
MariaDB [vmail]> INSERT INTO moderators (address, moderator, domain, dest_domain) VALUES ('all-users@domain.ru', 'moderatormail@domain.ru', 'domain.ru', 'domain.ru');
Формирую ещё один импорт-файл:
#nano createlist
#!/bin/bash
while IFS= read -r username
do
echo «INSERT INTO forwardings (address, forwarding, domain, dest_domain, is_list, active)»
echo «VALUES ('all-users@domain.ru', '$username@domain.ru', 'domain.ru', 'domain.ru', 1, 1);»
done < accesslist
#chmod +x createlist
#./changehash > addlist.sql
Этот скрипт использовался потом ещё несколько раз для создания целевых списков рассылки, например, главам отделов.
Импортирую оба файла в БД:
MariaDB [vmail]> SOURCE addusers.sql;
MariaDB [vmail]> SOURCE addlist.sql;
Можно попробовать залогиниться с известным паролем в веб-интерфейс.
Roundcube по умолчанию требует указывать в качестве логина почтовый адрес полностью.
Миграция
На этом этапе записи DNS были переключены на использование нового почтового сервера. Сделано это было в пятницу вечером, с предупреждением пользователей за неделю через общую рассылку. Как только волна обновлений дошла до заокеанских DNS, был подключён сертификат Let's Encrypt по мануалу iRedMail.
Также на этом этапе обязательно следовало ограничить количество отсылаемых писем в день. Я это сделал гораздо позже, когда последовала волна взломов аккаунтов из-за недостаточно надёжных паролей (пользователи привыкли, что почта работает на отправку только внутри сети, и широко использовали цифровые пароли и вариации qwerty) и постовик загремел в блоклисты спамеров. Поток исходящего спама также вводил в ступор dovecot, который начинал сыпать очень странными ошибками, посылавшими меня по ложному пути поиска их причины.
Сотни в день будет достаточно:
MariaDB [iredapd]> INSERT INTO throttle (account, kind, priority, period, msg_size, max_msgs, max_quota) VALUES ('@domain.ru','outbound',60,86400,-1,100,-1);
Отдельным аккаунтам можно поднять лимиты:
MariaDB [iredapd]> INSERT INTO throttle (account, kind, priority, period, msg_size, max_msgs, max_quota) VALUES ('mass@domain.ru','outbound',100,86400,-1,500,-1);
На старом сервере всем юзернеймам из аццеслиста выставляется один и тот же пароль:
sed «s/$/:some123/» accesslist > pwdpatch
chpasswd < pwdbatch
На новом сервере создаётся управляющий аккаунт, который может управлять любым ящиком без необходимости знать его пароль:
Формируем хэш (далее подразумевается пароль some456):
#doveadm pw -s SSHA512
Помещаем полученный хэш в
/etc/dovecot/dovecot-master-users
:postmigrate@domain.ru:{SSHA512}B0VHomJaMk6aLXOPglgNgJtCU...
Разворачивается imapsync по общедоступному мануалу. Формируется скрипт массового переноса почты:
#nano createmigrate
#!/bin/bash
echo «#!/bin/bash»
while IFS= read -r username
do
echo «/root/imapsync --nosyncacls --subscribe --syncinternaldates --nosslcheck \\»
echo «--host1 123.123.123.123 --authmech1 LOGIN --user1 $username --password1 some123 --nossl1 --notls1 \\»
echo «--host2 127.0.0.1 --authmech2 LOGIN --user2 $username@domain.ru*postmigrate@domain.ru --password2 some456 --prefix1 INBOX. --regextrans2 \«s/&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-/Sent/\» --addheader --folder \«Sent\» --folder \»&BB4EQgQ,BEAEMAQyBDsENQQ9BD0ESwQ1-\«»
done < accesslist
#chmod +x createmigrate
Запуск:
# ./createmigrate > domigrate
# chmod +x domigrate
# nohup ./domgrate > process.out &
На этом этапе возникло множество проблем, и скрипт несколько раз дорабатывался и запускался снова с учётом возникающих ошибок. Оказалось, что размер ящиков на старом сервере регламентирован не был, многие ящики были куда большего размера, чем изначальные 2Gb. Пришлось избирательно увеличивать квоты. С названиями почтовых директорий было ещё хуже — старый сервер стоял на костях ещё более древних реализаций почтового сервера, у части клиентов директории были на русском.
Работу imapsync следует распараллеливать на несколько процессов, формировать не один большой скрипт, а несколько для разных диапазонов почтовых аккаунтов. Но с учётом постоянных столкновений с очередными проблемами синхронизации, было уже не до того. Скрипт в целом закончил работу днём понедельника. После чего были синхронизированы почтовые ящики с алиасами. Алиасов было немного, так что мне было быстрее сформировать скрипты для imapsync и импорт-файл с форвардингами вручную.
Осталось перенести адресные книги в новый веб-интерфейс — Roundcube. SquirrelMail, как оказалось, лежал на другом сервере отдельно от MTA. После получения пароля от него выгрузил адресные книги в формате *.abook на новый сервер. Тут, по счастью, нашлось готовое решение — вот это.
В скрипте указываются параметры БД Roundcube (лежат в его конфиге). Всё достаточно просто, почтовые книги появились в веб-интерфейсе.
Последствия
По счастью, вся вертикаль власти от меня до директора весьма прогрессивная. Поток концентрированного недовольства от консерваторов был ожидаем, и от меня требовались только корректность и терпение. Критически недовольными изменениями были всего несколько пользователей, что составило менее 2% от их общего числа. Однозначный успех мероприятия.
Из-за слишком нового SSL отвалились старые версии TheBat (да, его ещё используют и даже пришлось покупать ключи от актуальной версии для совсем непримиримых пользователей).
Как я уже говорил выше, для некоторых пользователей весь процесс прошёл мимо их внимания, так что некоторые аккаунты приходилось доставать со старого сервера спустя почти год после того, как они перестали работать после внесения в блоклист. Со слов пользователей, аккаунты исключительно важные и часто используемые. Поверил им на слово.
Для нормальной работы оповещалок UPS-ов и части самописных сервисов института разрешил отправку сообщений с внутренних IP без авторизации с несуществующих аккаунтов:
#echo "MYNETWORKS = ['123.123.123.0/23']" >> /opt/iredapd/settings.py
#service iredapd restart
Что-то ещё тюнилось по мелочи типа более суровой настройки fail2ban или настройки DNS, но решения быстро находились в гугле и форуме iRedMail. Не отложилось в памяти.
На будущее
Что хотел бы реализовать, но пока не дошли руки:
- Служебный Telegram-бот, в том числе с сигнализацией о выходе аккаунта за лимит отправки писем в день (что в 99% случаев означает взлом аккаунта из-за слабого пароля). При сильном выходе за лимит — автоблокировка сменой пароля. Пока приходится мониторить maillog через grep.
- Интеграция с Nextcloud (был параллельно развёрнут на соседней виртуалке)
- Интеграция с OTRS.
На этом всё. Сервер работает с начала этого года. К концу года переедет с CentOs на что-то ещё по известным причинам. Но это будет уже совсем не так романтично, как переносить старый почтовик на Slackware.
— 15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS
Доступно до 31 декабря 2021 г.