Проблема

В решениях компании Synology присутствует vendor-lock на использование wildcard-сертификатов Let's Encrypt. Решение "из коробки" подразумевает использование wildcard-сертификатов только для динамических DNS компании Synology. На это накладывается требование держать открытым 80 порт, без которого автопродление не работает. В результате раз в три месяца надо открыть порты, обновить сертификат, закрыть порты, вот это вот всё.

Типичные решения?

Сразу стоит отметить, почему этот мануал актуален и почему нельзя, совершенно закономерно, установить acme в файловую систему и закрыть вопрос раз и навсегда. Моё первое решение было именно таким: установить acme из консоли из под root, установить cronjob на обновление сертификата и подтягивание обновлённых сертификатов из дебрей файловой системы в директорию, доступную из GUI для последующего применения. Оказалось, ребята из Synology тоже не дураки и регулярно очищают файловую систему от неожиданных юзерскриптов, даже если они лежат в /root. По крайней мере, когда вчера автоматика запустилась и вместо пакета сертификата выдала **not found** - было обидненько. Да, можно просто регулярно переустанавливать acme, но зачем тогда вообще что-то автоматизировать, если всё равно надо раз в N времени пинать его и переделывать?

Свой вариант

Свой вариант реализовывался исключительно средствами Synology, чтобы избежать проблемы с очисткой упомянутой выше. Используется Docker, официальный контейнер acme.sh и встроенные в GUI cronjobs. По отдельности всё просто, но свести воедино - есть нюансы.

Мануал рассчитан на тех, кто бегло разбирается в оболочке Synology DSM 7.1.

Докер

Находим и выкачиваем необходимый контейнер. Контейнер очень лёгкий, основан на alpine и на момент написания статьи весит всего 27 мегабайт.

Создаём директорию для файлов контейнера, где будут лежать конфиги и куда будут падать сгенерированные сертификаты. Директория может лежать где угодно. Обычно, если контейнеров много люди рано или поздно приходят к какому либо типичному решению вроде /docker/%containerName%.

При создании контейнера нужно выбрать скачавшийся образ и далее во вкладке Сеть нужно выбрать опцию Использовать ту же сеть, что и сеть хоста Docker. Если упустить этот момент, в дальнейшем это выльется в нетривиальный траблшутинг по общению acme с внешним миром, внешние файрволлы, внутренние файрволлы, что-то обратный прокси перехватит, динамические адреса контейнеров ни у кого не спрашивая ворвутся с конфликтом адресов в уже существующую подсеть (Synology использует для сетей контейнеризации подсети 172.17.0.0/16, 172.18.0.0/16 и.т.д с повышением второго октета на каждую новую сеть) - масса ненужного веселья.

Далее, стоит включить опцию Включить автоматический перезапуск, чтобы не заморачиваться каждый раз пинать контейнер после каждой перезагрузки. После чего нажать на кнопку Дополнительные настройки и во вкладке Команда выполнения в поле Команда установить параметр daemon.

Ключ для запуска acme в режиме демона явно упоминается в мануале и используется для того, чтобы можно было обратиться к acme через внешний планировщик задач. Малозаметная опция в малозаметном месте, которую легко упустить и непросто отдебажить. Synology будто специально прячут такие штуки поглубже в настройках, на третьем уровне вложенности.

После применения настроек, продолжая устанавливать контейнер, перейдя во вкладку Настройки тома надо нажать кнопку Добавить папку и привязать созданную ранее директорию к директории /acme.sh внутри контейнера.

Привязка директории на Synology к директории внутри контейнера.
Привязка директории на Synology к директории внутри контейнера.

На этом настройка контейнера завершена, система предложит проверить все настройки и запустить конейнер после создания.

Последующие настройки производятся в терминале контейнера. Тут стоит явно обратить внимание лишь на два момента:

  1. Окно терминала по умолчанию является терминалом без оболочки. Не зная этого нюанса можно биться в стену не понимая что происходит.

  2. При нажатии кнопки Создать создаётся новый терминал с оболочкой bash. Но, так как контейнер acme собран на alpine, в нем нет bash - используется оболочка sh. Нужно при создании терминала выбирать Запустить при помощи команды и явно указывать sh.

