
Всем привет!
В этой статье я опишу как мы решали проблему централизованного обновления сертификатов Let's Encrypt и управления инфраструктурой с помощью ansible.
В нашем решении мы будем использовать:
- ansible
- rsync, rsyncd
- inotify, incron
- certbot
- nginx
Я предложу два варианта архитектуры, при которой наше решение может быть полезным. В свою очередь вы можете в комментариях предложить свои варианты.
Вариант 1: У вас есть несколько frontend серверов с public ip (к примеру 3), обслуживающих несколько доменов. Эти домены могут добавляться/удаляться. Чтобы не следить за каждым из frontend серверов — удобнее это сделать на одном letsencrypt server'е:

Вариант 2: У вас есть только один сервер с public ip, а сертификаты вам нужны на серверах внутри сети:

Описание ролей ansible
Репозиторий с ролями доступны по ссылке.
В репозитории находится 4 роли:
- nginx-simple
Устанавливает на все хостыnginxи копирует базовые конфиги. Сама по себе роль не запускается из playbook. Она запускается по meta зависимости из других ролей. - letsencrypt-server
Настраиваетrsyncdна хостеletsencrypt server. В meta зависимостях имеет рольnginx-simple. Соответственно, сначала установитсяnginx, а потом проиграется рольletsencrypt server. - incron
Устанавливает необходимые пакеты дляincronи скопирует базовый конфиг. Роль так же не запускается на прямую как иnginx-simple. - front
В meta зависимостях имеет ролиincronиnginx-simple. После них рольfrontкопирует необходимые для example.com конфигиnginx, добавляет задачу вcronзабирать новые сертификаты сletsencrypt serverи задачу вincronпроверять изменения файлов и выполнять хукnginx -s reload
Перейдем к практике:
Исходная конфигурация
Изначально у нас имеются:
- 1 сервер для централизованного выписывания SSL сертификата (
letsencrypt server) - 1 или более публично доступных серверов с nginx (
front)
На всех серверах установлена Ubuntu 16.04.
Установка и настройка nginx
Для начала установим на все хосты nginx из общей роли nginx-simple и раскидаем общие для всех хостов конфиги nginx (nginx.conf, параметры ssl, пути к сертификатам, etc).
Для letsencrypt server'а в шаблоне .../site-available/default.conf папка .well_known будет находиться в /var/www/:
{% if letsencrypt_server %}
location /.well-known {
root /var/www/;
}
Для сервера/серверов группы front, так как папка .well_known используется не только для получения сертификатов, но и для другого ПО, мы импортируем в конфиг example.conf letsencrypt-proxy.conf и nginx будет искать папку локально на сервере front, используя дерективу try_file:
{% if nginx_proxy_well_known %}
try_files $uri $uri/ @letsencrypt;
{% endif %}
Конфиги для домена заполнятся в зависимости от переменных из inventory. В репозитории это домен example.com
Так же, в зависимости от переменной letsencrypt_server, роль nginx-simple установит на letsencrypt server certbot и добавит cron task на обновление сертификатов.
Получение сертификата
Так как мы решали эту задачу до появления wildcard сертификата от Let's Encrypt, мы рассмотрим оба варианта получения сертификата.
На сервере letsencrypt server выполняем:
certbot certonly --agree-tos -d example.ru --webroot -w /var/www/
Если доменов больше одного — дописываем последующие, используя ключ -d.
Для получения wildcard сертификата нам нужно будет добавить в DNS TXT записи. На текущий момент это единственный вариант получения такого сертификата:
certbot certonly --agree-tos -d example.ru -d *.example.ru --preferred-challenges dns --manual --server https://acme-v02.api.letsencrypt.org/directory
Certbot напишет какие TXT записи вам нужно будет добавить.
Обновление сертификатов
Сертификаты мы получили, осталось настроить копирование их на front сервер/сервера. Для этого мы настроим rsyncd на сервере letsencrypt с правами на чтение для ограниченого списка ip адресов:
hosts allow = {{ hosts_allow }}
hosts deny = *
list = true
use chroot = no
[cert]
path = /etc/letsencrypt/live/
uid = root
gid = root
read only = true
Каждые 5 минут cron task с серверов front будет проверять обновились ли сертификаты и забирать их. Т.к. сертификаты ротируются, в папке /etc/letsencrypt/live/{{ domain }} лежат симлинки. Добавим ключ -L чтобы вытаскивать оригиналы файлов:
/usr/bin/rsync -zavL --chmod=D0750,F640 --delete rsync://{{ hostvars['letsencrypt-server'].ansible_eth0.ipv4.address }}/cert /etc/letsencrypt/live/
Хук для nginx
Мы настроили nginx, получили сертификаты, забрали их на front сервер. Осталось определить, что файлы в папке /etc/letsencrypt/live/{{ domain }} изменились и выполнить хук nginx -s reload
В этом нам поможет подсистема ядра linux inotify и демон incron. Подробнее о них можно прочесть тут.
Роль incron установит нужные пакеты, а из шаблона роли front добавится задача на мониторинг сертификатов и нужный хук:
/etc/letsencrypt/live/{{ domain }}/ IN_CREATE,IN_DELETE,IN_MODIFY,IN_MOVED_TO nginx -s reload
В заключение
Мы постарались подробно описать весь процесс установки и настройки, а т.к. все описано в плейбуках ansible — статья получилась очень компактной. Как любят часто говорить — "чуть больше 100 строчек кода". На вопросы, критику и замечания с удовольствием ответим в комментариях.
Автор: Asten
