Всем привет!
Некоторое время назад ко мне обратился один мой хороший знакомый с внезапно образовавшейся у него проблемой и попросил помочь в её решении. Проблема заключалась в следующем: организация, в которой он работал, имела у себя Windows-сервер с поднятым на нём почтовиком MDaemon от компании Alt-N Technologies. Пару лет назад на этот почтовик был установлен SSL-сертификат StartSSL от компании StartCom. И всё работало вполне себе нормально, каши не просило, как вдруг от StartCom пришло грустное письмо, информирующее о том, что скоро всем их сертификатам придёт полный и безоговорочный кирдык. Мол, спасайтесь — кто может, пока не бомбануло. Сегодня я расскажу вам, как мы спасались — глядишь, кому-нибудь эта информация окажется полезной.
Немного лирики
Что перво-наперво приходит в голову нормальному человеку, когда ему задают вопрос про замену сертификата? Вариантов два: или — а почему бы вам не купить его? Или — так есть же замечательная артель Let's Encrypt, которая бесплатно раздаёт сертификаты направо и налево! Первый вариант был смущённо отвергнут как несостоятельный, ввиду того, что, как было сказано ранее, сервер работал, каши не просил, и объяснять руководству, почему оно должно расстаться с энной суммой вечнозелёных денег желания не было никакого. Второй вариант был просто суперпривлекательным, но на горизонте маячили кое-какие проблемы, которые предстояло объехать: оконность почтовика наводила на грустные размышления о его совместимости со скриптами LetsEncrypt, а получать и устанавливать сертификат вручную каждые три месяца совершенно не хотелось.
Поэтому был выбран второй вариант — только нужно было найти способ автоматизировать процессы получения сертификата и привязки его к почтовику.
Начали мы, естественно, с перекапывания великого и ужасного Интернета в поисках уже готового решения. И, о чудо! Оказалось, что доблестные программисты из Alt-N Technologies уже озаботились этим и выдали на-гора скрипты, делающие всё что нужно! Как говорится — снимаю шляпу! Но и тут не обошлось без ложки дёгтя: эти скрипты просто так всем и каждому не раздавались, а были включены в состав последних версий MDaemon. Однако наш подопечный сервер имел на борту довольно старую версию MDaemon — 13.6.3. Софт был совершенно легальный, купленный некогда за самые что ни на есть настоящие деньги, работал замечательно и его апгрейд в планы руководства конечно же не входил (см. пункт про покупку сертификата).
Поэтому было принято решение попытаться хирургическим путём пересадить скрипты из новой версии MDaemon в старую и заставить их там заработать. Подумано — сделано: на виртуальную машину была установлена самая свежая на тот момент триальная версия MDaemon и из неё изъята папка LetsEncrypt со всем содержимым. Что теперь делать с этим добром? — читайте ниже.
Исходные данные
- Сервер под управением ОС Windows Server 2008 R2.
- Почтовый сервер MDaemon версии 13.6.3.
- На этом же сервере поднят IIS, обслуживающий корпоративный сайт организации.
- MDaemon использовал собственный встроенный WEB-сервер WorldClient, который был доступен из интернета через порт 3000.
Обязательные требования
Как было написано в этой статье, скрипты LetsEncrypt для MDaemon не являются абсолютно универсальными и предполагают выполнение следующих обязательных условий:
- Наличие оболочки PowerShell версии 3.0.
- Наличие установленного фреймворка Microsoft .NET версии не ниже 4.0.
- Наличие установленного пакета IIS Management Scripts and Tools.
- Из интернета через порт 80 должен быть доступен WorldClient сервера — либо напрямую, либо через IIS.
Как видим — часть из этих требований исходно не выполнялась, поэтому сначала была выполнена привязка WorldClient к IIS с целью пересадки его на порт 80. Информация о том, как это сделать была получена из вот этой статьи с сайта Alt-N.
Пара слов о «граблях»
Прежде чем приступить к описанию пошаговой инструкции хочу задержать ваше внимание на кое-каких непредвиденных заморочках, осложнивших процесс пересадки скриптов и получения сертификатов.
Во-первых, практически в самом начале скрипта была реализована проверка на то, что параметр 'EnableWCServer' в файле 'Mdaemon.ini' установлен в 'Yes'. И если это было не так, то скрипт немедленно завершал свою работу с выдачей сообщения о критической ошибке 'Error: WorldClient must be enabled'. Но, как это ни странно, в нашем случае этот параметр был установлен в 'No' — несмотря на то, что нами уже была выполнена привязка WorldClient к IIS и WorldClient прекрасно открывался из интернета. Недолго думая, мы отключили эту проверку, закомментарив её в скрипте. Это позволило скрипту продолжить работу.
Во-вторых, на этом же сервере был поднят корпоративный сайт и к кое-каким страницам этого сайта доступ выполнялся по протоколу https с использованием самоподписанного сертификата. А старые Windows-сервера предполагают, что к одному IP может быть привязан только один сертификат. Мы наступили на эти грабли в самом конце пути — когда сертификат от LE уже успешно получался, но никак не мог прибиндиться к адресу 0.0.0.0. В итоге проблема была решена быстрым, но несколько кривоватым способом: WorldClient был отсажен на отдельный IP-адрес (благо он был в наличии) и опять же пришлось править скрипт — в список его входных параметров был добавлен IP-адрес, к которому нужно было привязывать сертификат. А так как привязка WorldClient к IIS была уже полностью выполнена, то мы не стали запускать собственный WEB-сервер MDaemon-а и оставили всё как есть.
Поехали.
Часть 1: предварительная подготовка
- Любым известным вам способом делаем бакап сервера!
- Устанавливаем .NET версии выше или равной 4.0.
- Добавляем Role Services: идём в 'Control Panel' -> 'Administrative Tools' -> 'Server Manager' -> 'Roles' и нажимаем на линк 'Add Role Services'.
Ставим крыжики на:- Web Server/Application Development/ISAPI Extensions
- Web Server/Application Development/ISAPI Filters
- Management Tools/IIS Management Scripts and Tools
Нажимаем 'Next', ну и так далее. - Устанавливаем Windows Management Framework 3.0 — это установит в систему PowerShell версии 3.0 (см. раздел 'Обязательные требования'):
- Скачиваем WMF 3.0 с сайта Microsoft.
- Устанавливаем нужный WMF. Для Windows Server 2008 R2 это 'Windows6.1-KB2506143-x64.msu'.
- Перезагружаем сервер.
Часть 2: создание в IIS сайта для доступа к серверу WorldClient
Примечание 1: если у вас используется встроенный в MDaemon сервер WorldClient и он уже монопольно сидит на порту 80, то можете смело пропустить эту часть и перейти сразу к части 3.
Примечание 2: 'Host name' сайта должно быть таким-же, как полное доменное имя хоста MDaemon, по которому он доступен из интернета.
Чтобы узнать полное доменное имя хоста MDaemon: запускаем GUI Mdaemon, идём в меню: 'Настройка' -> 'Первичный домен/серверы' -> 'Домен и серверы по умолчанию' -> 'Домен' и смотрим поле 'Полное доменное имя хоста'.
Итак, приступим. Запускаем IIS-менеджер и добавляем в нём новый сайт:
- В поле 'Site name' вводим название сайта — какое нравится.
- В поле 'Physical path' вводим путь к папке HTML World-клиента.
- В поле 'Host name' прописываем полное доменное имя хоста (см. примечание 2 выше).
- В поле 'IP-address' оставляем 'All unassigned', если интерфейс используется монопольно, или выбираем из списка IP, принадлежащий почтовику.
- Поля 'Type' и 'Port' оставляем как есть — 'http' и '80', соответственно.
Редактируем список дефолтных документов сайта - заходим в подраздел 'Default Document':
- Очищаем весь список.
- Добавляем документ 'WorldClient.dll': в правой панели 'Actions' нажимаем 'Add...' и в поле 'Name' набираем 'WorldClient.dll'.
- Добавляем документ 'MDSyncML.dll': в правой панели 'Actions' нажимаем 'Add...' и в поле 'Name' набираем 'MDSyncML.dll'.
- Ставим 'WorldClient.dll' первым в списке: выделяем его и нажимаем 'Move Up' в правой панели 'Actions'.
Переходим в раздел 'Handler Mappings':
- Редактируем 'Feature Permissions': в правой панели 'Actions' нажимаем на 'Edit Feature Permissions...' и ставим все крыжики - 'Read', 'Script' и 'Execute'.
- Находим в списке 'ISAPI-dll' и заходим в него.
- В поле 'Request path' пишем 'WorldClient.dll'.
- В списке 'Module' выбираем 'IsapiModule'.
- В поле 'Executable (optional)' указываем путь к WorldClient.dll.
- Добавляем новый обработчик: в правой панели 'Actions' нажимаем 'Add Module Mapping...'
- В поле 'Request path' пишем 'MDSyncML.dll'.
- В списке 'Module' выбираем 'IsapiModule'.
- В поле 'Executable (optional)' указываем путь к MDSyncML.dll.
- В поле 'Name' пишем что-нибудь членораздельное. Например, 'SyncML-ISAPI'.
Редактируем 'MIME Types' - если этого не сделать, то робот LetsEncrypt не сможет получить от нас файл без расширения:
- Переходим в раздел 'MIME Types'.
- В правой панели 'Actions' нажимаем 'Add...'.
- В поле 'File name extension' пишем точку.
- В поле 'MIME type' пишем 'text/plain'.
Редактируем 'Application Pool', автоматически созданный при создании нашего сайта:
- Идём в 'Application Pools' -> 'MDaemon WorldClient' -> 'Advanced Settings...'.
- В секции 'Process Model' меняем 'Identity' на 'Network Service'.
- Если операционка — 64-разрядная, то в секции 'General' меняем 'Enable 32-Bit Applications' на 'True'.
Закрываем консоль. IIS настроен.
Далее, даём пользователям 'IUSR' и 'NETWORK SERVICE' полный доступ к папке MDaemon:
- Идём в проводник, открываем 'Properties' папки 'MDaemon', переходим на закладку 'Security', нажимаем 'Edit'.
- Нажимаем 'Add' -> 'Advanced' -> 'Find Now' — выделяем в списке 'Search Results' пользователя 'IUSR', нажимаем 'OK'.
- Ставим крыжик 'Full control' в списке 'Permissions for IUSR'.
- Нажимаем 'Add' -> 'Advanced' -> 'Find Now' — выделяем в списке 'Search Results' пользователя 'NETWORK SERVICE', нажимаем 'OK'.
- Ставим крыжик 'Full control' в списке 'Permissions for NETWORK SERVICE'.
- Закрываем оба окна нажатием на 'OK'.
WorldClient настроен. Проверяем, что WorldClient открывается нормально, зайдя на него браузером через интернет по полному доменному имени хоста.
Часть 3: установка и настройка скриптов LetsEncrypt
- Скачиваем архив со скриптами отсюда и распаковываем его в корень папки 'MDaemon'. Важное примечание: в скрипте основной сервер LetsEncrypt заменён на тестовый — чтобы предотвратить бан из-за многократных попыток получить сертификат во время процесса отладки. В следующей части будет написано — как переключиться на основной сервер.
- Дописываем в переменную окружения 'PSModulePath' путь к модулям, используемым скриптом:
- Идём в 'Control Panel' -> 'System' -> 'Advanced system settings' -> 'Advanced' -> 'Environment Variables'.
- Ищем в списке 'System Variables' переменную 'PSModulePath'.
- Дописываем через ';' в её конец путь к папке 'Modules', находящейся внутри папки 'LetsEncrypt'. В моём случае такой: 'c:\MDaemon\LetsEncrypt\Modules\'
- Перелогиниваемся.
- Запускаем консоль cmd.
- Запускаем скрипт letsencrypt.ps1 командой:
Здесь параметром 'File' задаётся путь к скрипту.powershell -ExecutionPolicy ByPass -File c:\mdaemon\letsencrypt\letsencrypt.ps1
Можно использовать дополнительные параметры:
- -IISSiteName «MDaemon WorldClient»
Если WorldClient работает через IIS, то этим параметром нужно указать скрипту имя сайта WorldClient (см. часть 2) - -WCIPAddress xxx.xxx.xxx.xxx
Этим параметром задаётся IP-адрес, к которому скрипт должен прибиндить полученный сертификат. Его нет необходимости указывать, если к порту 443 не привязано никаких других сертификатов. - -To «admin@server.com»
Этим параметром задаётся имейл, на который будет отправлен лог работы скрипта в случае возникновения какой-либо ошибки.
Смотрим в окно консоли - скрипт должен выполниться без ошибок.
Если что-нибудь пойдёт не так — вам придётся разобраться с этой проблемой самостоятельно.
Если всё выполнилось успешно, то можно попробовать зайти в WorldClient браузером по протоколу https: так как мы использовали тестовый сервер LetsEncrypt, то браузер должен выругаться на сертификат сайта сообщением 'SEC_ERROR_UNKNOWN_ISSUER'.
Кстати говоря, помните — я рассказывал про «грабли» с параметром 'EnableWCServer' в файле 'Mdaemon.ini' — что при использовании связки с IIS он установлен в 'No'? Так вот после успешной отработки скрипта этот параметр изменился на 'Yes'. Однако произошло это несколько поздновато, поэтому раскомментаривать проверку этого параметра в скрипте мы не стали.
- -IISSiteName «MDaemon WorldClient»
Часть 4: перевод скрипта в «боевой режим»
- Открываем в текстовом редакторе скрипт letsencrypt.ps1 из папки LetsEncrypt.
- Находим в нём строки:
#Initialize-ACMEVault -ErrorVariable LogText Initialize-ACMEVault -BaseURI https://acme-staging.api.letsencrypt.org/ -ErrorVariable LogText
- Первую строку раскомментариваем, а вторую закомментариваем:
Initialize-ACMEVault -ErrorVariable LogText #Initialize-ACMEVault -BaseURI https://acme-staging.api.letsencrypt.org/ -ErrorVariable LogText
- Сохраняем скрипт.
Часть 5: Удаление всех следов «тестовой» жизнедеятельности
Если этого не сделать, то скрипт ещё пару месяцев будет продолжать выдавать нам «фальшивый» сертификат, несмотря на то, что мы внесли в скрипт нужные изменения.
- Удаляем тестовый сертификат из MDaemon:
- Запускаем GUI MDaemon и идём в меню 'Безопасность' -> 'Параметры безопасности' -> 'SSL & TLS'.
- В списке сертификатов выделяем наш тестовый сертификат (у него в поле 'Отправитель' будет 'Fake LE Intermediate X1') и нажимаем кнопку 'Удалить' под списком.
- Если список сертификатов стал пуст — придётся создать самоподписанный сертификат, иначе MDaemon будет ругаться при попытке закрыть окно.
- Удаляем хранилище ключей, созданное скриптом: если работали под админским аккаунтом, то идём в 'c:\ProgramData\', а если под пользовательским — в 'C:\Users\имя_пользователя\AppData\Local\' и удаляем оттуда папку 'ACMESharp' вместе со всем содержимым.
- Удаляем XML-файл, созданный скриптом: идём в папку 'MDaemon\LetsEncrypt' и удаляем файл LetsEncrypt.XML оттуда.
- Удаляем тестовый сертификат: идём в папку 'MDaemon\Pem', находим там сертификат (файл с расширением 'pfx') и удаляем его.
Часть 6: Настройка запуска скрипта по расписанию
- Идём в 'Control Panel' -> 'Administrative Tools' -> 'Computer Management' -> 'System Tools' -> 'Task Scheduler' -> 'Task Scheduler Library'.
- Создаём новую задачу: нажимаем 'Create Task...' в правой панели 'Actions'.
- На закладке 'General':
- В поле 'Name' пишем имя задачи — произвольно по вашему желанию.
- В подразделе 'Security Options' выбираем пункт 'Run whether user is logged on or not'.
- На закладке 'Triggers':
- Нажимаем кнопку 'New...' — откроется окно 'New Trigger'.
- В списке 'Begin the task' выбираем 'On a schedule'.
- Устанавливаем подходящую периодичность запуска: например, раз в неделю по воскресеньям. Скрипт при каждом старте будет проверять — сколько сертификату осталось жить: и если меньше месяца, то обновит его.
- На закладке 'Actions':
- Нажимаем кнопку 'New' — откроется окно 'New Action'.
- В списке 'Action' выбираем 'Start a program'.
- В поле 'Program/script' пишем 'powershell'.
- В поле 'Add arguments (optional)' пишем '-ExecutionPolicy ByPass -File c:\MDaemon\LetsEncrypt\letsencrypt.ps1'. В хвост строки дописываем требуемые дополнительные параметры (см. часть 3).
- На закладке 'Conditions' ставим крыжики по своему усмотрению.
- На закладке 'Settings' ставим крыжики:
- Allow task to be run on demand
- Stop the task if it runs longer than 1 hour
- If the running task does not end when requested, force it to stop
- Нажимаем кнопку 'OK'. Вводим пароль текущего пользователя.
Часть 7: первый «боевой» запуск
Выполняем старт скрипта вручную:
- Выделяем только-что созданную задачу в списке.
- Нажимаем 'Run' в правой панели Actions'. Никакого окна при этом не откроется.
- Время от времени рефрешим список задач — чтобы видеть изменения в поле 'Status': 'Status' должен смениться на 'Run'. Рефрешим список, пока 'Status' снова не станет 'Ready'.
- Смотрим результат выполнения скрипта в лог-файле 'MDaemon\Logs\LetsEncrypt.log'.
Если, судя по лог-файлу, всё прошло успешно, значит дело сделано — сертификат получен и можно проверять работоспособность приёма/отправки почты по защищённому каналу. И да, не забудьте зайти в почтовик браузером по протоколу https — чтобы убедиться, что WorldClient тоже работает без проблем.
Часть последняя — заключительная
В заключение хочу сказать, что во время написания статьи у меня уже не было доступа к боевому серверу, поэтому все скриншоты делались с виртуальной машины, на которую была установлена ещё более старая версия MDaemon — 13.0.4 — из-за чего внешний вид окон может отличаться от других версий.
Ну вот и всё. Всё что знал — рассказал. Поздравляю всех с наступающим Новым Годом! Здоровья вам и удачи!