Acme.sh

Нюансам настройки посвящено пол-интернета, поэтому стоит по быстрому пробежаться по ключевым моментам.

acme.sh --set-default-ca --server letsencrypt

По умолчанию, начиная с осени 2021 года acme по умолчанию переключился на работу с сертификатами ZeroSSL. Многие мануалы писались до 2021 года и после этого изменения не потрудились эти самые мануалы обновить. Не переключив вручную на letsencrypt можно долго недоумевать почему выхлоп скрипта не соответствует мануалам.

Далее я предпочитаю использовать DNS manual mode. Во первых, у Synology грустно с DNS API - всё же это в первую очередь NAS, а не домашний хостинг. Во вторых, не хотелось бы связываться с HTTP mode из-за упомянутой выше проблемы с пробросом порта 80 прямо на конкретный контейнер.

На этом этапе acme сделала дополнительную нетривиальную проверку в виде ключа --yes-I-know-dns-manual-mode-enough-go-ahead-please, без которого acme не запускается, но чтобы понять почему надо рыть дебаг. Хотя по факту он просто подтверждает "да, я прочитал мануал". Опять же, в мануале acme это уже есть, другие мануалы не затрагивают использование wildcard-сертификатов, как результат: это можно найти, но случай частный, который нужно просто один раз запомнить.

acme.sh --issue -d *.domain.name --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please

На этом этапе необходимые сертификаты создадутся в директории докер-контейнера но их ещё нельзя использовать, потому что надо явно прописать DNS TXT запись _acme-challenge.domain.name. Ошибиться сложно, acme caм подскажет что и куда прописывать.

Пока делал описание терминал отвалился по таймауту, отсюда "блеклость".
Пока делал описание терминал отвалился по таймауту, отсюда "блеклость".

После прописывания DNS TXT выжидаем какое-то время и вызываем

acme.sh -d *.domain.name --renew --yes-I-know-dns-manual-mode-enough-go-ahead-please

Всё работает, сертификаты создаются. Но нужна автоматизация.

Автоматизация

Всё заметно упростилось с появлением встроенного решения от acme, но есть нюансы.

Для начала - нужен пользователь с административными правами. Можно использовать встроенную запись администратора, можно свою. Я рекомендую создать нового пользователя, добавить в группу Administrators, явно запретить доступ ко всем приложениям и шарам и установить запрет на смену пароля. Исключительно по причине того, что пароль указывается в конфигурационном файле acme и лучше иметь отдельного пользователя с гигантским статическим паролем, чем не забывать модифицировать файл при каждом изменении своего.

Далее, нужно остановить созданный контейнер, сходить в директорию, которую мы подключали ранее и модифицировать файл account.conf, добавив в него данные про Synology NAS.

AUTO_UPGRADE='1'
DEFAULT_ACME_SERVER='https://acme-v02.api.letsencrypt.org/directory'
# Ниже добавляем:
export SYNO_Username="acme"
export SYNO_Password="myStrongPassword"
export SYNO_Certificate="acme.sh (docker) certificate"
export SYNO_Create=1

Дополнительное уточнение по параметру export SYNO_Create=1. Я советую включать его при первичной настройке, а потом, когда сертификаты установились, отключать его от греха подальше. Включение этой опции разрешает установку новых, несуществующих сертификатов в систему, отключение же разрешает лишь продление уже существующих. Даже при условии, что на прошлом шаге при настройке контейнера созданные сертификаты уже были добавлены в систему вручную есть смысл явно перезаписывать их ещё раз уже при помощи опции deploy, потому что можно столкнуться с тем, что она положит копии сертификатов рядом с оригиналами, они задвоятся, в результате при видимости успешной работы без каких-либо ошибок через три месяца сертификаты протухнут, потому что при кажущейся идентичности обновляются не оригиналы, а клоны.

Далее сохраняем файл, заново запускаем контейнер и после в терминале вводим

