Централизованный выпуск SSL сертификатов для смохостинга

Let’s Encrypt крут, но имеет ряд ограничений

  1. 50 сертификатов в неделю и 5 дублирующих за этот же период времени (раньше вроде было меньше сертификатов)
  2. Надо настраивать выпуск везде, где он используется, причем, без DNS challenge часто обновление не работает (не как факт, а из опыта настройки не мной, буквально на днях столкнулся с подобной проблемой)

У меня дома в traefik на текущий момент уже более 58 маршрутов и они постоянно добавляются.

Не буду в данном топике расписывать свой traefik кластер, но имею следующие узлы с certbot

  1. 4 traefik ноды
  2. truenas
  3. jellyfin
  4. mikroik router
  5. Home-assitant
  6. Старый сервер с certbot и bash скриптами деплоя (я сейчас от него избавляюсь)
  7. хз, может что-то еще

Раньше был еще NPM, но с него ушел на traefik

Вопрос в чем, как правильно и удобно все еще организовать с минимальным количеством перевыпуска сертификатов?

В traefik раньше был рашинг сертификатов, но от него отказались и в 3 версии сейчас на каждой ноде свой файл (я начинал разбираться с кубером, но так и не осилил эту тему за один заход)

Вариант 1. Базовый

Забиваем на это и выпускаем где надо сертификат, надеемся, что не упремся в лимиты

Вариант 2. Скриптовый

У меня он был ранее реализован. Выпускаем wildcard сертификат и копируем его куда надо.
Смысл в том, что у нас есть один инстанс с certbot, как правило, там еще и nginx крутится и в хуках получения сертификатов мы пишем кучу скриптов, которые копируют новый сертификат на нужный хост и там его применяют, но получается, что должен быть один хост для этого, нет отказоустойчивости, но зато на баше можно написать все, что угодно, например, у меня в микротике надо его еще было перепривязывать к сервисам

Вариант 3. Кластерный

Я пытался реализовать его в traefik + consul + vrrp, но в 3 версии traefik это убрали по причин проблем во 2 версии.
Смысл в том, что сертификаты хранятся в распределенной БД и выпускает его один узел, который успел залочить базу, далее он обновляет сертификат и снимает блокировку, остальные узлы подтягивают

Мне такой вариант понравился для traefik т.к. у меня дома реверс прокси работает при наличии хотя бы одного работающего узла proxmox, но при этом по мере увеличения количества узлов надежность увеличивается + сетевой трафик снижается (если интересно, то могу расписать схему)

Вариант 4. Распределенная БД

Для для traefik использовал consul, Proxmox использует corosync.
Суть в том, чтобы поднять некую распределенную ФС, которая бы синхронизировала каталоги во всех системах, а обновление было на одной или двух.

Грубо говоря, на certbot-node вызываем certbot certonly --standalone -d *.domain.com, а на остальных нодах имеем /etc/letsencrypt уже с сертификатом

Но тут надо понимать, что не все системы смогут корректно работать, proxmox, truenas и прочие можно просто настроить через веб интерфейс и они будут сами выпускать сертификаты

Вариант 4. Полукластерный, полускриптовый

Что-то типа k8s
Поднимаем ноду с certbot, она выпускает сертификаты и складывает их в vault, а сторонние узлы вытягивают из волта
Но тут надо понимать, что

  1. Надо подружить с волтом эти системы
  2. Надо отслеживать обновление сертификата

Вариант 5. Ansible

Это как развитие 2 варианта, выпускаем сертификат и дергаем ansible, а можно в самом ansible выпускать
Например, я пользую Semaphore UI для запуска плейбуков, там можно добавить запуск по расписанию, а в GIT сложить плейбук, который будет деплоить сертификаты на узлы

Можно еще вариант 5.1 преложить с волтом, когда сам сертификат остается в волте, а ansible его оттуда стягивает на хост

А какие еще есть варианты и что выбрать?

Про безопасность

Ну и не забываем про безопасность, для хомлабы не столь критично, но при утере wildcard сертификата злоумышленник получает возможность скомпрометировать любой домен

1 лайк