acme.sh --deploy -d *.domain.name --deploy-hook synology_dsm
Если всё прошло гладко, увидим Success.
Если всё прошло гладко, увидим Success.
Сертификат успешно появился в DSM.
Сертификат успешно появился в DSM.

Продление по расписанию

Идём в Настройки -> Планировщик задач -> Создать -> Запланированная задача -> Скрипт заданный пользователем. Вместо ContainerName подставить имя созданного ранее контейнера.

docker exec ContainerName acme.sh --renew -d *.domain.name --yes-I-know-dns-manual-mode-enough-go-ahead-please

Неочевидный нюанс: стоит явно указывать, что задача должна выполняться из под root. У любого пользователя с самыми расширенными полномочиями не хватает прав на выполнение скрипта внутри конейнера, при этом система явно не генерирует ошибок, как результат решение проблемы ищется совершенно не там. Спасибо неизвестному чуваку, который на ныне умершей борде где-то в 2016 году обнаружил это нетривиальное поведение.

К слову, на любом этапе можно обратиться в поддержку Synology, которая после всестороннего изучения вопроса вынесет вердикт, что:

  1. Such option is not implemented yet.

  2. Using wildcard-certificates is allowed only with Synology .. бла-бла-бла вендор-лок.

  3. Please use ONLY Synology's options, because .. ну вы поняли.

Тем не менее, всё работает.


Мануал не претендует на оригинальность, всё можно найти в разрозненных источниках и набить кучу своих шишек, но зачем?

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


  1. NAI
    10.07.2022 23:50

    потому что надо явно прописать DNS TXT запись

    ...

    Продление по расписанию...

    Эм, я может чего-то не понял, но ключ для DNS TXT каждый раз генерируется новый. Т.е. если у acme.sh нет доступа к DNS API, то ключ надо вписывать руками и смысл расписания теряется, как и идеологии LE - автоматический выпуск сертификатов.

    Второй вопрос, более холливарный - зачем выставлять DSM напрямую в интернет? VPN\Wireguard?

    Да тот же NGINX с реверс-прокси и BasicAuth будет явно безопаснее. На нем можно и 80 порт держать отдельно для LE.


    1. Lopar Автор
      11.07.2022 02:58

      зачем выставлять DSM напрямую в интернет

      Например, я держу на нём self-hosted Bitwarden, который категорически отказывается работать без валидного https. Мой смартфон синхронизируется с ним, получает с него список контактов, отправляет туда фотоньки, вот это вот всё. Я с него музыку себе стримлю и видео. Удобно. Файл другу пошарить ссылкой, которая автоматически удалится на следующий день, или открыть кому-то upload с той же целью. Очень удобно.

      Это всё если личное применение. Если в бизнесе, то там свой коленкор. Сейчас, когда все на удалёнке есть частные случаи, когда VPN не работает (обычно необновлённые домашние станции на Win7-), а обмен файлов прямо необходим. Опять же, что-то централизованно пошарить каким-то партнёрам, к которым не приедешь VPN настраивать в их офис.

      В паре филиалов у нас видеонаблюдение на базе Synology. Всё было красиво и изолировано, пока не нарисовалось пару насяльнике, которые хотели видео со склада ИРЛ со смартфона с любой точки мира смотреть. Заворачивали видеопоток в ВПН получали страшное проседание видеопотока

      Кейсы есть. Немало.

      Да тот же NGINX с реверс-прокси и BasicAuth будет явно безопаснее.

      Встороенными средствами? Я не придумал как. Если копаться в ssh и руками что-то доколхоживать - это может взять и пропасть. Второй абзац текста об этом. Докупать и устанавливать ещё один слой железа между роутером и насом? При наличии штатных средств вроде как оверкилл.

       но ключ для DNS TXT каждый раз генерируется новый. Т.е. если у acme.sh нет доступа к DNS API, то ключ надо вписывать руками и смысл расписания теряется

      Нет, ключ нужен один раз при первой инициализации, дальше acme после успешной проверки запоминает, что всё валидно и дальше нормально делает renew. На стороне acme ключ вообще нигде ни разу не вводится. По крайней мере на тестах и на демо-развёртывании под написание этой статьи такое поведение не было обнаружено. Более того, в апреле этого года у меня был успешный renew на старой реализации acme-автопродления, который так же сгенерировал сертификаты с полуручном режиме, но обновлять TXT запись, заведённую за месяц до этого не пришлось.


      1. benipaz
        11.07.2022 08:33

        тот же докер с Nginx Proxy Manager решает проблему и с сертификатами и с self-hosted Bitwarden и с другими аппликациями с внешним доступом


      1. NAI
        11.07.2022 20:17

        Нет, ключ нужен один раз при первой инициализации, дальше acme после успешной проверки запоминает, что всё валидно и дальше нормально делает renew.

        Т.к. вы не используете DNS API, следовательно используете DNS manual mode (это в принципе и из команд видно). Если заглянуть в документацию то можно увидеть:

        На главной

        Take care, this is dns manual mode, it can not be renewed automatically. you will have to add a new txt record to your domain by your hand when you renew your cert.

        Please use dns api mode instead.

        DNS Manual Mode

        Warning: DNS manual mode can not renew automatically.

        ...

        DNS manual mode should be used for testing. If you do use it for your production server, remember to renew your certificate within 90 days.

        Вангую, что у токена есть TTL и когда вы ставили тесты он еще не успел протухнуть. А по факту через 60-90 дней получите тыкву =) как-то так.

        ---

        Про торчащий наружу DSM - вопрос был не про юз кейсы, а про зачем сервисы DSM выставлять напрямую. Разверну мысль:

        1. Пользователям удобнее использовать домены 3 уровня для доступа к сервисам, а не запоминать порты. Что удобнее набирать video.example.com, files.example.com, photos.example.com или dsm.example.com:8001, dsm.example.com:8002, dsm.example.com:8004 и держать в голове что куда ведет? А потом появится еще пять сервисов который надо будет выставить в интернет (ну там х.з. корпоративный гитлаб, веб-морду почтаря и т.д.) и вот у вас уже люди ходят со списком а-ля телефонный справочник.

        2. Безопасность. Synology конечно выпускает апдейты и они молодцы что фиксят, но их количество наводит на мысль, что не все там так хорошо и радостно. Плюс сам DSM не то что бы сильно был защищен на L7 - да, там есть про брут-форс и защиту от DDoS - но эт такое себе. Предположу, что CPU на это не заточен и уйтдет в оверхеад сразу же и те кто работают в локалке получат тормоза и недоступность сервиса. И вот как вы в DSM будете давать отлуп всяким поисковым роботам и прочим сканерам?

        3. Надеяться на то что SSL защитит от всех и вся... оптимистичненько, особенно для корпоративных данных. Кстати, сколько попугаев DSM показывает в www.ssllabs.com/?


        1. Lopar Автор
          12.07.2022 15:24

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

          Иные допущения, основанные на факте необходимости в сертификатах тоже крайне любопытны. :)

          когда вы ставили тесты он еще не успел протухнуть. А по факту через 60-90 дней получите тыкву

          90 дней это как раз крайний срок обновления сертификата. при новом обновлении TTL токена должен обновиться, нет?

          Возможно, я в корне неправ, ближайшие полгода покажут что к чему. Я либо дополню статью с явным опровеждением этого нюанса чтобы он не смущал умы, либо снесу в черновики, если окажется, что таки да, это не панацея.


          1. NAI
            13.07.2022 01:09

            90 дней это как раз крайний срок обновления сертификата. при новом обновлении TTL токена должен обновиться, нет?

            Привел же ссылки на официальное репо: DNS manual mode > Please, make sure you understand DNS manual mode > The verification is valid for 30 days

            Для лиги лени

            На этом этапе acme сделала дополнительную нетривиальную проверку в виде ключа --yes-I-know-dns-manual-mode-enough-go-ahead-please, без которого acme не запускается, но чтобы понять почему надо рыть дебаг. Хотя по факту он просто подтверждает "да, я прочитал мануал".

            Там даже написано зачем и почему этот ключ добавили. Это защита от выстрела в ногу для совсем уж упорных.

            So many users are using dns manual mode, but they don't really understand the manual mode. I'd like to add a new command parameter, something like:

            ... --yes-I-know-dns-manual-mode-enough-go-ahead-please ...

            Which forces the user to read our wiki and make sure they know they will need to manually renew the cert in 90 days.

            ...но если вы не верите официальным wiki\man\issue и хотите самостоятельно походить по граблям, ваше право.

            Хотя все что требуется это добавить 2 переменные окружения в контейнер и добавить ключ к запуску acme.sh. Пример для рег.ру (там же список поддерживаемых DNS из коробки)

            И даже проделав это все вы с вероятностью в 90% получите тыкву. Потому что DNS-ы обновляются не мгновенно. И за дефолтные 300 с. могут тупо не успеть. Чтобы этого избежать необходимо добавить:

            acme.sh --dnssleep 3600 ... ...

            Обычно, часа хватает, но по фен-шую должно быть 86400 (привет яндекс-днс, который иногда не может синхронизировать свои NSки).

            ---

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

            Да понятно, что вы используете DSM'овский реверс-прокси и замкнули вообще все на железку которая, на минуточку, - attached storage, вместо построения нормальной инфры. (как там тест с ssllabs? HTTP2 завезли? Что по сжатию? Подмену заголовков в обе стороны поддерживает? Ботов\скнеров банит?) Выбор между тем что легко и тем что правильно сделан в сторону легко. И если для дома\soho это еще простительно, то для бизнеса - не надо так, потом будет больно и плохо. Впрочем, вам с этим жить-работать - см. выше про хождение по граблям.


            1. Lopar Автор
              13.07.2022 19:17

              С одной стороны я верю мануалу, с другой оно работало где-то с ноября прошлого года. Понятия не имею почему написано, что не работает, но работало.

              Как я и сказал, время покажет. Если окажется, что таки не работает. значит надо будет осваивать написание кастомных DNS API для acme. Тоже польза.


  1. AcckiyGerman
    11.07.2022 10:32

    регулярно очищают файловую систему от неожиданных юзерскриптов, даже если они лежат в /root

    Странное поведение. Но ведь папку с файлами пользователя синоложи автоматически не очищает (это было бы совсем странное поведение для железки, которая должна эти файлы хранить)? Положить скрипт туда и запускать CRON-ом без танцев с бубном.


    1. Lopar Автор
      11.07.2022 13:46

      Признаться, когда пилил это решение, о таком подумал вскользь. Решил не связываться ради упрощения восприятия.

      Внутри DSM даже кажущиеся корневыми директории не являются таковыми по умолчанию. Если положить скрипт, например в "корневую" директорию /home, по факту окажется, что это какой-то там /volumeX/home, например. И в случае переноса папки на другой раздел, я просто захожу в настройки директории и переключаю Volume1 на Volume2, например. Под капотом происходит незаметное перемещение, но в GUI отображение не меняется ни на йоту. А вот вызываемый скрипт работать перестанет потому что путей больше не существуют.

      В случае подобного системного переноса директории для контейнера acme на другой Volume для моего решения ничего не изменится: Докер это приложение в оболочке и он сам под капотом перепишет пути, при этом для пользователя и для процессов ничего не изменится.


  1. Sta2s
    13.07.2022 00:31

    Использую Synology DDNS и DSM7.1
    subject: mycoolnas.synology.me
    alternative name:*.mycoolnas.synology.me
    Без выставления 80го голым задом в интернет и всё работает ещё с DSM6, когда wildcard поддерживался acme, но не synology.
    Простите, если что-то понял неправильно.


    1. Lopar Автор
      13.07.2022 18:41

      subject: mycoolnas.synology.me
      alternative name:*.mycoolnas.synology.me

      Вендор-лок. Вы пользуетесь DDNS от вендора и не знаете проблем. Попробуйте своё, кастомное доменное имя.