В общем, сам спросил, сам и отвечаю, при помощи GPT и какой-то матери:

  1. Поднял менеджер секретов. После изучения решил остановиться на OpenBao - не очень дружественный, но зато очень функциональный и легкий + форк hashicorp vault, а это значит, что совместим с промышленным эталоном (Кстати, это единственный менеджер секретов, который умеет OIDC в бесплатной версии)
  2. В kv хранилище волта добавил ключ для cloudflare, чтобы проходить acme проверку по DNS (требуется для wildcard сертификатов)
  3. Поднял vault-agent, который из волта получает cloudflare_api_token складывает его в /secrets/cloudlare_token
  4. Собрал контейнер с openbao и lego, написал немного скриптов на баше, которые
    4.1. Получают wildcard сертификаты letsencrypt и загружают их в волт в kv хранилище по пути kv/certs/<domain> (в openbao есть pki хранилище, но, насколько я понял, оно не очень походит для LE)
    4.2. Запускают крон, который раз в сутки проверяет дату действия сертификатов и обновляет при необходимости
    4.3. При обновлении сертификатов вызывает webhook в semaphore UI
  5. Поскольку openbao требует тоже сертификаты (в production режиме), то собрал отдельный контейнер openbao-docker
    5.1. На основе openbao + docker-cli + пользователь и права для доступа к docker.sock
    5.2. Рядом с openbao поднял vault-agent, который подписывается на сертификаты в openbao и стягивает их в файлы, если сертификат обновлен, то вызывает docker exec openbao kill -HUP 1 что приводит к перечитыванию сертификатов самими openbao
  6. В нужных сервисах поднимаю vault-agent для получения сертификатов и прописывания их в нужные места
  7. Завел репу ansible_cert_deploy и прописал ее в Semaphore UI, завел таску и триггер ее из пункта 4.3.
  8. Пока еще не начал писать плейбуки, но идея в том, чтобы через ansible деплоить сертификаты туда, где не поддерживается vault-agent, например Mikrotik (но в последних версиях, насколько я знаю, уже есть полноценная поддержка certbot)

В итоге вместо кучи tls сертификатов с ограничением по количеству вызовов API LetsEncrypt в неделю у меня один сервис получает сертификаты для домена и всех его поддоменов и все остальные сервисы могут получить доступ к нему + автоатически подтягивать новый сервтификат при перевыпуске, тот же traefik вместо выпуска сертификата для каждого сервиса использует один из предварительно подготовленых, а поскольку у меня 4 инстанса с traefik, то они используют общий сертификат из волта, а не выпускают каждый для себя.

Ну и немного скринов:
Как выглядит сертификат в openbao

docker-compose сервиса, который получает и загружает сертификаты в openbao

Кусок конфига, который сохраняет файлы сертификата и обновляет openbao при изменении сертификата

“суперсложный” скрипт, который получает или обновляет сертификаты

Самое сложное тут было завернуть все в docker-entrypoint.sh так, чтобы

  1. Переменные окружения со списком доменов были доступны во всех скриптах
  2. Все работало в рамках одного основного процесса
  3. Крон выводил stdout скрипта в консоль докера, а не пытался отправить sendmail
5 лайков

Если нет задачи давать доступ снаружи, то можно поднять свой lets encypt :wink:. Только надо будет распространить корневой сертификат среди всех своих домочадцев и сервисов. На линуксы и винды в принципе проблем с этим нет, как обстоят дела в аппле - не знаю, а вот с андроидом придётся повоевать.

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

В общем я поднял step-ca и натравил на него траефик. В итоге про ручной выпуск и перевыпуск я забыл.

P.S.: Step-CA Certificate Authority Overview | Smallstep

1 лайк

Я для .lan домена поднял в тестовом режиме openbao PKI хранилище с подобным функционалом, но еще и с веб версией, отказоустойчивым кластером и упором на безопасность.
В целом да, самоподписные сертификаты являются одним из решений, но в моем случае это публичный доступ и 30-50 узлов для добавления корневого сертификата, частично это можно закрыть при помощи ansible, конечно

поддержу, для homelab - Small step